From d444d5cd2f5f203ce4afe7135bf2ebbb1f885b77 Mon Sep 17 00:00:00 2001 From: Dongjie He Date: Mon, 26 Dec 2022 21:10:58 +1100 Subject: [PATCH 001/145] add sootup.qilin --- pom.xml | 1 + .../java/sootup/core/types/ArrayType.java | 8 + .../BytecodeBodyInterceptors.java | 26 +- sootup.qilin/.DS_Store | Bin 0 -> 6148 bytes sootup.qilin/pom.xml | 89 ++ sootup.qilin/src/.DS_Store | Bin 0 -> 6148 bytes sootup.qilin/src/main/.DS_Store | Bin 0 -> 6148 bytes sootup.qilin/src/main/java/.DS_Store | Bin 0 -> 6148 bytes .../src/main/java/driver/ContextKind.java | 59 ++ sootup.qilin/src/main/java/driver/Main.java | 73 ++ .../src/main/java/driver/PTAComparator.java | 156 ++++ .../src/main/java/driver/PTAFactory.java | 151 +++ .../src/main/java/driver/PTAOption.java | 201 ++++ .../src/main/java/driver/PTAPattern.java | 221 +++++ sootup.qilin/src/main/java/qilin/.DS_Store | Bin 0 -> 6148 bytes .../src/main/java/qilin/CoreConfig.java | 176 ++++ .../java/qilin/core/ArtificialMethod.java | 180 ++++ .../src/main/java/qilin/core/CorePTA.java | 121 +++ .../src/main/java/qilin/core/PTA.java | 258 ++++++ .../src/main/java/qilin/core/PTAScene.java | 221 +++++ .../java/qilin/core/PointsToAnalysis.java | 83 ++ .../main/java/qilin/core/VirtualCalls.java | 212 +++++ .../qilin/core/builder/CallGraphBuilder.java | 266 ++++++ .../qilin/core/builder/ExceptionHandler.java | 102 +++ .../qilin/core/builder/FakeMainFactory.java | 152 ++++ .../qilin/core/builder/MethodNodeFactory.java | 339 +++++++ .../main/java/qilin/core/context/Context.java | 4 + .../qilin/core/context/ContextElement.java | 27 + .../qilin/core/context/ContextElements.java | 125 +++ .../core/context/TypeContextElement.java | 85 ++ .../JavaIoFileSystemGetFileSystemNative.java | 42 + .../natives/JavaIoFileSystemListNative.java | 42 + .../natives/JavaLangObjectCloneNative.java | 39 + ...efFinalizerInvokeFinalizeMethodNative.java | 36 + .../core/natives/JavaLangReflectArrayGet.java | 43 + .../core/natives/JavaLangReflectArraySet.java | 42 + .../JavaLangSystemArraycopyNative.java | 50 + .../natives/JavaLangSystemSetErr0Native.java | 40 + .../natives/JavaLangSystemSetIn0Native.java | 40 + .../natives/JavaLangSystemSetOut0Native.java | 40 + .../natives/JavaLangThreadCurrentThread.java | 38 + .../natives/JavaLangThreadStart0Native.java | 45 + ...ityAccessControllerDoPrivilegedNative.java | 39 + ...ontrollerDoPrivileged_ExceptionNative.java | 40 + .../java/qilin/core/natives/NativeMethod.java | 38 + .../core/natives/NativeMethodDriver.java | 84 ++ .../java/qilin/core/natives/package-info.java | 7 + .../main/java/qilin/core/pag/AllocNode.java | 76 ++ .../java/qilin/core/pag/ArrayElement.java | 55 ++ .../main/java/qilin/core/pag/CallSite.java | 68 ++ .../qilin/core/pag/ClassConstantNode.java | 41 + .../java/qilin/core/pag/ConstantNode.java | 29 + .../java/qilin/core/pag/ContextAllocNode.java | 47 + .../java/qilin/core/pag/ContextField.java | 86 ++ .../java/qilin/core/pag/ContextMethod.java | 56 ++ .../java/qilin/core/pag/ContextVarNode.java | 58 ++ .../qilin/core/pag/ExceptionThrowSite.java | 60 ++ .../src/main/java/qilin/core/pag/Field.java | 74 ++ .../java/qilin/core/pag/FieldRefNode.java | 58 ++ .../java/qilin/core/pag/FieldValNode.java | 36 + .../java/qilin/core/pag/GlobalVarNode.java | 54 ++ .../java/qilin/core/pag/LocalVarNode.java | 58 ++ .../java/qilin/core/pag/MergedNewExpr.java | 20 + .../main/java/qilin/core/pag/MethodPAG.java | 202 +++++ .../src/main/java/qilin/core/pag/Node.java | 72 ++ .../src/main/java/qilin/core/pag/PAG.java | 622 +++++++++++++ .../src/main/java/qilin/core/pag/Parm.java | 94 ++ .../main/java/qilin/core/pag/SparkField.java | 8 + .../qilin/core/pag/StringConstantNode.java | 41 + .../src/main/java/qilin/core/pag/ValNode.java | 59 ++ .../src/main/java/qilin/core/pag/VarNode.java | 126 +++ .../java/qilin/core/pag/VirtualCallSite.java | 83 ++ .../java/qilin/core/pag/package-info.java | 7 + .../core/reflection/NopReflectionModel.java | 77 ++ .../qilin/core/reflection/ReflectionKind.java | 39 + .../core/reflection/ReflectionModel.java | 104 +++ .../qilin/core/reflection/TamiflexModel.java | 428 +++++++++ .../qilin/core/sets/DoublePointsToSet.java | 155 ++++ .../qilin/core/sets/HybridPointsToSet.java | 198 ++++ .../java/qilin/core/sets/P2SetVisitor.java | 48 + .../java/qilin/core/sets/PointsToSet.java | 98 ++ .../qilin/core/sets/PointsToSetInternal.java | 64 ++ .../core/sets/UnmodifiablePointsToSet.java | 198 ++++ .../java/qilin/core/sets/package-info.java | 6 + .../java/qilin/core/solver/Propagator.java | 32 + .../main/java/qilin/core/solver/Solver.java | 322 +++++++ .../java/qilin/core/util/ArrayNumberer.java | 155 ++++ .../java/qilin/core/util/BitSetIterator.java | 92 ++ .../main/java/qilin/core/util/BitVector.java | 463 ++++++++++ .../qilin/core/util/IterableNumberer.java | 14 + .../main/java/qilin/core/util/Numberable.java | 6 + .../main/java/qilin/core/util/Numberer.java | 53 ++ .../parm/ctxcons/CallsiteCtxConstructor.java | 43 + .../qilin/parm/ctxcons/CtxConstructor.java | 33 + .../parm/ctxcons/HybObjCtxConstructor.java | 69 ++ .../parm/ctxcons/HybTypeCtxConstructor.java | 60 ++ .../parm/ctxcons/InsensCtxConstructor.java | 33 + .../qilin/parm/ctxcons/ObjCtxConstructor.java | 48 + .../parm/ctxcons/TypeCtxConstructor.java | 51 ++ .../parm/heapabst/AllocSiteAbstractor.java | 28 + .../qilin/parm/heapabst/HeapAbstractor.java | 25 + .../parm/heapabst/HeuristicAbstractor.java | 50 + .../parm/heapabst/MahjongAbstractor.java | 57 ++ .../java/qilin/parm/select/BeanSelector.java | 86 ++ .../java/qilin/parm/select/CtxSelector.java | 52 ++ .../qilin/parm/select/DebloatingSelector.java | 62 ++ .../parm/select/FullMethodLvSelector.java | 62 ++ .../qilin/parm/select/HeuristicSelector.java | 53 ++ .../java/qilin/parm/select/InsenSelector.java | 48 + .../parm/select/PartialMethodLvSelector.java | 75 ++ .../qilin/parm/select/PartialVarSelector.java | 82 ++ .../qilin/parm/select/PipelineSelector.java | 58 ++ .../qilin/parm/select/UniformSelector.java | 55 ++ .../java/qilin/parm/select/VarLvSelector.java | 69 ++ .../src/main/java/qilin/pta/PTAConfig.java | 74 ++ .../src/main/java/qilin/pta/StagedPTA.java | 31 + .../java/qilin/pta/toolkits/bean/Bean.java | 77 ++ .../pta/toolkits/bean/ContextSelector.java | 65 ++ .../bean/RepresentativeContextSelector.java | 122 +++ .../java/qilin/pta/toolkits/bean/gpl-3.0.txt | 674 ++++++++++++++ .../toolkits/common/FieldPointstoGraph.java | 106 +++ .../java/qilin/pta/toolkits/common/OAG.java | 151 +++ .../qilin/pta/toolkits/common/ToolUtil.java | 83 ++ .../pta/toolkits/conch/AbstractConch.java | 225 +++++ .../qilin/pta/toolkits/conch/AbstractPAG.java | 223 +++++ .../java/qilin/pta/toolkits/conch/CSDG.java | 63 ++ .../java/qilin/pta/toolkits/conch/Conch.java | 398 ++++++++ .../java/qilin/pta/toolkits/conch/DFA.java | 83 ++ .../toolkits/conch/DepOnParamAnalysis.java | 159 ++++ .../pta/toolkits/conch/LeakAnalysis.java | 218 +++++ .../qilin/pta/toolkits/conch/PathEdge.java | 102 +++ .../java/qilin/pta/toolkits/conch/SMPAG.java | 105 +++ .../qilin/pta/toolkits/conch/TranEdge.java | 70 ++ .../qilin/pta/toolkits/conch/Trilean.java | 33 + .../dd/CtxTunnelingFeaturesTrueTable.java | 203 +++++ .../pta/toolkits/dd/DataDrivenSelector.java | 95 ++ .../pta/toolkits/dd/FeaturesTrueTable.java | 139 +++ .../pta/toolkits/dd/TunnelingConstructor.java | 68 ++ .../pta/toolkits/dd/data-driven/README.md | 5 + .../qilin/pta/toolkits/dd/tunneling/README.md | 5 + .../java/qilin/pta/toolkits/eagle/BNode.java | 62 ++ .../java/qilin/pta/toolkits/eagle/Eagle.java | 381 ++++++++ .../pta/toolkits/mahjong/HeapAbstraction.java | 136 +++ .../qilin/pta/toolkits/mahjong/Mahjong.java | 68 ++ .../pta/toolkits/mahjong/automata/DFA.java | 74 ++ .../automata/DFAEquivalenceChecker.java | 105 +++ .../toolkits/mahjong/automata/DFAFactory.java | 102 +++ .../toolkits/mahjong/automata/DFAState.java | 91 ++ .../pta/toolkits/mahjong/automata/NFA.java | 88 ++ .../qilin/pta/toolkits/mahjong/gpl-3.0.txt | 674 ++++++++++++++ .../qilin/pta/toolkits/selectx/BNode.java | 60 ++ .../java/qilin/pta/toolkits/selectx/G.java | 59 ++ .../java/qilin/pta/toolkits/selectx/I.java | 64 ++ .../java/qilin/pta/toolkits/selectx/L.java | 107 +++ .../java/qilin/pta/toolkits/selectx/O.java | 36 + .../qilin/pta/toolkits/selectx/Selectx.java | 321 +++++++ .../pta/toolkits/turner/AbstractMVFG.java | 294 ++++++ .../java/qilin/pta/toolkits/turner/DFA.java | 58 ++ .../toolkits/turner/MethodLevelCallGraph.java | 69 ++ .../qilin/pta/toolkits/turner/MethodVFG.java | 45 + .../pta/toolkits/turner/ModularMVFG.java | 96 ++ .../java/qilin/pta/toolkits/turner/OCG.java | 261 ++++++ .../qilin/pta/toolkits/turner/TranEdge.java | 60 ++ .../qilin/pta/toolkits/turner/Turner.java | 232 +++++ .../qilin/pta/toolkits/zipper/Global.java | 87 ++ .../java/qilin/pta/toolkits/zipper/Main.java | 59 ++ .../java/qilin/pta/toolkits/zipper/ReadMe.txt | 6 + .../analysis/PotentialContextElement.java | 184 ++++ .../pta/toolkits/zipper/analysis/Zipper.java | 312 +++++++ .../pta/toolkits/zipper/cases/CaseA.java | 19 + .../pta/toolkits/zipper/cases/CaseB.java | 25 + .../pta/toolkits/zipper/cases/CaseC.java | 35 + .../pta/toolkits/zipper/cases/CaseD.java | 21 + .../pta/toolkits/zipper/flowgraph/Edge.java | 59 ++ .../zipper/flowgraph/FlowAnalysis.java | 269 ++++++ .../zipper/flowgraph/IObjectFlowGraph.java | 11 + .../pta/toolkits/zipper/flowgraph/Kind.java | 10 + .../zipper/flowgraph/ObjectFlowGraph.java | 124 +++ .../java/qilin/pta/toolkits/zipper/mit.txt | 24 + .../main/java/qilin/pta/tools/BasePTA.java | 65 ++ .../main/java/qilin/pta/tools/BeanPTA.java | 72 ++ .../java/qilin/pta/tools/CallSiteSensPTA.java | 51 ++ .../java/qilin/pta/tools/DataDrivenPTA.java | 56 ++ .../java/qilin/pta/tools/DebloatedPTA.java | 163 ++++ .../main/java/qilin/pta/tools/EaglePTA.java | 122 +++ .../qilin/pta/tools/HybridObjectSensPTA.java | 51 ++ .../qilin/pta/tools/HybridTypeSensPTA.java | 51 ++ .../main/java/qilin/pta/tools/MahjongPTA.java | 77 ++ .../java/qilin/pta/tools/ObjectSensPTA.java | 50 + .../pta/tools/PartialCallSiteSensPTA.java | 192 ++++ .../qilin/pta/tools/PartialObjSensPTA.java | 194 ++++ .../main/java/qilin/pta/tools/SelectxPTA.java | 48 + .../src/main/java/qilin/pta/tools/Spark.java | 41 + .../java/qilin/pta/tools/TunnelingPTA.java | 52 ++ .../main/java/qilin/pta/tools/TurnerPTA.java | 42 + .../java/qilin/pta/tools/TypeSensPTA.java | 50 + .../main/java/qilin/pta/tools/ZipperPTA.java | 159 ++++ .../main/java/qilin/stat/AbstractStat.java | 23 + .../main/java/qilin/stat/BenchmarkStat.java | 73 ++ .../main/java/qilin/stat/CallGraphStat.java | 198 ++++ .../src/main/java/qilin/stat/Exporter.java | 296 ++++++ .../src/main/java/qilin/stat/IEvaluator.java | 9 + .../src/main/java/qilin/stat/PAGStat.java | 80 ++ .../main/java/qilin/stat/PTAEvaluator.java | 113 +++ .../main/java/qilin/stat/PointsToStat.java | 293 ++++++ .../src/main/java/qilin/stat/RuntimeStat.java | 40 + .../java/qilin/stat/SimplifiedEvaluator.java | 183 ++++ .../main/java/qilin/stat/TypeClientStat.java | 155 ++++ .../src/main/java/qilin/stat/YummyStat.java | 104 +++ .../src/main/java/qilin/util/ANSIColor.java | 37 + .../src/main/java/qilin/util/DataFactory.java | 35 + .../main/java/qilin/util/MemoryWatcher.java | 79 ++ .../src/main/java/qilin/util/PTAUtils.java | 856 ++++++++++++++++++ .../src/main/java/qilin/util/Pair.java | 59 ++ .../src/main/java/qilin/util/Stopwatch.java | 71 ++ .../src/main/java/qilin/util/Triple.java | 65 ++ .../main/java/qilin/util/UnionFindSet.java | 93 ++ .../src/main/java/qilin/util/Util.java | 92 ++ .../java/qilin/util/collect/SetFactory.java | 38 + .../graph/ConcurrentDirectedGraphImpl.java | 63 ++ .../java/qilin/util/graph/DirectedGraph.java | 55 ++ .../qilin/util/graph/DirectedGraphImpl.java | 59 ++ .../java/qilin/util/graph/MergedNode.java | 65 ++ .../java/qilin/util/graph/Reachability.java | 76 ++ .../java/qilin/util/graph/SCCMergedGraph.java | 68 ++ .../graph/StronglyConnectedComponents.java | 102 +++ .../qilin/util/graph/TopologicalSorter.java | 66 ++ .../src/main/java/qilin/util/graph/Tree.java | 37 + .../main/java/qilin/util/graph/TreeImpl.java | 93 ++ .../main/java/qilin/util/graph/TreeNode.java | 61 ++ .../src/main/java/qilin/util/package.html | 27 + .../java/qilin/util/queue/ChunkedQueue.java | 98 ++ .../java/qilin/util/queue/QueueReader.java | 194 ++++ .../java/qilin/util/queue/UniqueQueue.java | 137 +++ .../main/java/qilin/util/queue/package.html | 27 + 235 files changed, 24090 insertions(+), 13 deletions(-) create mode 100644 sootup.qilin/.DS_Store create mode 100644 sootup.qilin/pom.xml create mode 100644 sootup.qilin/src/.DS_Store create mode 100644 sootup.qilin/src/main/.DS_Store create mode 100644 sootup.qilin/src/main/java/.DS_Store create mode 100644 sootup.qilin/src/main/java/driver/ContextKind.java create mode 100644 sootup.qilin/src/main/java/driver/Main.java create mode 100644 sootup.qilin/src/main/java/driver/PTAComparator.java create mode 100644 sootup.qilin/src/main/java/driver/PTAFactory.java create mode 100644 sootup.qilin/src/main/java/driver/PTAOption.java create mode 100644 sootup.qilin/src/main/java/driver/PTAPattern.java create mode 100644 sootup.qilin/src/main/java/qilin/.DS_Store create mode 100644 sootup.qilin/src/main/java/qilin/CoreConfig.java create mode 100644 sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java create mode 100644 sootup.qilin/src/main/java/qilin/core/CorePTA.java create mode 100644 sootup.qilin/src/main/java/qilin/core/PTA.java create mode 100644 sootup.qilin/src/main/java/qilin/core/PTAScene.java create mode 100644 sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java create mode 100644 sootup.qilin/src/main/java/qilin/core/VirtualCalls.java create mode 100644 sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java create mode 100644 sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java create mode 100644 sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java create mode 100644 sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java create mode 100644 sootup.qilin/src/main/java/qilin/core/context/Context.java create mode 100644 sootup.qilin/src/main/java/qilin/core/context/ContextElement.java create mode 100644 sootup.qilin/src/main/java/qilin/core/context/ContextElements.java create mode 100644 sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java create mode 100644 sootup.qilin/src/main/java/qilin/core/natives/package-info.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/CallSite.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ContextField.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/Field.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/Node.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/PAG.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/Parm.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/SparkField.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/ValNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/VarNode.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/package-info.java create mode 100644 sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java create mode 100644 sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java create mode 100644 sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java create mode 100644 sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java create mode 100644 sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java create mode 100644 sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java create mode 100644 sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java create mode 100644 sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java create mode 100644 sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java create mode 100644 sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java create mode 100644 sootup.qilin/src/main/java/qilin/core/sets/package-info.java create mode 100644 sootup.qilin/src/main/java/qilin/core/solver/Propagator.java create mode 100644 sootup.qilin/src/main/java/qilin/core/solver/Solver.java create mode 100644 sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java create mode 100644 sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java create mode 100644 sootup.qilin/src/main/java/qilin/core/util/BitVector.java create mode 100644 sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java create mode 100644 sootup.qilin/src/main/java/qilin/core/util/Numberable.java create mode 100644 sootup.qilin/src/main/java/qilin/core/util/Numberer.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/PTAConfig.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/StagedPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/bean/gpl-3.0.txt create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/dd/data-driven/README.md create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/dd/tunneling/README.md create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/gpl-3.0.txt create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/ReadMe.txt create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/mit.txt create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/Spark.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/AbstractStat.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/Exporter.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/IEvaluator.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/PAGStat.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/PointsToStat.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/YummyStat.java create mode 100644 sootup.qilin/src/main/java/qilin/util/ANSIColor.java create mode 100644 sootup.qilin/src/main/java/qilin/util/DataFactory.java create mode 100644 sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java create mode 100644 sootup.qilin/src/main/java/qilin/util/PTAUtils.java create mode 100644 sootup.qilin/src/main/java/qilin/util/Pair.java create mode 100644 sootup.qilin/src/main/java/qilin/util/Stopwatch.java create mode 100644 sootup.qilin/src/main/java/qilin/util/Triple.java create mode 100644 sootup.qilin/src/main/java/qilin/util/UnionFindSet.java create mode 100644 sootup.qilin/src/main/java/qilin/util/Util.java create mode 100644 sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/Reachability.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/Tree.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java create mode 100644 sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java create mode 100644 sootup.qilin/src/main/java/qilin/util/package.html create mode 100644 sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java create mode 100644 sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java create mode 100644 sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java create mode 100644 sootup.qilin/src/main/java/qilin/util/queue/package.html diff --git a/pom.xml b/pom.xml index 5831a1da1c8..ebb4b6f33f0 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,7 @@ sootup.analysis sootup.examples sootup.report + sootup.qilin diff --git a/sootup.core/src/main/java/sootup/core/types/ArrayType.java b/sootup.core/src/main/java/sootup/core/types/ArrayType.java index c0b78ecfe19..d2f380acab8 100644 --- a/sootup.core/src/main/java/sootup/core/types/ArrayType.java +++ b/sootup.core/src/main/java/sootup/core/types/ArrayType.java @@ -84,6 +84,14 @@ public int getDimension() { return dimension; } + public Type getArrayElementType() { + if (dimension > 1) { + return new ArrayType(baseType, dimension - 1); + } else { + return baseType; + } + } + @Override public void accept(@Nonnull TypeVisitor v) { v.caseArrayType(); diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/BytecodeBodyInterceptors.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/BytecodeBodyInterceptors.java index 5604d3e7301..9343123051e 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/BytecodeBodyInterceptors.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/BytecodeBodyInterceptors.java @@ -29,19 +29,19 @@ /** Built-in sets of {@link BodyInterceptor}s for the bytecode frontend */ public enum BytecodeBodyInterceptors { Default( - // new CastAndReturnInliner(), - // new DuplicateCatchAllTrapRemover(), - // new UnreachableCodeEliminator(), - // // new LocalSplitter(), - // new Aggregator(), - // //new UnusedLocalEliminator(), - // new TypeAssigner(), - // new LocalNameStandardizer(), - // new CopyPropagator(), - // new DeadAssignmentEliminator(), - // new NopEliminator(), - // new ConditionalBranchFolder(), - // new EmptySwitchEliminator()); + new CastAndReturnInliner(), +// new DuplicateCatchAllTrapRemover(), + new UnreachableCodeEliminator(), + new LocalSplitter(), + new Aggregator(), + new UnusedLocalEliminator(), + new TypeAssigner(), + new LocalNameStandardizer(), + new CopyPropagator(), + new DeadAssignmentEliminator(), + new NopEliminator(), + new ConditionalBranchFolder(), + new EmptySwitchEliminator() ); @Nonnull private final List bodyInterceptors; diff --git a/sootup.qilin/.DS_Store b/sootup.qilin/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..845106103b9852232a6cf03b52fbc3414521b8bc GIT binary patch literal 6148 zcmeHK!AiqG5S?wSO%b67g&r5Y7Hw4&@e-pRyc*GiN^NY>V9b^#wL&T6tRLgmFY$MD zW_MdGtyi%!1G8^-b|%Tb4LiF4AiQ3y4p0UF2bC~a!e)lhIO&w+tfzn|^fR8}5u%ew z-3HNAG&}wx1GIKU=zzkNTZeD!rveTX4*@w|0iZlC!$D zv47flh#q70qGtsH|6nc47Dw=khMn`1-;E;`-=Sv|J&Iyv2ABb6V4fJTdziB{PankT=~j)&Jw4@BfoY++zlqfq%t- zC>;4m9!|;D)~U%+t(B-Zs3a7Z862mep-VBwQYo&WYC*pw1JSjZ8AJ~X9|SZF+%N;b G%D@+tIbiDm literal 0 HcmV?d00001 diff --git a/sootup.qilin/pom.xml b/sootup.qilin/pom.xml new file mode 100644 index 00000000000..632ca28c9e7 --- /dev/null +++ b/sootup.qilin/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + SootUp Qilin + sootup.qilin + + + org.soot-oss + sootup + 1.0.0-SNAPSHOT + + + + + org.soot-oss + sootup.core + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.java.core + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.java.bytecode + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.java.sourcecode + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.callgraph + 1.0.0-SNAPSHOT + + + + commons-cli + commons-cli + 1.5.0 + + + + com.github.oshi + oshi-core + 6.4.0 + + + + + + + org.soot-oss + sootup.java.sourcecode + 1.0.0-SNAPSHOT + pom + import + + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + + true + + + + org.apache.maven.plugins + maven-compiler-plugin + + 16 + 16 + + + + + + \ No newline at end of file diff --git a/sootup.qilin/src/.DS_Store b/sootup.qilin/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c9420b0e9741716ca50e4983e426769cb8cc943d GIT binary patch literal 6148 zcmeHKy-ve05I(norb0*^KV31rZ@eO-hEUQf7D@iEpQ>12 zci2_C+N;&aQG@)3}G?{p~JD?HU5Q0 z9S%axjN_P@g~?EaNj!w3+(Eb+xnu^Ifwv5lb+bnI|IXL>|JxvLF$2uNzhXdGUBBz$ zlFZ%uVR3ZVI;f|pB;;3UoQ7aUUB&22S8*Lx3ECa1Ai4$%jc7sPhk&Ai3ufR)8F&UZ CU|@#; literal 0 HcmV?d00001 diff --git a/sootup.qilin/src/main/.DS_Store b/sootup.qilin/src/main/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..242a4d504888332fae1a774fc94a5830141029bf GIT binary patch literal 6148 zcmeHK%}T>S5Z-O0O(;SS3OxqA7VVEz#7m6z;MIs8RBB?2Mq^f*v^kVQ&iX<=iLawG zyPJYmPl8C9f!S{}JF{WF4Lcde7dz0>K=W|q0JxxIhVe~2Dq@vNxl@Lft-(^$X@ zOy>Dayipv9_!ex1f8j?+3=jjvz%nwR?>e)(jLA_>!~ikyD+cg>ut506H3TgS5T31Rn<_#N3Oz1(E!tM8h?iLP;MIs8RBB_224l9Se}_`YSs%u$PvYz7 z%@Qc>7LU4N4zKRx5?jr%=))?d6{81x6V+AGT~ zSouQHF4{}>rF$#J?w~Um_FJ9!oK`17gx<%z-FQP#wh`O;12>dR(T$}}w zFUBn~jQqZgb=8JlvP!NIUY}O^WT#Q9@~zG0bXu}k*EV*K+jrr8Bp&5g z1H<|xWm)3~JmDmh)5wjZP((LqrGnA{4@hpA2=$ZqcKq^O9u|}3V>*#SqjdnIZ_PQ=x9t7;tmQ^p@=G! z=_>|P;b`aD&(WADRN=t%<%8)rGkrs0^6mJ1F5Q7S3e9L3FbrfFSWwF{_5Z`~@Bi5# zvoZ`A2Ih(ZW*xW(Elf%G)|up}*K*V=R1)$_6v_}BbUT(4YQ+^)DY(aJg6L>W6ru&i P{0K-I%wQP!RR-PxJCC70 literal 0 HcmV?d00001 diff --git a/sootup.qilin/src/main/java/driver/ContextKind.java b/sootup.qilin/src/main/java/driver/ContextKind.java new file mode 100644 index 00000000000..cfbf74c8475 --- /dev/null +++ b/sootup.qilin/src/main/java/driver/ContextKind.java @@ -0,0 +1,59 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package driver; + +import qilin.util.Util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public enum ContextKind { + INSENS, CALLSITE, OBJECT, TYPE, HYBOBJ, HYBTYPE; + static final Map contextKinds = new HashMap<>(); + + static { + Util.add(contextKinds, INSENS, "insensitive", "insens", "ci"); + Util.add(contextKinds, CALLSITE, "callsite", "call", "c"); + Util.add(contextKinds, OBJECT, "object", "obj", "o"); + Util.add(contextKinds, HYBOBJ, "hybobj", "ho", "h"); + Util.add(contextKinds, HYBTYPE, "hybtype", "ht"); + Util.add(contextKinds, TYPE, "type", "t"); + } + + public static Collection contextAliases() { + return contextKinds.keySet(); + } + + public static ContextKind toCtxKind(String name) { + return contextKinds.getOrDefault(name, INSENS); + } + + @Override + public String toString() { + return switch (this) { + case CALLSITE -> "callsite"; + case OBJECT -> "object"; + case HYBOBJ -> "hybobj"; + case HYBTYPE -> "hybtype"; + case TYPE -> "type"; + default -> "insensitive"; + }; + } +} diff --git a/sootup.qilin/src/main/java/driver/Main.java b/sootup.qilin/src/main/java/driver/Main.java new file mode 100644 index 00000000000..4dd9198ed27 --- /dev/null +++ b/sootup.qilin/src/main/java/driver/Main.java @@ -0,0 +1,73 @@ +package driver; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sootup.core.inputlocation.ClassLoadingOptions; +import sootup.core.model.SourceType; +import sootup.java.bytecode.inputlocation.BytecodeClassLoadingOptions; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaProject; +import sootup.java.core.language.JavaLanguage; +import sootup.java.core.views.JavaView; + +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.stream.Collectors; + +public class Main { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + private static Collection getJreJars(String JRE) { + if (JRE == null) { + return Collections.emptySet(); + } + final String jreLibDir = JRE + File.separator + "lib"; + return FileUtils.listFiles(new File(jreLibDir), new String[]{"jar"}, false).stream().map(File::toString) + .collect(Collectors.toList()); + } + + /** + * Returns a collection of files, one for each of the jar files in the app's lib + * folder + */ + private static Collection getLibJars(String LIB_PATH) { + if (LIB_PATH == null) { + return Collections.emptySet(); + } + File libFile = new File(LIB_PATH); + if (libFile.exists()) { + if (libFile.isDirectory()) { + return FileUtils.listFiles(libFile, new String[]{"jar"}, true).stream().map(File::toString) + .collect(Collectors.toList()); + } else if (libFile.isFile()) { + if (libFile.getName().endsWith(".jar")) { + return Collections.singletonList(LIB_PATH); + } + logger.error("Project not configured properly. Application library path {} is not a jar file.", + libFile); + System.exit(1); + } + } + logger.error("Project not configured properly. Application library path {} is not correct.", libFile); + System.exit(1); + return null; + } + + public static void main(String[] args) { + String appPath = "/Users/dongjie/Documents/Work/QilinOfficial/artifact/benchmarks/dacapo2006/luindex.jar"; + String libPath = "/Users/dongjie/Documents/Work/QilinOfficial/artifact/benchmarks/dacapo2006/luindex-deps.jar"; + String jrePath = "/Users/dongjie/Documents/Work/QilinOfficial/artifact/benchmarks/JREs/jre1.6.0_45"; + JavaProject.JavaProjectBuilder builder = new JavaProject.JavaProjectBuilder(new JavaLanguage(6)); + builder.addInputLocation(new JavaClassPathAnalysisInputLocation(appPath, SourceType.Application)); + for (String libJar : getLibJars(libPath)) { + builder.addInputLocation(new JavaClassPathAnalysisInputLocation(libJar, SourceType.Library)); + } + for (String jreJar : getJreJars(jrePath)) { + builder.addInputLocation(new JavaClassPathAnalysisInputLocation(jreJar, SourceType.Library)); + } + JavaProject project = builder.build(); + JavaView view = project.createOnDemandView(ail -> BytecodeClassLoadingOptions.Default); + + } +} diff --git a/sootup.qilin/src/main/java/driver/PTAComparator.java b/sootup.qilin/src/main/java/driver/PTAComparator.java new file mode 100644 index 00000000000..91a29ccb0ab --- /dev/null +++ b/sootup.qilin/src/main/java/driver/PTAComparator.java @@ -0,0 +1,156 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package driver; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.core.pag.PAG; +import qilin.core.pag.VarNode; +import qilin.core.sets.PointsToSet; +import qilin.pta.PTAConfig; +import qilin.util.Util; +import sootup.core.jimple.basic.Local; + +import java.io.PrintStream; +import java.util.*; + +public class PTAComparator { + static final boolean verbose = true; + public static int count, count2; + + public static void main(String[] args) { + List list = new ArrayList<>(); + for (String arg : args) { + if (!arg.startsWith("-pta=")) { + list.add(arg); + } + } + runCompare(list.toArray(new String[0]), "2o", "E-2o"); + } + + public static void runCompare(String[] args, String ptaPtn1, String ptaPtn2) { + Comparator comparator = new PTSComparator(); + String[] ptaArg1 = Util.concat(args, new String[]{"-pta=" + ptaPtn1}); + comparator.record(Main.run(ptaArg1)); + PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPtn2); + PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + pta.pureRun(); + comparator.compare(pta); + comparator.out.close(); + count = comparator.count; + count2 = comparator.count2; + } + + abstract static class Comparator { + protected int count, count2; + PrintStream out; + + public Comparator() { + out = System.out; + } + + abstract void record(PTA pta); + + abstract void compare(PTA pta); + } + + static class PTSComparator extends Comparator { + private final Map> valToOldAllocs = new HashMap<>(); + private final Map> valToNewAllocs = new HashMap<>(); + + private Set getOldAllocs(Object val) { + return valToOldAllocs.computeIfAbsent(val, k -> new HashSet<>()); + } + + private Set getNewAllocs(Object val) { + return valToNewAllocs.computeIfAbsent(val, k -> new HashSet<>()); + } + + @Override + void record(PTA pta) { + pta.getPag().getValNodes().forEach(valNode -> { + if (valNode instanceof VarNode varNode) { + final Set allocSites = getOldAllocs(varNode.getVariable()); + PointsToSet pts = pta.reachingObjects(varNode).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + allocSites.add(n.getNewExpr()); + } + } + }); + } + + @Override + void compare(PTA pta) { + count = 0; + PAG pag = pta.getPag(); + pag.getValNodes().forEach(valNode -> { + if (valNode instanceof VarNode varNode) { + final Set allocSites = getNewAllocs(varNode.getVariable()); + + PointsToSet pts1 = pta.reachingObjects(varNode).toCIPointsToSet(); + for (Iterator it = pts1.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + allocSites.add(n.getNewExpr()); + } + } + }); + valToNewAllocs.forEach((val, allocSites) -> { + if (val.toString().contains("Parm THIS_NODE")) { + return; + } + Set oldAllocSites = getOldAllocs(val); + if (oldAllocSites == null) + oldAllocSites = Collections.emptySet(); + if (!oldAllocSites.equals(allocSites)) { + if (verbose) { + out.println("\nPoint-to sets not equal!"); + if (val instanceof Local) { + out.println("local: " + pag.findLocalVarNode(val).getMethod() + ": " + val); + } else { + out.println("not local: " + pag.findValNode(val) + ": " + val); + } + + out.println("Old Points-to set:" + oldAllocSites.size()); +// oldAllocSites.forEach(a -> System.out.println(qilin.pta.getPag().valToAllocNode.get(a))); + out.println("New Points-to set:" + allocSites.size()); +// allocSites.forEach(a -> System.out.println(qilin.pta.getPag().valToAllocNode.get(a))); + } + int diff = allocSites.size() - oldAllocSites.size(); + if (diff > 0) + count += diff; + else if (diff < 0) + count2 -= diff; + if (verbose) { + out.println("difference:" + diff); + if (diff > 0) { + allocSites.removeAll(oldAllocSites); + allocSites.forEach(a -> out.println(pag.findAllocNode(a))); + } else if (diff < 0) { + oldAllocSites.removeAll(allocSites); + oldAllocSites.forEach(a -> out.println(pag.findAllocNode(a))); + } + } + } + }); + out.println("\nTotal pts over:" + count); + out.println("\nTotal pts lose:" + count2); + } + } +} diff --git a/sootup.qilin/src/main/java/driver/PTAFactory.java b/sootup.qilin/src/main/java/driver/PTAFactory.java new file mode 100644 index 00000000000..6b873478e5f --- /dev/null +++ b/sootup.qilin/src/main/java/driver/PTAFactory.java @@ -0,0 +1,151 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package driver; + +import qilin.core.PTA; +import qilin.parm.ctxcons.*; +import qilin.pta.PTAConfig; +import qilin.pta.tools.*; + +public class PTAFactory { + public static PTA createPTA(PTAPattern ptaPattern) { + switch (ptaPattern.getContextKind()) { + case HYBOBJ: { + switch (ptaPattern.getApproach()) { + case DATADRIVEN -> { + // data-driven hybrid-2obj, Sehun Jeong oopsla'17 + CtxConstructor ctxCons = new HybObjCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new HybObjCtxConstructor(); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + default -> { + // static method using callsite as context, Yannis pldi'13 + return new HybridObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + } + } + case OBJECT: { + switch (ptaPattern.getApproach()) { + case EAGLE -> { + // k-obj pointer analysis with Eagle pre-analysis, Jingbo OOPSLA'19 + assert ptaPattern.getContextDepth() == ptaPattern.getHeapContextDepth() + 1; + BasePTA eagle = new EaglePTA(ptaPattern.getContextDepth()); + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(eagle); + } else { + return eagle; + } + } + case BEAN -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + return new BeanPTA(ctxCons); + } + case TURNER -> { + return new TurnerPTA(ptaPattern.getContextDepth()); + } + case ZIPPER -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + BasePTA zipperPTA = new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(zipperPTA); + } else { + return zipperPTA; + } + } + case MAHJONG -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + BasePTA mahjongPTA = new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(mahjongPTA); + } else { + return mahjongPTA; + } + } + case DATADRIVEN -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + default -> { + BasePTA kobj = new ObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(kobj); + } else { + // normal object-sensitive pointer analysis, Milanova TOSEM'05 + return kobj; + } + } + } + } + case TYPE: { + switch (ptaPattern.getApproach()) { + case DATADRIVEN -> { + CtxConstructor ctxCons = new TypeCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new TypeCtxConstructor(); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + default -> { + // normal type-sensitive pointer analysis, Yannis popl'11 + return new TypeSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + } + } + case CALLSITE: { + switch (ptaPattern.getApproach()) { + case ZIPPER -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + } + case MAHJONG -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + } + case DATADRIVEN -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + case SELECTX -> { + return new SelectxPTA(ptaPattern.getContextDepth()); + } + default -> { + // CallSite Sensitive + return new CallSiteSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + } + } + case INSENS: + default: + return new Spark(); + } + } +} diff --git a/sootup.qilin/src/main/java/driver/PTAOption.java b/sootup.qilin/src/main/java/driver/PTAOption.java new file mode 100644 index 00000000000..9aa19148d32 --- /dev/null +++ b/sootup.qilin/src/main/java/driver/PTAOption.java @@ -0,0 +1,201 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package driver; + +import org.apache.commons.cli.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import qilin.pta.PTAConfig; +import qilin.pta.toolkits.turner.Turner; + +import java.util.*; + +public class PTAOption extends Options { + private static final Logger logger = LoggerFactory.getLogger(PTAOption.class); + + /** + * add option "-brief -option" with description + */ + protected void addOption(String brief, String option, String description) { + addOption(new Option(brief, option, false, description)); + } + + /** + * add option "-brief -option " with description + */ + protected void addOption(String brief, String option, String arg, String description) { + addOption(OptionBuilder.withLongOpt(option).withArgName(arg).hasArg().withDescription(description).create(brief)); + } + + public PTAOption() { + // input configurations + addOption("app", "apppath", "dir or jar", + "The directory containing the classes for the application or the application jar file (default: .)"); + addOption("lib", "libpath", "dir or jar", + "The directory containing the library jar files for the application or the library jar file"); + addOption(null, "includeall", "Include packages which are not analyzed by default. (default value: false)"); + addOption(null, "exclude", "packages", "Exclude selected packages. (delimiting symbol: semicolon ';')"); + addOption(null, "jre", "dir", + "The directory containing the version of JRE to be used for whole program analysis"); + addOption("reflog", "reflectionlog", "file", + "The reflection log file for the application for resolving reflective call sites"); + addOption("main", "mainclass", "class name", + "Name of the main class for the application (must be specified when appmode)"); + + // output configurations. + addOption("cg", "dumpcallgraph", "Output .dot callgraph file (default value: false)"); + addOption("jimple", "dumpjimple", "Dump appclasses to jimple. (default value: false)"); + addOption("stats", "dumpstats", "Dump statistics into files. (default value: false)"); + addOption("ptsall", "dumpallpts", + "Dump points-to of lib vars results to output/pts.txt (default value: false)"); + addOption("pag", "dumppag", "Print PAG to terminal. (default value: false)"); + addOption("pts", "dumppts", "Dump points-to results to output/pts.txt (default value: false)"); + + // general PTA configurations + addOption("clinit", "clinitmode", "APP|FULL|ONFLY", "clinit methods loading mode, default: ONFLY"); + addOption("mh", "mergeheap", + "merge heaps of StringBuilder/StringBuffer/Throwable (default value: false)"); + addOption("lcs", "emptycontextforignoretypes", "Limit heap context to 0 for Strings/Exceptions in PTA (default value: false)"); + addOption("pta", "pointstoanalysis", "(c|o)+?(h)?|insens", + "Specify Pointer Analysis e.g. 2o1h or 2o -> 2obj+1heap (default value: insens; default h: k-1.)"); + addOption("se", "singleentry", "A lightweight mode with only one main method entry. (default value: false)"); + addOption("sc", "stringconstants", "Propagate all string constants (default value: false)"); + addOption("pae", "precisearray", "Enable precise Array Element type (default value: false)"); + addOption("pe", "preciseexceptions", "Enable precisely handling exceptions (default value: false)"); + + // a specific PTA's configuration + addOption("tc", "turnerconfig", "[DEFAULT, PHASE_ONE, PHASE_TWO]", "Run Turner in the given setting (default value: DEFAULT)"); + addOption("cd", "ctxdebloat", "Enable context debloating optimization (default value: false)"); + addOption("tmd", "modular", "Enable Turner to run modularly (default value: false)"); + + // others + addOption("h", "help", "print this message"); + addOption("pre", "preonly", "Run only pre-analysis (default value: false)"); + + } + + public void parseCommandLine(String[] args) { + try { + CommandLine cmd = new GnuParser().parse(this, args); + if (cmd.hasOption("help")) { + new HelpFormatter().printHelp("qilin", this); + System.exit(0); + } + parseCommandLineOptions(cmd); + } catch (Exception e) { + logger.error("Error parsing command line options", e); + System.exit(1); + } + } + + /** + * Set all variables from the command line arguments. + * + * @param cmd + */ + protected void parseCommandLineOptions(CommandLine cmd) { + // pointer analysis configuration + if (cmd.hasOption("apppath")) { + PTAConfig.v().getAppConfig().APP_PATH = cmd.getOptionValue("apppath"); + } + String ptacmd = cmd.hasOption("pta") ? cmd.getOptionValue("pta") : "insens"; + PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptacmd); + PTAConfig.v().getPtaConfig().ptaName = PTAConfig.v().getPtaConfig().ptaPattern.toString(); + if (cmd.hasOption("singleentry")) { + PTAConfig.v().getPtaConfig().singleentry = true; + } + if (cmd.hasOption("mergeheap")) { + PTAConfig.v().getPtaConfig().mergeHeap = true; + } + if (cmd.hasOption("stringconstants")) { + PTAConfig.v().getPtaConfig().stringConstants = true; + } + if (cmd.hasOption("emptycontextforignoretypes")) { + PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes = true; + } + if (cmd.hasOption("clinitmode")) { + PTAConfig.v().getPtaConfig().clinitMode = PTAConfig.ClinitMode.valueOf(cmd.getOptionValue("clinitmode")); + } + if (cmd.hasOption("preonly")) { + PTAConfig.v().getPtaConfig().preAnalysisOnly = true; + } + if (cmd.hasOption("ctxdebloat")) { + PTAConfig.v().getPtaConfig().ctxDebloating = true; + } + if (cmd.hasOption("preciseexceptions")) { + PTAConfig.v().getPtaConfig().preciseExceptions = true; + } + if (cmd.hasOption("modular")) { + Turner.isModular = true; + } + if (cmd.hasOption("precisearray")) { + PTAConfig.v().getPtaConfig().preciseArrayElement = true; + } + // application configuration + if (cmd.hasOption("mainclass")) { + PTAConfig.v().getAppConfig().MAIN_CLASS = cmd.getOptionValue("mainclass"); + } + if (cmd.hasOption("jre")) { + PTAConfig.v().getAppConfig().JRE = cmd.getOptionValue("jre"); + } + if (cmd.hasOption("libpath")) { + PTAConfig.v().getAppConfig().LIB_PATH = cmd.getOptionValue("libpath"); + } + if (cmd.hasOption("exclude")) { + PTAConfig.v().getAppConfig().EXCLUDE = parsePackages(cmd.getOptionValue("exclude")); + } + if (cmd.hasOption("reflectionlog")) { + PTAConfig.v().getAppConfig().REFLECTION_LOG = cmd.getOptionValue("reflectionlog"); + } + if (cmd.hasOption("inlcudeall")) { + PTAConfig.v().getAppConfig().INCLUDE_ALL = true; + } + if (cmd.hasOption("turnerconfig")) { + PTAConfig.v().turnerConfig = PTAConfig.TurnerConfig.valueOf(cmd.getOptionValue("turnerconfig")); + } + + // output + if (cmd.hasOption("dumpjimple")) { + PTAConfig.v().getOutConfig().dumpJimple = true; + } + if (cmd.hasOption("dumppts")) { + PTAConfig.v().getOutConfig().dumppts = true; + } + if (cmd.hasOption("dumpallpts")) { + PTAConfig.v().getOutConfig().dumppts = true; + PTAConfig.v().getOutConfig().dumplibpts = true; + } + if (cmd.hasOption("dumpcallgraph")) { + PTAConfig.v().getOutConfig().dumpCallGraph = true; + } + if (cmd.hasOption("dumppag")) { + PTAConfig.v().getOutConfig().dumppag = true; + } + if (cmd.hasOption("dumpstats")) { + PTAConfig.v().getOutConfig().dumpStats = true; + } + } + + static List parsePackages(String packagesString) { + ArrayList pkgList = new ArrayList<>(); + String[] pkgs = packagesString.split(";"); + Collections.addAll(pkgList, pkgs); + return pkgList; + } +} diff --git a/sootup.qilin/src/main/java/driver/PTAPattern.java b/sootup.qilin/src/main/java/driver/PTAPattern.java new file mode 100644 index 00000000000..9d901994a87 --- /dev/null +++ b/sootup.qilin/src/main/java/driver/PTAPattern.java @@ -0,0 +1,221 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package driver; + +import qilin.util.Util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PTAPattern { + private ContextKind ctxKind; + private Approach approach; + private int k, hk; + + public PTAPattern(String ptacmd) { + parsePTACommand(ptacmd); + } + + private Pattern getSupportPTAPattern() { + String approachPtn = "(" + String.join("|", Approach.approachAliases()) + ")"; + String ctxLenPtn = "(\\d*)"; + String ctxKindPtn = "(" + String.join("|", ContextKind.contextAliases()) + ")"; + String heapLenPtn = "(\\+?(\\d*)h(eap)?)?"; + String regexPattern = "^(" + approachPtn + "-)?" + ctxLenPtn + ctxKindPtn + heapLenPtn + "$"; + return Pattern.compile(regexPattern); + } + + private void parsePTACommand(String ptacmd) { + Pattern pattern = getSupportPTAPattern(); + Matcher matcher = pattern.matcher(ptacmd); + if (!matcher.find()) { + throw new RuntimeException("Unsupported PTA: " + ptacmd + " !"); + } + + String approachString = matcher.group(2); + String kString = matcher.group(3); + String typeString = matcher.group(4); + String hkString = matcher.group(6); + + approach = Approach.toApproach(approachString); + k = kString.equals("") ? 1 : Integer.parseInt(kString); + ctxKind = ContextKind.toCtxKind(typeString); + hk = hkString == null ? -1 : hkString.equals("") ? 1 : Integer.parseInt(hkString); + + if (k == 0) { + ctxKind = ContextKind.INSENS; + } + if (hk == -1) { + hk = k - 1; + } + validateApproachCompatibility(); + validateContextLength(); + } + + private void validateApproachCompatibility() { + switch (ctxKind) { + case HYBOBJ: + if (approach != Approach.DATADRIVEN && approach != Approach.NONE && approach != Approach.TUNNELING) { + throw new RuntimeException("Approach <" + approach.toString() + " > is currently not designed for hybrid sensitivity"); + } + break; + case HYBTYPE: + if (approach != Approach.NONE) { + throw new RuntimeException("Approach <" + approach.toString() + " > is currently not designed for hybrid sensitivity"); + } + break; + case TYPE: { + if (approach != Approach.NONE && approach != Approach.TUNNELING) { + throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for type sensitivity."); + } + } + break; + case CALLSITE: { + if (approach != Approach.NONE && approach != Approach.ZIPPER && approach != Approach.MAHJONG + && approach != Approach.DATADRIVEN && approach != Approach.TUNNELING + && approach != Approach.SELECTX + ) { + throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for call-site sensitivity."); + } + } + break; + case OBJECT: { + if (approach != Approach.EAGLE && approach != Approach.ZIPPER && approach != Approach.TURNER && + approach != Approach.DATADRIVEN && approach != Approach.TUNNELING + && approach != Approach.MERCURIAL && approach != Approach.MAHJONG && approach != Approach.BEAN + && approach != Approach.NONE) { + throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for object sensitivity."); + } + } + break; + case INSENS: { + if (approach != Approach.SPARK && approach != Approach.NONE) { + throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for context insensitive pointer analysis."); + } + } + default: + break; + } + } + + private void validateContextLength() { + if (ctxKind == ContextKind.INSENS) { + return; + } + if (hk > k) { + throw new RuntimeException("Heap context depth cannot exceed method context depth!"); + } + if (hk < k - 1 && (ctxKind == ContextKind.OBJECT || ctxKind == ContextKind.TYPE)) { + throw new RuntimeException("Heap context depth can only be k or k-1 for object/type-sensitive analysis!"); + } + } + + public ContextKind getContextKind() { + return ctxKind; + } + + public Approach getApproach() { + return approach; + } + + public int getContextDepth() { + return k; + } + + public int getHeapContextDepth() { + return hk; + } + + @Override + public String toString() { + if (ctxKind == ContextKind.INSENS) { + return "insensitive"; + } + StringBuilder builder = new StringBuilder(); + if (!approach.toString().isEmpty()) { + builder.append(approach); + builder.append('-'); + } + builder.append(k); + builder.append(ctxKind.toString()); + builder.append('+'); + builder.append(hk); + builder.append("heap"); + return builder.toString(); + } + + public enum Approach { + // for insens + NONE, + SPARK, + // + BEAN, + ZIPPER, + EAGLE, + TURNER, + DATADRIVEN, + TUNNELING, + MERCURIAL, + MAHJONG, + SELECTX; + + static final Map approaches = new HashMap<>(); + + static { + Util.add(approaches, BEAN, "bean", "B"); + Util.add(approaches, ZIPPER, "zipper", "Z"); + Util.add(approaches, EAGLE, "eagle", "E"); + Util.add(approaches, TURNER, "turner", "T"); + Util.add(approaches, MERCURIAL, "mercurial", "hg"); + Util.add(approaches, MAHJONG, "mahjong", "M"); + Util.add(approaches, DATADRIVEN, "datadriven", "D"); + Util.add(approaches, TUNNELING, "tunneling", "t"); + Util.add(approaches, SELECTX, "selectx", "s"); + Util.add(approaches, SPARK, "insens", "ci"); + } + + public static Collection approachAliases() { + return approaches.keySet(); + } + + public static Approach toApproach(String name) { + return approaches.getOrDefault(name, NONE); + } + + @Override + public String toString() { + return switch (this) { + case DATADRIVEN -> "data-driven"; + case TUNNELING -> "tunneling"; + case BEAN -> "bean"; + case ZIPPER -> "zipper"; + case EAGLE -> "eagle"; + case TURNER -> "turner"; + case MERCURIAL -> "mercurial"; + case MAHJONG -> "mahjong"; + case SELECTX -> "selectx"; + case SPARK -> "spark"; + default -> ""; + }; + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/.DS_Store b/sootup.qilin/src/main/java/qilin/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0f17e6702794b7aa7588abb4fee87fce56b11723 GIT binary patch literal 6148 zcmeHK!A|2a5FNJxQV^mCR^oybiE9NdAQ0jb3VYb=W(5a8C7}fZA+D0NJyex)-u;-p z?w9Z{dxDv=*zuZp~^yc+y|o)wJJzTR>E1pO#Xvu5*7RI1k0^o%`Y&)KKm zl^l7QpAFKspB&Tdhm=w9IQE0Xus7<|7x!hH`C;5kI3euzkaBVq#$7pT%R$^tIoDGG zyJpuq^`-H6YkR%nY_wXFhBMw-Z#JCGjjhR~W`9{(+x_0TiEd;0leGhZJ0#n@#z!EX zbj?FAi6a?bqKDWPq@)C7Ma3!<|NnQfV1T?3q9RW$zr_0>s{O0Gq#KrP>=g>=f22M4 z3a+6T1&jipO99#+9BhQH##|w99oX>|0MSA>8;<$YAJHKPqN_1ih#oYdQV~_E&{qth zZw^AGW8BsJT%k$_!B56@^pl0Yp$L8P5DwEpxC%{g6fg=D6{xCdozDNSFW>)*NoHmg zFbaGq1%!3r9kj6|eYQR+j?P*K+Zi@8;^hiC1v`Bl^MH=xC2VXMb7+9*YRna)2hDs4 MuneX%3cRTT4^;5Y. + */ + +package qilin; + +import java.util.List; + +public class CoreConfig { + protected static CoreConfig coreConfig = null; + + public static CoreConfig v() { + if (coreConfig == null) { + throw new RuntimeException("Core configuration is not initialized!"); + } + return coreConfig; + } + + public static void reset() { + coreConfig = null; + } + + public enum ClinitMode { + FULL, ONFLY, APP + } + + public static class CorePTAConfiguration { + public boolean singleentry = false; + /** + * Clinit loading mode: + * APP: A debug mode for testing which load only the minimum of classes needed. + * FULL: load all of classes that are currently loaded in the scene. + * ON_THE_FLY: we load on the fly, this mode is same as DOOP (default mode). + */ + public ClinitMode clinitMode = ClinitMode.ONFLY; + + /** + * enable to merge heaps like StringBuilder/StringBuffer, exceptions by types. + */ + public boolean mergeHeap = false; + + /** + * the type of array element is java.lang.Object by default. + * if set to be true, we will use more precise type for array elements. + */ + public boolean preciseArrayElement = false; + + /** + * in qilin.spark propagate all string constants false means merge all string + * constants, see the corresponding flag, DISTINGUISH_NO_STRING_CONSTANTS, in DOOP. + */ + public boolean stringConstants = false; + + /** + * The default setting (same as the imprecise version in Doop): + * there is a global variable for all thrown exceptions and + * any caught exception variable points to all those exceptions. + * Obviously, this is extremely imprecise. + *

+ * This imprecision does not seem to matter too much for typical + * programs in the context-insensitive and 1-call-site-sensitive + * analyses, but is disastrous in the 1-object-sensitive analysis. + *

+ * once this switch is open, it will model exception flow-sensitively + * (same as the precise version in Doop). + * Implicitly thrown exceptions are not included. + */ + public boolean preciseExceptions = false; + + /** + * in qilin.spark limit heap context for strings if we are object sensitive + */ + public boolean enforceEmptyCtxForIgnoreTypes = false; + + public String ptaName; + } + + public static class ApplicationConfiguration { + /** + * Path for the root folder for the application classes or for the application + * jar file. + */ + public String APP_PATH = "."; + /** + * Path for the JRE to be used for whole program analysis. + */ + public String JRE = null; + /** + * Path for the root folder for the library jars. + */ + public String LIB_PATH = null; + + /** + * Path for the reflection log file for the application. + */ + public String REFLECTION_LOG = null; + + /** + * Main class for the application. + */ + public String MAIN_CLASS = null; + + /** + * include selected packages which are not analyzed by default + */ + public List INCLUDE = null; + /** + * exclude selected packages + */ + public List EXCLUDE = null; + /** + * include packages which are not analyzed by default + */ + public boolean INCLUDE_ALL = false; + } + + public static class OutputConfiguration { + public String outDir = "sootUpOut"; + /** + * dump appclasses to jimple + */ + public boolean dumpJimple = false; + /** + * if true, dump pts in app code to a file + */ + public boolean dumppts = false; + /** + * if true, dump pts of vars in library + */ + public boolean dumplibpts = false; + /** + * print a CG graph + */ + public boolean dumpCallGraph = false; + /** + * print a PAG graph + */ + public boolean dumppag = false; + + /** + * if true, dump stats into files. + */ + public boolean dumpStats = false; + } + + protected CorePTAConfiguration ptaConfig; + protected final ApplicationConfiguration appConfig = new ApplicationConfiguration(); + protected final OutputConfiguration outConfig = new OutputConfiguration(); + + public CorePTAConfiguration getPtaConfig() { + return ptaConfig; + } + + public ApplicationConfiguration getAppConfig() { + return appConfig; + } + + public OutputConfiguration getOutConfig() { + return outConfig; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java new file mode 100644 index 00000000000..8560f2bf2ce --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -0,0 +1,180 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core; + +import sootup.core.IdentifierFactory; +import sootup.core.jimple.Jimple; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.ref.IdentityRef; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JParameterRef; +import sootup.core.jimple.common.ref.JThisRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JIdentityStmt; +import sootup.core.jimple.common.stmt.JReturnStmt; +import sootup.core.model.Body; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.core.types.ClassType; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; + +import java.util.Arrays; +import java.util.List; + +public abstract class ArtificialMethod { + + protected IdentifierFactory identifierFactory; + protected SootMethod method; + protected Body body; + protected Value thisLocal; + protected Local[] paraLocals; + protected int paraStart; + protected int localStart; + + protected Value getThis() { + if (thisLocal == null) { + ClassType type = method.getDeclaringClassType(); + Value thisRef = new JThisRef(type); + thisLocal = getLocal(type, 0); + addIdentity(thisLocal, thisRef); + } + return thisLocal; + } + + protected Value getPara(int index) { + Value paraLocal = paraLocals[index]; + if (paraLocal == null) { + Type type = method.getParameterType(index); + return getPara(index, type); + } + return paraLocal; + } + + protected Value getPara(int index, Type type) { + Local paraLocal = paraLocals[index]; + if (paraLocal == null) { + IdentityRef paraRef = new JParameterRef(type, index); + paraLocal = getLocal(type, paraStart + index); + addIdentity(paraLocal, paraRef); + paraLocals[index] = paraLocal; + } + return paraLocal; + } + + private void addIdentity(Local lValue, IdentityRef rValue) { + body.getUnits().add(Jimple.newIdentityStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); + } + + protected Value getNew(ClassType type) { + Value newExpr = new JNewExpr(type); + Value local = getNextLocal(type); + addAssign(local, newExpr); + return local; + } + + protected Value getNewArray(ReferenceType type) { + Value newExpr = new JNewArrayExpr(type, IntConstant.getInstance(1), identifierFactory); + Value local = getNextLocal(identifierFactory.getArrayType(type, 1)); + addAssign(local, newExpr); + return local; + } + + protected Value getNextLocal(Type type) { + return getLocal(type, localStart++); + } + + private Local getLocal(Type type, int index) { + Local local = Jimple.newLocal("r" + index, type); + body.getLocals().add(local); + return local; + } + + protected void addReturn(Immediate ret) { + body.getUnits().add(Jimple.newReturnStmt(ret, StmtPositionInfo.createNoStmtPositionInfo())); + } + + protected Value getStaticFieldRef(String className, String name) { + return Jimple.newStaticFieldRef(RefType.v(className).getSootClass().getFieldByName(name).makeRef()); + } + + protected Value getArrayRef(Value base) { + return new JArrayRef((Local) base, IntConstant.getInstance(0), ); + } + + /** + * add an instance invocation receiver.sig(args) + */ + protected void addInvoke(Value receiver, String sig, Immediate... args) { + MethodSignature methodRef = PTAScene.v().getMethod(sig).getSignature(); + List argsL = Arrays.asList(args); + AbstractInvokeExpr invoke = methodRef.getDeclaringClass().isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, methodRef, argsL) + : Jimple.newVirtualInvokeExpr((Local) receiver, methodRef, argsL); + body.getUnits().add(Jimple.newInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo())); + } + + /** + * add an instance invocation and get the return value rx = receiver.sig(args) + * + * @return rx + */ + protected Value getInvoke(Value receiver, String sig, Value... args) { + SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + List argsL = Arrays.asList(args); + Value invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) + : new JVirtualInvokeExpr(receiver, methodRef, argsL); + Value rx = getNextLocal(methodRef.getReturnType()); + addAssign(rx, invoke); + return rx; + } + + /** + * add a static invocation sig(args) + */ + protected void addInvoke(String sig, Value... args) { + SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + List argsL = Arrays.asList(args); + body.getUnits().add(new JInvokeStmt(new JStaticInvokeExpr(methodRef, argsL))); + } + + /** + * add a static invocation and get the return value rx = sig(args) + * + * @return rx + */ + protected Value getInvoke(String sig, Value... args) { + MethodSignature msig = identifierFactory.parseMethodSignature(sig); + SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + List argsL = Arrays.asList(args); + Value rx = getNextLocal(methodRef.getReturnType()); + addAssign(rx, new JStaticInvokeExpr(methodRef, argsL)); + return rx; + } + + protected void addAssign(Value lValue, Value rValue) { + body.getUnits().add(Jimple.newAssignStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/CorePTA.java b/sootup.qilin/src/main/java/qilin/core/CorePTA.java new file mode 100644 index 00000000000..fc2abd458ff --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/CorePTA.java @@ -0,0 +1,121 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core; + +import qilin.core.pag.*; +import qilin.core.solver.Propagator; +import qilin.parm.ctxcons.CtxConstructor; +import qilin.parm.heapabst.HeapAbstractor; +import qilin.parm.select.CtxSelector; +import soot.*; + +/* + * This represents a parameterized PTA which could be concreted to many pointer analyses. + * */ +public abstract class CorePTA extends PTA { + /* + * The following three parameterized functions must be initialized before doing the pointer analysis. + * */ + protected CtxConstructor ctxCons; + protected CtxSelector ctxSel; + protected HeapAbstractor heapAbst; + + public CtxSelector ctxSelector() { + return ctxSel; + } + + public void setContextSelector(CtxSelector ctxSelector) { + this.ctxSel = ctxSelector; + } + + public CtxConstructor ctxConstructor() { + return ctxCons; + } + + public HeapAbstractor heapAbstractor() { + return this.heapAbst; + } + + public abstract Propagator getPropagator(); + + @Override + public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + return ctxCons.constructCtx(caller, (ContextAllocNode) receiverNode, callSite, target); + } + + public Context emptyContext() { + return CtxConstructor.emptyContext; + } + + @Override + public Node parameterize(Node n, Context context) { + if (context == null) { + throw new RuntimeException("null context!!!"); + } + if (n instanceof LocalVarNode lvn) { + return parameterize(lvn, context); + } + if (n instanceof FieldRefNode frn) { + return parameterize(frn, context); + } + if (n instanceof AllocNode an) { + return parameterize(an, context); + } + if (n instanceof FieldValNode fvn) { + return parameterize(fvn, context); + } + if (n instanceof GlobalVarNode gvn) { + return pag.makeContextVarNode(gvn, emptyContext()); + } + throw new RuntimeException("cannot parameterize this node: " + n); + + } + + public ContextField parameterize(FieldValNode fvn, Context context) { + Context ctx = ctxSel.select(fvn, context); + return pag.makeContextField(ctx, fvn); + } + + protected ContextVarNode parameterize(LocalVarNode vn, Context context) { + Context ctx = ctxSel.select(vn, context); + return pag.makeContextVarNode(vn, ctx); + } + + protected FieldRefNode parameterize(FieldRefNode frn, Context context) { + return pag.makeFieldRefNode((VarNode) parameterize(frn.getBase(), context), frn.getField()); + } + + protected ContextAllocNode parameterize(AllocNode node, Context context) { + Context ctx = ctxSel.select(node, context); + return pag.makeContextAllocNode(node, ctx); + } + + /** + * Finds or creates the ContextMethod for method and context. + */ + @Override + public MethodOrMethodContext parameterize(SootMethod method, Context context) { + Context ctx = ctxSel.select(method, context); + return pag.makeContextMethod(ctx, method); + } + + public AllocNode getRootNode() { + return rootNode; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/PTA.java b/sootup.qilin/src/main/java/qilin/core/PTA.java new file mode 100644 index 00000000000..564e3a45cef --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/PTA.java @@ -0,0 +1,258 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core; + +import qilin.core.builder.CallGraphBuilder; +import qilin.core.builder.ExceptionHandler; +import qilin.core.pag.*; +import qilin.core.sets.*; +import qilin.core.sets.PointsToSet; +import qilin.core.solver.Propagator; +import qilin.parm.ctxcons.CtxConstructor; +import qilin.parm.heapabst.HeapAbstractor; +import qilin.parm.select.CtxSelector; +import soot.*; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.CallGraph; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public abstract class PTA implements PointsToAnalysis { + + protected AllocNode rootNode; + protected PAG pag; + protected CallGraph callGraph; + protected CallGraphBuilder cgb; + protected ExceptionHandler eh; + + public PTA() { + this.pag = createPAG(); + this.cgb = createCallGraphBuilder(); + this.eh = new ExceptionHandler(this); + AllocNode rootBase = pag.makeAllocNode("ROOT", RefType.v("java.lang.Object"), null); + this.rootNode = new ContextAllocNode(rootBase, CtxConstructor.emptyContext); + } + + protected abstract PAG createPAG(); + + protected abstract CallGraphBuilder createCallGraphBuilder(); + + public void run() { + pureRun(); + } + + public void pureRun() { + getPropagator().propagate(); + } + + public PAG getPag() { + return pag; + } + + public CallGraphBuilder getCgb() { + return cgb; + } + + public ExceptionHandler getExceptionHandler() { + return eh; + } + + public CallGraph getCallGraph() { + if (callGraph == null) { + callGraph = cgb.getCICallGraph(); + } + return callGraph; + } + + public Collection getReachableMethods() { + return cgb.getReachableMethods(); + } + + private Set nakedReachables = null; + + public Collection getNakedReachableMethods() { + if (nakedReachables == null) { + nakedReachables = new HashSet<>(); + cgb.getReachableMethods().forEach(momc -> nakedReachables.add(momc.method())); + } + return nakedReachables; + } + + protected abstract Propagator getPropagator(); + + public abstract Node parameterize(Node n, Context context); + + public abstract MethodOrMethodContext parameterize(SootMethod method, Context context); + + public abstract AllocNode getRootNode(); + + public abstract Context emptyContext(); + + public abstract Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target); + + public abstract HeapAbstractor heapAbstractor(); + + public abstract CtxConstructor ctxConstructor(); + + public abstract CtxSelector ctxSelector(); + + /** + * Returns the set of objects pointed to by variable l. + */ + @Override + public PointsToSet reachingObjects(Local l) { + // find all context nodes, and collect their answers + final PointsToSetInternal ret = new HybridPointsToSet(); + pag.getVarNodes(l).forEach(vn -> { + ret.addAll(vn.getP2Set(), null); + }); + return new UnmodifiablePointsToSet(this, ret); + } + + /** + * Returns the set of objects pointed by n: + * case 1: n is an insensitive node, return objects pointed by n under every possible context. + * case 2: n is a context-sensitive node, return objects pointed by n under the given context. + */ + public PointsToSet reachingObjects(Node n) { + final PointsToSetInternal ret; + if (n instanceof ContextVarNode cvn) { + ret = cvn.getP2Set(); + } else if (n instanceof ContextField cf) { + ret = cf.getP2Set(); + } else { + VarNode varNode = (VarNode) n; + ret = new HybridPointsToSet(); + if (pag.getContextVarNodeMap().containsKey(varNode)) { + pag.getContextVarNodeMap().get(varNode).values().forEach(vn -> { + ret.addAll(vn.getP2Set(), null); + }); + } + } + return new UnmodifiablePointsToSet(this, ret); + } + + /** + * Returns the set of objects pointed to by elements of the arrays in the + * PointsToSet s. + */ + @Override + public PointsToSet reachingObjectsOfArrayElement(PointsToSet s) { + return reachingObjectsInternal(s, ArrayElement.v()); + } + + /** + * Returns the set of objects pointed to by variable l in context c. + */ + @Override + public PointsToSet reachingObjects(Context c, Local l) { + VarNode n = pag.findContextVarNode(l, c); + PointsToSetInternal pts; + if (n == null) { + pts = HybridPointsToSet.getEmptySet(); + } else { + pts = n.getP2Set(); + } + return new UnmodifiablePointsToSet(this, pts); + } + + /** + * Returns the set of objects pointed to by instance field f of the objects + * pointed to by l. + */ + @Override + public PointsToSet reachingObjects(Local l, SootField f) { + return reachingObjects(reachingObjects(l), f); + } + + /** + * Returns the set of objects pointed to by instance field f of the objects in + * the PointsToSet s. + */ + @Override + public PointsToSet reachingObjects(PointsToSet s, final SootField f) { + if (f.isStatic()) { + throw new RuntimeException("The parameter f must be an *instance* field."); + } + return reachingObjectsInternal(s, new Field(f)); + } + + /** + * Returns the set of objects pointed to by instance field f of the objects + * pointed to by l in context c. + */ + @Override + public PointsToSet reachingObjects(Context c, Local l, SootField f) { + return reachingObjects(reachingObjects(c, l), f); + } + + @Override + public PointsToSet reachingObjects(SootField f) { + PointsToSetInternal ret; + if (f.isStatic()) { + VarNode n = pag.findGlobalVarNode(f); + if (n == null) { + ret = HybridPointsToSet.getEmptySet(); + } else { + ret = n.getP2Set(); + } + } else { + ret = new HybridPointsToSet(); + SparkField sparkField = new Field(f); + pag.getContextFieldVarNodeMap().values().stream().filter(map -> map.containsKey(sparkField)).forEach(map -> { + ContextField contextField = map.get(sparkField); + ret.addAll(contextField.getP2Set(), null); + }); + } + return new UnmodifiablePointsToSet(this, ret); + } + + public PointsToSet reachingObjectsInternal(PointsToSet bases, final SparkField f) { + final PointsToSetInternal ret = new HybridPointsToSet(); + pag.getContextFieldVarNodeMap().values().stream().filter(map -> map.containsKey(f)).forEach(map -> { + ContextField contextField = map.get(f); + AllocNode base = contextField.getBase(); + if (bases.contains(base)) { + ret.addAll(contextField.getP2Set(), null); + } + }); + return new UnmodifiablePointsToSet(this, ret); + } + + public PointsToSet reachingObjectsInternal(AllocNode heap, final SparkField f) { + final PointsToSetInternal ret = new HybridPointsToSet(); + pag.getContextFieldVarNodeMap().values().stream().filter(map -> map.containsKey(f)).forEach(map -> { + ContextField contextField = map.get(f); + AllocNode base = contextField.getBase(); + if (heap.equals(base)) { + ret.addAll(contextField.getP2Set(), null); + } + }); + return new UnmodifiablePointsToSet(this, ret); + } + + @Override + public boolean mayAlias(Local l1, Local l2) { + PointsToSet pts1 = reachingObjects(l1).toCIPointsToSet(); + PointsToSet pts2 = reachingObjects(l2).toCIPointsToSet(); + return pts1.hasNonEmptyIntersection(pts2); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java new file mode 100644 index 00000000000..2becfa9b1e7 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -0,0 +1,221 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core; + +import qilin.core.builder.FakeMainFactory; +import qilin.util.DataFactory; +import soot.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.util.Chain; +import soot.util.IterableNumberer; +import soot.util.StringNumberer; + +import java.util.Set; + +public class PTAScene { + private static volatile PTAScene instance = null; + private final Scene sootScene; + private final FakeMainFactory fakeMainFactory; + + public static PTAScene v() { + if (instance == null) { + synchronized (PTAScene.class) { + if (instance == null) { + instance = new PTAScene(); + } + } + } + return instance; + } + + public static void junitReset() { + VirtualCalls.reset(); + instance = null; + } + + public static void reset() { + G.reset(); + VirtualCalls.reset(); + instance = null; + } + + private PTAScene() { + this.sootScene = Scene.v(); + this.fakeMainFactory = new FakeMainFactory(); + } + + public final Set nativeBuilt = DataFactory.createSet(); + public final Set reflectionBuilt = DataFactory.createSet(); + public final Set arraycopyBuilt = DataFactory.createSet(); + + /* + * wrapper methods for FakeMain. + * */ + public SootMethod getFakeMainMethod() { + return this.fakeMainFactory.getFakeMain(); + } + + public Value getFieldCurrentThread() { + return this.fakeMainFactory.getFieldCurrentThread(); + } + + public Value getFieldGlobalThrow() { + return this.fakeMainFactory.getFieldGlobalThrow(); + } + + public void setMainClass(SootClass m) { + sootScene.setMainClass(m); + } + + /* + * wrapper methods of Soot Scene. Note, we do not allow you to use Soot Scene directly in qilin.qilin.pta subproject + * to avoid confusing. + * */ + public void setCallGraph(CallGraph cg) { + sootScene.setCallGraph(cg); + } + + public CallGraph getCallGraph() { + return sootScene.getCallGraph(); + } + + public IterableNumberer getLocalNumberer() { + return sootScene.getLocalNumberer(); + } + + public IterableNumberer getTypeNumberer() { + return sootScene.getTypeNumberer(); + } + + public FastHierarchy getOrMakeFastHierarchy() { + return sootScene.getOrMakeFastHierarchy(); + } + + public SootClass loadClassAndSupport(String className) { + return sootScene.loadClassAndSupport(className); + } + + public SootMethod getMethod(String methodSignature) { + return sootScene.getMethod(methodSignature); + } + + public Chain getApplicationClasses() { + return sootScene.getApplicationClasses(); + } + + public Chain getLibraryClasses() { + return sootScene.getLibraryClasses(); + } + + public boolean containsMethod(String methodSignature) { + return sootScene.containsMethod(methodSignature); + } + + public boolean containsField(String fieldSignature) { + return sootScene.containsField(fieldSignature); + } + + public void loadBasicClasses() { + sootScene.loadBasicClasses(); + } + + public void addBasicClass(String name, int level) { + sootScene.addBasicClass(name, level); + } + + public Chain getClasses() { + return sootScene.getClasses(); + } + + public Chain getPhantomClasses() { + return sootScene.getPhantomClasses(); + } + + public SootClass getSootClass(String className) { + return sootScene.getSootClass(className); + } + + public boolean containsClass(String className) { + return sootScene.containsClass(className); + } + + public SootField getField(String fieldSignature) { + return sootScene.getField(fieldSignature); + } + + public Type getTypeUnsafe(String arg, boolean phantomNonExist) { + return sootScene.getTypeUnsafe(arg, phantomNonExist); + } + + public StringNumberer getSubSigNumberer() { + return sootScene.getSubSigNumberer(); + } + + public IterableNumberer getMethodNumberer() { + return sootScene.getMethodNumberer(); + } + + public void loadNecessaryClasses() { + sootScene.loadNecessaryClasses(); + } + + public boolean containsType(String className) { + return sootScene.containsType(className); + } + + public RefType getRefType(String className) { + return sootScene.getRefType(className); + } + + /* + * copy from doop's soot-fact-generator + * */ + public void addBasicClasses() { + /* + * Set resolution level for sun.net.www.protocol.ftp.FtpURLConnection + * to 1 (HIERARCHY) before calling produceFacts(). The following line is necessary to avoid + * a runtime exception when running soot with java 1.8, however it leads to different + * input fact generation thus leading to different analysis results + */ + sootScene.addBasicClass("sun.net.www.protocol.ftp.FtpURLConnection", SootClass.HIERARCHY); + sootScene.addBasicClass("javax.crypto.extObjectInputStream"); + sootScene.addBasicClass("sun.misc.Launcher$AppClassLoader"); + /* + * For simulating the FileSystem class, we need the implementation + * of the FileSystem, but the classes are not loaded automatically + * due to the indirection via native code. + */ + addCommonDynamicClass("java.io.UnixFileSystem"); + addCommonDynamicClass("java.io.WinNTFileSystem"); + addCommonDynamicClass("java.io.Win32FileSystem"); + + /* java.net.URL loads handlers dynamically */ + addCommonDynamicClass("sun.net.www.protocol.file.Handler"); + addCommonDynamicClass("sun.net.www.protocol.ftp.Handler"); + addCommonDynamicClass("sun.net.www.protocol.http.Handler"); + addCommonDynamicClass("sun.net.www.protocol.https.Handler"); + addCommonDynamicClass("sun.net.www.protocol.jar.Handler"); + } + + private void addCommonDynamicClass(String className) { + if (SourceLocator.v().getClassSource(className) != null) { + sootScene.addBasicClass(className); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java b/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java new file mode 100644 index 00000000000..6cc6c893024 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java @@ -0,0 +1,83 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core; + +import qilin.core.context.Context; +import qilin.core.pag.Node; +import qilin.core.sets.PointsToSet; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootField; + +/** + * A generic interface to any type of pointer analysis. + * + * @author Ondrej Lhotak + */ + +public interface PointsToAnalysis { + + int THIS_NODE = -1; + int RETURN_NODE = -2; + int THROW_NODE = -3; + String STRING_NODE = "STRING_NODE"; + String EXCEPTION_NODE = "EXCEPTION_NODE"; + String MAIN_THREAD_GROUP_NODE_LOCAL = "MAIN_THREAD_GROUP_NODE_LOCAL"; + + /** + * Returns the set of objects pointed to by variable l. + */ + PointsToSet reachingObjects(Local l); + + PointsToSet reachingObjects(Node n); + + /** + * Returns the set of objects pointed to by variable l in context c. + */ + PointsToSet reachingObjects(Context c, Local l); + + /** + * Returns the set of objects pointed to by static field f. + */ + PointsToSet reachingObjects(SootField f); + + /** + * Returns the set of objects pointed to by instance field f of the objects in the PointsToSet s. + */ + PointsToSet reachingObjects(PointsToSet s, SootField f); + + /** + * Returns the set of objects pointed to by instance field f of the objects pointed to by l. + */ + PointsToSet reachingObjects(Local l, SootField f); + + /** + * Returns the set of objects pointed to by instance field f of the objects pointed to by l in context c. + */ + PointsToSet reachingObjects(Context c, Local l, SootField f); + + /** + * Returns the set of objects pointed to by elements of the arrays in the PointsToSet s. + */ + PointsToSet reachingObjectsOfArrayElement(PointsToSet s); + + /* + * Return true if l1 and l2 are aliases. + * */ + boolean mayAlias(Local l1, Local l2); +} diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java new file mode 100644 index 00000000000..fbdcf210e46 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -0,0 +1,212 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core; + +import qilin.util.DataFactory; +import soot.*; +import soot.jimple.SpecialInvokeExpr; +import soot.util.*; +import soot.util.queue.ChunkedQueue; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +/** + * Resolves virtual calls. + * + * @author Ondrej Lhotak + */ +public class VirtualCalls { + private static volatile VirtualCalls instance = null; + private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); + protected Map> baseToSubTypes = DataFactory.createMap(); + + private VirtualCalls() { + } + + public static VirtualCalls v() { + if (instance == null) { + synchronized (VirtualCalls.class) { + if (instance == null) { + instance = new VirtualCalls(); + } + } + } + return instance; + } + + public static void reset() { + instance = null; + } + + public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container) { + return resolveSpecial(iie, subSig, container, false); + } + + public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container, boolean appOnly) { + SootMethod target = iie.getMethod(); + /* cf. JVM spec, invokespecial instruction */ + if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClass().getType(), + target.getDeclaringClass().getType()) + && container.getDeclaringClass().getType() != target.getDeclaringClass().getType() + && !target.getName().equals("") + && subSig != Scene.v().getSubSigNumberer().findOrAdd("void ()")) { + + return resolveNonSpecial(container.getDeclaringClass().getSuperclass().getType(), subSig, appOnly); + } else { + return target; + } + } + + public SootMethod resolveNonSpecial(RefType t, NumberedString subSig) { + return resolveNonSpecial(t, subSig, false); + } + + public SootMethod resolveNonSpecial(RefType t, NumberedString subSig, boolean appOnly) { + Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); + SootMethod ret = vtbl.get(subSig); + if (ret != null) { + return ret; + } + SootClass cls = t.getSootClass(); + if (appOnly && cls.isLibraryClass()) { + return null; + } + + SootMethod m = cls.getMethodUnsafe(subSig); + if (m != null) { + if (!m.isAbstract()) { + ret = m; + } + } else { + SootClass c = cls.getSuperclassUnsafe(); + if (c != null) { + ret = resolveNonSpecial(c.getType(), subSig); + } + } + if (ret == null) { + return null; + } + vtbl.put(subSig, ret); + return ret; + } + + public void resolve(Type t, Type declaredType, NumberedString subSig, SootMethod container, + ChunkedQueue targets) { + resolve(t, declaredType, null, subSig, container, targets); + } + + public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + ChunkedQueue targets) { + resolve(t, declaredType, sigType, subSig, container, targets, false); + } + + public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + ChunkedQueue targets, boolean appOnly) { + if (declaredType instanceof ArrayType) { + declaredType = RefType.v("java.lang.Object"); + } + if (sigType instanceof ArrayType) { + sigType = RefType.v("java.lang.Object"); + } + if (t instanceof ArrayType) { + t = RefType.v("java.lang.Object"); + } + + if (declaredType != null && !Scene.v().getFastHierarchy().canStoreType(t, declaredType)) { + return; + } + if (sigType != null && !Scene.v().getFastHierarchy().canStoreType(t, sigType)) { + return; + } + if (t instanceof RefType) { + SootMethod target = resolveNonSpecial((RefType) t, subSig, appOnly); + if (target != null) { + targets.add(target); + } + } else if (t instanceof AnySubType) { + RefType base = ((AnySubType) t).getBase(); + + /* + * Whenever any sub type of a specific type is considered as receiver for a method to call and the base type is an + * interface, calls to existing methods with matching signature (possible implementation of method to call) are also + * added. As Javas' subtyping allows contra-variance for return types and co-variance for parameters when overriding a + * method, these cases are also considered here. + * + * Example: Classes A, B (B sub type of A), interface I with method public A foo(B b); and a class C with method public + * B foo(A a) { ... }. The extended class hierarchy will contain C as possible implementation of I. + * + * Since Java has no multiple inheritance call by signature resolution is only activated if the base is an interface. + */ + resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); + } else if (t instanceof NullType) { + } else { + throw new RuntimeException("oops " + t); + } + } + + protected void resolveAnySubType(Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + ChunkedQueue targets, boolean appOnly, RefType base) { + { + Set subTypes = baseToSubTypes.get(base); + if (subTypes != null && !subTypes.isEmpty()) { + for (final Type st : subTypes) { + resolve(st, declaredType, sigType, subSig, container, targets, appOnly); + } + return; + } + } + + Set newSubTypes = new HashSet<>(); + newSubTypes.add(base); + + LinkedList worklist = new LinkedList<>(); + HashSet workset = new HashSet<>(); + SootClass cl = base.getSootClass(); + + if (workset.add(cl)) { + worklist.add(cl); + } + while (!worklist.isEmpty()) { + cl = worklist.removeFirst(); + if (cl.isInterface()) { + for (final SootClass c : Scene.v().getFastHierarchy().getAllImplementersOfInterface(cl)) { + if (workset.add(c)) { + worklist.add(c); + } + } + } else { + if (cl.isConcrete()) { + resolve(cl.getType(), declaredType, sigType, subSig, container, targets, appOnly); + newSubTypes.add(cl.getType()); + } + for (final SootClass c : Scene.v().getFastHierarchy().getSubclassesOf(cl)) { + if (workset.add(c)) { + worklist.add(c); + } + } + } + } + + baseToSubTypes.computeIfAbsent(base, k -> DataFactory.createSet()).addAll(newSubTypes); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java new file mode 100644 index 00000000000..35053c41b60 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -0,0 +1,266 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.builder; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.context.Context; +import qilin.core.pag.*; +import qilin.core.sets.P2SetVisitor; +import qilin.core.sets.PointsToSetInternal; +import qilin.util.DataFactory; +import qilin.util.PTAUtils; + +import qilin.util.queue.ChunkedQueue; +import qilin.util.queue.QueueReader; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; + +import java.util.*; + +public class CallGraphBuilder { + protected final Map> receiverToSites; + protected final Map> methodToInvokeStmt; + protected final Set reachMethods; + private ChunkedQueue rmQueue; + + protected final Set calledges; + protected final PTA pta; + protected final PAG pag; + protected CallGraph cicg; + + public CallGraphBuilder(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + PTAScene.v().setCallGraph(new CallGraph()); + receiverToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); + methodToInvokeStmt = DataFactory.createMap(); + reachMethods = DataFactory.createSet(); + calledges = DataFactory.createSet(); + } + + public void setRMQueue(ChunkedQueue rmQueue) { + this.rmQueue = rmQueue; + } + + public Collection getReachableMethods() { + return reachMethods; + } + + // initialize the receiver to sites map with the number of locals * an + // estimate for the number of contexts per methods + public Map> getReceiverToSitesMap() { + return receiverToSites; + } + + public Collection callSitesLookUp(VarNode receiver) { + return receiverToSites.getOrDefault(receiver, Collections.emptySet()); + } + + public CallGraph getCallGraph() { + if (cicg == null) { + constructCallGraph(); + } + return PTAScene.v().getCallGraph(); + } + + public CallGraph getCICallGraph() { + if (cicg == null) { + constructCallGraph(); + } + return cicg; + } + + private void constructCallGraph() { + cicg = new CallGraph(); + Map>> map = DataFactory.createMap(); + calledges.forEach(e -> { + PTAScene.v().getCallGraph().addEdge(e); + SootMethod src = e.src(); + SootMethod tgt = e.tgt(); + Unit unit = e.srcUnit(); + Map> submap = map.computeIfAbsent(unit, k -> DataFactory.createMap()); + Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); + if (set.add(tgt)) { + cicg.addEdge(new Edge(src, e.srcUnit(), tgt, e.kind())); + } + }); + } + + public List getEntryPoints() { + Node thisRef = pag.getMethodPAG(PTAScene.v().getFakeMainMethod()).nodeFactory().caseThis(); + thisRef = pta.parameterize(thisRef, pta.emptyContext()); + pag.addEdge(pta.getRootNode(), thisRef); + return Collections.singletonList(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext())); + } + + public void initReachableMethods() { + for (ContextMethod momc : getEntryPoints()) { + if (reachMethods.add(momc)) { + rmQueue.add(momc); + } + } + } + + public VarNode getReceiverVarNode(Local receiver, ContextMethod m) { + LocalVarNode base = pag.makeLocalVarNode(receiver, receiver.getType(), m.method()); + return (VarNode) pta.parameterize(base, m.context()); + } + + protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { + Type type = receiverNode.getType(); + final QueueReader targets = PTAUtils.dispatch(type, site); + while (targets.hasNext()) { + SootMethod target = targets.next(); + if (site.iie() instanceof JSpecialInvokeExpr) { + Type calleeDeclType = target.getDeclaringClassType(); + if (!Scene.v().getFastHierarchy().canStoreType(type, calleeDeclType)) { + continue; + } + } + addVirtualEdge(site.container(), site.getUnit(), target, site.kind(), receiverNode); + } + } + + private void addVirtualEdge(ContextMethod caller, Stmt callStmt, SootMethod callee, Kind kind, AllocNode receiverNode) { + Context tgtContext = pta.createCalleeCtx(caller, receiverNode, new CallSite(callStmt), callee); + ContextMethod cstarget = pta.parameterize(callee, tgtContext); + handleCallEdge(new Edge(caller, callStmt, cstarget, kind)); + Node thisRef = pag.getMethodPAG(callee).nodeFactory().caseThis(); + thisRef = pta.parameterize(thisRef, cstarget.context()); + pag.addEdge(receiverNode, thisRef); + } + + public void injectCallEdge(Object heapOrType, ContextMethod callee, Kind kind) { + Map stmtMap = methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap()); + if (!stmtMap.containsKey(heapOrType)) { + AbstractInvokeExpr ie = new JStaticInvokeExpr(callee.method().getSignature(), Collections.emptyList()); + JInvokeStmt stmt = new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo()); + stmtMap.put(heapOrType, stmt); + handleCallEdge(new Edge(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext()), stmtMap.get(heapOrType), callee, kind)); + } + } + + public void addStaticEdge(ContextMethod caller, Stmt callStmt, SootMethod calleem, Kind kind) { + Context typeContext = pta.createCalleeCtx(caller, null, new CallSite(callStmt), calleem); + ContextMethod callee = pta.parameterize(calleem, typeContext); + handleCallEdge(new Edge(caller, callStmt, callee, kind)); + } + + protected void handleCallEdge(Edge edge) { + if (calledges.add(edge)) { + ContextMethod callee = edge.getTgt(); + if (reachMethods.add(callee)) { + rmQueue.add(callee); + } + processCallAssign(edge); + } + } + + public boolean recordVirtualCallSite(VarNode receiver, VirtualCallSite site) { + Collection sites = receiverToSites.computeIfAbsent(receiver, k -> DataFactory.createSet()); + return sites.add(site); + } + + public void virtualCallDispatch(PointsToSetInternal p2set, VirtualCallSite site) { + p2set.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + dispatch((AllocNode) n, site); + } + }); + } + + /** + * Adds method target as a possible target of the invoke expression in s. If + * target is null, only creates the nodes for the call site, without actually + * connecting them to any target method. + **/ + private void processCallAssign(Edge e) { + MethodPAG srcmpag = pag.getMethodPAG(e.src()); + MethodPAG tgtmpag = pag.getMethodPAG(e.tgt()); + Stmt s = (Stmt) e.srcUnit(); + Context srcContext = e.srcCtxt(); + Context tgtContext = e.tgtCtxt(); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + SootMethod tgtmtd = tgtmpag.getMethod(); + AbstractInvokeExpr ie = s.getInvokeExpr(); + // add arg --> param edges. + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + Type tgtType = tgtmtd.getParameterType(i); + if (!(tgtType instanceof ReferenceType)) { + continue; + } + Node argNode = srcnf.getNode(arg); + argNode = pta.parameterize(argNode, srcContext); + Node parm = tgtnf.caseParm(i); + parm = pta.parameterize(parm, tgtContext); + pag.addEdge(argNode, parm); + } + // add normal return edge + if (s instanceof JAssignStmt jassign) { + Value dest = (jassign.getLeftOp(); + + if (dest.getType() instanceof ReferenceType) { + Node destNode = srcnf.getNode(dest); + destNode = pta.parameterize(destNode, srcContext); + if (tgtmtd.getReturnType() instanceof ReferenceType) { + Node retNode = tgtnf.caseRet(); + retNode = pta.parameterize(retNode, tgtContext); + pag.addEdge(retNode, destNode); + } + } + + } + // add throw return edge + if (CoreConfig.v().getPtaConfig().preciseExceptions) { + Node throwNode = tgtnf.caseMethodThrow(); + /* + * If an invocation statement may throw exceptions, we create a special local variables + * to receive the exception objects. + * a_ret = x.foo(); here, a_ret is a variable to receive values from return variables of foo(); + * a_throw = x.foo(); here, a_throw is a variable to receive exception values thrown by foo(); + * */ + throwNode = pta.parameterize(throwNode, tgtContext); + MethodNodeFactory mnf = srcmpag.nodeFactory(); + Node dst = mnf.makeInvokeStmtThrowVarNode(s, srcmpag.getMethod()); + dst = pta.parameterize(dst, srcContext); + pag.addEdge(throwNode, dst); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java new file mode 100644 index 00000000000..7ef0aefcadb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -0,0 +1,102 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.builder; + +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.context.Context; +import qilin.core.pag.*; +import qilin.core.sets.P2SetVisitor; +import qilin.core.sets.PointsToSetInternal; +import qilin.util.DataFactory; +import sootup.core.jimple.basic.Trap; +import sootup.core.jimple.common.stmt.JIdentityStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; + +import java.util.*; + +public class ExceptionHandler { + protected final Map> throwNodeToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); + protected PTA pta; + protected PAG pag; + + public ExceptionHandler(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + } + + public Collection throwSitesLookUp(VarNode throwNode) { + return throwNodeToSites.getOrDefault(throwNode, Collections.emptySet()); + } + + public boolean addThrowSite(Node throwNode, ExceptionThrowSite ets) { + Collection throwSites = throwNodeToSites.computeIfAbsent(throwNode, k -> DataFactory.createSet()); + return throwSites.add(ets); + } + + public void exceptionDispatch(PointsToSetInternal p2set, ExceptionThrowSite site) { + p2set.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + dispatch((AllocNode) n, site); + } + }); + } + + /* + * dispatch the exception objects by following the exception-cath-links in Doop-ISSTA09. + * */ + public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { + Type type = throwObj.getType(); + ContextMethod momc = site.container(); + SootMethod sm = momc.method(); + Context context = momc.context(); + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory nodeFactory = mpag.nodeFactory(); + VarNode throwNode = site.getThrowNode(); + List trapList = mpag.stmt2wrapperedTraps.getOrDefault(site.getUnit(), Collections.emptyList()); + for (Trap trap : trapList) { + if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, trap.getExceptionType())) { + Stmt handler = trap.getHandlerStmt(); + assert handler instanceof JIdentityStmt; + JIdentityStmt handlerStmt = (JIdentityStmt) handler; + Node caughtParam = nodeFactory.getNode(handlerStmt.getRightOp()); + Node dst = pta.parameterize(caughtParam, context); + pag.addEdge(throwObj, dst); + // record an edge from base --> caughtParam on the methodPag. + recordImplictEdge(throwNode, caughtParam, mpag); + return; + } + } + // No trap handle the throwable object in the method. + Node methodThrowNode = nodeFactory.caseMethodThrow(); + Node dst = pta.parameterize(methodThrowNode, context); + pag.addEdge(throwObj, dst); + // record an edge from base --> methodThrowNode on the methodPag. + recordImplictEdge(throwNode, methodThrowNode, mpag); + } + + private void recordImplictEdge(Node src, Node dst, MethodPAG mpag) { + if (src instanceof ContextVarNode) { + src = ((ContextVarNode) src).base(); + } + mpag.addExceptionEdge(src, dst); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java new file mode 100644 index 00000000000..a069637031f --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -0,0 +1,152 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.builder; + +import qilin.CoreConfig; +import qilin.core.ArtificialMethod; +import qilin.util.PTAUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FakeMainFactory extends ArtificialMethod { + public static FakeMainFactory instance; + + public static int implicitCallEdges; + private final SootClass fakeClass; + + public FakeMainFactory() { + this.localStart = 0; + this.fakeClass = new SootClass("FakeMain"); + this.fakeClass.setResolvingLevel(SootClass.BODIES); + this.method = new SootMethod("fakeMain", null, VoidType.v()); + this.method.setModifiers(Modifier.STATIC); + SootField currentThread = new SootField("currentThread", RefType.v("java.lang.Thread"), Modifier.STATIC); + SootField globalThrow = new SootField("globalThrow", RefType.v("java.lang.Exception"), Modifier.STATIC); + fakeClass.addMethod(this.method); + fakeClass.addField(currentThread); + fakeClass.addField(globalThrow); + } + + private List getEntryPoints() { + List ret = new ArrayList<>(); + if (CoreConfig.v().getPtaConfig().clinitMode == CoreConfig.ClinitMode.FULL) { + ret.addAll(EntryPoints.v().clinits()); + } else { + // on the fly mode, resolve the clinit methods on the fly. + ret.addAll(Collections.emptySet()); + } + + if (CoreConfig.v().getPtaConfig().singleentry) { + List entries = EntryPoints.v().application(); + if (entries.isEmpty()) { + throw new RuntimeException("Must specify MAINCLASS when appmode enabled!!!"); + } else { + ret.addAll(entries); + } + } else { + System.out.println("include implicit entry!"); + ret.addAll(EntryPoints.v().application()); + ret.addAll(EntryPoints.v().implicit()); + } + System.out.println("#EntrySize:" + ret.size()); + return ret; + } + + public SootMethod getFakeMain() { + if (body == null) { + synchronized (this) { + if (body == null) { + this.method.setSource((m, phaseName) -> new JimpleBody(this.method)); + this.body = PTAUtils.getMethodBody(method); + makeFakeMain(); + } + } + } + return this.method; + } + + public Value getFieldCurrentThread() { + return getStaticFieldRef("FakeMain", "currentThread"); + } + + public Value getFieldGlobalThrow() { + return getStaticFieldRef("FakeMain", "globalThrow"); + } + + private void makeFakeMain() { + implicitCallEdges = 0; + for (SootMethod entry : getEntryPoints()) { + if (entry.isStatic()) { + if (entry.getSubSignature().equals("void main(java.lang.String[])")) { + Value mockStr = getNew(RefType.v("java.lang.String")); + Value strArray = getNewArray(RefType.v("java.lang.String")); + addAssign(getArrayRef(strArray), mockStr); + addInvoke(entry.getSignature(), strArray); + implicitCallEdges++; + } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !entry.isStaticInitializer()) { + // in the on fly mode, we won't add a call directly for methods. + addInvoke(entry.getSignature()); + implicitCallEdges++; + } + } + } + if (CoreConfig.v().getPtaConfig().singleentry) { + return; + } + Value sv = getNextLocal(RefType.v("java.lang.String")); + Value mainThread = getNew(RefType.v("java.lang.Thread")); + Value mainThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + Value systemThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + + Value gCurrentThread = getFieldCurrentThread(); + addAssign(gCurrentThread, mainThread); // Store + Value vRunnable = getNextLocal(RefType.v("java.lang.Runnable")); + + Value lThreadGroup = getNextLocal(RefType.v("java.lang.ThreadGroup")); + addInvoke(mainThread, "(java.lang.ThreadGroup,java.lang.String)>", mainThreadGroup, sv); + Value tmpThread = getNew(RefType.v("java.lang.Thread")); + addInvoke(tmpThread, "(java.lang.ThreadGroup,java.lang.Runnable)>", lThreadGroup, vRunnable); + addInvoke(tmpThread, ""); + + addInvoke(systemThreadGroup, "()>"); + addInvoke(mainThreadGroup, "(java.lang.ThreadGroup,java.lang.String)>", systemThreadGroup, sv); + + Value lThread = getNextLocal(RefType.v("java.lang.Thread")); + Value lThrowable = getNextLocal(RefType.v("java.lang.Throwable")); + Value tmpThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + addInvoke(tmpThreadGroup, "", lThread, lThrowable); // TODO. + + + // ClassLoader + Value defaultClassLoader = getNew(RefType.v("sun.misc.Launcher$AppClassLoader")); + addInvoke(defaultClassLoader, "()>"); + Value vClass = getNextLocal(RefType.v("java.lang.Class")); + Value vDomain = getNextLocal(RefType.v("java.security.ProtectionDomain")); + addInvoke(defaultClassLoader, "", sv); + addInvoke(defaultClassLoader, "", vClass, vDomain); + addInvoke(defaultClassLoader, "", vClass); + + // PrivilegedActionException + Value privilegedActionException = getNew(RefType.v("java.security.PrivilegedActionException")); + Value gLthrow = getNextLocal(RefType.v("java.lang.Exception")); + addInvoke(privilegedActionException, "(java.lang.Exception)>", gLthrow); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java new file mode 100644 index 00000000000..cbe2779d350 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -0,0 +1,339 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.builder; + +import qilin.CoreConfig; +import qilin.core.PTAScene; +import qilin.core.PointsToAnalysis; +import qilin.core.pag.*; +import qilin.util.PTAUtils; +import qilin.util.Pair; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JNewMultiArrayExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JCaughtExceptionRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; +import sootup.core.jimple.common.ref.JParameterRef; +import sootup.core.jimple.common.ref.JStaticFieldRef; +import sootup.core.jimple.common.ref.JThisRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JIdentityStmt; +import sootup.core.jimple.common.stmt.JReturnStmt; +import sootup.core.jimple.common.stmt.JThrowStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Modifier; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; + +/** + * @author Ondrej Lhotak + */ +public class MethodNodeFactory { + protected PAG pag; + protected MethodPAG mpag; + protected SootMethod method; + + public MethodNodeFactory(PAG pag, MethodPAG mpag) { + this.pag = pag; + this.mpag = mpag; + method = mpag.getMethod(); + } + + public Node getNode(Value v) { + if (v instanceof Local l) { + return caseLocal(l); + } else if (v instanceof JCastExpr castExpr) { + return caseCastExpr(castExpr); + } else if (v instanceof JNewExpr ne) { + return caseNewExpr(ne); + } else if (v instanceof JStaticFieldRef sfr) { + return caseStaticFieldRef(sfr); + } else if (v instanceof JNewArrayExpr nae) { + return caseNewArrayExpr(nae); + } else if (v instanceof JArrayRef ar) { + return caseArrayRef(ar); + } else if (v instanceof ClassConstant cc) { + return caseClassConstant(cc); + } else if (v instanceof StringConstant sc) { + return caseStringConstant(sc); + } else if (v instanceof JCaughtExceptionRef cef) { + return caseCaughtExceptionRef(cef); + } else if (v instanceof JParameterRef pr) { + return caseParameterRef(pr); + } else if (v instanceof NullConstant nc) { + return caseNullConstant(nc); + } else if (v instanceof JInstanceFieldRef ifr) { + return caseInstanceFieldRef(ifr); + } else if (v instanceof JThisRef) { + return caseThis(); + } else if (v instanceof JNewMultiArrayExpr nmae) { + return caseNewMultiArrayExpr(nmae); + } + System.out.println(v + ";;" + v.getClass()); + return null; + } + + /** + * Adds the edges required for this statement to the graph. + */ + final public void handleStmt(Stmt s) { + if (s.containsInvokeExpr()) { + mpag.addCallStmt(s); + handleInvokeStmt(s); + } else { + handleIntraStmt(s); + } + } + + /** + * Adds the edges required for this statement to the graph. Add throw stmt if + * the invoke method throws an Exception. + */ + protected void handleInvokeStmt(Stmt s) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + getNode(arg); + } + if (s instanceof JAssignStmt assignStmt) { + Value l = assignStmt.getLeftOp(); + if ((l.getType() instanceof ReferenceType)) { + getNode(l); + } + } + if (ie instanceof AbstractInstanceInvokeExpr iie) { + getNode(iie.getBase()); + } + } + + private void resolveClinit(JStaticFieldRef staticFieldRef) { + PTAUtils.clinitsOf(staticFieldRef.getField().getDeclaringClass()).forEach(mpag::addTriggeredClinit); + } + + /** + * Adds the edges required for this statement to the graph. + */ + private void handleIntraStmt(Stmt s) { + s.apply(new AbstractStmtSwitch<>() { + public void caseAssignStmt(JAssignStmt as) { + Value l = as.getLeftOp(); + Value r = as.getRightOp(); + if (l instanceof JStaticFieldRef sfr) { + resolveClinit(sfr); + } else if (r instanceof JStaticFieldRef sfr) { + resolveClinit(sfr); + } + + if (!(l.getType() instanceof ReferenceType)) + return; + // check for improper casts, with mal-formed code we might get + // l = (refliketype)int_type, if so just return + if (r instanceof JCastExpr && (!(((JCastExpr) r).getOp().getType() instanceof ReferenceType))) { + return; + } + + if (!(r.getType() instanceof ReferenceType)) + throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + as + + " in method " + method.getSignature()); + Node dest = getNode(l); + Node src = getNode(r); + mpag.addInternalEdge(src, dest); + } + + public void caseReturnStmt(JReturnStmt rs) { + if (!(rs.getOp().getType() instanceof ReferenceType)) + return; + Node retNode = getNode(rs.getOp()); + mpag.addInternalEdge(retNode, caseRet()); + } + + public void caseIdentityStmt(JIdentityStmt is) { + if (!(is.getLeftOp().getType() instanceof ReferenceType)) { + return; + } + Node dest = getNode(is.getLeftOp()); + Node src = getNode(is.getRightOp()); + mpag.addInternalEdge(src, dest); + } + + public void caseThrowStmt(JThrowStmt ts) { + if (!CoreConfig.v().getPtaConfig().preciseExceptions) { + mpag.addInternalEdge(getNode(ts.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); + } + } + }); + } + + private VarNode caseLocal(Local l) { + return pag.makeLocalVarNode(l, l.getType(), method); + } + + private AllocNode caseNewArrayExpr(JNewArrayExpr nae) { + return pag.makeAllocNode(nae, nae.getType(), method); + } + + private AllocNode caseNewExpr(JNewExpr ne) { + SootClass cl = PTAScene.v().loadClassAndSupport(ne.getType().toString()); + PTAUtils.clinitsOf(cl).forEach(mpag::addTriggeredClinit); + return pag.makeAllocNode(ne, ne.getType(), method); + } + + private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { + SootField sf = ifr.getField(); +// if (sf == null) { +// sf = new SootField(ifr.getFieldSignature(), ifr.getType(), Modifier.PUBLIC); +// sf.setNumber(Scene.v().getFieldNumberer().size()); +// Scene.v().getFieldNumberer().add(sf); +// System.out.println("Warnning:" + ifr + " is resolved to be a null field in Scene."); +// } + return pag.makeFieldRefNode(pag.makeLocalVarNode(ifr.getBase(), ifr.getBase().getType(), method), new Field(sf)); + } + + private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { + ArrayType type = (ArrayType) nmae.getType(); + int pos = 0; + AllocNode prevAn = pag.makeAllocNode(new JNewArrayExpr(type, nmae.getSize(pos)), type, method); + VarNode prevVn = pag.makeLocalVarNode(prevAn.getNewExpr(), prevAn.getType(), method); + mpag.addInternalEdge(prevAn, prevVn); // new + VarNode ret = prevVn; + while (true) { + Type t = type.getArrayElementType(); + if (!(t instanceof ArrayType)) { + break; + } + type = (ArrayType) t; + ++pos; + Value sizeVal; + if (pos < nmae.getSizeCount()) { + sizeVal = nmae.getSize(pos); + } else { + sizeVal = IntConstant.getInstance(1); + } + AllocNode an = pag.makeAllocNode(new JNewArrayExpr(type, sizeVal), type, method); + VarNode vn = pag.makeLocalVarNode(an.getNewExpr(), an.getType(), method); + mpag.addInternalEdge(an, vn); // new + mpag.addInternalEdge(vn, pag.makeFieldRefNode(prevVn, ArrayElement.v())); // store + prevVn = vn; + } + return ret; + } + + private VarNode caseCastExpr(JCastExpr ce) { + Node opNode = getNode(ce.getOp()); + VarNode castNode = pag.makeLocalVarNode(ce, ce.getType(), method); + mpag.addInternalEdge(opNode, castNode); + return castNode; + } + + public VarNode caseThis() { + Type type = method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); + VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THIS_NODE), type, method); + ret.setInterProcTarget(); + return ret; + } + + public VarNode caseParm(int index) { + VarNode ret = pag.makeLocalVarNode(new Parm(method, index), method.getParameterType(index), method); + ret.setInterProcTarget(); + return ret; + } + + public VarNode caseRet() { + VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.RETURN_NODE), method.getReturnType(), method); + ret.setInterProcSource(); + return ret; + } + + public VarNode caseMethodThrow() { + VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), RefType.v("java.lang.Throwable"), method); + ret.setInterProcSource(); + return ret; + } + + final public FieldRefNode caseArray(VarNode base) { + return pag.makeFieldRefNode(base, ArrayElement.v()); + } + + private Node caseCaughtExceptionRef(JCaughtExceptionRef cer) { + if (CoreConfig.v().getPtaConfig().preciseExceptions) { + // we model caughtException expression as an local assignment. + return pag.makeLocalVarNode(cer, cer.getType(), method); + } else { + return getNode(PTAScene.v().getFieldGlobalThrow()); + } + } + + private FieldRefNode caseArrayRef(JArrayRef ar) { + return caseArray(caseLocal((Local) ar.getBase())); + } + + private VarNode caseParameterRef(JParameterRef pr) { + return caseParm(pr.getIndex()); + } + + private VarNode caseStaticFieldRef(JStaticFieldRef sfr) { + return pag.makeGlobalVarNode(sfr.getField(), sfr.getType()); + } + + private Node caseNullConstant(NullConstant nr) { + return null; + } + + private VarNode caseStringConstant(StringConstant sc) { + AllocNode stringConstantNode = pag.makeStringConstantNode(sc); + VarNode stringConstantVar = pag.makeGlobalVarNode(sc, RefType.v("java.lang.String")); + mpag.addInternalEdge(stringConstantNode, stringConstantVar); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), RefType.v("java.lang.String"), method); + mpag.addInternalEdge(stringConstantVar, vn); + return vn; + } + + public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { + return pag.makeLocalVarNode(invoke, RefType.v("java.lang.Throwable"), method); + } + + final public VarNode caseClassConstant(ClassConstant cc) { + AllocNode classConstant = pag.makeClassConstantNode(cc); + VarNode classConstantVar = pag.makeGlobalVarNode(cc, RefType.v("java.lang.Class")); + mpag.addInternalEdge(classConstant, classConstantVar); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), RefType.v("java.lang.Class"), method); + mpag.addInternalEdge(classConstantVar, vn); + return vn; + } + + +} diff --git a/sootup.qilin/src/main/java/qilin/core/context/Context.java b/sootup.qilin/src/main/java/qilin/core/context/Context.java new file mode 100644 index 00000000000..94b8b6829f2 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/context/Context.java @@ -0,0 +1,4 @@ +package qilin.core.context; + +public interface Context { +} diff --git a/sootup.qilin/src/main/java/qilin/core/context/ContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/ContextElement.java new file mode 100644 index 00000000000..bb4a896eab6 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/context/ContextElement.java @@ -0,0 +1,27 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.context; + +public interface ContextElement { + @Override + int hashCode(); + + @Override + boolean equals(Object obj); +} diff --git a/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java b/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java new file mode 100644 index 00000000000..0ad3f869158 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java @@ -0,0 +1,125 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.context; + +import java.util.Arrays; + +public class ContextElements implements Context { + private final ContextElement[] array; + private final int size; + private int hashCode = 0; + + public ContextElements(ContextElement[] array, int s) { + this.array = array; + this.size = s; + } + + public ContextElement[] getElements() { + return array; + } + + public ContextElement get(int i) { + return array[i]; + } + + public boolean contains(ContextElement heap) { + for (int i = 0; i < size; ++i) { + if (array[i] == heap) { + return true; + } + } + return false; + } + + public boolean isEmpty() { + return size == 0; + } + + public int size() { + return size; + } + + @Override + public int hashCode() { + if (hashCode == 0) { + hashCode = Arrays.hashCode(array); + } + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (getClass() != obj.getClass()) + return false; + ContextElements other = (ContextElements) obj; + + // if (!Arrays.equals(array, other.array)) return false; + + // custom array equals for context + // allows for checking of different sized arrays, but represent same + // context-sensitive heap object + if (this.array == null || other.array == null) + return false; + + if (this.size() != other.size()) + return false; + + for (int i = 0; i < size(); i++) { + Object o1 = this.array[i]; + Object o2 = other.array[i]; + if (!(o1 == null ? o2 == null : o1.equals(o2))) + return false; + } + + return true; + } + + @Override + public String toString() { + StringBuilder localStringBuilder = new StringBuilder(); + localStringBuilder.append('['); + for (int i = 0; i < array.length; i++) { + localStringBuilder.append(array[i]); + if (i < array.length - 1) { + localStringBuilder.append(", "); + } + } + localStringBuilder.append(']'); + return localStringBuilder.toString(); + } + + /** + * Compose a new context by a given context and a heap. + * The depth of new context is also required. + */ + public static ContextElements newContext(ContextElements c, ContextElement ce, int depth) { + ContextElement[] array; + if (c.size() < depth) { + array = new ContextElement[c.size() + 1]; + System.arraycopy(c.getElements(), 0, array, 1, c.size()); + } else { + array = new ContextElement[depth]; + System.arraycopy(c.getElements(), 0, array, 1, depth - 1); + } + array[0] = ce; + return new ContextElements(array, array.length); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java new file mode 100644 index 00000000000..5df60c5810a --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java @@ -0,0 +1,85 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.context; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.ClassConstantNode; +import qilin.core.pag.StringConstantNode; +import sootup.core.IdentifierFactory; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; +import sootup.core.views.View; + +/** + * Type based context element in the points to analysis. + */ +public class TypeContextElement implements ContextElement { + + private final Type type; + + private TypeContextElement(Type type) { + this.type = type; + } + + public static TypeContextElement getTypeContextElement(View view, AllocNode a) { + SootMethod declaringMethod = a.getMethod(); + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + Type declType = identifierFactory.getType("java.lang.Object"); + if (declaringMethod != null) { + declType = declaringMethod.getDeclaringClassType(); + } else if (a instanceof ClassConstantNode) { + declType = identifierFactory.getType("java.lang.System"); + } else if (a instanceof StringConstantNode) { + declType = identifierFactory.getType("java.lang.String"); + } + return new TypeContextElement(declType); + } + + public Type getType() { + return type; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TypeContextElement other = (TypeContextElement) obj; + if (type == null) { + return other.type == null; + } else { + return type.equals(other.type); + } + } + + public String toString() { + return "TypeContext: " + type; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java new file mode 100644 index 00000000000..72a3c1ec335 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -0,0 +1,42 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.RefType; +import soot.SootMethod; +import soot.Value; + +public class JavaIoFileSystemGetFileSystemNative extends NativeMethod { + public JavaIoFileSystemGetFileSystemNative(SootMethod method) { + super(method); + } + + /************************ java.io.FileSystem ***********************/ + /** + * Returns a variable pointing to the file system constant + *

+ * public static native java.io.FileSystem getFileSystem(); + * only exists in old version of JDK(e.g., JDK6). + */ + public void simulate() { + Value newLocal0 = getNew(RefType.v("java.io.UnixFileSystem")); + addInvoke(newLocal0, "()>"); + addReturn(newLocal0); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java new file mode 100644 index 00000000000..9aa887897a7 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -0,0 +1,42 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.RefType; +import soot.SootMethod; +import soot.Value; + +public class JavaIoFileSystemListNative extends NativeMethod { + public JavaIoFileSystemListNative(SootMethod method) { + super(method); + } + + /************************ java.io.FileSystem ***********************/ + /** + * Returns a String[] + * only exists in old JDK(e.g., JDK6). + */ + public void simulate() { + Value arrLocal = getNewArray(RefType.v("java.lang.String")); + Value elem = getNew(RefType.v("java.lang.String")); +// addInvoke(elem, "()>"); + addAssign(getArrayRef(arrLocal), elem); + addReturn(arrLocal); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java new file mode 100644 index 00000000000..2015305c614 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.SootMethod; +import soot.Value; + +public class JavaLangObjectCloneNative extends NativeMethod { + + public JavaLangObjectCloneNative(SootMethod method) { + super(method); + } + + /** + * Implements the abstract method simulateMethod. It distributes the request to + * the corresponding methods by signatures. + */ + public void simulate() { + Value r0 = getThis(); + addReturn(r0); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java new file mode 100644 index 00000000000..88c109910de --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.SootMethod; +import soot.Value; + +public class JavaLangRefFinalizerInvokeFinalizeMethodNative extends NativeMethod { + public JavaLangRefFinalizerInvokeFinalizeMethodNative(SootMethod method) { + super(method); + } + + /** + * "" + */ + public void simulate() { + Value r0 = getPara(0); + addInvoke(r0, ""); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java new file mode 100644 index 00000000000..829f8bab37a --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -0,0 +1,43 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.ArrayType; +import soot.RefType; +import soot.SootMethod; +import soot.Value; + +/* + * + * */ + +public class JavaLangReflectArrayGet extends NativeMethod { + JavaLangReflectArrayGet(SootMethod method) { + super(method); + } + + @Override + void simulate() { + Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + Value arrayRef = getArrayRef(arrayBase); + Value ret = getNextLocal(RefType.v("java.lang.Object")); + addAssign(ret, arrayRef); + addReturn(ret); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java new file mode 100644 index 00000000000..c608b635fc8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -0,0 +1,42 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.ArrayType; +import soot.RefType; +import soot.SootMethod; +import soot.Value; + +/* + * handle + * */ + +public class JavaLangReflectArraySet extends NativeMethod { + JavaLangReflectArraySet(SootMethod method) { + super(method); + } + + @Override + void simulate() { + Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + Value rightValue = getPara(2); + Value arrayRef = getArrayRef(arrayBase); + addAssign(arrayRef, rightValue); // a[] = b; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java new file mode 100644 index 00000000000..f03dcfc9c81 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -0,0 +1,50 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.ArrayType; +import soot.RefType; +import soot.SootMethod; +import soot.Value; + +/* + * This file will be temporarily discarded. Yes, it is correct but need one more level of context. + * Thus it will make qilin.spark less precise than its counterpart in Doop. + * */ +public class JavaLangSystemArraycopyNative extends NativeMethod { + public JavaLangSystemArraycopyNative(SootMethod method) { + super(method); + } + + /** + * never make a[] = b[], it violates the principle of jimple statement. make a + * temporary variable. + */ + public void simulate() { +// Value srcArr = getPara(0); +// Value dstArr = getPara(2); + Value srcArr = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + Value dstArr = getPara(2, ArrayType.v(RefType.v("java.lang.Object"), 1)); + Value src = getArrayRef(srcArr); + Value dst = getArrayRef(dstArr); + Value temp = getNextLocal(RefType.v("java.lang.Object")); + addAssign(temp, src); + addAssign(dst, temp); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java new file mode 100644 index 00000000000..84d5f0786e5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.SootMethod; +import soot.Value; + +public class JavaLangSystemSetErr0Native extends NativeMethod { + public JavaLangSystemSetErr0Native(SootMethod method) { + super(method); + } + + /** + * NOTE: this native method is not documented in JDK API. It should have the + * side effect: System.err = parameter + *

+ * private static native void setErr0(java.io.PrintStream); + */ + public void simulate() { + Value r1 = getPara(0); + Value systemErr = getStaticFieldRef("java.lang.System", "err"); + addAssign(systemErr, r1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java new file mode 100644 index 00000000000..e6d36202de4 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.SootMethod; +import soot.Value; + +public class JavaLangSystemSetIn0Native extends NativeMethod { + public JavaLangSystemSetIn0Native(SootMethod method) { + super(method); + } + + /** + * NOTE: this native method is not documented in JDK API. It should have the + * side effect: System.in = parameter + *

+ * private static native void setIn0(java.io.InputStream); + */ + public void simulate() { + Value r1 = getPara(0); + Value systemIn = getStaticFieldRef("java.lang.System", "in"); + addAssign(systemIn, r1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java new file mode 100644 index 00000000000..203a5f0ce0f --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.SootMethod; +import soot.Value; + +public class JavaLangSystemSetOut0Native extends NativeMethod { + public JavaLangSystemSetOut0Native(SootMethod method) { + super(method); + } + + /** + * NOTE: this native method is not documented in JDK API. It should have the + * side effect: System.out = parameter + *

+ * private static native void setOut0(java.io.PrintStream); + */ + public void simulate() { + Value r1 = getPara(0); + Value systemOut = getStaticFieldRef("java.lang.System", "out"); + addAssign(systemOut, r1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java new file mode 100644 index 00000000000..c8eda289ed1 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import qilin.core.PTAScene; +import soot.RefType; +import soot.SootMethod; +import soot.Value; + +public class JavaLangThreadCurrentThread extends NativeMethod { + JavaLangThreadCurrentThread(SootMethod method) { + super(method); + } + + @Override + void simulate() { + Value lv = getNextLocal(RefType.v("java.lang.Thread")); + Value rv = PTAScene.v().getFieldCurrentThread(); + addAssign(lv, rv); + addReturn(lv); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java new file mode 100644 index 00000000000..c1dd4da9507 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java @@ -0,0 +1,45 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import qilin.core.PTAScene; +import soot.SootMethod; +import soot.Value; + +public class JavaLangThreadStart0Native extends NativeMethod { + + public JavaLangThreadStart0Native(SootMethod method) { + super(method); + } + + /** + * Calls to Thread.start() get redirected to Thread.run. + *

+ * In JRE 1.5 and JRE 1.6 Thread.start() is defined in Java + * and there is native method start0. + */ + + @Override + void simulate() { + Value mThis = getThis(); + addInvoke(mThis, ""); + Value lv = PTAScene.v().getFieldCurrentThread(); + addAssign(lv, mThis); // store. + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java new file mode 100644 index 00000000000..3ff7f9d4c31 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ +package qilin.core.natives; + +import soot.SootMethod; +import soot.Value; + +public class JavaSecurityAccessControllerDoPrivilegedNative extends NativeMethod { + public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { + super(method); + } + + /** + * public static native java.lang.Object + * doPrivileged(java.security.PrivilegedAction) public static native + * java.lang.Object + * doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext) + */ + public void simulate() { + Value r0 = getPara(0); + Value r1 = getInvoke(r0, ""); + addReturn(r1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java new file mode 100644 index 00000000000..dee72f7f120 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import soot.SootMethod; +import soot.Value; + +public class JavaSecurityAccessControllerDoPrivileged_ExceptionNative extends NativeMethod { + public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod method) { + super(method); + } + + /** + * public static native java.lang.Object + * doPrivileged(java.security.PrivilegedExceptionAction) public static native + * java.lang.Object + * doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext) + */ + public void simulate() { + Value r0 = getPara(0); + Value r1 = getInvoke(r0, ""); + addReturn(r1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java new file mode 100644 index 00000000000..d54d470b0a5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import qilin.core.ArtificialMethod; +import qilin.util.PTAUtils; +import soot.SootMethod; +import soot.Value; + +public abstract class NativeMethod extends ArtificialMethod { + + NativeMethod(SootMethod method) { + this.method = method; + this.body = PTAUtils.getMethodBody(method); + int paraCount = method.getParameterCount(); + paraLocals = new Value[paraCount]; + this.paraStart = method.isStatic() ? 0 : 1; + this.localStart = this.paraStart + paraCount; + } + + abstract void simulate(); +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java new file mode 100644 index 00000000000..aaa70916b69 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java @@ -0,0 +1,84 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.natives; + +import qilin.core.PTAScene; +import soot.SootMethod; + +public class NativeMethodDriver { + public void buildNative(SootMethod method) { + if (!PTAScene.v().nativeBuilt.add(method)) { + return; + } + String sig = method.getSignature(); + switch (sig) { + case "": + case "": + new JavaLangObjectCloneNative(method).simulate(); + break; + case "": + new JavaLangSystemSetIn0Native(method).simulate(); + break; + case "": + new JavaLangSystemSetOut0Native(method).simulate(); + break; + case "": + new JavaLangSystemSetErr0Native(method).simulate(); + break; +// case "": +// new JavaLangSystemArraycopyNative(method).simulate(); +// break; + case "": + case "": + new JavaIoFileSystemGetFileSystemNative(method).simulate(); + break; + case "": + case "": + new JavaIoFileSystemListNative(method).simulate(); + break; + case "": + new JavaLangRefFinalizerInvokeFinalizeMethodNative(method).simulate(); + break; + case "": + case "": + new JavaSecurityAccessControllerDoPrivilegedNative(method).simulate(); + break; + case "": + case "": + new JavaSecurityAccessControllerDoPrivileged_ExceptionNative(method).simulate(); + break; + case "": + new JavaLangThreadCurrentThread(method).simulate(); + break; + case "": + new JavaLangThreadStart0Native(method).simulate(); + break; + case "": +// new JavaLangReflectArrayGet(method).simulate(); + break; + case "": +// new JavaLangReflectArraySet(method).simulate(); + break; + default: + // System.out.println("Warning: unhandled native method " + sig); + break; + } + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/natives/package-info.java b/sootup.qilin/src/main/java/qilin/core/natives/package-info.java new file mode 100644 index 00000000000..8c45204821b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/natives/package-info.java @@ -0,0 +1,7 @@ +package qilin.core.natives; + +/* + * In this package, we currently only handle a subset of native methods that are supported in Doop. + * In the future, we will append more simulations to native methods that are frequently used by + * real-world applications. + * */ \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java new file mode 100644 index 00000000000..7e0d7d48f8d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java @@ -0,0 +1,76 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.CoreConfig; +import qilin.core.context.ContextElement; +import qilin.core.util.Numberable; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.core.types.Type; +import sootup.core.views.View; + +/** + * Represents an allocation site node in the pointer assignment graph. + * + * @author Ondrej Lhotak + */ +public class AllocNode extends Node implements ContextElement, Numberable { + protected Object newExpr; + private final SootMethod method; + + public AllocNode(View view, Object newExpr, Type t, SootMethod m) { + super(view, t); + this.method = m; + if (t instanceof ClassType rt) { + SootClass sc = (SootClass) view.getClass(rt).get(); + if (sc.isAbstract()) { + boolean usesReflectionLog = CoreConfig.v().getAppConfig().REFLECTION_LOG != null; + if (!usesReflectionLog) { + throw new RuntimeException("Attempt to create allocnode with abstract type " + t); + } + } + } + this.newExpr = newExpr; + } + + /** + * Returns the new expression of this allocation site. + */ + public Object getNewExpr() { + return newExpr; + } + + public String toString() { + return "AllocNode " + getNumber() + " " + newExpr + " in method " + method; + } + + public String toString2() { + return newExpr + " in method " + method; + } + + public SootMethod getMethod() { + return method; + } + + public AllocNode base() { + return this; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java new file mode 100644 index 00000000000..d6b74fa2c2b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java @@ -0,0 +1,55 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import soot.RefType; +import sootup.core.types.Type; + +/** + * Represents an array element. + * + * @author Ondrej Lhotak + */ +public class ArrayElement implements SparkField { + private static ArrayElement instance = null; + private int number = 0; + + public static ArrayElement v() { + if (instance == null) { + synchronized (ArrayElement.class) { + if (instance == null) { + instance = new ArrayElement(); + } + } + } + return instance; + } + + public final int getNumber() { + return number; + } + + public final void setNumber(int number) { + this.number = number; + } + + public Type getType() { + return RefType.v("java.lang.Object"); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java new file mode 100644 index 00000000000..8e31efd4d52 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java @@ -0,0 +1,68 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.context.ContextElement; +import sootup.core.jimple.common.stmt.Stmt; + +/** + * callsite based context element in the points to analysis. + */ +public class CallSite implements ContextElement { + + private final Stmt unit; + + public CallSite(Stmt unit) { + this.unit = unit; + } + + public Stmt getUnit() { + return unit; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((unit == null) ? 0 : unit.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CallSite other = (CallSite) obj; + if (unit == null) { + return other.unit == null; + } else if (other.unit == null) { + return false; + } else { + return unit.equals(other.unit); + } + } + + public String toString() { + return "CallSite: " + unit; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java new file mode 100644 index 00000000000..b568fcce8c7 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.views.View; + +/** + * Represents an allocation site node the represents a known java.lang.Class object. + * + * @author Ondrej Lhotak + */ +public class ClassConstantNode extends ConstantNode { + public ClassConstantNode(View view, ClassConstant cc) { + super(view, cc, view.getIdentifierFactory().getType("java.lang.Class"), null); + } + + public String toString() { + return "ClassConstantNode " + getNumber() + " " + newExpr; + } + + public ClassConstant getClassConstant() { + return (ClassConstant) newExpr; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java new file mode 100644 index 00000000000..2a00eee045d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java @@ -0,0 +1,29 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import sootup.core.model.SootMethod; +import sootup.core.types.Type; +import sootup.core.views.View; + +public abstract class ConstantNode extends AllocNode { + protected ConstantNode(View view, Object newExpr, Type t, SootMethod m) { + super(view, newExpr, t, m); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java new file mode 100644 index 00000000000..97487f5068e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java @@ -0,0 +1,47 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.context.Context; +import sootup.core.views.View; + +public class ContextAllocNode extends AllocNode { + private final Context context; + private final AllocNode base; + + public ContextAllocNode(View view, AllocNode base, Context context) { + super(view, base.getNewExpr(), base.getType(), base.getMethod()); + this.context = context; + this.base = base; + } + + public Context context() { + return context; + } + + @Override + public AllocNode base() { + return base; + } + + public String toString() { + return "ContextAllocNode " + getNumber() + "(" + base + ", " + context + ")"; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java new file mode 100644 index 00000000000..869df5d4ebd --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java @@ -0,0 +1,86 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.CoreConfig; +import qilin.core.context.Context; +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; +import sootup.core.views.View; + +public class ContextField extends ValNode { + protected Context context; + protected SparkField field; + + public ContextField(View view, Context context, SparkField field) { + super(view, refineFieldType(view, context, field)); + this.context = context; + this.field = field; + } + + private static Type refineFieldType(View view, Context context, SparkField field) { + if (!CoreConfig.v().getPtaConfig().preciseArrayElement) { + return view.getIdentifierFactory().getType("java.lang.Object"); + } + if (field instanceof ArrayElement) { + ContextElement[] contextElements = ((ContextElements) context).getElements(); + if (contextElements.length > 0) { + Type baseHeapType = ((AllocNode) ((ContextElements) context).getElements()[0]).getType(); + if (baseHeapType instanceof ArrayType arrayType) { + return arrayType.getArrayElementType(); + } else { + throw new RuntimeException(baseHeapType + " is not an array type."); + } + } else { + throw new RuntimeException("Context does not have any elements:" + context + ";" + field); + } + } + return field.getType(); + } + + /** + * Returns the base AllocNode. + */ + public Context getContext() { + return context; + } + + public boolean hasBase() { + ContextElements ctxs = (ContextElements) context; + return ctxs.size() > 0; + } + + public AllocNode getBase() { + ContextElements ctxs = (ContextElements) context; + return (AllocNode) ctxs.getElements()[0]; + } + + /** + * Returns the field of this node. + */ + public SparkField getField() { + return field; + } + + public String toString() { + return "ContextField " + getNumber() + " " + getBase() + "." + field; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java new file mode 100644 index 00000000000..ee7a59adcf1 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java @@ -0,0 +1,56 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.context.Context; +import sootup.core.model.SootMethod; + +public final class ContextMethod { + private final SootMethod method; + private final Context context; + + public SootMethod method() { + return this.method; + } + + public Context context() { + return this.context; + } + + public ContextMethod(SootMethod method, Context context) { + this.method = method; + this.context = context; + } + + public int hashCode() { + return this.method.hashCode() + this.context.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof ContextMethod other)) { + return false; + } else { + return this.method.equals(other.method) && this.context.equals(other.context); + } + } + + public String toString() { + return "Method " + this.method + " in context " + this.context; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java new file mode 100644 index 00000000000..75f597d7c21 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java @@ -0,0 +1,58 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.context.Context; +import sootup.core.views.View; + +public class ContextVarNode extends VarNode { + private final Context context; + private final VarNode base; + + public ContextVarNode(View view, VarNode base, Context context) { + super(view, base.getVariable(), base.getType()); + this.context = context; + this.base = base; + } + + + @Override + public boolean isInterProcTarget() { + return base.isInterProcTarget(); + } + + @Override + public boolean isInterProcSource() { + return base.isInterProcSource(); + } + + @Override + public Context context() { + return context; + } + + @Override + public VarNode base() { + return base; + } + + public String toString() { + return "ContextVarNode " + getNumber() + "(" + base + ", " + context + ")"; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java new file mode 100644 index 00000000000..68a8618bdab --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java @@ -0,0 +1,60 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import sootup.core.jimple.common.stmt.Stmt; + +import java.util.Objects; + +public class ExceptionThrowSite { + private final Stmt unit; + private final VarNode throwNode; + private final ContextMethod container; + + public ExceptionThrowSite(VarNode throwNode, Stmt unit, ContextMethod container) { + this.unit = unit; + this.container = container; + this.throwNode = throwNode; + } + + public ContextMethod container() { + return container; + } + + public VarNode getThrowNode() { + return throwNode; + } + + public Stmt getUnit() { + return unit; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExceptionThrowSite that = (ExceptionThrowSite) o; + return Objects.equals(unit, that.unit) && Objects.equals(throwNode, that.throwNode) && Objects.equals(container, that.container); + } + + @Override + public int hashCode() { + return Objects.hash(unit, throwNode, container); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Field.java b/sootup.qilin/src/main/java/qilin/core/pag/Field.java new file mode 100644 index 00000000000..4244773bea1 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/Field.java @@ -0,0 +1,74 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + + +import sootup.core.model.SootField; +import sootup.core.types.Type; + +import java.util.Objects; + +/** + * a wrapper of normal field. + */ +public class Field implements SparkField { + private final SootField field; + + public Field(SootField sf) { + this.field = sf; + } + + @Override + public int getNumber() { + throw new UnsupportedOperationException(); + // return field.getNumber(); + } + + @Override + public void setNumber(int number) { + throw new UnsupportedOperationException(); + } + + @Override + public Type getType() { + return field.getType(); + } + + public SootField getField() { + return field; + } + + @Override + public String toString() { + return "FieldNode " + getNumber() + " " + field; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Field field1 = (Field) o; + return field.equals(field1.field); + } + + @Override + public int hashCode() { + return Objects.hash(field); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java new file mode 100644 index 00000000000..cd7650eb92d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java @@ -0,0 +1,58 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + + +import qilin.core.util.Numberable; +import sootup.core.views.View; + +/** + * Represents a field reference node in the pointer assignment graph. + * + * @author Ondrej Lhotak + */ +public class FieldRefNode extends Node implements Numberable { + protected VarNode base; + protected SparkField field; + + public FieldRefNode(View view, VarNode base, SparkField field) { + super(view, field.getType()); + this.base = base; + this.field = field; + base.addField(this, field); + } + + /** + * Returns the base of this field reference. + */ + public VarNode getBase() { + return base; + } + + /** + * Returns the field of this field reference. + */ + public SparkField getField() { + return field; + } + + public String toString() { + return "FieldRefNode " + getNumber() + " " + base + "." + field; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java new file mode 100644 index 00000000000..768cec9a516 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import sootup.core.views.View; + +public class FieldValNode extends ValNode { + // note, field could only be ArrayElement or Field type. + // Parm should be a local variable in some methods. + private final SparkField field; + + public FieldValNode(View view, SparkField field) { + super(view, field.getType()); + this.field = field; + } + + public SparkField getField() { + return field; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java new file mode 100644 index 00000000000..6524251dbc5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java @@ -0,0 +1,54 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + + +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.types.Type; +import sootup.core.views.View; + +/** + * Represents a simple variable node in the pointer assignment graph that is not associated with any particular + * method invocation. + * + * @author Ondrej Lhotak + */ +public class GlobalVarNode extends VarNode { + public GlobalVarNode(View view, Object variable, Type t) { + super(view, variable, t); + } + + @Override + public VarNode base() { + return this; + } + + public String toString() { + return "GlobalVarNode " + getNumber() + " " + variable; + } + + public SootClass getDeclaringClass() { + if (variable instanceof SootField sootField) { + return (SootClass) view.getClass(sootField.getDeclaringClassType()).get(); + } + + return null; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java new file mode 100644 index 00000000000..64692d104fa --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java @@ -0,0 +1,58 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import sootup.core.model.SootMethod; +import sootup.core.types.Type; +import sootup.core.views.View; + +/** + * @author Ondrej Lhotak + */ +public class LocalVarNode extends VarNode { + protected SootMethod method; + + public LocalVarNode(View view, Object variable, Type t, SootMethod m) { + super(view, variable, t); + this.method = m; + } + + public SootMethod getMethod() { + return method; + } + + public String toString() { + return "LocalVarNode " + getNumber() + " " + variable + " " + method; + } + + /** + * Returns true if this VarNode represents the THIS pointer + */ + public boolean isThis() { + if (variable instanceof Parm parm) { + return parm.isThis(); + } + return false; + } + + @Override + public VarNode base() { + return this; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java new file mode 100644 index 00000000000..7dd9fc02601 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java @@ -0,0 +1,20 @@ +package qilin.core.pag; + +import qilin.util.DataFactory; +import sootup.core.types.ReferenceType; + +import java.util.Map; + +public class MergedNewExpr { + private final ReferenceType type; + private static final Map map = DataFactory.createMap(); + + private MergedNewExpr(ReferenceType type) { + this.type = type; + } + + public static MergedNewExpr v(ReferenceType type) { + return map.computeIfAbsent(type, k -> new MergedNewExpr(type)); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java new file mode 100644 index 00000000000..84975fa87a0 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -0,0 +1,202 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.CoreConfig; +import qilin.util.DataFactory; +import qilin.core.builder.MethodNodeFactory; +import qilin.util.PTAUtils; + +import qilin.util.queue.ChunkedQueue; +import qilin.util.queue.QueueReader; +import sootup.core.jimple.Jimple; +import sootup.core.jimple.basic.Trap; +import sootup.core.jimple.common.ref.JStaticFieldRef; +import sootup.core.jimple.common.stmt.JThrowStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootMethod; + +import java.util.*; + +/** + * Part of a pointer assignment graph for a single method. + * + * @author Ondrej Lhotak + */ +public class MethodPAG { + private final ChunkedQueue internalEdges = new ChunkedQueue<>(); + private final QueueReader internalReader = internalEdges.reader(); + private final Set clinits = DataFactory.createSet(); + private final Collection invokeStmts = DataFactory.createSet(); + public Body body; + /** + * Since now the exception analysis is handled on-the-fly, we should record the + * exception edges explicitly for Eagle and Turner. + */ + private final Map> exceptionEdges = DataFactory.createMap(); + protected MethodNodeFactory nodeFactory; + SootMethod method; + /* + * List[i-1] is wrappered in List[i]. + * We have to extend the following structure from Map> to + * Map>> because there exists cases where the same + * node are thrown more than once and lies in different catch blocks. + * */ + public final Map> stmt2wrapperedTraps = DataFactory.createMap(); + public final Map>> node2wrapperedTraps = DataFactory.createMap(); + + public MethodPAG(PAG pag, SootMethod m, Body body) { + this.method = m; + this.nodeFactory = new MethodNodeFactory(pag, this); + this.body = body; + build(); + } + + public SootMethod getMethod() { + return method; + } + + public MethodNodeFactory nodeFactory() { + return nodeFactory; + } + + public Collection getInvokeStmts() { + return invokeStmts; + } + + public boolean addCallStmt(Stmt unit) { + return this.invokeStmts.add(unit); + } + + protected void build() { + // this method is invalid but exists in pmd-deps.jar + if (method.getSignature().equals("")) { + return; + } + buildException(); + buildNormal(); + addMiscEdges(); + } + + protected void buildNormal() { + if (method.isStatic()) { + PTAUtils.clinitsOf(method.getDeclaringClass()).forEach(this::addTriggeredClinit); + } + for (Stmt unit : body.getStmts()) { + try { + nodeFactory.handleStmt(unit); + } catch (Exception e) { + System.out.println("Warning:" + e); + } + } + } + + protected void buildException() { + // we use the same logic as doop (library/exceptions/precise.logic). + if (!CoreConfig.v().getPtaConfig().preciseExceptions) { + return; + } + List traps = body.getTraps(); + List units = body.getStmts(); + Set inTraps = DataFactory.createSet(); + /* + * The traps is already visited in order. , ; implies is a previous Trap of . + * */ + traps.forEach(trap -> { + units.iterator().forEachRemaining(unit -> { + if (unit == trap.getEndStmt()) { + return; + } + inTraps.add(unit); + Stmt stmt = unit; + Node src = null; + if (stmt.containsInvokeExpr()) { + // note, method.getExceptions() does not return implicit exceptions. + src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); + } else if (stmt instanceof JThrowStmt ts) { + src = nodeFactory.getNode(ts.getOp()); + } + if (src != null) { + addStmtTrap(src, stmt, trap); + } + }); + }); + + for (Stmt unit : body.getStmts()) { + if (inTraps.contains(unit)) { + continue; + } + Stmt stmt = (Stmt) unit; + Node src = null; + if (stmt.containsInvokeExpr()) { + src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); + } else if (stmt instanceof JThrowStmt ts) { + src = nodeFactory.getNode(ts.getOp()); + } + if (src != null) { + node2wrapperedTraps.computeIfAbsent(src, k -> DataFactory.createMap()); + stmt2wrapperedTraps.computeIfAbsent(stmt, k -> DataFactory.createList()); + } + } + } + + private void addStmtTrap(Node src, Stmt stmt, Trap trap) { + Map> stmt2Traps = node2wrapperedTraps.computeIfAbsent(src, k -> DataFactory.createMap()); + List trapList = stmt2Traps.computeIfAbsent(stmt, k -> DataFactory.createList()); + trapList.add(trap); + stmt2wrapperedTraps.computeIfAbsent(stmt, k -> DataFactory.createList()).add(trap); + } + + protected void addMiscEdges() { + if (method.getSignature().equals("(java.lang.Object,java.lang.ref.ReferenceQueue)>")) { + // Implements the special status of java.lang.ref.Reference just as in Doop (library/reference.logic). + JStaticFieldRef sfr = Jimple.newStaticFieldRef(RefType.v("java.lang.ref.Reference").getSootClass().getFieldByName("pending").makeRef()); + addInternalEdge(nodeFactory.caseThis(), nodeFactory.getNode(sfr)); + } + } + + public void addInternalEdge(Node src, Node dst) { + if (src == null) { + return; + } + internalEdges.add(src); + internalEdges.add(dst); + } + + public QueueReader getInternalReader() { + return internalReader; + } + + public void addTriggeredClinit(SootMethod clinit) { + clinits.add(clinit); + } + + public Iterator triggeredClinits() { + return clinits.iterator(); + } + + public void addExceptionEdge(Node from, Node to) { + this.exceptionEdges.computeIfAbsent(from, k -> DataFactory.createSet()).add(to); + } + + public Map> getExceptionEdges() { + return this.exceptionEdges; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Node.java b/sootup.qilin/src/main/java/qilin/core/pag/Node.java new file mode 100644 index 00000000000..09877c8e3aa --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/Node.java @@ -0,0 +1,72 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.sets.DoublePointsToSet; +import qilin.core.util.Numberable; +import qilin.util.PTAUtils; +import sootup.core.types.Type; +import sootup.core.views.View; + +/** + * Represents every node in the pointer assignment graph. + * + * @author Ondrej Lhotak + */ +public class Node implements Numberable { + protected View view; + protected Type type; + protected DoublePointsToSet p2set; + private int number = 0; + + /** + * Creates a new node of pointer assignment graph pag, with type type. + */ + protected Node(View view, Type type) { + if (PTAUtils.isUnresolved(type)) { + throw new RuntimeException("Unresolved type " + type); + } + this.view = view; + this.type = type; + } + + @Override + public final int hashCode() { + return number; + } + + public final boolean equals(Object other) { + return this == other; + } + + /** + * Returns the declared type of this node, null for unknown. + */ + public Type getType() { + return type; + } + + public final int getNumber() { + return number; + } + + public final void setNumber(int number) { + this.number = number; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java new file mode 100644 index 00000000000..a60c480e68a --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -0,0 +1,622 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.PointsToAnalysis; +import qilin.core.context.Context; +import qilin.core.natives.NativeMethodDriver; +import qilin.core.reflection.NopReflectionModel; +import qilin.core.reflection.ReflectionModel; +import qilin.core.reflection.TamiflexModel; +import qilin.core.util.ArrayNumberer; +import qilin.parm.heapabst.HeapAbstractor; +import qilin.util.DataFactory; +import qilin.util.PTAUtils; +import qilin.util.queue.ChunkedQueue; +import qilin.util.queue.QueueReader; +import sootup.core.IdentifierFactory; +import sootup.core.jimple.Jimple; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; +import sootup.core.views.View; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * Pointer assignment graph. + * + * @author Ondrej Lhotak + */ +public class PAG { + protected final NativeMethodDriver nativeDriver; + protected final ReflectionModel reflectionModel; + + // ========================= context-sensitive nodes ================================= + protected final Map> contextVarNodeMap; + protected final Map> contextAllocNodeMap; + protected final Map> contextMethodMap; + protected final Map> addedContexts; + protected final Map> contextFieldMap; + + // ==========================data========================= + protected ArrayNumberer allocNodeNumberer = new ArrayNumberer<>(); + protected ArrayNumberer valNodeNumberer = new ArrayNumberer<>(); + protected ArrayNumberer fieldRefNodeNumberer = new ArrayNumberer<>(); + private static AtomicInteger maxFinishNumber = new AtomicInteger(0); + + // ========================= ir to Node ============================================== + protected final Map valToAllocNode; + protected final Map valToValNode; + protected final Map methodToPag; + protected final Set globals; + protected final Set locals; + // ==========================outer objects============================== + protected ChunkedQueue edgeQueue; + + protected final Map> simple; + protected final Map> simpleInv; + protected final Map> load; + protected final Map> loadInv; + protected final Map> alloc; + protected final Map> allocInv; + protected final Map> store; + protected final Map> storeInv; + + protected final View view; + protected final PTA pta; + + public PAG(View view, PTA pta) { + this.view = view; + this.pta = pta; + this.simple = DataFactory.createMap(); + this.simpleInv = DataFactory.createMap(); + this.load = DataFactory.createMap(); + this.loadInv = DataFactory.createMap(); + this.alloc = DataFactory.createMap(); + this.allocInv = DataFactory.createMap(); + this.store = DataFactory.createMap(); + this.storeInv = DataFactory.createMap(); + this.nativeDriver = new NativeMethodDriver(); + this.reflectionModel = createReflectionModel(); + this.contextVarNodeMap = DataFactory.createMap(16000); + this.contextAllocNodeMap = DataFactory.createMap(6000); + this.contextMethodMap = DataFactory.createMap(6000); + this.addedContexts = DataFactory.createMap(); + this.contextFieldMap = DataFactory.createMap(6000); + this.valToAllocNode = DataFactory.createMap(10000); + this.valToValNode = DataFactory.createMap(100000); + this.methodToPag = DataFactory.createMap(); + this.globals = DataFactory.createSet(100000); + this.locals = DataFactory.createSet(100000); + } + + public void setEdgeQueue(ChunkedQueue edgeQueue) { + this.edgeQueue = edgeQueue; + } + + public Map> getAlloc() { + return alloc; + } + + public Map> getSimple() { + return simple; + } + + public Map> getSimpleInv() { + return simpleInv; + } + + public Map> getLoad() { + return load; + } + + public Map> getStoreInv() { + return storeInv; + } + + public PTA getPta() { + return this.pta; + } + + public QueueReader edgeReader() { + return edgeQueue.reader(); + } + + // =======================add edge=============================== + protected boolean addToMap(Map> m, K key, V value) { + Set valueList = m.computeIfAbsent(key, k -> DataFactory.createSet(4)); + return valueList.add(value); + } + + private boolean addAllocEdge(AllocNode from, VarNode to) { + if (addToMap(alloc, from, to)) { + addToMap(allocInv, to, from); + return true; + } + return false; + } + + private boolean addSimpleEdge(ValNode from, ValNode to) { + if (addToMap(simple, from, to)) { + addToMap(simpleInv, to, from); + return true; + } + return false; + } + + private boolean addStoreEdge(VarNode from, FieldRefNode to) { + if (addToMap(storeInv, to, from)) { + addToMap(store, from, to); + return true; + } + return false; + } + + private boolean addLoadEdge(FieldRefNode from, VarNode to) { + if (addToMap(load, from, to)) { + addToMap(loadInv, to, from); + return true; + } + return false; + } + + public void addGlobalPAGEdge(Node from, Node to) { + from = pta.parameterize(from, pta.emptyContext()); + to = pta.parameterize(to, pta.emptyContext()); + addEdge(from, to); + } + + /** + * Adds an edge to the graph, returning false if it was already there. + */ + public final void addEdge(Node from, Node to) { + if (addEdgeIntenal(from, to)) { + edgeQueue.add(from); + edgeQueue.add(to); + } + } + + private boolean addEdgeIntenal(Node from, Node to) { + if (from instanceof ValNode) { + if (to instanceof ValNode) { + return addSimpleEdge((ValNode) from, (ValNode) to); + } else { + return addStoreEdge((VarNode) from, (FieldRefNode) to); + } + } else if (from instanceof FieldRefNode) { + return addLoadEdge((FieldRefNode) from, (VarNode) to); + } else { + AllocNode heap = (AllocNode) from; + return addAllocEdge(heap, (VarNode) to); + } + } + + // ======================lookups=========================== + protected Set lookup(Map> m, K key) { + return m.getOrDefault(key, Collections.emptySet()); + } + + public Set allocLookup(AllocNode key) { + return lookup(alloc, key); + } + + public Set allocInvLookup(VarNode key) { + return lookup(allocInv, key); + } + + public Set simpleLookup(ValNode key) { + return lookup(simple, key); + } + + public Set simpleInvLookup(ValNode key) { + return lookup(simpleInv, key); + } + + public Set loadInvLookup(VarNode key) { + return lookup(loadInv, key); + } + + public Set loadLookup(FieldRefNode key) { + return lookup(load, key); + } + + public Set storeLookup(VarNode key) { + return lookup(store, key); + } + + public Set storeInvLookup(FieldRefNode key) { + return lookup(storeInv, key); + } + + public static int nextFinishNumber() { + return maxFinishNumber.incrementAndGet(); + } + + public ArrayNumberer getAllocNodeNumberer() { + return allocNodeNumberer; + } + + public ArrayNumberer getFieldRefNodeNumberer() { + return fieldRefNodeNumberer; + } + + public ArrayNumberer getValNodeNumberer() { + return valNodeNumberer; + } + + public Collection getValNodes() { + return valToValNode.values(); + } + + public Collection getAllocNodes() { + return valToAllocNode.values(); + } + + public Set getGlobalPointers() { + return globals; + } + + public Set getLocalPointers() { + return locals; + } + + /** + * Finds the ValNode for the variable value, or returns null. + */ + public ValNode findValNode(Object value) { + return valToValNode.get(value); + } + + public AllocNode findAllocNode(Object obj) { + return valToAllocNode.get(obj); + } + + // ==========================create nodes================================== + public AllocNode makeAllocNode(Object newExpr, Type type, SootMethod m) { + AllocNode ret = valToAllocNode.get(newExpr); + if (ret == null) { + valToAllocNode.put(newExpr, ret = new AllocNode(view, newExpr, type, m)); + allocNodeNumberer.add(ret); + } else if (!(ret.getType().equals(type))) { + throw new RuntimeException("NewExpr " + newExpr + " of type " + type + " previously had type " + ret.getType()); + } + return ret; + } + + public AllocNode makeStringConstantNode(StringConstant sc) { + StringConstant stringConstant = sc; + if (!CoreConfig.v().getPtaConfig().stringConstants) { + stringConstant = StringConstant.v(PointsToAnalysis.STRING_NODE); + } + AllocNode ret = valToAllocNode.get(stringConstant); + if (ret == null) { + valToAllocNode.put(stringConstant, ret = new StringConstantNode(view, stringConstant)); + allocNodeNumberer.add(ret); + } + return ret; + } + + public AllocNode makeClassConstantNode(ClassConstant cc) { + AllocNode ret = valToAllocNode.get(cc); + if (ret == null) { + valToAllocNode.put(cc, ret = new ClassConstantNode(view, cc)); + allocNodeNumberer.add(ret); + } + return ret; + } + + /** + * Finds or creates the GlobalVarNode for the variable value, of type type. + */ + public GlobalVarNode makeGlobalVarNode(Object value, Type type) { + GlobalVarNode ret = (GlobalVarNode) valToValNode.get(value); + if (ret == null) { + ret = (GlobalVarNode) valToValNode.computeIfAbsent(value, k -> new GlobalVarNode(view, value, type)); + valNodeNumberer.add(ret); + if (value instanceof SootField) { + globals.add((SootField) value); + } + } else if (!(ret.getType().equals(type))) { + throw new RuntimeException("Value " + value + " of type " + type + " previously had type " + ret.getType()); + } + return ret; + } + + /** + * Finds or creates the LocalVarNode for the variable value, of type type. + */ + public LocalVarNode makeLocalVarNode(Object value, Type type, SootMethod method) { + LocalVarNode ret = (LocalVarNode) valToValNode.get(value); + if (ret == null) { + valToValNode.put(value, ret = new LocalVarNode(view, value, type, method)); + valNodeNumberer.add(ret); + if (value instanceof Local local) { +// if (local.getNumber() == 0) { +// PTAScene.v().getLocalNumberer().add(local); +// } + locals.add(local); + } + } else if (!(ret.getType().equals(type))) { + throw new RuntimeException("Value " + value + " of type " + type + " previously had type " + ret.getType()); + } + return ret; + } + + /** + * Finds or creates the FieldVarNode for the Java field or array element. + * Treat Java field and array element as normal local variable. + */ + public FieldValNode makeFieldValNode(SparkField field) { + FieldValNode ret = (FieldValNode) valToValNode.get(field); + if (ret == null) { + valToValNode.put(field, ret = new FieldValNode(view, field)); + valNodeNumberer.add(ret); + } + return ret; + } + + /** + * Finds or creates the FieldRefNode for base variable base and field field, of + * type type. + */ + public FieldRefNode makeFieldRefNode(VarNode base, SparkField field) { + FieldRefNode ret = base.dot(field); + if (ret == null) { + ret = new FieldRefNode(view, base, field); + fieldRefNodeNumberer.add(ret); + } + return ret; + } + + /** + * Finds or creates the ContextVarNode for base variable base and context. + */ + public ContextVarNode makeContextVarNode(VarNode base, Context context) { + Map contextMap = contextVarNodeMap.computeIfAbsent(base, k1 -> DataFactory.createMap()); + ContextVarNode ret = contextMap.get(context); + if (ret == null) { + contextMap.put(context, ret = new ContextVarNode(view, base, context)); + valNodeNumberer.add(ret); + } + return ret; + } + + /** + * Finds or creates the ContextAllocNode for base alloc site and context. + */ + public ContextAllocNode makeContextAllocNode(AllocNode allocNode, Context context) { + Map contextMap = contextAllocNodeMap.computeIfAbsent(allocNode, k1 -> DataFactory.createMap()); + ContextAllocNode ret = contextMap.get(context); + if (ret == null) { + contextMap.put(context, ret = new ContextAllocNode(view, allocNode, context)); + allocNodeNumberer.add(ret); + } + return ret; + } + + /** + * Finds or creates the ContextMethod for method and context. + */ + public ContextMethod makeContextMethod(Context context, SootMethod method) { + Map contextMap = contextMethodMap.computeIfAbsent(method, k1 -> DataFactory.createMap()); + return contextMap.computeIfAbsent(context, k -> new ContextMethod(method, context)); + } + + public AllocNode getAllocNode(Object val) { + return valToAllocNode.get(val); + } + + public Map> getMethod2ContextsMap() { + return addedContexts; + } + + public boolean containsMethodPAG(SootMethod m) { + return methodToPag.containsKey(m); + } + + public Collection getContextFields() { + return contextFieldMap.values().stream().flatMap(m -> m.values().stream()).collect(Collectors.toSet()); + } + + public Map> getContextVarNodeMap() { + return contextVarNodeMap; + } + + public Map> getContextAllocNodeMap() { + return contextAllocNodeMap; + } + + public Map> getContextMethodMap() { + return contextMethodMap; + } + + public Map> getContextFieldVarNodeMap() { + return contextFieldMap; + } + + public ContextField makeContextField(Context context, FieldValNode fieldValNode) { + SparkField field = fieldValNode.getField(); + Map field2odotf = contextFieldMap.computeIfAbsent(context, k -> DataFactory.createMap()); + ContextField ret = field2odotf.get(field); + if (ret == null) { + field2odotf.put(field, ret = new ContextField(view, context, field)); + valNodeNumberer.add(ret); + } + return ret; + } + + public Collection getVarNodes(Local local) { + Map subMap = contextVarNodeMap.get(findLocalVarNode(local)); + if (subMap == null) { + return Collections.emptySet(); + } + return new HashSet<>(subMap.values()); + } + + // ===================find nodes============================== + + /** + * Finds the GlobalVarNode for the variable value, or returns null. + */ + public GlobalVarNode findGlobalVarNode(Object value) { + return (GlobalVarNode) findValNode(value); + } + + /** + * Finds the LocalVarNode for the variable value, or returns null. + */ + public LocalVarNode findLocalVarNode(Object value) { + ValNode ret = findValNode(value); + if (ret instanceof LocalVarNode) { + return (LocalVarNode) ret; + } + return null; + } + + /** + * Finds the ContextVarNode for base variable value and context context, or + * returns null. + */ + public ContextVarNode findContextVarNode(Local baseValue, Context context) { + Map contextMap = contextVarNodeMap.get(findLocalVarNode(baseValue)); + return contextMap == null ? null : contextMap.get(context); + } + + protected ReflectionModel createReflectionModel() { + ReflectionModel model; + if (CoreConfig.v().getAppConfig().REFLECTION_LOG != null && CoreConfig.v().getAppConfig().REFLECTION_LOG.length() > 0) { + model = new TamiflexModel(); + } else { + model = new NopReflectionModel(); + } + return model; + } + + public MethodPAG getMethodPAG(SootMethod m) { + if (methodToPag.containsKey(m)) { + return methodToPag.get(m); + } + Body body = PTAUtils.getMethodBody(m); + synchronized (body) { + // Some other thread may have created the MethodPAG for this method. + if (methodToPag.containsKey(m)) { + return methodToPag.get(m); + } + if (m.isConcrete()) { + reflectionModel.buildReflection(m); + } + if (m.isNative()) { + nativeDriver.buildNative(m); + } else { + // we will revert these back in the future. + /* + * To keep same with Doop, we move the simulation of + * + * directly to its caller methods. + * */ + if (PTAScene.v().arraycopyBuilt.add(m)) { + handleArrayCopy(m); + } + } + } + return methodToPag.computeIfAbsent(m, k -> new MethodPAG(this, m, body)); + } + + private void handleArrayCopy(SootMethod method) { + Map> newUnits = DataFactory.createMap(); + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + Body body = PTAUtils.getMethodBody(method); + for (Stmt s : body.getStmts()) { + if (s.containsInvokeExpr()) { + AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); + if (invokeExpr instanceof JStaticInvokeExpr sie) { + SootMethod sm = sie.getMethod(); + String sig = sm.getSignature(); + if (sig.equals("")) { + Value srcArr = sie.getArg(0); + if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { + continue; + } + Type objType = identifierFactory.getType("java.lang.Object"); + if (srcArr.getType() == objType) { + Local localSrc = Jimple.newLocal("intermediate/" + body.getLocalCount(), identifierFactory.getArrayType(objType, 1)); + body.getLocals().add(localSrc); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(Jimple.newAssignStmt(localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); + srcArr = localSrc; + } + Value dstArr = sie.getArg(2); + if (PTAUtils.isPrimitiveArrayType(dstArr.getType())) { + continue; + } + if (dstArr.getType() == objType) { + Local localDst = Jimple.newLocal("intermediate/" + body.getLocalCount(), identifierFactory.getArrayType(objType, 1)); + body.getLocals().add(localDst); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(Jimple.newAssignStmt(localDst, dstArr, StmtPositionInfo.createNoStmtPositionInfo())); + dstArr = localDst; + } + Value src = new JArrayRef((Local) srcArr, IntConstant.getInstance(0), identifierFactory); + Value dst = new JArrayRef((Local) dstArr, IntConstant.getInstance(0), identifierFactory); + Local local = Jimple.newLocal("nativeArrayCopy" + body.getLocalCount(), identifierFactory.getType("java.lang.Object")); + body.getLocals().add(local); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(Jimple.newAssignStmt(local, src, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(Jimple.newAssignStmt(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); + } + } + } + } + for (Stmt unit : newUnits.keySet()) { + body.getUnits().insertAfter(newUnits.get(unit), unit); + } + } + + public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { + return makeLocalVarNode(invoke, view.getIdentifierFactory().getType("java.lang.Throwable"), method); + } + + public HeapAbstractor heapAbstractor() { + return pta.heapAbstractor(); + } + + + public void resetPointsToSet() { + this.addedContexts.clear(); + contextVarNodeMap.values().stream().flatMap(m -> m.values().stream()).forEach(ValNode::discardP2Set); + contextFieldMap.values().stream().flatMap(m -> m.values().stream()).forEach(ValNode::discardP2Set); + valToValNode.values().forEach(ValNode::discardP2Set); + addedContexts.clear(); + } + +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java new file mode 100644 index 00000000000..38e0d7f0487 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java @@ -0,0 +1,94 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.PointsToAnalysis; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; + +import java.util.Objects; + +/** + * Represents a method parameter. + * + * @author Ondrej Lhotak + */ +public class Parm { + private final int index; + private final SootMethod method; + + public Parm(SootMethod m, int i) { + index = i; + method = m; + } + + public String toString() { + if (index == PointsToAnalysis.THIS_NODE) { + return "Parm THIS_NODE to " + method; + } else if (index == PointsToAnalysis.RETURN_NODE) { + return "Parm RETURN to " + method; + } else { + return "Parm " + index + " to " + method; + } + } + + public int getIndex() { + return index; + } + + public boolean isThis() { + return index == PointsToAnalysis.THIS_NODE; + } + + public boolean isReturn() { + return index == PointsToAnalysis.RETURN_NODE; + } + + public boolean isThrowRet() { + return index == PointsToAnalysis.THROW_NODE; + } + + public Type getType() { + if (index == PointsToAnalysis.RETURN_NODE) { + return method.getReturnType(); + } else if (index == PointsToAnalysis.THIS_NODE) { + return method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); + } + + return method.getParameterType(index); + } + + public SootMethod method() { + return method; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Parm parm = (Parm) o; + return index == parm.index && + method.equals(parm.method); + } + + @Override + public int hashCode() { + return Objects.hash(index, method); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java new file mode 100644 index 00000000000..ce3593a9f66 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java @@ -0,0 +1,8 @@ +package qilin.core.pag; + +import qilin.core.util.Numberable; +import sootup.core.types.Type; + +public interface SparkField extends Numberable { + public Type getType(); +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java new file mode 100644 index 00000000000..cdf1ee456e1 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.views.View; + +/** + * Represents an allocation site node the represents a constant string. + * + * @author Ondrej Lhotak + */ +public class StringConstantNode extends ConstantNode { + public StringConstantNode(View view, StringConstant sc) { + super(view, sc, view.getIdentifierFactory().getType("java.lang.String"), null); + } + + public String toString() { + return "StringConstantNode " + getNumber() + " " + newExpr; + } + + public String getString() { + return ((StringConstant) newExpr).getValue(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java new file mode 100644 index 00000000000..ef63d8aae18 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java @@ -0,0 +1,59 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.sets.DoublePointsToSet; +import qilin.core.util.Numberable; +import sootup.core.types.Type; +import sootup.core.views.View; + +/** + * Represents a simple of pointer node in the pointer assignment graph. + */ +public class ValNode extends Node implements Comparable, Numberable { + + protected ValNode(View view, Type t) { + super(view, t); + } + + public int compareTo(Object o) { + ValNode other = (ValNode) o; + return other.getNumber() - this.getNumber(); + } + + /** + * Returns the points-to set for this node. + */ + public DoublePointsToSet getP2Set() { + if (p2set != null) { + return p2set; + } else { + p2set = new DoublePointsToSet(); + return p2set; + } + } + + /** + * Delete current points-to set and make a new one + */ + public void discardP2Set() { + p2set = null; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java new file mode 100644 index 00000000000..446a8f6e935 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java @@ -0,0 +1,126 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import qilin.core.context.Context; +import qilin.util.DataFactory; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; +import sootup.core.views.View; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +/** + * Represents a simple variable node in the pointer assignment graph. + * + * @author Ondrej Lhotak + */ +public abstract class VarNode extends ValNode { + protected Object variable; + protected Map fields; + + protected boolean interProcTarget = false; + protected boolean interProcSource = false; + + protected VarNode(View view, Object variable, Type t) { + super(view, t); + if (!(t instanceof ReferenceType)) { + throw new RuntimeException("Attempt to create VarNode of type " + t); + } + this.variable = variable; + } + + public Context context() { + return null; + } + + /** + * Returns all field ref nodes having this node as their base. + */ + public Collection getAllFieldRefs() { + if (fields == null) { + return Collections.emptyList(); + } + return fields.values(); + } + + /** + * Returns the field ref node having this node as its base, and field as its field; null if nonexistent. + */ + public FieldRefNode dot(SparkField field) { + return fields == null ? null : fields.get(field); + } + + /** + * Returns the underlying variable that this node represents. + */ + public Object getVariable() { + return variable; + } + + /** + * Designates this node as the potential target of a interprocedural assignment edge which may be added during on-the-fly + * call graph updating. + */ + public void setInterProcTarget() { + interProcTarget = true; + } + + /** + * Returns true if this node is the potential target of a interprocedural assignment edge which may be added during + * on-the-fly call graph updating. + */ + public boolean isInterProcTarget() { + return interProcTarget; + } + + /** + * Designates this node as the potential source of a interprocedural assignment edge which may be added during on-the-fly + * call graph updating. + */ + public void setInterProcSource() { + interProcSource = true; + } + + /** + * Returns true if this node is the potential source of a interprocedural assignment edge which may be added during + * on-the-fly call graph updating. + */ + public boolean isInterProcSource() { + return interProcSource; + } + + public abstract VarNode base(); + + /** + * Registers a frn as having this node as its base. + */ + void addField(FieldRefNode frn, SparkField field) { + if (fields == null) { + synchronized (this) { + if (fields == null) { + fields = DataFactory.createMap(); + } + } + } + fields.put(field, frn); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java new file mode 100644 index 00000000000..42cf808a364 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java @@ -0,0 +1,83 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.pag; + +import soot.Kind; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.signatures.MethodSubSignature; + +import java.util.Objects; + +/** + * Holds relevant information about a particular virtual call site. + * + * @author Ondrej Lhotak + */ +public class VirtualCallSite extends CallSite { + private final VarNode recNode; + private final ContextMethod container; + private final AbstractInstanceInvokeExpr iie; + private final MethodSubSignature subSig; + private final Kind kind; + + public VirtualCallSite(VarNode recNode, Stmt stmt, ContextMethod container, AbstractInstanceInvokeExpr iie, + MethodSubSignature subSig, Kind kind) { + super(stmt); + this.recNode = recNode; + this.container = container; + this.iie = iie; + this.subSig = subSig; + this.kind = kind; + } + + public VarNode recNode() { + return recNode; + } + + public ContextMethod container() { + return container; + } + + public AbstractInstanceInvokeExpr iie() { + return iie; + } + + public MethodSubSignature subSig() { + return subSig; + } + + public Kind kind() { + return kind; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + VirtualCallSite that = (VirtualCallSite) o; + return recNode.equals(that.recNode) && container.equals(that.container) && iie.equals(that.iie) && subSig.equals(that.subSig) && kind.equals(that.kind); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), recNode, container, iie, subSig, kind); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/package-info.java b/sootup.qilin/src/main/java/qilin/core/pag/package-info.java new file mode 100644 index 00000000000..64368593443 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/package-info.java @@ -0,0 +1,7 @@ +package qilin.core.pag; + +/* + * Most of the class files in this package can be seen in the Soot/jimple/spark/pag. + * We have changed them a lot but (at least) their names are kept the same here. + * We hope our framework could be merged into soot and replace the original Spark one day. + * */ \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java new file mode 100644 index 00000000000..a144beb3e32 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java @@ -0,0 +1,77 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.reflection; + + +import sootup.core.jimple.common.stmt.Stmt; + +import java.util.Collection; +import java.util.Collections; + +/* + * This is an empty reflection model which does nothing for reflection statements. + * */ + +public class NopReflectionModel extends ReflectionModel { + + @Override + Collection transformClassForName(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformClassNewInstance(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformContructorNewInstance(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformMethodInvoke(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformFieldSet(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformFieldGet(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformArrayNewInstance(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformArrayGet(Stmt s) { + return Collections.emptySet(); + } + + @Override + Collection transformArraySet(Stmt s) { + return Collections.emptySet(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java new file mode 100644 index 00000000000..f950fc560b8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.reflection; + +public enum ReflectionKind { + ClassForName, ClassNewInstance, ConstructorNewInstance, MethodInvoke, FieldSet, FieldGet, MethodGet, ArrayNewInstance, + ArrayGet, ArraySet, FieldGetName; + + public static ReflectionKind parse(String kindStr) { + return switch (kindStr) { + case "Class.forName" -> ClassForName; + case "Class.newInstance" -> ClassNewInstance; + case "Constructor.newInstance" -> ConstructorNewInstance; + case "Method.invoke" -> MethodInvoke; + case "Method.getName" -> MethodGet; + case "Field.set*" -> FieldSet; + case "Field.get*" -> FieldGet; + case "Field.getName" -> FieldGetName; + case "Array.newInstance" -> ArrayNewInstance; + default -> null; + }; + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java new file mode 100644 index 00000000000..55f38f035d5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -0,0 +1,104 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.reflection; + +import qilin.core.PTAScene; +import qilin.util.DataFactory; +import qilin.util.PTAUtils; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +public abstract class ReflectionModel { + protected final String sigForName = ""; + protected final String sigForName2 = ""; + protected final String sigClassNewInstance = ""; + protected final String sigConstructorNewInstance = ""; + protected final String sigMethodInvoke = ""; + protected final String sigFieldSet = ""; + protected final String sigFieldGet = ""; + protected final String sigArrayNewInstance = ""; + protected final String sigArrayGet = ""; + protected final String sigArraySet = ""; + protected final String sigReifiedField = ""; + protected final String sigReifiedDeclaredField = ""; + protected final String sigReifiedFieldArray = ""; + protected final String sigReifiedDeclaredFieldArray = ""; + protected final String sigReifiedMethod = ""; + protected final String sigReifiedDeclaredMethod = ""; + protected final String sigReifiedMethodArray = ""; + protected final String sigReifiedDeclaredMethodArray = ""; + + private Collection transform(Stmt s) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + return switch (ie.getMethodSignature().toString()) { + case sigForName, sigForName2 -> transformClassForName(s); + case sigClassNewInstance -> transformClassNewInstance(s); + case sigConstructorNewInstance -> transformContructorNewInstance(s); + case sigMethodInvoke -> transformMethodInvoke(s); + case sigFieldSet -> transformFieldSet(s); + case sigFieldGet -> transformFieldGet(s); + case sigArrayNewInstance -> transformArrayNewInstance(s); + case sigArrayGet -> transformArrayGet(s); + case sigArraySet -> transformArraySet(s); + default -> Collections.emptySet(); + }; + } + + /** + * replace reflection call with appropriate statements + */ + public void buildReflection(SootMethod m) { + if (!PTAScene.v().reflectionBuilt.add(m)) { + return; + } + Map> newUnits = DataFactory.createMap(); + UnitPatchingChain units = PTAUtils.getMethodBody(m).getStmts(); + for (final Stmt s : units) { + if (s.containsInvokeExpr()) { + newUnits.put(s, transform(s)); + } + } + for (Stmt unit : newUnits.keySet()) { + units.insertAfter(newUnits.get(unit), unit); + } + } + + abstract Collection transformClassForName(Stmt s); + + abstract Collection transformClassNewInstance(Stmt s); + + abstract Collection transformContructorNewInstance(Stmt s); + + abstract Collection transformMethodInvoke(Stmt s); + + abstract Collection transformFieldSet(Stmt s); + + abstract Collection transformFieldGet(Stmt s); + + abstract Collection transformArrayNewInstance(Stmt s); + + abstract Collection transformArrayGet(Stmt s); + + abstract Collection transformArraySet(Stmt s); +} diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java new file mode 100644 index 00000000000..e8f6152ce4d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -0,0 +1,428 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.reflection; + +import qilin.CoreConfig; +import qilin.core.PTAScene; +import qilin.util.DataFactory; +import qilin.util.PTAUtils; +import sootup.core.jimple.Jimple; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JFieldRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.Position; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; + +/** + * This reflection model handles reflection according to the dynamic traces recorded through Tamiflex. + */ +public class TamiflexModel extends ReflectionModel { + + protected Map>> reflectionMap; + + public TamiflexModel() { + reflectionMap = DataFactory.createMap(); + parseTamiflexLog(CoreConfig.v().getAppConfig().REFLECTION_LOG, false); + } + + @Override + Collection transformClassForName(Stmt s) { + // + // + Collection ret = DataFactory.createSet(); + Map> classForNames = reflectionMap.getOrDefault(ReflectionKind.ClassForName, Collections.emptyMap()); + if (classForNames.containsKey(s)) { + Collection fornames = classForNames.get(s); + for (String clazz : fornames) { + Type refType = RefType.v(clazz); + ClassConstant cc = ClassConstant.fromType(refType); + if (s instanceof JAssignStmt jassign) { + Value lvalue = jassign.getLeftOp(); + ret.add(new JAssignStmt(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); + } + } + } + return ret; + } + + @Override + protected Collection transformClassNewInstance(Stmt s) { + // + if (!(s instanceof JAssignStmt)) { + return Collections.emptySet(); + } + Value lvalue = ((JAssignStmt) s).getLeftOp(); + Collection ret = DataFactory.createSet(); + Map> classNewInstances = reflectionMap.getOrDefault(ReflectionKind.ClassNewInstance, Collections.emptyMap()); + if (classNewInstances.containsKey(s)) { + Collection classNames = classNewInstances.get(s); + for (String clsName : classNames) { + SootClass cls = PTAScene.v().getSootClass(clsName); + if (cls.declaresMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()"))) { + JNewExpr newExpr = Jimple.newNewExpr(cls.getType()); + ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + SootMethod constructor = cls.getMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()")); + ret.add(Jimple.newInvokeStmt(Jimple.newSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), Collections.emptyList()), StmtPositionInfo.createNoStmtPositionInfo())); + } + } + } + return ret; + } + + @Override + protected Collection transformContructorNewInstance(Stmt s) { + // + if (!(s instanceof JAssignStmt)) { + return Collections.emptySet(); + } + Value lvalue = ((JAssignStmt) s).getLeftOp(); + Collection ret = DataFactory.createSet(); + Map> constructorNewInstances = reflectionMap.getOrDefault(ReflectionKind.ConstructorNewInstance, Collections.emptyMap()); + if (constructorNewInstances.containsKey(s)) { + Collection constructorSignatures = constructorNewInstances.get(s); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value args = iie.getArg(0); + JArrayRef arrayRef = new JArrayRef(args, IntConstant.getInstance(0), ); + Local arg = Jimple.newLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + ret.add(Jimple.newAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + for (String constructorSignature : constructorSignatures) { + SootMethod constructor = PTAScene.v().getMethod(constructorSignature); + SootClass cls = constructor.getDeclaringClass(); + JNewExpr newExpr = new JNewExpr(cls.getType()); + ret.add(Jimple.newAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + int argCount = constructor.getParameterCount(); + List mArgs = new ArrayList<>(argCount); + for (int i = 0; i < argCount; i++) { + mArgs.add(arg); + } + ret.add(Jimple.newInvokeStmt(Jimple.newSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), mArgs), StmtPositionInfo.createNoStmtPositionInfo())); + } + } + return ret; + } + + @Override + protected Collection transformMethodInvoke(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> methodInvokes = reflectionMap.getOrDefault(ReflectionKind.MethodInvoke, Collections.emptyMap()); + if (methodInvokes.containsKey(s)) { + Collection methodSignatures = methodInvokes.get(s); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + Value args = iie.getArg(1); + Local arg = null; + if (args.getType() instanceof ArrayType) { + JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0), ); + arg = Jimple.newLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + ret.add(Jimple.newAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + } + + for (String methodSignature : methodSignatures) { + SootMethod method = PTAScene.v().getMethod(methodSignature); + int argCount = method.getParameterCount(); + List mArgs = new ArrayList<>(argCount); + for (int i = 0; i < argCount; i++) { + mArgs.add(arg); + } + AbstractInvokeExpr ie; + if (method.isStatic()) { + assert base instanceof NullConstant; + ie = Jimple.newStaticInvokeExpr(method.getSignature(), mArgs); + } else { + assert !(base instanceof NullConstant); + ie = Jimple.newVirtualInvokeExpr((Local) base, method.getSignature(), mArgs); + } + if (s instanceof JAssignStmt jassign) { + Value lvalue = jassign.getLeftOp(); + ret.add(Jimple.newAssignStmt(lvalue, ie, StmtPositionInfo.createNoStmtPositionInfo())); + } else { + ret.add(Jimple.newInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo())); + } + } + } + return ret; + } + + @Override + protected Collection transformFieldSet(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> fieldSets = reflectionMap.getOrDefault(ReflectionKind.FieldSet, Collections.emptyMap()); + if (fieldSets.containsKey(s)) { + Collection fieldSignatures = fieldSets.get(s); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + Value rValue = iie.getArg(1); + for (String fieldSignature : fieldSignatures) { + SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + JFieldRef fieldRef; + if (field.isStatic()) { + assert base instanceof NullConstant; + fieldRef = Jimple.newStaticFieldRef(field.getSignature()); + } else { + assert !(base instanceof NullConstant); + fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); + } + Stmt stmt = Jimple.newAssignStmt(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + ret.add(stmt); + } + } + return ret; + } + + @Override + protected Collection transformFieldGet(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> fieldGets = reflectionMap.getOrDefault(ReflectionKind.FieldGet, Collections.emptyMap()); + if (fieldGets.containsKey(s) && s instanceof JAssignStmt) { + Collection fieldSignatures = fieldGets.get(s); + Value lvalue = ((JAssignStmt) s).getLeftOp(); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + for (String fieldSignature : fieldSignatures) { + SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + JFieldRef fieldRef; + if (field.isStatic()) { + assert base instanceof NullConstant; + fieldRef = Jimple.newStaticFieldRef(field.getSignature()); + } else { + assert !(base instanceof NullConstant); + fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); + } + if (fieldRef.getType() instanceof ReferenceType) { + Stmt stmt = Jimple.newAssignStmt(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); + ret.add(stmt); + } + } + } + return ret; + } + + @Override + protected Collection transformArrayNewInstance(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> mappedToArrayTypes = reflectionMap.getOrDefault(ReflectionKind.ArrayNewInstance, Collections.emptyMap()); + Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); + for (String arrayType : arrayTypes) { + ArrayType at = (ArrayType) PTAScene.v().getTypeUnsafe(arrayType, true); + JNewArrayExpr newExpr = new JNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1), ); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + ret.add(Jimple.newAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + } + } + return ret; + } + + @Override + Collection transformArrayGet(Stmt s) { + Collection ret = DataFactory.createSet(); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + Value arrayRef = null; + if (base.getType() instanceof ArrayType) { + arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0), ); + } else if (base.getType() == RefType.v("java.lang.Object")) { + Local local = Jimple.newLocal("intermediate/" + base, ArrayType.v(RefType.v("java.lang.Object"), 1)); + ret.add(Jimple.newAssignStmt(local, base, StmtPositionInfo.createNoStmtPositionInfo())); + arrayRef = new JArrayRef(local, IntConstant.getInstance(0), ); + } + if (arrayRef != null) { + ret.add(Jimple.newAssignStmt(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + } + } + return ret; + } + + @Override + Collection transformArraySet(Stmt s) { + Collection ret = DataFactory.createSet(); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + if (base.getType() instanceof ArrayType) { + Value from = iie.getArg(2); + Value arrayRef = new JArrayRef(base, IntConstant.v(0)); + ret.add(Jimple.newAssignStmt(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); + } + return ret; + } + + + /* + * parse reflection log generated by Tamiflex. + * */ + private void parseTamiflexLog(String logFile, boolean verbose) { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(logFile))); + String line; + while ((line = reader.readLine()) != null) { + String[] portions = line.split(";", -1); + if (portions.length < 4) { + if (verbose) { + System.out.println("Warning: illegal tamiflex log: " + line); + } + continue; + } + ReflectionKind kind = ReflectionKind.parse(portions[0]); + String mappedTarget = portions[1]; + String inClzDotMthdStr = portions[2]; + int lineNumber = portions[3].length() == 0 ? -1 : Integer.parseInt(portions[3]); + // sanity check. + if (kind == null) { + if (verbose) { + System.out.println("Warning: illegal tamiflex reflection kind: " + portions[0]); + } + continue; + } + switch (kind) { + case ClassForName: + break; + case ClassNewInstance: + if (!PTAScene.v().containsClass(mappedTarget)) { + if (verbose) { + System.out.println("Warning: Unknown mapped class for signature: " + mappedTarget); + } + continue; + } + break; + case ConstructorNewInstance: + case MethodInvoke: + if (!PTAScene.v().containsMethod(mappedTarget)) { + if (verbose) { + System.out.println("Warning: Unknown mapped method for signature: " + mappedTarget); + } + continue; + } + break; + case FieldSet: + case FieldGet: + if (!PTAScene.v().containsField(mappedTarget)) { + if (verbose) { + System.out.println("Warning: Unknown mapped field for signature: " + mappedTarget); + } + continue; + } + break; + case ArrayNewInstance: + break; + default: + if (verbose) { + System.out.println("Warning: Unsupported reflection kind: " + kind); + } + break; + } + Collection possibleSourceStmts = inferSourceStmt(inClzDotMthdStr, kind, lineNumber); + for (Stmt stmt : possibleSourceStmts) { + reflectionMap.computeIfAbsent(kind, m -> DataFactory.createMap()). + computeIfAbsent(stmt, k -> DataFactory.createSet()).add(mappedTarget); + } + } + reader.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Collection inferSourceMethod(String inClzDotMthd) { + String inClassStr = inClzDotMthd.substring(0, inClzDotMthd.lastIndexOf(".")); + String inMethodStr = inClzDotMthd.substring(inClzDotMthd.lastIndexOf(".") + 1); + if (!PTAScene.v().containsClass(inClassStr)) { + System.out.println("Warning: unknown class \"" + inClassStr + "\" is referenced."); + } + SootClass sootClass = PTAScene.v().getSootClass(inClassStr); + Set ret = DataFactory.createSet(); + for (SootMethod m : sootClass.getMethods()) { + if (m.isConcrete() && m.getName().equals(inMethodStr)) { + ret.add(m); + } + } + return ret; + } + + private Collection inferSourceStmt(String inClzDotMthd, ReflectionKind kind, int lineNumber) { + Set ret = DataFactory.createSet(); + Set potential = DataFactory.createSet(); + Collection sourceMethods = inferSourceMethod(inClzDotMthd); + for (SootMethod sm : sourceMethods) { + Body body = PTAUtils.getMethodBody(sm); + for (Stmt stmt : body.getStmts()) { + if (stmt.containsInvokeExpr()) { + String methodSig = stmt.getInvokeExpr().getMethodSignature().toString(); + if (matchReflectionKind(kind, methodSig)) { + potential.add(stmt); + } + } + } + } + for (Stmt stmt : potential) { + Position pos = stmt.getPositionInfo().getStmtPosition(); + if (lineNumber < 0 || pos != null && pos.getLastLine() >= lineNumber && pos.getFirstLine() <= lineNumber) { + ret.add(stmt); + } + } + if (ret.size() == 0 && potential.size() > 0) { + System.out.print("Warning: Mismatch between statement and reflection log entry - "); + System.out.println(kind + ";" + inClzDotMthd + ";" + lineNumber + ";"); + return potential; + } else { + return ret; + } + } + + private boolean matchReflectionKind(ReflectionKind kind, String methodSig) { + return switch (kind) { + case ClassForName -> methodSig.equals(sigForName) || methodSig.equals(sigForName2); + case ClassNewInstance -> methodSig.equals(sigClassNewInstance); + case ConstructorNewInstance -> methodSig.equals(sigConstructorNewInstance); + case MethodInvoke -> methodSig.equals(sigMethodInvoke); + case FieldSet -> methodSig.equals(sigFieldSet); + case FieldGet -> methodSig.equals(sigFieldGet); + case ArrayNewInstance -> methodSig.equals(sigArrayNewInstance); + default -> false; + }; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java new file mode 100644 index 00000000000..de6a888afc2 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java @@ -0,0 +1,155 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.sets; + +import java.util.Iterator; + +/** + * Implementation of points-to set that holds two sets: one for new elements that have not yet been propagated, and the other + * for elements that have already been propagated. + * + * @author Ondrej Lhotak + */ +public class DoublePointsToSet extends PointsToSetInternal { + protected HybridPointsToSet newSet; + protected HybridPointsToSet oldSet; + + public DoublePointsToSet() { + newSet = new HybridPointsToSet(); + oldSet = new HybridPointsToSet(); + } + + /** + * Returns true if this set contains no run-time objects. + */ + @Override + public boolean isEmpty() { + return oldSet.isEmpty() && newSet.isEmpty(); + } + + /** + * Returns true if this set shares some objects with other. + */ + public boolean hasNonEmptyIntersection(PointsToSetInternal other) { + return oldSet.hasNonEmptyIntersection(other) || newSet.hasNonEmptyIntersection(other); + } + + @Override + public int size() { + return oldSet.size() + newSet.size(); + } + + private class DoublePTSIterator implements Iterator { + private final Iterator oldIt = oldSet.iterator(); + private final Iterator newIt = newSet.iterator(); + + @Override + public boolean hasNext() { + return oldIt.hasNext() || newIt.hasNext(); + } + + @Override + public Integer next() { + if (oldIt.hasNext()) { + return oldIt.next(); + } else { + return newIt.next(); + } + } + } + + public Iterator iterator() { + return new DoublePTSIterator(); + } + + /* + * Empty this set. + * */ + @Override + public void clear() { + oldSet.clear(); + newSet.clear(); + } + + /** + * Adds contents of other into this set, returns true if this set changed. + */ + public boolean addAll(PointsToSetInternal other, PointsToSetInternal exclude) { + if (exclude != null) { + throw new RuntimeException("exclude set must be null."); + } + return newSet.addAll(other, oldSet); + } + + /** + * Calls v's visit method on all nodes in this set. + */ + @Override + public boolean forall(P2SetVisitor v) { + oldSet.forall(v); + newSet.forall(v); + return v.getReturnValue(); + } + + /** + * Adds n to this set, returns true if idx was not already in this set. + */ + public boolean add(int idx) { + if (oldSet.contains(idx)) { + return false; + } + return newSet.add(idx); + } + + /** + * Returns set of nodes already present before last call to flushNew. + */ + public HybridPointsToSet getOldSet() { + return oldSet; + } + + /** + * Returns set of newly-added nodes since last call to flushNew. + */ + public HybridPointsToSet getNewSet() { + return newSet; + } + + public HybridPointsToSet getNewSetCopy() { + HybridPointsToSet newCopy = new HybridPointsToSet(); + newCopy.addAll(newSet, null); + return newCopy; + } + + /** + * Sets all newly-added nodes to old nodes. + */ + public void flushNew() { + oldSet.addAll(newSet, null); + newSet = new HybridPointsToSet(); + } + + /** + * Returns true iff the set contains idx. + */ + @Override + public boolean contains(int idx) { + return oldSet.contains(idx) || newSet.contains(idx); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java new file mode 100644 index 00000000000..cac5754cb90 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java @@ -0,0 +1,198 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.sets; + +import qilin.core.util.BitSetIterator; +import qilin.core.util.BitVector; + +import java.util.Arrays; +import java.util.Iterator; + +/** + * Hybrid implementation of points-to set, which uses an explicit array for small sets, and a bit vector for large sets. + * + * @author Ondrej Lhotak + */ +public final class HybridPointsToSet extends PointsToSetInternal { + private static HybridPointsToSet emptySet = null; + + public static HybridPointsToSet getEmptySet() { + if (emptySet == null) { + emptySet = new HybridPointsToSet(); + } + return emptySet; + } + + private final int[] nodeIdxs = new int[16]; + private BitVector bits = null; + private int size = 0; + + private boolean empty = true; + + /** + * Returns true if this set contains no run-time objects. + */ + @Override + public boolean isEmpty() { + return empty; + } + + @Override + public void clear() { + Arrays.fill(nodeIdxs, 0); + bits = null; + empty = true; + size = 0; + } + + private boolean nativeAddAll(HybridPointsToSet other, PointsToSetInternal exclude) { + boolean ret = false; + for (Iterator it = other.iterator(); it.hasNext(); ) { + int idx = it.next(); + if (exclude == null || !exclude.contains(idx)) { + ret |= add(idx); + } + } + return ret; + } + + /** + * Adds contents of other into this set, returns true if this set changed. + */ + public boolean addAll(final PointsToSetInternal other, final PointsToSetInternal exclude) { + if (other == null) { + return false; + } + if (other instanceof DoublePointsToSet dpts) { + return nativeAddAll(dpts.getNewSet(), exclude) | nativeAddAll(dpts.getOldSet(), exclude); + } + return nativeAddAll((HybridPointsToSet) other, exclude); + } + + private class HybridPTSIterator implements Iterator { + private BitSetIterator it; + private int idx; + + public HybridPTSIterator() { + if (bits == null) { + idx = 0; + } else { + it = bits.iterator(); + } + } + + @Override + public boolean hasNext() { + if (bits == null) { + return idx < nodeIdxs.length && nodeIdxs[idx] != 0; + } else { + return it.hasNext(); + } + } + + @Override + public Integer next() { + if (bits == null) { + return nodeIdxs[idx++]; + } else { + return it.next(); + } + } + } + + @Override + public Iterator iterator() { + return new HybridPTSIterator(); + } + + @Override + public int size() { + return size; + } + + /** + * Calls v's visit method on all nodes in this set. + */ + public boolean forall(P2SetVisitor v) { + if (bits == null) { + for (int nodeIdx : nodeIdxs) { + if (nodeIdx == 0) { + return v.getReturnValue(); + } + v.visit(nodeIdx); + } + } else { + for (BitSetIterator it = bits.iterator(); it.hasNext(); ) { + v.visit(it.next()); + } + } + return v.getReturnValue(); + } + + /** + * Returns true iff the set contains node idx. + */ + public boolean contains(int idx) { + if (bits == null) { + for (int nodeIdx : nodeIdxs) { + if (idx == nodeIdx) { + return true; + } + if (nodeIdx == 0) { + break; + } + } + return false; + } else { + return bits.get(idx); + } + } + + /** + * Adds idx to this set, returns true if idx was not already in this set. + */ + public boolean add(int idx) { + if (bits == null) { + for (int i = 0; i < nodeIdxs.length; i++) { + if (nodeIdxs[i] == 0) { + empty = false; + nodeIdxs[i] = idx; + ++size; + return true; + } else if (nodeIdxs[i] == idx) { + return false; + } + } + // convert to Bits + bits = new BitVector(); + for (int nodeIdx : nodeIdxs) { + if (nodeIdx != 0) { + bits.set(nodeIdx); + } + } + } + boolean ret = bits.set(idx); + if (ret) { + ++size; + empty = false; + } + return ret; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java b/sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java new file mode 100644 index 00000000000..624e82cd7b8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.sets; + +import qilin.core.PTA; +import qilin.core.pag.Node; + +/** + * Abstract base class for points-to set visitors used to enumerate points-to sets. + * + * @author Ondrej Lhotak + */ +public abstract class P2SetVisitor { + protected boolean returnValue = false; + protected final PTA pta; + + protected P2SetVisitor(PTA pta) { + this.pta = pta; + } + + + protected abstract void visit(Node n); + + public void visit(long idx) { + Node node = pta.getPag().getAllocNodeNumberer().get(idx); + visit(node); + } + + public boolean getReturnValue() { + return returnValue; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java new file mode 100644 index 00000000000..e608a16a634 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java @@ -0,0 +1,98 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.sets; + +import qilin.core.pag.AllocNode; +import soot.Type; +import soot.jimple.ClassConstant; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +/** + * A generic interface to some set of runtime objects computed by a pointer analysis. + * + * @author Ondrej Lhotak + */ +public interface PointsToSet { + /** + * Returns true if this set contains no run-time objects. + */ + boolean isEmpty(); + + /** + * Returns true iff the set contains n. + */ + boolean contains(AllocNode n); + + /** + * Returns true if this set shares some objects with other. + */ + boolean hasNonEmptyIntersection(PointsToSet other); + + /** + * Set of all possible run-time types of objects in the set. + */ + Set possibleTypes(); + + /** + * If this points-to set consists entirely of string constants, returns a set of these constant strings. If this point-to + * set may contain something other than constant strings, returns null. + */ + Set possibleStringConstants(); + + /** + * If this points-to set consists entirely of objects of type java.lang.Class of a known class, returns a set of + * ClassConstant's that are these classes. If this point-to set may contain something else, returns null. + */ + Set possibleClassConstants(); + + /** + * Size of objects in this set. + * + * @author Dongjie He + */ + int size(); + + /* + * Empty this set. + * + * @author Dongjie He + * */ + void clear(); + + /** + * Computes a hash code based on the contents of the points-to set. Note that hashCode() is not overwritten on purpose. + * This is because Spark relies on comparison by object identity. + */ + int pointsToSetHashCode(); + + /** + * Returns true if and only if other holds the same alloc nodes as this. Note that equals() is not overwritten + * on purpose. This is because Spark relies on comparison by object identity. + */ + boolean pointsToSetEquals(Object other); + + PointsToSet toCIPointsToSet(); + + Collection toCollection(); + + Iterator iterator(); +} diff --git a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java new file mode 100644 index 00000000000..42ce659f6f3 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java @@ -0,0 +1,64 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.sets; + +import java.util.Iterator; + +/** + * Abstract base class for implementations of points-to sets. + * + * @author Ondrej Lhotak + */ +public abstract class PointsToSetInternal { + /** + * Calls v's visit method on all nodes in this set. + */ + public abstract boolean forall(P2SetVisitor v); + + public abstract boolean addAll(final PointsToSetInternal other, final PointsToSetInternal exclude); + + /** + * Adds node index idx to this set, returns true if idx was not already in this set. + */ + public abstract boolean add(int idx); + + /** + * Returns true iff the set contains the node number index. + */ + public abstract boolean contains(int idx); + + public abstract Iterator iterator(); + + public abstract void clear(); + + public abstract boolean isEmpty(); + + public boolean hasNonEmptyIntersection(final PointsToSetInternal other) { + Iterator it = iterator(); + while (it.hasNext()) { + int idx = it.next(); + if (other.contains(idx)) { + return true; + } + } + return false; + } + + public abstract int size(); +} diff --git a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java new file mode 100644 index 00000000000..cefd6f3b0ca --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java @@ -0,0 +1,198 @@ +package qilin.core.sets; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.core.pag.ClassConstantNode; +import qilin.core.pag.Node; +import qilin.core.pag.StringConstantNode; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.types.ClassType; +import sootup.core.types.Type; + +import java.util.*; + +public class UnmodifiablePointsToSet implements PointsToSet { + private final PointsToSetInternal pts; + private final PTA pta; + + public UnmodifiablePointsToSet(PTA pta, PointsToSetInternal pts) { + this.pta = pta; + this.pts = pts; + } + + @Override + public boolean isEmpty() { + return pts.isEmpty(); + } + + @Override + public boolean contains(AllocNode n) { + return pts.contains(n.getNumber()); + } + + @Override + public boolean hasNonEmptyIntersection(PointsToSet other) { + if (other instanceof UnmodifiablePointsToSet uother) { + return pta == uother.pta && pts.hasNonEmptyIntersection(uother.pts); + } + return false; + } + + @Override + public Set possibleTypes() { + final Set ret = new HashSet<>(); + pts.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + Type t = n.getType(); + if (t instanceof ClassType rt) { + if (rt.getSootClass().isAbstract()) { + return; + } + } + ret.add(t); + } + }); + return ret; + } + + @Override + public Set possibleStringConstants() { + final Set ret = new HashSet<>(); + return pts.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + if (n instanceof StringConstantNode) { + ret.add(((StringConstantNode) n).getString()); + } else { + returnValue = true; + } + } + }) ? null : ret; + } + + @Override + public Set possibleClassConstants() { + final Set ret = new HashSet<>(); + return pts.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + if (n instanceof ClassConstantNode) { + ret.add(((ClassConstantNode) n).getClassConstant()); + } else { + returnValue = true; + } + } + }) ? null : ret; + } + + @Override + public int size() { + return pts.size(); + } + + @Override + public void clear() { + pts.clear(); + } + + @Override + public String toString() { + final StringBuffer ret = new StringBuffer(); + pts.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + ret.append(n).append(","); + } + }); + return ret.toString(); + } + + @Override + public int pointsToSetHashCode() { + long intValue = 1; + final long PRIME = 31; + for (Iterator it = pts.iterator(); it.hasNext(); ) { + intValue = PRIME * intValue + it.next(); + } + return (int) intValue; + } + + @Override + public boolean pointsToSetEquals(Object other) { + if (this == other) { + return true; + } + if (other instanceof UnmodifiablePointsToSet otherPts) { + if (otherPts.pta != pta) { + return false; + } + // both sets are equal if they are supersets of each other + return superSetOf(otherPts.pts, pts) && superSetOf(pts, otherPts.pts); + } + return false; + } + + @Override + public PointsToSet toCIPointsToSet() { + PointsToSetInternal ptoSet = new HybridPointsToSet(); + pts.forall(new P2SetVisitor(pta) { + @Override + public void visit(Node n) { + AllocNode heap = (AllocNode) n; + ptoSet.add(heap.base().getNumber()); + } + }); + return new UnmodifiablePointsToSet(pta, ptoSet); + } + + @Override + public Collection toCollection() { + Set ret = new HashSet<>(); + for (Iterator it = iterator(); it.hasNext(); ) { + ret.add(it.next()); + } + return ret; + } + + /** + * Returns true if onePts is a (non-strict) superset of otherPts. + */ + private boolean superSetOf(PointsToSetInternal onePts, final PointsToSetInternal otherPts) { + Iterator it = onePts.iterator(); + while (it.hasNext()) { + int idx = it.next(); + if (!otherPts.contains(idx)) { + return false; + } + } + return true; + } + + public Iterator iterator() { + return new UnmodifiablePTSIterator(); + } + + private class UnmodifiablePTSIterator implements Iterator { + Iterator it = pts.iterator(); + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public AllocNode next() { + int idx = it.next(); + return pta.getPag().getAllocNodeNumberer().get(idx); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + return pointsToSetEquals(o); + } + + @Override + public int hashCode() { + return Objects.hash(pointsToSetHashCode(), pta); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/sets/package-info.java b/sootup.qilin/src/main/java/qilin/core/sets/package-info.java new file mode 100644 index 00000000000..b35233665ed --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/sets/package-info.java @@ -0,0 +1,6 @@ +package qilin.core.sets; + +/* + * We reuse the data structures of points-to set which are originally designed for Spark in Soot. + * In future, we plan to design more memory-efficient data structures for replacements. + * */ \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Propagator.java b/sootup.qilin/src/main/java/qilin/core/solver/Propagator.java new file mode 100644 index 00000000000..355173d4ed5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/solver/Propagator.java @@ -0,0 +1,32 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.solver; + +/** + * Abstract base class for a propagator that propagates points-to sets along pointer assignment graph. + * + * @author Ondrej Lhotak + */ + +public abstract class Propagator { + /** + * Actually does the propagation. + */ + public abstract void propagate(); +} diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java new file mode 100644 index 00000000000..cb5acf43a4a --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -0,0 +1,322 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.core.solver; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.builder.CallGraphBuilder; +import qilin.core.builder.ExceptionHandler; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.context.Context; +import qilin.core.pag.*; +import qilin.core.sets.DoublePointsToSet; +import qilin.core.sets.P2SetVisitor; +import qilin.core.sets.PointsToSetInternal; +import qilin.util.PTAUtils; +import qilin.util.queue.ChunkedQueue; +import qilin.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JDynamicInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JThrowStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSubSignature; + +import java.util.*; + +public class Solver extends Propagator { + private final TreeSet valNodeWorkList = new TreeSet<>(); + private final PAG pag; + private final PTA pta; + private final CallGraphBuilder cgb; + private final ExceptionHandler eh; + private final ChunkedQueue throwSiteQueue = new ChunkedQueue<>(); + private final ChunkedQueue virtualCallSiteQueue = new ChunkedQueue<>(); + private final ChunkedQueue edgeQueue = new ChunkedQueue<>(); + + private final ChunkedQueue rmQueue = new ChunkedQueue<>(); + + public Solver(PTA pta) { + this.cgb = pta.getCgb(); + this.cgb.setRMQueue(rmQueue); + this.pag = pta.getPag(); + this.pag.setEdgeQueue(edgeQueue); + this.eh = pta.getExceptionHandler(); + this.pta = pta; + } + + @Override + public void propagate() { + final QueueReader newRMs = rmQueue.reader(); + final QueueReader newPAGEdges = edgeQueue.reader(); + final QueueReader newThrows = throwSiteQueue.reader(); + final QueueReader newCalls = virtualCallSiteQueue.reader(); + cgb.initReachableMethods(); + processStmts(newRMs); + pag.getAlloc().forEach((a, set) -> set.forEach(v -> propagatePTS(v, a))); + while (!valNodeWorkList.isEmpty()) { + ValNode curr = valNodeWorkList.pollFirst(); + // Step 1: Resolving Direct Constraints + assert curr != null; + final DoublePointsToSet pts = curr.getP2Set(); + final PointsToSetInternal newset = pts.getNewSet(); + pag.simpleLookup(curr).forEach(to -> propagatePTS(to, newset)); + + if (curr instanceof VarNode mSrc) { + // Step 1 continues. + Collection throwSites = eh.throwSitesLookUp(mSrc); + for (ExceptionThrowSite site : throwSites) { + eh.exceptionDispatch(newset, site); + } + // Step 2: Resolving Indirect Constraints. + handleStoreAndLoadOnBase(mSrc); + // Step 3: Collecting New Constraints. + Collection sites = cgb.callSitesLookUp(mSrc); + for (VirtualCallSite site : sites) { + cgb.virtualCallDispatch(newset, site); + } + processStmts(newRMs); + } + pts.flushNew(); + // Step 4: Activating New Constraints. + activateConstraints(newCalls, newRMs, newThrows, newPAGEdges); + } + } + + public void processStmts(Iterator newRMs) { + while (newRMs.hasNext()) { + ContextMethod momc = newRMs.next(); + SootMethod method = momc.method(); + if (method.isPhantom()) { + continue; + } + MethodPAG mpag = pag.getMethodPAG(method); + addToPAG(mpag, momc.context()); + // !FIXME in a context-sensitive pointer analysis, clinits in a method maybe added multiple times. + if (CoreConfig.v().getPtaConfig().clinitMode == CoreConfig.ClinitMode.ONFLY) { + // add find in the method to reachableMethods. + Iterator it = mpag.triggeredClinits(); + while (it.hasNext()) { + SootMethod sm = it.next(); + cgb.injectCallEdge(sm.getDeclaringClassType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); + } + } + recordCallStmts(momc, mpag.getInvokeStmts()); + recordThrowStmts(momc, mpag.stmt2wrapperedTraps.keySet()); + } + } + + private void recordCallStmts(ContextMethod m, Collection units) { + for (final Stmt s : units) { + if (s.containsInvokeExpr()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof AbstractInstanceInvokeExpr iie) { + Local receiver = iie.getBase(); + VarNode recNode = cgb.getReceiverVarNode(receiver, m); + MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); + VirtualCallSite virtualCallSite = new VirtualCallSite(recNode, s, m, iie, subSig, Edge.ieToKind(iie)); + if (cgb.recordVirtualCallSite(recNode, virtualCallSite)) { + virtualCallSiteQueue.add(virtualCallSite); + } + } else if (ie instanceof JDynamicInvokeExpr) { + // !TODO dynamicInvoke is provided in JDK after Java 7. + // currently, PTA does not handle dynamicInvokeExpr. + } else if (ie instanceof JStaticInvokeExpr sie) { + SootMethod tgt = ie.getMethod(); + VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); + recNode = (VarNode) pta.parameterize(recNode, m.context()); + cgb.addStaticEdge(m, s, tgt, Edge.ieToKind(ie)); + } else { + throw new InternalError("Unresolved target " + ie.getMethodSignature() + + ". Resolution error should have occured earlier."); + } + } + } + } + + private void recordThrowStmts(ContextMethod m, Collection stmts) { + for (final Stmt stmt : stmts) { + SootMethod sm = m.method(); + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory nodeFactory = mpag.nodeFactory(); + Node src; + if (stmt.containsInvokeExpr()) { + src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, sm); + } else { + assert stmt instanceof JThrowStmt; + JThrowStmt ts = (JThrowStmt) stmt; + src = nodeFactory.getNode(ts.getOp()); + } + VarNode throwNode = (VarNode) pta.parameterize(src, m.context()); + ExceptionThrowSite throwSite = new ExceptionThrowSite(throwNode, stmt, m); + if (eh.addThrowSite(throwNode, throwSite)) { + throwSiteQueue.add(throwSite); + } + } + } + + private void addToPAG(MethodPAG mpag, Context cxt) { + Set contexts = pag.getMethod2ContextsMap().computeIfAbsent(mpag, k1 -> new HashSet<>()); + if (!contexts.add(cxt)) { + return; + } + for (QueueReader reader = mpag.getInternalReader().clone(); reader.hasNext(); ) { + Node from = reader.next(); + Node to = reader.next(); + if (from instanceof AllocNode heap) { + from = pta.heapAbstractor().abstractHeap(heap); + } + if (from instanceof AllocNode && to instanceof GlobalVarNode) { + pag.addGlobalPAGEdge(from, to); + } else { + from = pta.parameterize(from, cxt); + to = pta.parameterize(to, cxt); + if (from instanceof AllocNode) { + handleImplicitCallToFinalizerRegister((AllocNode) from); + } + pag.addEdge(from, to); + } + } + } + + // handle implicit calls to java.lang.ref.Finalizer.register by the JVM. + // please refer to library/finalization.logic in doop. + private void handleImplicitCallToFinalizerRegister(AllocNode heap) { + if (PTAUtils.supportFinalize(heap)) { + SootMethod rm = PTAScene.v().getMethod(""); + MethodPAG tgtmpag = pag.getMethodPAG(rm); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + Node parm = tgtnf.caseParm(0); + Context calleeCtx = pta.emptyContext(); + AllocNode baseHeap = heap.base(); + parm = pta.parameterize(parm, calleeCtx); + pag.addEdge(heap, parm); + cgb.injectCallEdge(baseHeap, pta.parameterize(rm, calleeCtx), Kind.STATIC); + } + } + + private void handleStoreAndLoadOnBase(VarNode base) { + for (final FieldRefNode fr : base.getAllFieldRefs()) { + for (final VarNode v : pag.storeInvLookup(fr)) { + handleStoreEdge(base.getP2Set().getNewSet(), fr.getField(), v); + } + for (final VarNode to : pag.loadLookup(fr)) { + handleLoadEdge(base.getP2Set().getNewSet(), fr.getField(), to); + } + } + } + + private void handleStoreEdge(PointsToSetInternal baseHeaps, SparkField field, ValNode from) { + baseHeaps.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + if (disallowStoreOrLoadOn((AllocNode) n)) { + return; + } + final FieldValNode fvn = pag.makeFieldValNode(field); + final ValNode oDotF = (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); + pag.addEdge(from, oDotF); + } + }); + } + + private void handleLoadEdge(PointsToSetInternal baseHeaps, SparkField field, ValNode to) { + baseHeaps.forall(new P2SetVisitor(pta) { + public void visit(Node n) { + if (disallowStoreOrLoadOn((AllocNode) n)) { + return; + } + final FieldValNode fvn = pag.makeFieldValNode(field); + final ValNode oDotF = (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); + pag.addEdge(oDotF, to); + } + }); + } + + private void activateConstraints(QueueReader newCalls, QueueReader newRMs, QueueReader newThrows, QueueReader addedEdges) { + while (newCalls.hasNext()) { + while (newCalls.hasNext()) { + final VirtualCallSite site = newCalls.next(); + final VarNode receiver = site.recNode(); + cgb.virtualCallDispatch(receiver.getP2Set().getOldSet(), site); + } + processStmts(newRMs); // may produce new calls, thus an out-loop is a must. + } + + while (newThrows.hasNext()) { + final ExceptionThrowSite ets = newThrows.next(); + final VarNode throwNode = ets.getThrowNode(); + eh.exceptionDispatch(throwNode.getP2Set().getOldSet(), ets); + } + /* + * there are some actual parameter to formal parameter edges whose source nodes are not in the worklist. + * For this case, we should use the following loop to update the target nodes and insert the + * target nodes into the worklist if nesseary. + * */ + while (addedEdges.hasNext()) { + final Node addedSrc = addedEdges.next(); + final Node addedTgt = addedEdges.next(); + if (addedSrc instanceof VarNode && addedTgt instanceof VarNode + || addedSrc instanceof ContextField || addedTgt instanceof ContextField + ) { // x = y; x = o.f; o.f = y; + final ValNode srcv = (ValNode) addedSrc; + final ValNode tgtv = (ValNode) addedTgt; + propagatePTS(tgtv, srcv.getP2Set().getOldSet()); + } else if (addedSrc instanceof final FieldRefNode srcfrn) { // b = a.f + handleLoadEdge(srcfrn.getBase().getP2Set().getOldSet(), srcfrn.getField(), (ValNode) addedTgt); + } else if (addedTgt instanceof final FieldRefNode tgtfrn) { // a.f = b; + handleStoreEdge(tgtfrn.getBase().getP2Set().getOldSet(), tgtfrn.getField(), (ValNode) addedSrc); + } else if (addedSrc instanceof AllocNode) { // alloc x = new T; + propagatePTS((VarNode) addedTgt, (AllocNode) addedSrc); + } + } + } + + protected void propagatePTS(final ValNode pointer, PointsToSetInternal other) { + final DoublePointsToSet addTo = pointer.getP2Set(); + P2SetVisitor p2SetVisitor = new P2SetVisitor(pta) { + @Override + public void visit(Node n) { + if (PTAUtils.addWithTypeFiltering(addTo, pointer.getType(), n)) { + returnValue = true; + } + } + }; + other.forall(p2SetVisitor); + if (p2SetVisitor.getReturnValue()) { + valNodeWorkList.add(pointer); + } + } + + protected void propagatePTS(final ValNode pointer, AllocNode heap) { + if (PTAUtils.addWithTypeFiltering(pointer.getP2Set(), pointer.getType(), heap)) { + valNodeWorkList.add(pointer); + } + } + + // we do not allow store to and load from constant heap/empty array. + private boolean disallowStoreOrLoadOn(AllocNode heap) { + AllocNode base = heap.base(); + // return base instanceof StringConstantNode || PTAUtils.isEmptyArray(base); + return PTAUtils.isEmptyArray(base); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java b/sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java new file mode 100644 index 00000000000..d261c903c2f --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java @@ -0,0 +1,155 @@ +package qilin.core.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Arrays; +import java.util.BitSet; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A class that numbers objects, so they can be placed in bitsets. + * + * @author Ondrej Lhotak + * @author xiao, generalize it. + */ +public class ArrayNumberer implements IterableNumberer { + + protected E[] numberToObj; + protected int lastNumber; + protected BitSet freeNumbers; + + @SuppressWarnings("unchecked") + public ArrayNumberer() { + this.numberToObj = (E[]) new Numberable[1024]; + this.lastNumber = 0; + } + + public ArrayNumberer(E[] elements) { + this.numberToObj = elements; + this.lastNumber = elements.length; + } + + private void resize(int n) { + numberToObj = Arrays.copyOf(numberToObj, n); + } + + @Override + public synchronized void add(E o) { + if (o.getNumber() != 0) { + return; + } + + // In case we removed entries from the numberer, we want to re-use the free space + int chosenNumber = -1; + if (freeNumbers != null) { + int ns = freeNumbers.nextSetBit(0); + if (ns != -1) { + chosenNumber = ns; + freeNumbers.clear(ns); + } + } + if (chosenNumber == -1) { + chosenNumber = ++lastNumber; + } + if (chosenNumber >= numberToObj.length) { + resize(numberToObj.length * 2); + } + numberToObj[chosenNumber] = o; + o.setNumber(chosenNumber); + } + + @Override + public long get(E o) { + if (o == null) { + return 0; + } + int ret = o.getNumber(); + if (ret == 0) { + throw new RuntimeException("unnumbered: " + o); + } + return ret; + } + + @Override + public E get(long number) { + if (number == 0) { + return null; + } + E ret = numberToObj[(int) number]; + if (ret == null) { + return null; + } + return ret; + } + + @Override + public int size() { + return lastNumber; + } + + @Override + public Iterator iterator() { + return new Iterator() { + int cur = 1; + + @Override + public final boolean hasNext() { + return cur <= lastNumber && cur < numberToObj.length && numberToObj[cur] != null; + } + + @Override + public final E next() { + if (hasNext()) { + return numberToObj[cur++]; + } + throw new NoSuchElementException(); + } + + @Override + public final void remove() { + ArrayNumberer.this.remove(numberToObj[cur - 1]); + } + }; + } + + @Override + public boolean remove(E o) { + if (o == null) { + return false; + } + + int num = o.getNumber(); + if (num == 0) { + return false; + } + if (freeNumbers == null) { + freeNumbers = new BitSet(2 * num); + } + numberToObj[num] = null; + o.setNumber(0); + freeNumbers.set(num); + return true; + } +} + diff --git a/sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java b/sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java new file mode 100644 index 00000000000..db1f0dae3ff --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java @@ -0,0 +1,92 @@ +package qilin.core.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2001 Felix Kwok + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.NoSuchElementException; + +/** + * A fast enumerator for sparse bit sets. When the enumerator is created, it takes a snapshot of the underlying BitVector, + * and iterates through the set bits. Note that this class almost implements the Iterator interface, but it doesn't because + * the return type of next is int rather than Object. + */ +public class BitSetIterator { + + long[] bits; // Bits inherited from the underlying BitVector + int index; // The 64-bit block currently being examined + long save = 0; // A copy of the 64-bit block (for fast access) + + /* + * Computes log_2(x) modulo 67. This uses the fact that 2 is a primitive root modulo 67 + */ + final static int[] lookup = { -1, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, -1, 13, 10, 17, 62, 60, 28, + 42, 30, 20, 51, 25, 44, 55, 47, 5, 32, -1, 38, 14, 22, 11, 58, 18, 53, -1, 9, 61, 27, 29, 50, 43, 46, 31, 37, 21, 57, + 52, 8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33 }; + + /** Creates a new BitSetIterator */ + BitSetIterator(long[] bits) { + // this.bits = new long[bits.length]; + // System.arraycopy(bits,0,this.bits,0,bits.length); + this.bits = bits; + index = 0; + + /* Zip through empty blocks */ + while (index < bits.length && bits[index] == 0L) { + index++; + } + if (index < bits.length) { + save = bits[index]; + } + } + + /** Returns true if there are more set bits in the BitVector; false otherwise. */ + public boolean hasNext() { + return index < bits.length; + } + + /** + * Returns the index of the next set bit. Note that the return type is int, and not Object. + */ + public int next() { + if (index >= bits.length) { + throw new NoSuchElementException(); + } + + long k = (save & (save - 1)); // Clears the last non-zero bit. save is guaranteed non-zero. + long diff = save ^ k; // Finds out which bit it is. diff has exactly one bit set. + save = k; + + // Computes the position of the set bit. + int result = (diff < 0) ? 64 * index + 63 : 64 * index + lookup[(int) (diff % 67)]; + + if (save == 0) { + index++; + while (index < bits.length && bits[index] == 0L) { + index++; + } + if (index < bits.length) { + save = bits[index]; + } + } + return result; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/util/BitVector.java b/sootup.qilin/src/main/java/qilin/core/util/BitVector.java new file mode 100644 index 00000000000..5765d4723eb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/util/BitVector.java @@ -0,0 +1,463 @@ +package qilin.core.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * This is the Soot internal implementation of java.util.BitSet with Felix and Jerome's clever efficient iterator. It was + * re-implemented from scratch by Ondrej Lhotak to avoid licence issues. It was named BitVector rather than BitSet to avoid a + * name clash with the one in the standard Java library. + * + * @author Ondrej Lhotak + */ +public class BitVector { + + private long[] bits; + + public BitVector() { + this(64); + } + + /** Copy constructor */ + // Added by Adam Richard. More efficient than clone(), and easier to extend + public BitVector(BitVector other) { + final long[] otherBits = other.bits; + bits = new long[otherBits.length]; + System.arraycopy(otherBits, 0, bits, 0, otherBits.length); + } + + public BitVector(int numBits) { + int lastIndex = indexOf(numBits - 1); + bits = new long[lastIndex + 1]; + } + + private int indexOf(int bit) { + return bit >> 6; + } + + private long mask(int bit) { + return 1L << (bit & 63); + } + + public void and(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int numToAnd = otherBits.length; + if (bits.length < numToAnd) { + numToAnd = bits.length; + } + int i; + for (i = 0; i < numToAnd; i++) { + bits[i] = bits[i] & otherBits[i]; + } + for (; i < bits.length; i++) { + bits[i] = 0L; + } + } + + public void andNot(BitVector other) { + final long[] otherBits = other.bits; + int numToAnd = otherBits.length; + if (bits.length < numToAnd) { + numToAnd = bits.length; + } + for (int i = 0; i < numToAnd; i++) { + bits[i] = bits[i] & ~otherBits[i]; + } + } + + public void clear(int bit) { + if (indexOf(bit) < bits.length) { + bits[indexOf(bit)] &= ~mask(bit); + } + } + + @Override + public Object clone() { + try { + BitVector ret = (BitVector) super.clone(); + System.arraycopy(bits, 0, ret.bits, 0, ret.bits.length); + return ret; + } catch (CloneNotSupportedException e) { + // cannot occur + throw new RuntimeException(e); + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof BitVector)) { + return false; + } + final long[] otherBits = ((BitVector) o).bits; + long[] longer = otherBits; + int min = bits.length; + if (otherBits.length < min) { + min = otherBits.length; + longer = bits; + } + int i; + for (i = 0; i < min; i++) { + if (bits[i] != otherBits[i]) { + return false; + } + } + for (; i < longer.length; i++) { + if (longer[i] != 0L) { + return false; + } + } + return true; + } + + public boolean get(int bit) { + if (indexOf(bit) >= bits.length) { + return false; + } + return (bits[indexOf(bit)] & mask(bit)) != 0L; + } + + @Override + public int hashCode() { + long ret = 0; + for (long element : bits) { + ret ^= element; + } + return (int) ((ret >> 32) ^ ret); + } + + /** Returns index of highest-numbered one bit. */ + public int length() { + int i; + for (i = bits.length - 1; i >= 0; i--) { + if (bits[i] != 0L) { + break; + } + } + if (i < 0) { + return 0; + } + long j = bits[i]; + i++; + i <<= 6; + for (long k = 1L << 63; (k & j) == 0L; k >>= 1, i--) { + } + return i; + } + + public void copyFrom(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + int i = j + 1; + for (; j >= 0; j--) { + bits[j] = otherBits[j]; + } + for (; i < bits.length; i++) { + bits[i] = 0L; + } + } + + public void or(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + for (; j >= 0; j--) { + bits[j] |= otherBits[j]; + } + } + + /** + * Count the number of ones in the bitvector. + * + * @author Adam Richard This is Brian Kernighan's algorithm from: http://graphics.stanford.edu/~seander/bithacks.html and + * is efficient for sparse bit sets. + */ + public int cardinality() { + int c = 0; + for (long v : bits) { + while (v != 0) { + v &= v - 1; + ++c; + } + } + return c; + } + + /** + * Returns true if the both the current and the specified bitvectors have at least one bit set in common. + * + * @author Quentin Sabah Inspired by the BitVector.and method. + */ + public boolean intersects(BitVector other) { + final long[] otherBits = other.bits; + int numToCheck = otherBits.length; + if (bits.length < numToCheck) { + numToCheck = bits.length; + } + int i; + for (i = 0; i < numToCheck; i++) { + if ((bits[i] & otherBits[i]) != 0) { + return true; + } + } + return false; + } + + private void expand(int bit) { + int n = indexOf(bit) + 1; + if (n <= bits.length) { + return; + } + if (bits.length * 2 > n) { + n = bits.length * 2; + } + long[] newBits = new long[n]; + System.arraycopy(bits, 0, newBits, 0, bits.length); + bits = newBits; + } + + public void xor(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + for (; j >= 0; j--) { + bits[j] ^= otherBits[j]; + } + } + + public boolean set(int bit) { + expand(bit); + boolean ret = !get(bit); + bits[indexOf(bit)] |= mask(bit); + return ret; + } + + /** Returns number of bits in the underlying array. */ + public int size() { + return bits.length << 6; + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + ret.append('{'); + boolean start = true; + for (BitSetIterator it = new BitSetIterator(bits); it.hasNext();) { + int bit = it.next(); + if (start) { + start = false; + } else { + ret.append(", "); + } + ret.append(bit); + } + ret.append('}'); + return ret.toString(); + } + + /** + * Computes this = this OR ((orset AND andset ) AND (NOT andnotset)) Returns true iff this is modified. + */ + public boolean orAndAndNot(BitVector orset, BitVector andset, BitVector andnotset) { + final long[] a, b, c, d; + final int al, bl, cl, dl; + { + a = this.bits; + al = a.length; + } + if (orset == null) { + b = null; + bl = 0; + } else { + b = orset.bits; + bl = b.length; + } + if (andset == null) { + c = null; + cl = 0; + } else { + c = andset.bits; + cl = c.length; + } + if (andnotset == null) { + d = null; + dl = 0; + } else { + d = andnotset.bits; + dl = d.length; + } + + final long[] e; + if (al < bl) { + e = new long[bl]; + System.arraycopy(a, 0, e, 0, al); + this.bits = e; + } else { + e = a; + } + + boolean ret = false; + if (c == null) { + if (dl <= bl) { + int i = 0; + for (; i < dl; i++) { + long l = b[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + for (; i < bl; i++) { + long l = b[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else { + for (int i = 0; i < bl; i++) { + long l = b[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } + } else if (bl <= cl && bl <= dl) { + // bl is the shortest + for (int i = 0; i < bl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else if (cl <= bl && cl <= dl) { + // cl is the shortest + for (int i = 0; i < cl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else { + // dl is the shortest + int i = 0; + for (; i < dl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + for (int shorter = (bl < cl) ? bl : cl; i < shorter; i++) { + long l = b[i] & c[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } + + return ret; + } + + public static BitVector and(BitVector set1, BitVector set2) { + int min = set1.size(); + { + int max = set2.size(); + if (min > max) { + min = max; + } + // max is not necessarily correct at this point, so let it go + // out of scope + } + + BitVector ret = new BitVector(min); + long[] retbits = ret.bits; + long[] bits1 = set1.bits; + long[] bits2 = set2.bits; + min >>= 6; + for (int i = 0; i < min; i++) { + retbits[i] = bits1[i] & bits2[i]; + } + return ret; + } + + public static BitVector or(BitVector set1, BitVector set2) { + int min = set1.size(); + int max = set2.size(); + if (min > max) { + min = max; + max = set1.size(); + } + + BitVector ret = new BitVector(max); + long[] retbits = ret.bits; + long[] bits1 = set1.bits; + long[] bits2 = set2.bits; + min >>= 6; + max >>= 6; + for (int i = 0; i < min; i++) { + retbits[i] = bits1[i] | bits2[i]; + } + if (bits1.length == min) { + System.arraycopy(bits2, min, retbits, min, max - min); + } else { + System.arraycopy(bits1, min, retbits, min, max - min); + } + return ret; + } + + public BitSetIterator iterator() { + return new BitSetIterator(bits); + } +} + diff --git a/sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java b/sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java new file mode 100644 index 00000000000..24efd6e012c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java @@ -0,0 +1,14 @@ +package qilin.core.util; + +import java.util.Iterator; + +/** + * A numberer which also supports an iterator on newly-added objects. + * + * @author xiao, generalize the interface + */ +public interface IterableNumberer extends Numberer, Iterable { + /** Returns an iterator over all objects added to the numberer. */ + @Override + Iterator iterator(); +} diff --git a/sootup.qilin/src/main/java/qilin/core/util/Numberable.java b/sootup.qilin/src/main/java/qilin/core/util/Numberable.java new file mode 100644 index 00000000000..cacf87f6b4e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/util/Numberable.java @@ -0,0 +1,6 @@ +package qilin.core.util; + +public interface Numberable { + void setNumber(int number); + int getNumber(); +} diff --git a/sootup.qilin/src/main/java/qilin/core/util/Numberer.java b/sootup.qilin/src/main/java/qilin/core/util/Numberer.java new file mode 100644 index 00000000000..b6882917415 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/util/Numberer.java @@ -0,0 +1,53 @@ +package qilin.core.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2004 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A numberer converts objects to unique non-negative integers, and vice-versa. + * + * @author xiao, generalize the interface + */ +public interface Numberer { + /** Tells the numberer that a new object needs to be assigned a number. */ + public void add(E o); + + /** + * Removes the number for a given object. + * + * @param o + * the element + * @return true if the removal was successful, false when not + */ + public boolean remove(E o); + + /** + * Should return the number that was assigned to object o that was previously passed as an argument to add(). + */ + public long get(E o); + + /** Should return the object that was assigned the number number. */ + public E get(long number); + + /** Should return the number of objects that have been assigned numbers. */ + public int size(); +} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java new file mode 100644 index 00000000000..5309b88908b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java @@ -0,0 +1,43 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.ctxcons; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +public class CallsiteCtxConstructor implements CtxConstructor { + + @Override + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + Context callerContext = caller.context(); + assert callerContext instanceof ContextElements; + ContextElements ctxElems = (ContextElements) callerContext; + int s = ctxElems.size(); + ContextElement[] cxt = ctxElems.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = callSite; + System.arraycopy(cxt, 0, array, 1, s); + return new ContextElements(array, s + 1); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java new file mode 100644 index 00000000000..c7cb8e5a990 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java @@ -0,0 +1,33 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.ctxcons; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +public interface CtxConstructor { + Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target); + + Context emptyContext = new ContextElements(new ContextElement[0], 0); +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java new file mode 100644 index 00000000000..32f6439254a --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java @@ -0,0 +1,69 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.ctxcons; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +// implementation of selective hybrid context...(Yannis pldi'13) +public class HybObjCtxConstructor implements CtxConstructor { + /* + * Support Sb-1obj, S-2obj+H, ... + * */ + @Override + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + assert callerContext instanceof ContextElements; + ContextElements callerCtx = (ContextElements) callerContext; + ContextElement[] cxtAllocs = callerCtx.getElements(); + int s = callerCtx.size(); + ContextElement[] array; + if (s >= 1) { + array = new ContextElement[s + 1]; + array[1] = callSite; + array[0] = cxtAllocs[0]; + if (s > 1) { + System.arraycopy(cxtAllocs, 1, array, 2, s - 1); + } + return new ContextElements(array, s + 1); + } else { + array = new ContextElement[2]; + array[1] = callSite; + array[0] = null; + return new ContextElements(array, 2); + } + } else { + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctx = (ContextElements) context; + int s = ctx.size(); + ContextElement[] cxtAllocs = ctx.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = receiverNode.base(); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java new file mode 100644 index 00000000000..2e7cc3dbd5b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java @@ -0,0 +1,60 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.ctxcons; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.context.TypeContextElement; +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +// implementation of selective hybrid context...(Yannis pldi'13) +public class HybTypeCtxConstructor implements CtxConstructor { + + @Override + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + assert callerContext instanceof ContextElements; + ContextElements callerCtxs = (ContextElements) callerContext; + ContextElement[] cxtAllocs = callerCtxs.getElements(); + int s = callerCtxs.size(); + ContextElement[] array = new ContextElement[s + 1]; + array[1] = callSite; + array[0] = cxtAllocs[0]; + if (s > 1) { + System.arraycopy(cxtAllocs, 1, array, 2, s - 1); + } + return new ContextElements(array, s + 1); + } else { + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctx = (ContextElements) context; + int s = ctx.size(); + ContextElement[] cxtAllocs = ctx.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = TypeContextElement.getTypeContextElement(receiverNode.base()); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java new file mode 100644 index 00000000000..cdd393d9b10 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java @@ -0,0 +1,33 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.ctxcons; + +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +public class InsensCtxConstructor implements CtxConstructor { + + @Override + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + return emptyContext; + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java new file mode 100644 index 00000000000..8b7131df7bb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.ctxcons; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +// implementation of obj context...(Ana Tosem'05) +public class ObjCtxConstructor implements CtxConstructor { + + @Override + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + return callerContext; + } + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctxElems = (ContextElements) context; + int s = ctxElems.size(); + ContextElement[] cxtAllocs = ctxElems.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = receiverNode.base(); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java new file mode 100644 index 00000000000..6cf034383e4 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java @@ -0,0 +1,51 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.ctxcons; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.context.TypeContextElement; +import qilin.core.pag.AllocNode; +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +// implementation of type context...(Yannis popl'11) +public class TypeCtxConstructor implements CtxConstructor { + + @Override + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + return callerContext; + } + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctxElems = (ContextElements) context; + int s = ctxElems.size(); + ContextElement[] cxtAllocs = ctxElems.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + AllocNode base = receiverNode.base(); + array[0] = TypeContextElement.getTypeContextElement(base); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java new file mode 100644 index 00000000000..3c8a03e1cdd --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java @@ -0,0 +1,28 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.heapabst; + +import qilin.core.pag.AllocNode; + +public class AllocSiteAbstractor implements HeapAbstractor { + @Override + public AllocNode abstractHeap(AllocNode heap) { + return heap; + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java new file mode 100644 index 00000000000..027e7079de3 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java @@ -0,0 +1,25 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.heapabst; + +import qilin.core.pag.AllocNode; + +public interface HeapAbstractor { + AllocNode abstractHeap(AllocNode heap); +} diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java new file mode 100644 index 00000000000..ed388baa161 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -0,0 +1,50 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.heapabst; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.MergedNewExpr; +import qilin.core.pag.PAG; +import qilin.util.DataFactory; +import qilin.util.PTAUtils; +import soot.*; + +import java.util.Set; + +public class HeuristicAbstractor implements HeapAbstractor { + private final PAG pag; + private final Set mergedTypes = DataFactory.createSet(); + + public HeuristicAbstractor(PAG pag) { + this.pag = pag; + mergedTypes.add(RefType.v("java.lang.StringBuffer")); + mergedTypes.add(RefType.v("java.lang.StringBuilder")); + } + + @Override + public AllocNode abstractHeap(AllocNode heap) { + Type type = heap.getType(); + SootMethod m = heap.getMethod(); + if (mergedTypes.contains(type) || (PTAUtils.isThrowable(type) && mergedTypes.add(type))) { + return pag.makeAllocNode(MergedNewExpr.v((RefLikeType) type), type, null); + } else { + return heap; + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java new file mode 100644 index 00000000000..1f3ffe1689d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java @@ -0,0 +1,57 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.heapabst; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.PAG; +import qilin.util.PTAUtils; +import soot.SootMethod; +import soot.Type; + +import java.util.Map; +import java.util.Set; + +public class MahjongAbstractor implements HeapAbstractor { + private final Set mergedHeap; + private final Map heapModelMap; + private final PAG pag; + + public MahjongAbstractor(PAG pag, Set mergedHeap, Map heapModelMap) { + this.pag = pag; + this.mergedHeap = mergedHeap; + this.heapModelMap = heapModelMap; + } + + @Override + public AllocNode abstractHeap(AllocNode heap) { + Object newExpr = heap.getNewExpr(); + Type type = heap.getType(); + SootMethod m = heap.getMethod(); + Object mergedIr = this.heapModelMap.get(newExpr); + if (this.mergedHeap.contains(mergedIr)) { + return pag.makeAllocNode(mergedIr, type, null); + } else { + if (PTAUtils.isThrowable(type)) { + // Mahjong still needs heuristics to handle throwable types. + return pag.makeAllocNode("Merged " + type, type, null); + } + return pag.makeAllocNode(newExpr, type, m); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java new file mode 100644 index 00000000000..ec804562d98 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java @@ -0,0 +1,86 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.PAG; +import soot.Context; +import soot.SootMethod; + +import java.util.Map; + +public class BeanSelector extends CtxSelector { + private final PAG pag; + private final Map>> beanNexCtxMap; + // currently, we only support k = 2 and hk = 1; + // we will generalize Bean in future. + private final int k = 2; + private final int hk = 1; + + public BeanSelector(PAG pag, Map>> beanNexCtxMap) { + this.pag = pag; + this.beanNexCtxMap = beanNexCtxMap; + } + + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(AllocNode heap, Context context) { + assert context instanceof ContextElements; + ContextElements ctxElems = (ContextElements) context; + int s = ctxElems.size(); + if (s > 1) { + ContextElement[] cxtAllocs = ctxElems.getElements(); + AllocNode allocator = (AllocNode) cxtAllocs[0]; + if (beanNexCtxMap.containsKey(heap.getNewExpr())) { + Map> mMap1 = beanNexCtxMap.get(heap.getNewExpr()); + if (mMap1.containsKey(allocator.getNewExpr())) { + Map mMap2 = mMap1.get(allocator.getNewExpr()); + AllocNode allocAllocNode = (AllocNode) cxtAllocs[1]; + if (allocAllocNode != null && mMap2.containsKey(allocAllocNode.getNewExpr())) { + Object newCtxNode = mMap2.get(allocAllocNode.getNewExpr()); + AllocNode newCtxAllocNode = pag.getAllocNode(newCtxNode); + ContextElement[] array = new ContextElement[s]; + System.arraycopy(cxtAllocs, 0, array, 0, s); + array[0] = newCtxAllocNode; + context = new ContextElements(array, s); + } + } + } + } + return contextTailor(context, hk); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java new file mode 100644 index 00000000000..c549881c9d4 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java @@ -0,0 +1,52 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.parm.ctxcons.CtxConstructor; +import soot.Context; +import soot.SootMethod; + +public abstract class CtxSelector { + public abstract Context select(SootMethod m, Context context); + + public abstract Context select(LocalVarNode lvn, Context context); + + public abstract Context select(FieldValNode fvn, Context context); + + public abstract Context select(AllocNode heap, Context context); + + protected Context contextTailor(Context context, int length) { + if (length == 0) { + return CtxConstructor.emptyContext; + } + ContextElements ctx = (ContextElements) context; + ContextElement[] fullContexts = ctx.getElements(); + if (length >= ctx.size()) { + return context; + } + ContextElement[] newContexts = new ContextElement[length]; + System.arraycopy(fullContexts, 0, newContexts, 0, length); + return new ContextElements(newContexts, length); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java new file mode 100644 index 00000000000..83476653680 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java @@ -0,0 +1,62 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.parm.ctxcons.CtxConstructor; +import soot.Context; +import soot.SootMethod; + +import java.util.Set; + +public class DebloatingSelector extends CtxSelector { + + protected final Set ctxDepHeaps; + + public DebloatingSelector(Set ctxDepHeaps) { + this.ctxDepHeaps = ctxDepHeaps; + } + + @Override + public Context select(SootMethod m, Context context) { + return context; + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return context; + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return context; + } + + @Override + public Context select(AllocNode heap, Context context) { + Object ir = heap.getNewExpr(); + if (ctxDepHeaps.contains(ir)) { + return context; + } else { + return CtxConstructor.emptyContext; + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java new file mode 100644 index 00000000000..0244781aaa9 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java @@ -0,0 +1,62 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import soot.Context; +import soot.SootMethod; + +import java.util.Map; + +public class FullMethodLvSelector extends CtxSelector { + private final int k; + /* + * Methods and its corresponding context length obtained by Data-driven (OOPSLA 2017). + * */ + private final Map m2len; + + public FullMethodLvSelector(Map m2len, int k) { + this.m2len = m2len; + this.k = k; + } + + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, m2len.getOrDefault(m, 0)); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + SootMethod sm = lvn.getMethod(); + return contextTailor(context, m2len.getOrDefault(sm, 0)); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(AllocNode heap, Context context) { + SootMethod sm = heap.getMethod(); + return contextTailor(context, Math.max(0, m2len.getOrDefault(sm, 0) - 1)); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java new file mode 100644 index 00000000000..ec0479c0238 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java @@ -0,0 +1,53 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.parm.ctxcons.CtxConstructor; +import qilin.util.PTAUtils; +import soot.Context; +import soot.SootMethod; + +public class HeuristicSelector extends CtxSelector { + + @Override + public Context select(SootMethod m, Context context) { + return context; + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return context; + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return context; + } + + @Override + public Context select(AllocNode heap, Context context) { + if (PTAUtils.isThrowable(heap.getType()) || PTAUtils.subtypeOfAbstractStringBuilder(heap.getType())) { + return CtxConstructor.emptyContext; + } + return context; + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java new file mode 100644 index 00000000000..ead5ce4c20e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.parm.ctxcons.CtxConstructor; +import soot.Context; +import soot.SootMethod; + +public class InsenSelector extends CtxSelector { + @Override + public Context select(SootMethod m, Context context) { + return CtxConstructor.emptyContext; + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return CtxConstructor.emptyContext; + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, 1); + } + + @Override + public Context select(AllocNode heap, Context context) { + return CtxConstructor.emptyContext; + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java new file mode 100644 index 00000000000..e81c93d89b3 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java @@ -0,0 +1,75 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.parm.ctxcons.CtxConstructor; +import soot.Context; +import soot.SootMethod; + +import java.util.Set; + +public class PartialMethodLvSelector extends CtxSelector { + private final int k; + private final int hk; + // precision-critical methods selected by the method-level approaches, e.g., Zipper. + private final Set pcm; + + public PartialMethodLvSelector(int k, int hk, Set pcm) { + this.k = k; + this.hk = hk; + this.pcm = pcm; + } + + @Override + public Context select(SootMethod m, Context context) { + if (pcm.contains(m)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; + } + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + SootMethod sm = lvn.getMethod(); + if (pcm.contains(sm)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; + } + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(AllocNode heap, Context context) { + SootMethod sm = heap.getMethod(); + if (pcm.contains(sm)) { + return contextTailor(context, hk); + } else { + return context; + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java new file mode 100644 index 00000000000..d5f7a5af813 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java @@ -0,0 +1,82 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.parm.ctxcons.CtxConstructor; +import soot.Context; +import soot.SootMethod; + +import java.util.Set; + +public class PartialVarSelector extends CtxSelector { + private final int k; + private final int hk; + // precision-critical nodes selected by the partial-variable-level approaches, e.g., Eagle, Turner. + private final Set csnodes; + private final Set pcm; + + public PartialVarSelector(int k, int hk, Set csnodes, Set pcm) { + this.k = k; + this.hk = hk; + this.csnodes = csnodes; + this.pcm = pcm; + } + + @Override + public Context select(SootMethod m, Context context) { + if (pcm.contains(m)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; + } + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + Object ir = lvn.getVariable(); + if (csnodes.contains(ir)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; + } + } + + + @Override + public Context select(FieldValNode fvn, Context context) { + if (csnodes.contains(fvn.getField())) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; + } + } + + @Override + public Context select(AllocNode heap, Context context) { + Object ir = heap.getNewExpr(); + if (csnodes.contains(ir)) { + return contextTailor(context, hk); + } else { + return CtxConstructor.emptyContext; + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java new file mode 100644 index 00000000000..4528c0a8523 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java @@ -0,0 +1,58 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import soot.Context; +import soot.SootMethod; + +/* + * A pipeline context selector which selects context by firstly using ctxSelA and then ctxSelB. + * */ +public class PipelineSelector extends CtxSelector { + private final CtxSelector ctxSelA; + private final CtxSelector ctxSelB; + + public PipelineSelector(CtxSelector lenSelA, CtxSelector lenSelB) { + this.ctxSelA = lenSelA; + this.ctxSelB = lenSelB; + } + + @Override + public Context select(SootMethod m, Context context) { + return ctxSelB.select(m, ctxSelA.select(m, context)); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return ctxSelA.select(lvn, ctxSelB.select(lvn, context)); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return ctxSelA.select(fvn, ctxSelB.select(fvn, context)); + } + + @Override + public Context select(AllocNode heap, Context context) { + return ctxSelA.select(heap, ctxSelB.select(heap, context)); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java new file mode 100644 index 00000000000..c3ee0b8fc05 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java @@ -0,0 +1,55 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import soot.Context; +import soot.SootMethod; + +public class UniformSelector extends CtxSelector { + private final int k; + private final int hk; + + public UniformSelector(int k, int hk) { + this.k = k; + this.hk = hk; + } + + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(AllocNode heap, Context context) { + return contextTailor(context, hk); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java new file mode 100644 index 00000000000..d8f0b02bcf2 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java @@ -0,0 +1,69 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.parm.select; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import soot.Context; +import soot.SootMethod; + +import java.util.Map; + +/* + * This class is for a future technique and thus currently has no usage. + * */ +public class VarLvSelector extends CtxSelector { + private final int k; + private final int hk; + /* mapping from nodes to the context length they require. + * This is designed for a future approaches. + */ + private final Map node2Len; + private final Map mthd2Len; + + public VarLvSelector(int k, int hk, Map node2Len, Map m2len) { + this.k = k; + this.hk = hk; + this.node2Len = node2Len; + this.mthd2Len = m2len; + } + + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, Math.min(k, mthd2Len.getOrDefault(m, 0))); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + Object ir = lvn.getVariable(); + return contextTailor(context, Math.min(k, node2Len.getOrDefault(ir, 0))); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, Math.min(k, node2Len.getOrDefault(fvn.getField(), 0))); + } + + @Override + public Context select(AllocNode heap, Context context) { + Object ir = heap.getNewExpr(); + return contextTailor(context, Math.min(hk, node2Len.getOrDefault(ir, 0))); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java b/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java new file mode 100644 index 00000000000..7b6e40aa43b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java @@ -0,0 +1,74 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021 Dongjie He + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta; + +import driver.PTAPattern; +import qilin.CoreConfig; + +public class PTAConfig extends CoreConfig { + private static PTAConfig config = null; + + public static PTAConfig v() { + if (config == null) { + config = new PTAConfig(); + coreConfig = config; + } + return config; + } + + public static void reset() { + CoreConfig.reset(); + config = null; + } + + public static class PointerAnalysisConfiguration extends CorePTAConfiguration { + public PTAPattern ptaPattern; + + /** + * If this option is turned on, then main analysis will not run. + */ + public boolean preAnalysisOnly = false; + + /** + * If this option is turned on, we will apply context debloating techniques. + */ + public boolean ctxDebloating = false; + + } + + /* + * Notice that the DEFAULT option is equivalent to Full Turner. + * PHASE_TWO: all objects are assumed to be CS-likely. + * PHASE_ONE: only non-CS-likely objects are analyzed context-insensitively. All other variables and objects + * are analyzed context-sensitively. + * */ + public enum TurnerConfig { + DEFAULT, PHASE_TWO, PHASE_ONE + } + + public TurnerConfig turnerConfig = TurnerConfig.DEFAULT; + + private PTAConfig() { + this.ptaConfig = new PointerAnalysisConfiguration(); + } + + public PointerAnalysisConfiguration getPtaConfig() { + return (PointerAnalysisConfiguration) this.ptaConfig; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java b/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java new file mode 100644 index 00000000000..cc9a56ccff9 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java @@ -0,0 +1,31 @@ +package qilin.pta; + +import qilin.pta.tools.BasePTA; + +/* + * Many recent pointer analyses are two-staged analyses with a preanalysis and a main analysis. + * This class gives a structure for such kinds of analyses. + * */ +public abstract class StagedPTA extends BasePTA { + protected BasePTA prePTA; + + public BasePTA getPrePTA() { + return this.prePTA; + } + + protected abstract void preAnalysis(); + + protected void mainAnalysis() { + if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { + System.out.println("selective pta starts!"); + super.run(); + } + } + + @Override + public void run() { + preAnalysis(); + prePTA.getPag().resetPointsToSet(); + mainAnalysis(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java new file mode 100644 index 00000000000..abbc0ece48e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java @@ -0,0 +1,77 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.bean; + +import qilin.core.PTA; +import qilin.core.context.ContextElements; +import qilin.core.pag.AllocNode; +import qilin.pta.toolkits.common.OAG; +import qilin.util.ANSIColor; +import qilin.util.Pair; +import qilin.util.Stopwatch; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class Bean { + public static void run(PTA pta, Map>> beanNexCtxMap) { + System.out.println("Constructing object allocation graph (OAG) ..."); + Stopwatch timer = Stopwatch.newAndStart("OAG construction"); + OAG oag = new OAG(pta); + oag.build(); + timer.stop(); + System.out.print(ANSIColor.BOLD + "OAG construction: " + ANSIColor.GREEN + + String.format("%.2fs", timer.elapsed()) + ANSIColor.RESET + "\n"); + + System.out.println("Computing contexts..."); + timer.restart(); + // The depth indicates the depth of heap context. + // The method context has 1 more level than heap context. + // Here depth is 1 which corresponds to 2-object-sensitive analysis + // with 1 heap context. + ContextSelector cs = new RepresentativeContextSelector(oag, 1); + timer.stop(); + System.out.print(ANSIColor.BOLD + "Context computation: " + ANSIColor.GREEN + + String.format("%.2fs", timer.elapsed()) + ANSIColor.RESET + "\n"); + + writeContext(cs, oag, beanNexCtxMap); + } + + /* + * Should be generalized for k >= 3. + * */ + private static void writeContext(ContextSelector cs, OAG oag, Map>> beanNexCtxMap) { + oag.allNodes().forEach(allocator -> { + Set ctxs = cs.contextsOf(allocator); + for (ContextElements ctx : ctxs) { + AllocNode allocHctx = (AllocNode) ctx.get(0); + Set> csheaps = cs.allocatedBy(ctx, allocator); + if (csheaps != null) { + csheaps.forEach(csheap -> { + AllocNode newHctx = (AllocNode) csheap.getFirst().get(0); + AllocNode heap = csheap.getSecond(); + beanNexCtxMap.computeIfAbsent(heap.getNewExpr(), k -> new HashMap<>()).computeIfAbsent(allocator.getNewExpr(), k -> new HashMap<>()).put(allocHctx.getNewExpr(), newHctx.getNewExpr()); + }); + } + } + }); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java new file mode 100644 index 00000000000..a3ee4260ac2 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java @@ -0,0 +1,65 @@ +/* Bean - Making k-Object-Sensitive Pointer Analysis More Precise with Still k-Limiting + * + * Copyright (C) 2016 Tian Tan, Yue Li, Jingling Xue + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package qilin.pta.toolkits.bean; + +import qilin.core.context.ContextElements; +import qilin.core.pag.AllocNode; +import qilin.pta.toolkits.common.OAG; +import qilin.util.Pair; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Compute the contexts of each heap object via OAG. + */ +public abstract class ContextSelector { + + protected int depth; // the depth of context + protected Map> contextMap; + protected Map, Set>> allocation = + new HashMap<>(); + + protected ContextSelector(OAG oag) { + this(oag, Integer.MAX_VALUE); + } + + protected ContextSelector(OAG oag, int depth) { + this.depth = depth; + selectContext(oag); + } + + public Set contextsOf(AllocNode heap) { + return contextMap.get(heap); + } + + public Set> allocatedBy(ContextElements ctx, AllocNode heap) { + return allocation.get(new Pair<>(ctx, heap)); + } + + protected abstract void selectContext(OAG oag); + + protected void addAllocation(ContextElements ctx, AllocNode heap, ContextElements newCtx, AllocNode succ) { + Pair csheap = new Pair<>(ctx, heap); + allocation.computeIfAbsent(csheap, k -> new HashSet<>()); + allocation.get(csheap).add(new Pair<>(newCtx, succ)); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java new file mode 100644 index 00000000000..95f6acf226e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java @@ -0,0 +1,122 @@ +/* Bean - Making k-Object-Sensitive Pointer Analysis More Precise with Still k-Limiting + * + * Copyright (C) 2016 Tian Tan, Yue Li, Jingling Xue + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package qilin.pta.toolkits.bean; + +import qilin.core.context.ContextElements; +import qilin.core.pag.AllocNode; +import qilin.parm.ctxcons.CtxConstructor; +import qilin.pta.toolkits.common.OAG; +import qilin.util.Triple; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Context selector of BEAN. This selector aims to avoid redundant + * context elements while selecting contexts. + */ +public class RepresentativeContextSelector extends ContextSelector { + + public RepresentativeContextSelector(OAG oag, int depth) { + super(oag, depth); + } + + @Override + protected void selectContext(OAG oag) { + contextMap = new HashMap<>(); + oag.tailNodes().forEach(node -> { + mergeContextMap(selectContext(oag, node)); + }); + oag.allNodes().forEach(node -> { + if (!contextMap.containsKey(node)) { + mergeContextMap(selectContext(oag, node)); + } + }); + } + + private Map> selectContext(OAG oag, AllocNode dest) { + Map> tempContextMap = new HashMap<>(); + Queue> worklist = new LinkedList<>(); + initialWorkList(worklist, oag, dest); + while (!worklist.isEmpty()) { + Triple triple = worklist.poll(); + AllocNode heap = triple.getFirst(); + ContextElements ctx = triple.getSecond(); + boolean split = triple.getThird(); + if (!tempContextMap.containsKey(heap)) { + tempContextMap.put(heap, new HashSet<>()); + } + if (tempContextMap.get(heap).add(ctx)) { + Set reachSuccs = selectReachNodes(oag.getSuccsOf(heap), dest, oag); + final boolean isFork = reachSuccs.size() > 1; + reachSuccs.forEach(succ -> { + final boolean isJoinSucc = oag.getInDegreeOf(succ) > 1; + ContextElements newCtx; + boolean succSplit = split; + if (split && isJoinSucc && !ctx.contains(heap)) { + newCtx = ContextElements.newContext(ctx, heap, depth); + succSplit = false; + } else { + newCtx = ctx; + } + if (isFork) { + succSplit = true; + } + Set ctxs = tempContextMap.get(succ); + if (ctxs == null || !ctxs.contains(newCtx)) { + addAllocation(ctx, heap, newCtx, succ); + worklist.add(new Triple<>(succ, newCtx, succSplit)); + } + }); + } + } + return tempContextMap; + } + + private void mergeContextMap(Map> anoContextMap) { + anoContextMap.forEach((heap, ctxs) -> { + if (contextMap.containsKey(heap)) { + contextMap.get(heap).addAll(ctxs); + } else { + contextMap.put(heap, ctxs); + } + }); + } + + /** + * Select the nodes from a node set which can reach the destination node + * + * @param nodes + * @param dest + * @param oag + * @return + */ + private Set selectReachNodes(Collection nodes, AllocNode dest, OAG oag) { + return nodes.stream().filter(node -> oag.reaches(node, dest)).collect(Collectors.toSet()); + } + + private void initialWorkList(Queue> worklist, OAG oag, AllocNode node) { + Set reachRoots = selectReachNodes(oag.rootNodes(), node, oag); + boolean split = reachRoots.size() > 1; + ContextElements emptyCtx = (ContextElements) CtxConstructor.emptyContext; + reachRoots.forEach(root -> + worklist.add(new Triple<>(root, ContextElements.newContext(emptyCtx, root, depth), split))); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/gpl-3.0.txt b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/gpl-3.0.txt new file mode 100644 index 00000000000..f288702d2fa --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java new file mode 100644 index 00000000000..2dc40e83df9 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java @@ -0,0 +1,106 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.common; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.core.pag.PAG; +import qilin.core.sets.PointsToSet; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; + +public class FieldPointstoGraph { + private final Map>> pointsTo = new HashMap<>(); + private final Map>> pointedBy = new HashMap<>(); + + public FieldPointstoGraph(PTA pta) { + buildFPG(pta); + } + + private void buildFPG(PTA pta) { + PAG pag = pta.getPag(); + pag.getAllocNodes().forEach(this::insertObj); + pag.getContextFields().forEach(contextField -> { + AllocNode base = contextField.getBase(); + if (base.getMethod() == null) { + return; + } + SparkField field = contextField.getField(); + PointsToSet pts = pta.reachingObjects(contextField).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + insertFPT(base, field, n); + } + }); + } + + public Set getAllObjs() { + return pointsTo.keySet(); + } + + public Set outFieldsOf(AllocNode baseObj) { + return pointsTo.getOrDefault(baseObj, Collections.emptyMap()).keySet(); + } + + public Set inFieldsOf(AllocNode obj) { + return pointedBy.get(obj).keySet(); + } + + public Set pointsTo(AllocNode baseObj, SparkField field) { + return pointsTo.get(baseObj).get(field); + } + + public Set pointedBy(AllocNode obj, SparkField field) { + return pointedBy.get(obj).get(field); + } + + public boolean hasFieldPointer(AllocNode obj, SparkField field) { + return pointsTo.get(obj).containsKey(field); + } + + + private void insertObj(AllocNode obj) { + pointsTo.computeIfAbsent(obj, k -> new HashMap<>()); + pointedBy.computeIfAbsent(obj, k -> new HashMap<>()); + } + + /** + * Insert field points-to relation. + * + * @param baseObj the base object + * @param field a field of `baseObj' + * @param obj the object pointed by `field' + */ + private void insertFPT(AllocNode baseObj, SparkField field, AllocNode obj) { + insertPointsTo(baseObj, field, obj); + insertPointedBy(baseObj, field, obj); + } + + private void insertPointsTo(AllocNode baseObj, SparkField field, AllocNode obj) { + Map> fpt = pointsTo.computeIfAbsent(baseObj, k -> new HashMap<>()); + fpt.computeIfAbsent(field, k -> new HashSet<>()).add(obj); + } + + private void insertPointedBy(AllocNode baseObj, SparkField field, AllocNode obj) { + Map> fpb = pointedBy.computeIfAbsent(obj, k -> new HashMap<>()); + fpb.computeIfAbsent(field, k -> new HashSet<>()).add(baseObj); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java new file mode 100644 index 00000000000..4f497cb5201 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java @@ -0,0 +1,151 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.common; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.AllocNode; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.MethodPAG; +import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; +import qilin.util.graph.DirectedGraph; +import soot.SootMethod; +import soot.util.queue.QueueReader; + +import java.util.*; + +/** + * Implementation of Object Allocation Graph (OAG). + */ +public class OAG implements DirectedGraph { + protected final PTA pta; + protected final Map> successors; + protected final Map> predecessors; + private final Set nodes = new HashSet<>(); + private Collection rootNodes; + private Collection tailNodes; + + public OAG(PTA prePta) { + this.pta = prePta; + this.predecessors = new HashMap<>(); + this.successors = new HashMap<>(); + } + + public void build() { + buildOAG(); + rootNodes = computeRootNodes(); + tailNodes = computeTailNodes(); + } + + @Override + public Collection allNodes() { + return nodes; + } + + @Override + public Collection predsOf(AllocNode p) { + return getPredsOf(p); + } + + @Override + public Collection succsOf(AllocNode p) { + return getSuccsOf(p); + } + + public Collection rootNodes() { + return rootNodes; + } + + public Collection tailNodes() { + return tailNodes; + } + + public Set getPredsOf(AllocNode n) { + return predecessors.getOrDefault(n, Collections.emptySet()); + } + + public Set getSuccsOf(AllocNode n) { + return successors.getOrDefault(n, Collections.emptySet()); + } + + public int getInDegreeOf(AllocNode n) { + return getPredsOf(n).size(); + } + + /** + * @param source + * @param dest + * @return whether there is a path from source to target in the OAG + */ + Map> reachableMap = new HashMap<>(); + + public boolean reaches(AllocNode source, AllocNode dest) { + Collection reachableNodes = reachableMap.get(source); + if (reachableNodes == null) { + reachableNodes = computeReachableNodes(source); + reachableMap.put(source, reachableNodes); + } + return reachableNodes.contains(dest); + } + + protected void buildOAG() { + Map> pts = PTAUtils.calcStaticThisPTS(this.pta); + for (SootMethod method : this.pta.getNakedReachableMethods()) { + if (method.isPhantom()) { + continue; + } + MethodPAG srcmpag = pta.getPag().getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + qilin.core.pag.Node from = reader.next(), to = reader.next(); + if (from instanceof AllocNode tgt) { + if (PTAUtils.isFakeMainMethod(method)) { + // special treatment for fake main + AllocNode src = pta.getRootNode(); + addEdge(src, tgt); + } else if (method.isStatic()) { + pts.getOrDefault(thisRef, Collections.emptySet()).forEach(src -> { + addEdge(src, tgt); + }); + } else { + PointsToSet thisPts = pta.reachingObjects(thisRef).toCIPointsToSet(); + for (Iterator it = thisPts.iterator(); it.hasNext(); ) { + AllocNode src = it.next(); + addEdge(src, tgt); + } + } + } + } + } + } + + /** + * Add a directed object allocation edge to the OAG. + */ + protected void addEdge(AllocNode src, AllocNode tgt) { + nodes.add(src); + nodes.add(tgt); + this.predecessors.computeIfAbsent(tgt, k -> new HashSet<>()).add(src); + this.successors.computeIfAbsent(src, k -> new HashSet<>()).add(tgt); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java new file mode 100644 index 00000000000..e542c95bfe6 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -0,0 +1,83 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.common; + +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.PAG; +import qilin.core.pag.VarNode; +import soot.RefLikeType; +import soot.RefType; +import soot.SootClass; +import soot.SootMethod; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class ToolUtil { + public static VarNode getThis(PAG pag, SootMethod m) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + return mthdNF.caseThis(); + } + + public static Set getParameters(PAG pag, SootMethod m) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + Set ret = new HashSet<>(); + for (int i = 0; i < m.getParameterCount(); ++i) { + if (m.getParameterType(i) instanceof RefLikeType) { + qilin.core.pag.VarNode param = mthdNF.caseParm(i); + ret.add(param); + } + } + return ret; + } + + public static Set getRetVars(PAG pag, SootMethod m) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + if (m.getReturnType() instanceof RefLikeType) { + VarNode ret = mthdNF.caseRet(); + return Collections.singleton(ret); + } + return Collections.emptySet(); + } + + public static int pointsToSetSizeOf(final PTA pta, VarNode var) { + return pta.reachingObjects(var).toCIPointsToSet().size(); + } + + /** + * @param pInner potential inner class + * @param pOuter potential outer class + * @return whether pInner is an inner class of pOuter + */ + public static boolean isInnerType(final RefType pInner, RefType pOuter) { + final String pInnerStr = pInner.toString(); + while (!pInnerStr.startsWith(pOuter.toString() + "$")) { + SootClass sc = pOuter.getSootClass(); + if (sc.hasSuperclass()) { + pOuter = sc.getSuperclass().getType(); + } else { + return false; + } + } + return true; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java new file mode 100644 index 00000000000..5af968d47c5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java @@ -0,0 +1,225 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; +import qilin.util.Pair; +import soot.ArrayType; +import soot.PrimType; +import soot.SootMethod; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; + +public class AbstractConch { + public final PTA pta; + public final PAG pag; + + protected final Map> invokedMethods = new HashMap<>(); + // field |--> + protected final Map>>> m2thisFStores = new HashMap<>(); + protected final Map>>> o2nonThisFStores = new HashMap<>(); + protected final Map>> m2thisFLoads = new HashMap<>(); + protected final Map>> o2nonThisFLoads = new HashMap<>(); + protected final Map> o2fs = new HashMap<>(); + + public AbstractConch(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + init(); + } + + private void init() { + /* + * Static methods are modeled as a special instance methods of its most recent instance methods' receciver objects. + * thus, inherit its most recent instance methods' contexts (which is standard in the literature). + * The following line computes the receiver objects for the this_ptr of static methods. + * */ + Map> pts = PTAUtils.calcStaticThisPTS(pta); + pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(method -> { + collectStoresIn(method); + collectLoadsIn(method); + buildInvokedOnFor(method, pts); + }); + + buildHeap2AccessedFieldsMap(); + } + + /* + * build a map, heap |--> {fields}. + * */ + private void buildHeap2AccessedFieldsMap() { + for (AllocNode heap : pag.getAllocNodes()) { + Set tmp = new HashSet<>(); + tmp.addAll(o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()).keySet()); + tmp.addAll(o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()).keySet()); + for (SootMethod sm : invokedMethods.getOrDefault(heap, Collections.emptySet())) { + tmp.addAll(m2thisFLoads.getOrDefault(sm, Collections.emptyMap()).keySet()); + tmp.addAll(m2thisFStores.getOrDefault(sm, Collections.emptyMap()).keySet()); + } + o2fs.put(heap, tmp); + } + } + + /* + * give a method, we map its receiver objects to this method. + * */ + private void buildInvokedOnFor(SootMethod m, Map> pts) { + MethodPAG srcmpag = pag.getMethodPAG(m); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + + if (m.isStatic()) { + pts.getOrDefault(thisRef, Collections.emptySet()).forEach(a -> { + invokedMethods.computeIfAbsent(a, k -> new HashSet<>()).add(m); + }); + } else { + PointsToSet thisPts = pta.reachingObjects(thisRef).toCIPointsToSet(); + for (Iterator it = thisPts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + invokedMethods.computeIfAbsent(n, k -> new HashSet<>()).add(m); + } + } + } + + private final Map methodSMPAGMap = new HashMap<>(); + + public SMPAG getSMAPG(MethodPAG mpag) { + return methodSMPAGMap.computeIfAbsent(mpag, k -> new SMPAG(mpag)); + } + + private void collectLoadsIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + SMPAG smpag = getSMAPG(srcmpag); + for (Pair ld : smpag.getLoads()) { + FieldRefNode fr = (FieldRefNode) ld.getSecond(); + LocalVarNode loadBase = (LocalVarNode) fr.getBase(); + SparkField field = fr.getField(); + if (primitiveField(field)) { + continue; + } + if (PTAUtils.mustAlias(pta, thisRef, loadBase)) { // handle THIS LOAD, i.e., ... = this.f + Map> f2bs = m2thisFLoads.computeIfAbsent(method, k -> new HashMap<>()); + f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(loadBase); + } else { + for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { + if (heap.getMethod() != method) { + /* we filter loads in the containing method, + * since this often not satisfy the second theoretical condition O.f*--)-->v. + */ + Map> f2bs = o2nonThisFLoads.computeIfAbsent(heap, k -> new HashMap<>()); + f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(loadBase); + } + } + } + } + } + + private void collectStoresIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + SMPAG smpag = getSMAPG(srcmpag); + for (Pair st : smpag.getStores()) { + LocalVarNode from = (LocalVarNode) st.getSecond(); + FieldRefNode fr = (FieldRefNode) st.getFirst(); + LocalVarNode storeBase = (LocalVarNode) fr.getBase(); + SparkField field = fr.getField(); + if (primitiveField(field)) { + continue; + } + if (PTAUtils.mustAlias(pta, thisRef, storeBase)) { // handle this STORE, i.e., this.f = ... + Map>> m2s = m2thisFStores.computeIfAbsent(method, k -> new HashMap<>()); + m2s.computeIfAbsent(field, k -> new HashSet<>()).add(new Pair<>(storeBase, from)); + } else { + for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { + if (!emptyFieldPts(heap, field)) { + Map>> f2bs = o2nonThisFStores.computeIfAbsent(heap, k -> new HashMap<>()); + f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(new Pair<>(storeBase, from)); + } + } + } + } + } + + private boolean primitiveField(SparkField f) { + String s = "java.lang.String"; + if (f.getType() instanceof PrimType) { + return true; + } else if (f.getType() instanceof ArrayType at) { + /* + * here, we let primitive array as primitive type as that in Turner. + * this wont hurt precision of clients. + * */ + return at.baseType instanceof PrimType; + } else return f.getType().toString().equals(s); + } + + protected boolean emptyFieldPts(AllocNode heap, SparkField field) { + PointsToSet pts = pta.reachingObjectsInternal(heap, field); + Set tmp = new HashSet<>(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + // filter StringConstant. + if (!(n instanceof StringConstantNode)) { + tmp.add(n); + } + } + return tmp.isEmpty(); + } + + protected boolean hasLoadOn(AllocNode heap, SparkField field) { + Map> f2bs = o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()); + Set loadBases = f2bs.getOrDefault(field, Collections.emptySet()); + if (!loadBases.isEmpty()) { + return true; + } + for (SootMethod method : invokedMethods.getOrDefault(heap, Collections.emptySet())) { + Map> f2bsX = m2thisFLoads.getOrDefault(method, Collections.emptyMap()); + Set loadBasesX = f2bsX.getOrDefault(field, Collections.emptySet()); + if (!loadBasesX.isEmpty()) { + return true; + } + } + return false; + } + + protected boolean hasStoreOn(AllocNode heap, SparkField field) { + Map>> f2bs = o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); + Set> storeBases = f2bs.getOrDefault(field, Collections.emptySet()); + if (!storeBases.isEmpty()) { + return true; + } + for (SootMethod method : invokedMethods.getOrDefault(heap, Collections.emptySet())) { + Map>> f2bsX = m2thisFStores.getOrDefault(method, Collections.emptyMap()); + Set> storeBasesX = f2bsX.getOrDefault(field, Collections.emptySet()); + if (!storeBasesX.isEmpty()) { + return true; + } + } + return false; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java new file mode 100644 index 00000000000..514c5841096 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -0,0 +1,223 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import com.google.common.collect.Streams; +import heros.solver.CountingThreadPoolExecutor; +import qilin.core.PTA; +import qilin.core.PointsToAnalysis; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import soot.RefLikeType; +import soot.SootMethod; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.util.queue.QueueReader; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/* + * The abstract pointer assignment graph constructed by rules in Fig. 10 and Fig. 11 in our paper. + * our IFDS analysis is running on PAG rather than the conventional control flow graph. + * */ +public abstract class AbstractPAG { + /* + * A symbolic object is introduced to abstract all the possible objects returned from a callsite. + * */ + protected final Map> symbolicHeaps = new ConcurrentHashMap<>(); + protected final Map> outEdges = new ConcurrentHashMap<>(); + protected final Map> sumEdges = new ConcurrentHashMap<>(); + + protected CountingThreadPoolExecutor executor; + + protected final PTA prePTA; + protected final PAG prePAG; + protected final CallGraph callGraph; + + protected AbstractPAG(PTA prePTA) { + this.prePTA = prePTA; + this.prePAG = prePTA.getPag(); + this.callGraph = prePTA.getCallGraph(); + int threadNum = Runtime.getRuntime().availableProcessors(); + this.executor = new CountingThreadPoolExecutor(threadNum, Integer.MAX_VALUE, 30, + TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + } + + protected void build() { + prePTA.getNakedReachableMethods() + .parallelStream().filter(m -> !m.isPhantom()) + .forEach(this::buildFG); + } + + private void buildFG(SootMethod method) { + MethodPAG srcmpag = prePAG.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + } // local-global + + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + } // global-local + + } + + // add param and return edges + addParamEdge(thisRef); + + int numParms = method.getParameterCount(); + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof RefLikeType) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + addParamEdge(param); + } + } + if (method.getReturnType() instanceof RefLikeType) { + LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); + addReturnEdge(mret); + } + Node throwNode = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); + if (throwNode != null) { + addThrowEdge(throwNode); + } + } + + protected void addNormalEdge(TranEdge edge) { + outEdges.computeIfAbsent(edge.getSource(), k -> ConcurrentHashMap.newKeySet()).add(edge); + } + + protected void addThrowEdge(Node throwNode) { + addNormalEdge(new TranEdge(throwNode, throwNode, DFA.TranCond.THROW)); + addNormalEdge(new TranEdge(throwNode, throwNode, DFA.TranCond.I_THROW)); + } + + protected void addParamEdge(LocalVarNode param) { + addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); + addNormalEdge(new TranEdge(param, param, DFA.TranCond.I_PARAM)); + } + + protected void addReturnEdge(LocalVarNode mret) { + addNormalEdge(new TranEdge(mret, mret, DFA.TranCond.RETURN)); + addNormalEdge(new TranEdge(mret, mret, DFA.TranCond.I_RETURN)); + } + + protected void addNewEdge(AllocNode from, LocalVarNode to) { + // skip merged heaps. + if (from.getMethod() == null && !(from instanceof ConstantNode)) { + return; + } + TranEdge newEdge = new TranEdge(from, to, DFA.TranCond.NEW); + addNormalEdge(newEdge); + TranEdge newInvEdge = new TranEdge(to, from, DFA.TranCond.I_NEW); + addNormalEdge(newInvEdge); + } + + protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { + TranEdge assignEdge = new TranEdge(from, to, DFA.TranCond.ASSIGN); + addNormalEdge(assignEdge); + TranEdge assignInvEdge = new TranEdge(to, from, DFA.TranCond.I_ASSIGN); + addNormalEdge(assignInvEdge); + } + + protected void addStoreEdge(LocalVarNode from, LocalVarNode base) { + TranEdge storeEdge = new TranEdge(from, base, DFA.TranCond.STORE); + addNormalEdge(storeEdge); + TranEdge storeInvEdge = new TranEdge(base, from, DFA.TranCond.I_STORE); + addNormalEdge(storeInvEdge); + } + + protected void addLoadEdge(LocalVarNode base, LocalVarNode to) { + TranEdge loadEdge = new TranEdge(base, to, DFA.TranCond.LOAD); + addNormalEdge(loadEdge); + TranEdge loadInvEdge = new TranEdge(to, base, DFA.TranCond.I_LOAD); + addNormalEdge(loadInvEdge); + } + + /* + * The following code forms the bases of a multi-threaded IFDS solver. + * The codes is modified from the implementation of the fast IFDS solver in FlowDroid. + */ + protected void solve() { + submitInitialSeeds(); + awaitCompletionComputeValuesAndShutdown(); + } + + protected Collection outAndSummaryEdges(Node node) { + return Streams.concat(outEdges.getOrDefault(node, Collections.emptySet()).stream(), + sumEdges.getOrDefault(node, Collections.emptySet()).stream()).collect(Collectors.toSet()); + } + + protected abstract void submitInitialSeeds(); + + protected void awaitCompletionComputeValuesAndShutdown() { + { + // run executor and await termination of tasks + runExecutorAndAwaitCompletion(); + } + // ask executor to shut down; + // this will cause new submissions to the executor to be rejected, + // but at this point all tasks should have completed anyway + executor.shutdown(); + + // Wait for the executor to be really gone + while (!executor.isTerminated()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // silently ignore the exception, it's not an issue if the + // thread gets aborted + } + } + executor = null; + } + + private void runExecutorAndAwaitCompletion() { + try { + executor.awaitCompletion(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Throwable exception = executor.getException(); + if (exception != null) { + throw new RuntimeException("There were exceptions during IFDS analysis. Exiting.", exception); + } + } + + protected AllocNode getSymbolicHeapOf(SootMethod method, Stmt invokeStmt) { + return symbolicHeaps.computeIfAbsent(method, k -> new ConcurrentHashMap<>()).computeIfAbsent(invokeStmt, k -> new AllocNode(invokeStmt, null, method)); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java new file mode 100644 index 00000000000..f7e3b24682e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java @@ -0,0 +1,63 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.pag.AllocNode; +import qilin.util.graph.DirectedGraphImpl; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/* + * context-sensitivity dependent graph: + * an edge l1 --> l2 means if l2 is context-insensitive, then l1 should be context-insensitive. + * if l2 is context-sensitive, then l1 also should be context-sensitive. + * if edges form a cycle, i.e, l1-->l2-->l3-->l1 and non nodes's context-sensitivity + * in this cycle could be decide yet, we assume all of them to be context-insensitive. + * To efficiently check Obs 3(b) (lines 18-23 in Algorithm 1), we introduce this graph structure. + * */ +public class CSDG extends DirectedGraphImpl { + /* + * Remove node on the graph that does not have successor. + * */ + public void removeNode(final AllocNode to) { + if (succs.containsKey(to) && !succs.get(to).isEmpty()) { + return; + } + succs.remove(to); + if (preds.containsKey(to)) { + for (AllocNode from : preds.get(to)) { + succs.get(from).remove(to); + } + preds.remove(to); + } + nodes.remove(to); + } + + public Set noOutDegreeNodes() { + Set ret = new HashSet<>(); + for (AllocNode node : allNodes()) { + if (succs.getOrDefault(node, Collections.emptySet()).isEmpty()) { + ret.add(node); + } + } + return ret; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java new file mode 100644 index 00000000000..deaad929bfe --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -0,0 +1,398 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; +import qilin.util.Pair; +import soot.SootMethod; +import soot.Unit; +import soot.Value; +import soot.jimple.InvokeExpr; +import soot.jimple.InvokeStmt; +import soot.jimple.SpecialInvokeExpr; +import soot.jimple.Stmt; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; +import java.util.stream.Collectors; + +/* + * This classifier will classify heaps into context-dependent and context-independent heaps. + * */ +public class Conch extends AbstractConch { + + private final LeakAnalysis mfg; + private final DepOnParamAnalysis pfg; + + private final Set csHeaps = new HashSet<>(); + private final Set ciHeaps = new HashSet<>(); + + public Set ctxDependentHeaps() { + return csHeaps.stream().map(AllocNode::getNewExpr).collect(Collectors.toSet()); + } + + public Set ctxIndenpendentHeaps() { + return ciHeaps; + } + + public Set ctxDependentHeaps2() { + return csHeaps; + } + + public Conch(PTA pta) { + super(pta); + this.mfg = new LeakAnalysis(pta); + this.pfg = new DepOnParamAnalysis(pta); + } + + private SootMethod findInvokedConstructorOf(AllocNode heap) { + SootMethod containingMethod = heap.getMethod(); + MethodPAG cmpag = pag.getMethodPAG(containingMethod); + MethodNodeFactory nodeFactory = cmpag.nodeFactory(); + for (Unit unit : cmpag.getInvokeStmts()) { + if (unit instanceof InvokeStmt invokeStmt) { + InvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof SpecialInvokeExpr iie) { + Value base = iie.getBase(); + VarNode baseNode = (VarNode) nodeFactory.getNode(base); + PointsToSet v1pts = pta.reachingObjects(baseNode); + SootMethod target = iie.getMethod(); + if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && target.isConstructor()) { + return target; + } + } + } + } + return null; // not found. + } + + private SootMethod findInvokedConstructorOf(SootMethod outerInit) { + MethodPAG cmpag = pag.getMethodPAG(outerInit); + MethodNodeFactory nodeFactory = cmpag.nodeFactory(); + VarNode thisNode = nodeFactory.caseThis(); + for (Unit unit : cmpag.getInvokeStmts()) { + if (unit instanceof InvokeStmt invokeStmt) { + InvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof SpecialInvokeExpr iie) { + Value base = iie.getBase(); + VarNode baseNode = (VarNode) nodeFactory.getNode(base); + SootMethod target = iie.getMethod(); + if (PTAUtils.mustAlias(pta, thisNode, baseNode) && target.isConstructor()) { + return target; + } + } + } + } + return null; // not found. + } + + private ArrayList recoverConstructorChain(SootMethod sm, AllocNode heap) { + ArrayList ret = new ArrayList<>(); + SootMethod origInit = findInvokedConstructorOf(heap); + if (origInit != null) { + while (origInit != sm) { + ret.add(0, origInit); + origInit = findInvokedConstructorOf(origInit); + if (origInit == null) { + break; + } + } + } + return ret; + } + + private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMethod curr, SootMethod caller) { + MethodPAG cmpag = pag.getMethodPAG(caller); + Set ret = new HashSet<>(); + for (Unit unit : cmpag.getInvokeStmts()) { + Stmt stmt = (Stmt) unit; + if (!(stmt.getInvokeExpr() instanceof SpecialInvokeExpr)) { + continue; + } + SootMethod target = stmt.getInvokeExpr().getMethod(); + if (target != null && target.equals(curr)) { + for (Node n : params) { + if (n instanceof VarNode paramNode) { + LocalVarNode argNode = PTAUtils.paramToArg(pag, stmt, cmpag, paramNode); + if (argNode != null) { + ret.addAll(this.pfg.fetchReachableParamsOf(argNode)); + } + } + } + } + } + return ret; + } + + private boolean containHeaps(Set nodes) { + boolean ret = false; + for (Node n : nodes) { + if (n instanceof AllocNode) { + ret = true; + break; + } + } + return ret; + } + + private Trilean handleTransitiveConstructors(SootMethod sm, AllocNode heap, Set params) { + SootMethod containingMethod = heap.getMethod(); + ArrayList chain = recoverConstructorChain(sm, heap); + SootMethod caller = sm; + SootMethod curr; + Set ret = params; + boolean notSure = containHeaps(params); + for (SootMethod method : chain) { + curr = caller; + caller = method; + ret = mappingtoCallerCommingParamsOrHeaps(ret, curr, caller); + notSure |= containHeaps(ret); + Trilean res = checkResult(ret); + if (res != Trilean.TRUE) { + if (notSure) { + return Trilean.UNKNOWN; + } else { + return Trilean.FALSE; + } + } + } + curr = caller; + caller = containingMethod; + ret = mappingtoCallerCommingParamsOrHeaps(ret, curr, caller); + Trilean tmpRes2 = checkResult(ret); + if (notSure) { + tmpRes2 = Trilean.OR(tmpRes2, Trilean.UNKNOWN); + } + return tmpRes2; + } + + private Trilean checkResult(Set res) { + if (res.isEmpty()) { + return Trilean.FALSE; + } + boolean hasParam = false; + for (Node n : res) { + if (!(n instanceof AllocNode)) { + hasParam = true; + break; + } + } + if (hasParam) { + return Trilean.TRUE; + } else { + return Trilean.UNKNOWN; + } + } + + private Trilean isCommingFromParams(LocalVarNode from, SootMethod method, AllocNode heap) { + Set ret = this.pfg.fetchReachableParamsOf(from); + if (method.isConstructor()) { + return handleTransitiveConstructors(method, heap, ret); + } else { + return checkResult(ret); + } + } + + private final Map> notSureFields = new HashMap<>(); + + private Trilean checkHeap(AllocNode heap) { + Set fields = o2fs.getOrDefault(heap, Collections.emptySet()); + Trilean ret = Trilean.FALSE; + for (SparkField field : fields) { + Trilean csorci = Trilean.FALSE; + if (!hasLoadOn(heap, field) || !hasStoreOn(heap, field) || emptyFieldPts(heap, field)) { + continue; + } + + // check stores: + Map>> f2sts = o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); + Set> pairs = f2sts.getOrDefault(field, Collections.emptySet()); + if (!pairs.isEmpty()) { + for (Pair pair : pairs) { + LocalVarNode storeBase = (LocalVarNode) pair.getFirst(); + VarNode from = pair.getSecond(); + if (storeBase.getMethod() != heap.getMethod()) { + csorci = Trilean.TRUE; + } else { + Trilean fromparam = isCommingFromParams((LocalVarNode) from, storeBase.getMethod(), heap); + csorci = Trilean.OR(csorci, fromparam); + if (fromparam == Trilean.UNKNOWN) { + notSureFields.computeIfAbsent(heap, k -> new HashSet<>()).add(field); + } + } + } + } + Set onMethods = invokedMethods.getOrDefault(heap, Collections.emptySet()); + for (SootMethod method : onMethods) { + Map>> f2stsX = m2thisFStores.getOrDefault(method, Collections.emptyMap()); + Set> thisFStores = f2stsX.getOrDefault(field, Collections.emptySet()); + if (!thisFStores.isEmpty()) { + for (Pair pair : thisFStores) { + VarNode from = pair.getSecond(); + Trilean fromparam = isCommingFromParams((LocalVarNode) from, method, heap); + csorci = Trilean.OR(csorci, fromparam); + } + } + } + + ret = Trilean.OR(ret, csorci); + if (csorci == Trilean.UNKNOWN) { + notSureFields.computeIfAbsent(heap, k -> new HashSet<>()).add(field); + } + } + return ret; + } + + private boolean hasInstanceFieldWithStoreLoad(AllocNode heap) { + Set fields = o2fs.getOrDefault(heap, Collections.emptySet()); + for (SparkField field : fields) { + boolean hasLoads = hasLoadOn(heap, field); + boolean hasStores = hasStoreOn(heap, field); + boolean emptyFieldPts = emptyFieldPts(heap, field); + if (!hasLoads || !hasStores || emptyFieldPts) { + continue; + } + return true; + } + return false; + } + + public void runClassifier() { + Collection allHeaps = pag.getAllocNodes(); + int heapCnt = allHeaps.size(); + int[] condACnt = new int[1]; + + /* + * pre-process. + * Those heaps usually are assigned empty context in a tradition pointer analysis. + * Classify them to be CS or CI does not affect the efficiency of pointer analysis. + * Thus, we handle them in the pre-process. + */ + Set remainToSolve = new HashSet<>(); + allHeaps.forEach(heap -> { + if (heap.getMethod() == null + || heap instanceof ConstantNode + || PTAUtils.isEmptyArray(heap) + || PTAUtils.isOfPrimitiveBaseType(heap)) { + ciHeaps.add(heap); + } else { + SootMethod mthd = heap.getMethod(); + if (mthd.isStaticInitializer()) { + ciHeaps.add(heap); + } else { + remainToSolve.add(heap); + } + } + }); + + // check by rules. + Set unknownyet = new HashSet<>(); + remainToSolve.forEach(heap -> { + // Obs 2 + boolean condA = this.mfg.isLeakObject(heap); + condACnt[0] += (condA ? 1 : 0); + if (!condA) { + ciHeaps.add(heap); + return; + } + // Obs 1 + boolean condB = hasInstanceFieldWithStoreLoad(heap); + if (!condB) { + ciHeaps.add(heap); + return; + } + // Obs 3 (a) + Trilean condExtra = checkHeap(heap); + if (condExtra == Trilean.TRUE) { + csHeaps.add(heap); + } else if (condExtra == Trilean.FALSE) { + ciHeaps.add(heap); + } else { + unknownyet.add(heap); + } + }); + // Obs 3 (b) + classifyForRemain(unknownyet); + // stat + System.out.println("#Heaps:" + heapCnt); + System.out.println("#CondA:" + condACnt[0]); + System.out.println("#CS:" + csHeaps.size()); + System.out.println("#CI:" + ciHeaps.size()); + } + + private void classifyForRemain(Set unknownyet) { + CSDG csdg = new CSDG(); + // build the dependency graph. + for (AllocNode heap : unknownyet) { + Set ifs = notSureFields.getOrDefault(heap, Collections.emptySet()); + boolean cs = false; + boolean existUnknown = false; + Set tos = new HashSet<>(); + for (SparkField sf : ifs) { + PointsToSet pts = pta.reachingObjectsInternal(heap, sf); + for (AllocNode o : pts.toCIPointsToSet().toCollection()) { + // if o is cs, then heap is cs; + if (csHeaps.contains(o)) { + cs = true; + break; + } + if (!ciHeaps.contains(o)) { + // exist unknown. + tos.add(o); + existUnknown = true; + } + } + if (cs) { + break; + } + } + if (cs) { + csHeaps.add(heap); + } else if (existUnknown) { + for (AllocNode to : tos) { + csdg.addEdge(heap, to); + } + } else { + ciHeaps.add(heap); + } + } + // recursively classify heaps for these on CSDG. + System.out.println("#InitOnCSDG:" + csdg.allNodes().size()); + while (true) { + Set noOutDegree = csdg.noOutDegreeNodes(); + if (noOutDegree.isEmpty()) { + break; + } + for (AllocNode nod : noOutDegree) { + if (csHeaps.contains(nod)) { + csHeaps.addAll(csdg.predsOf(nod)); + } else { + ciHeaps.add(nod); + } + csdg.removeNode(nod); + } + } + System.out.println("#StillOnCSDG:" + csdg.allNodes().size()); + ciHeaps.addAll(csdg.allNodes()); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java new file mode 100644 index 00000000000..67f6ca12d46 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java @@ -0,0 +1,83 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/* + * This class defines two DFA used for leak analysis and depOnParam analysis introduced in our paper respectively. + * */ +public class DFA { + public enum State { + O, F, B, E, ERROR; + } + + public enum TranCond { + PARAM, I_PARAM, RETURN, I_RETURN, THROW, I_THROW, ASSIGN, I_ASSIGN, + LOAD, I_LOAD, + STORE, I_STORE, NEW, I_NEW, + INTER_STORE, INTER_ASSIGN, I_INTER_LOAD; + } + + private static final Map> transitionFunc = new HashMap<>(); + + /* + * This is another automaton for PFG. + * */ + private static final Map> transitionFunc2 = new HashMap<>(); + + static { + // The first DFA introduced in Figure 13 for leak analysis. + Map mO = transitionFunc.computeIfAbsent(State.O, k -> new HashMap<>()); + mO.put(TranCond.NEW, State.F); + + Map mF = transitionFunc.computeIfAbsent(State.F, k -> new HashMap<>()); + mF.put(TranCond.ASSIGN, State.F); + mF.put(TranCond.STORE, State.B); + mF.put(TranCond.INTER_STORE, State.B); + mF.put(TranCond.INTER_ASSIGN, State.F); + mF.put(TranCond.RETURN, State.E); + mF.put(TranCond.THROW, State.E); + + Map mB = transitionFunc.computeIfAbsent(State.B, k -> new HashMap<>()); + mB.put(TranCond.I_ASSIGN, State.B); + mB.put(TranCond.I_LOAD, State.B); + mB.put(TranCond.I_PARAM, State.E); + mB.put(TranCond.I_INTER_LOAD, State.B); + mB.put(TranCond.I_NEW, State.O); + + // The second DFA introduced in Figure 15 for depOnParma analysis. + Map mF2 = transitionFunc2.computeIfAbsent(State.F, k -> new HashMap<>()); + mF2.put(TranCond.NEW, State.F); + mF2.put(TranCond.ASSIGN, State.F); + mF2.put(TranCond.LOAD, State.F); + mF2.put(TranCond.RETURN, State.E); + mF2.put(TranCond.INTER_ASSIGN, State.F); + } + + public static State nextState(State curr, TranCond tranCond) { + return transitionFunc.getOrDefault(curr, Collections.emptyMap()).getOrDefault(tranCond, State.ERROR); + } + + public static State nextState2(TranCond tranCond) { + return transitionFunc2.get(State.F).getOrDefault(tranCond, State.ERROR); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java new file mode 100644 index 00000000000..b99aaefd3f5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -0,0 +1,159 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.util.PTAUtils; +import soot.SootMethod; +import soot.jimple.AssignStmt; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.Edge; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/* + * It try to answer where the value of a variable comes from. + * (1) comes from p.f* + * (2) comes from O.f* + * (3) comes from S.f* (S stands for a symbolic heap). + * for the later two case, we are not sure whether the value of current variable comes from the out of its containing method or not. + * We will rely on cs-dependent graph for further checking. + * These two cases is not mentioned in the paper since it does not affect our results. + * */ + +public class DepOnParamAnalysis extends AbstractPAG { + private final Map> pathEdges = new ConcurrentHashMap<>(); + private final Set initialSeeds = ConcurrentHashMap.newKeySet(); + + public DepOnParamAnalysis(PTA prePTA) { + super(prePTA); + build(); + solve(); + } + + protected void solve() { + System.out.println("start analysis!"); + super.solve(); + System.out.println("finish PFG analysis!"); + } + + protected void addParamEdge(LocalVarNode param) { + super.addParamEdge(param); + initialSeeds.add(param); + } + + protected void addNewEdge(AllocNode from, LocalVarNode to) { + super.addNewEdge(from, to); + initialSeeds.add(from); + } + + protected void submitInitialSeeds() { + for (Node node : initialSeeds) { + propagate(node, node); + } + } + + private void propagate(Node srcParam, Node currNode) { + Set fromParams = pathEdges.computeIfAbsent(currNode, k -> ConcurrentHashMap.newKeySet()); + if (!fromParams.contains(srcParam)) { + executor.execute(new PathEdgeProcessingTask(srcParam, currNode)); + } + } + + private class PathEdgeProcessingTask implements Runnable { + private final Node sourceParam; + private final Node currNode; + + public PathEdgeProcessingTask(Node param, Node node) { + this.sourceParam = param; + this.currNode = node; + } + + @Override + public void run() { + pathEdges.computeIfAbsent(currNode, k -> ConcurrentHashMap.newKeySet()).add(sourceParam); + for (TranEdge e : outAndSummaryEdges(currNode)) { + Node nextNode = e.getTarget(); + DFA.TranCond tranCond = e.getTranCond(); + DFA.State nextState = DFA.nextState2(tranCond); + if (nextState == DFA.State.ERROR) { + continue; + } + propagate(sourceParam, nextNode); + if (nextState == DFA.State.E) { + // do something. + SootMethod containingMethod; + if (sourceParam instanceof LocalVarNode pj) { + containingMethod = pj.getMethod(); + } else { + AllocNode heap = (AllocNode) sourceParam; + containingMethod = heap.getMethod(); + } + + Iterator it = callGraph.edgesInto(containingMethod); + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + Stmt invokeStmt = (Stmt) edge.srcUnit(); + if (invokeStmt instanceof AssignStmt assignStmt) { + + VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); + if (sourceParam instanceof LocalVarNode pj) { + VarNode aj = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pj); + if (aj != null) { + addSummaryEdge(new TranEdge(aj, r, DFA.TranCond.INTER_ASSIGN)); + } + } else { + AllocNode symbolHeap = getSymbolicHeapOf(srcMethod, invokeStmt); + addSummaryEdge(new TranEdge(symbolHeap, r, DFA.TranCond.NEW)); + propagate(symbolHeap, symbolHeap); + } + } + } + } + } + } + } + + private void addSummaryEdge(TranEdge tranEdge) { + Node src = tranEdge.getSource(); + Node tgt = tranEdge.getTarget(); + DFA.TranCond tranCond = tranEdge.getTranCond(); + sumEdges.computeIfAbsent(src, k -> ConcurrentHashMap.newKeySet()).add(tranEdge); + for (Node srcParam : pathEdges.getOrDefault(src, Collections.emptySet())) { + DFA.State nextState = DFA.nextState2(tranCond); + if (nextState == DFA.State.ERROR) { + continue; + } + propagate(srcParam, tgt); + } + } + + public Set fetchReachableParamsOf(Node node) { + return pathEdges.getOrDefault(node, Collections.emptySet()); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java new file mode 100644 index 00000000000..dcee2a57e59 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -0,0 +1,218 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.PTA; +import qilin.core.pag.*; +import qilin.util.PTAUtils; +import soot.SootMethod; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.Edge; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/* + * This structure is used to check whether an object could flow out of its containing method. + * */ +public class LeakAnalysis extends AbstractPAG { + private final Map> pathEdges = new ConcurrentHashMap<>(); + private final Set initialSeeds = ConcurrentHashMap.newKeySet(); + private final Set result = ConcurrentHashMap.newKeySet(); + + public LeakAnalysis(PTA prePTA) { + super(prePTA); + build(); + solve(); + } + + protected void solve() { + System.out.println("start analysis!"); + super.solve(); + System.out.println("finish MFG analysis!"); + } + + protected void submitInitialSeeds() { + initialSeeds.forEach(pe -> executor.execute(new PathEdgeProcessingTask(pe))); + } + + protected void addThrowEdge(Node throwNode) { + super.addThrowEdge(throwNode); + initialSeeds.add(new PathEdge(throwNode, DFA.State.B, throwNode, DFA.State.B)); + } + + protected void addParamEdge(LocalVarNode param) { + super.addParamEdge(param); + initialSeeds.add(new PathEdge(param, DFA.State.F, param, DFA.State.F)); + } + + protected void addReturnEdge(LocalVarNode mret) { + super.addReturnEdge(mret); + initialSeeds.add(new PathEdge(mret, DFA.State.B, mret, DFA.State.B)); + } + + protected void addNewEdge(AllocNode from, LocalVarNode to) { + super.addNewEdge(from, to); + initialSeeds.add(new PathEdge(from, DFA.State.O, from, DFA.State.O)); + } + + private void addPathEdge(PathEdge pe) { + Node tgtNode = pe.getTgtNode(); + pathEdges.computeIfAbsent(tgtNode, k -> ConcurrentHashMap.newKeySet()).add(pe); + } + + private boolean containPathEdge(PathEdge pe) { + Node tgtNode = pe.getTgtNode(); + return pathEdges.getOrDefault(tgtNode, Collections.emptySet()).contains(pe); + } + + private void propagate(PathEdge pe) { + if (!containPathEdge(pe)) { + executor.execute(new PathEdgeProcessingTask(pe)); + } + } + + private class PathEdgeProcessingTask implements Runnable { + PathEdge pe; + + public PathEdgeProcessingTask(PathEdge pe) { + this.pe = pe; + } + + @Override + public void run() { + addPathEdge(pe); + DFA.State initState = pe.getSrcState(); + Node sourceNode = pe.getSrcNode(); + DFA.State targetState = pe.getTgtState(); + Node targetNode = pe.getTgtNode(); + + for (TranEdge e : outAndSummaryEdges(targetNode)) { + Node newTargetNode = e.getTarget(); + DFA.TranCond tranCond = e.getTranCond(); + DFA.State nextState = DFA.nextState(targetState, tranCond); + if (nextState == DFA.State.ERROR) { + continue; + } + if (initState == DFA.State.B && nextState == DFA.State.O) { + // disallow such kinds of pathedge: --> + continue; + } + PathEdge nPE = new PathEdge(sourceNode, initState, newTargetNode, nextState); + propagate(nPE); + if (nextState != DFA.State.E) { + continue; + } + // reach the end state. + if (initState == DFA.State.O) { + // report a heap flows out of its containing method. + AllocNode sourceHeap = (AllocNode) sourceNode; + result.add(sourceHeap); + SootMethod containingMethod = sourceHeap.getMethod(); + Iterator it = callGraph.edgesInto(containingMethod); + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + Stmt invokeStmt = (Stmt) edge.srcUnit(); + if (targetState == DFA.State.F) { // ret.f* = heap + // add S -new-> r summary edge for symbolic heaps. + VarNode ret = (VarNode) targetNode; + VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, ret); + if (r != null) { + AllocNode s = getSymbolicHeapOf(srcMethod, invokeStmt); + addSummaryEdge(new TranEdge(s, r, DFA.TranCond.NEW)); + addSummaryEdge(new TranEdge(r, s, DFA.TranCond.I_NEW)); + } + } + } + } else if (initState == DFA.State.F) { + LocalVarNode pj = (LocalVarNode) sourceNode; + SootMethod containingMethod = pj.getMethod(); + Iterator it = callGraph.edgesInto(containingMethod); + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + Stmt invokeStmt = (Stmt) edge.srcUnit(); + VarNode aj = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pj); + // a param reach end state. + if (targetState == DFA.State.B && sourceNode != targetNode) { // pi.f* = pj, pi != pj. + // add aj --> ai summary edge. inter_store. + VarNode pi = (VarNode) targetNode; + VarNode ai = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pi); + if (ai != null && aj != null && ai != aj) { + addSummaryEdge(new TranEdge(aj, ai, DFA.TranCond.INTER_STORE)); + } + } else if (targetState == DFA.State.F) { // ret.f* = pj + // add aj --> r summary edge. inter_load. + VarNode ret = (VarNode) targetNode; + VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, ret); + if (r != null && aj != null) { + addSummaryEdge(new TranEdge(aj, r, DFA.TranCond.INTER_ASSIGN)); + } + } + } + } else if (initState == DFA.State.B && targetState == DFA.State.B) { + // ret = pi.f* + LocalVarNode retOrThrow = (LocalVarNode) sourceNode; + SootMethod containingMethod = retOrThrow.getMethod(); + Iterator it = callGraph.edgesInto(containingMethod); + VarNode pi = (VarNode) pe.getTgtNode(); + // add r --> ai summary edge inverse_inter_load. + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + Stmt invokeStmt = (Stmt) edge.srcUnit(); + VarNode ai = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pi); + VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, retOrThrow); + if (r != null && ai != null) { + addSummaryEdge(new TranEdge(r, ai, DFA.TranCond.I_INTER_LOAD)); + } + } + } + } + } + } + + private void addSummaryEdge(TranEdge tranEdge) { + Node src = tranEdge.getSource(); + Node tgt = tranEdge.getTarget(); + DFA.TranCond tranCond = tranEdge.getTranCond(); + sumEdges.computeIfAbsent(src, k -> ConcurrentHashMap.newKeySet()).add(tranEdge); + for (PathEdge pe : pathEdges.getOrDefault(src, Collections.emptySet())) { + DFA.State tgtState = pe.getTgtState(); + DFA.State nextState = DFA.nextState(tgtState, tranCond); + if (nextState == DFA.State.ERROR) { + continue; + } + PathEdge nPE = new PathEdge(pe.getSrcNode(), pe.getSrcState(), tgt, nextState); + propagate(nPE); + } + } + + // Condition(A): heap that could flow out of its containing methods. + public boolean isLeakObject(AllocNode heap) { + return result.contains(heap); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java new file mode 100644 index 00000000000..3f80556d14f --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java @@ -0,0 +1,102 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.pag.Node; + +/* + * This is the path edge defined as the standard in IFDS algorithm. + * */ +public class PathEdge { + final Node srcNode; + final DFA.State srcState; + final Node tgtNode; + final DFA.State tgtState; + final int hashCode; + + public PathEdge(Node srcNode, DFA.State srcState, Node tgtNode, DFA.State tgtState) { + this.srcNode = srcNode; + this.srcState = srcState; + this.tgtNode = tgtNode; + this.tgtState = tgtState; + + final int prime = 31; + int result = 1; + result = prime * result + ((srcNode == null) ? 0 : srcNode.hashCode()); + result = prime * result + ((srcState == null) ? 0 : srcState.hashCode()); + result = prime * result + ((tgtNode == null) ? 0 : tgtNode.hashCode()); + result = prime * result + ((tgtState == null) ? 0 : tgtState.hashCode()); + this.hashCode = result; + } + + public Node getSrcNode() { + return srcNode; + } + + public DFA.State getSrcState() { + return srcState; + } + + public Node getTgtNode() { + return tgtNode; + } + + public DFA.State getTgtState() { + return tgtState; + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PathEdge other = (PathEdge) obj; + if (srcNode == null) { + if (other.srcNode != null) + return false; + } else if (!srcNode.equals(other.srcNode)) + return false; + if (tgtNode == null) { + if (other.tgtNode != null) + return false; + } else if (!tgtNode.equals(other.tgtNode)) + return false; + if (srcState == null) { + if (other.srcState != null) + return false; + } else if (!srcState.equals(other.srcState)) + return false; + if (tgtState == null) { + return other.tgtState == null; + } else return tgtState.equals(other.tgtState); + } + + @Override + public String toString() { + return "(" + srcNode + "," + srcState + ")\n\t" + "-->" + "(" + tgtNode + "," + tgtState + ")"; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java new file mode 100644 index 00000000000..67719f67d54 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java @@ -0,0 +1,105 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.pag.*; +import qilin.util.Pair; +import qilin.util.graph.DirectedGraphImpl; +import qilin.util.queue.UniqueQueue; +import soot.util.queue.QueueReader; + +import java.util.HashSet; +import java.util.Set; + +/* + * a simplified method PAG with the effects of static load and store being eliminated. + * */ +public class SMPAG extends DirectedGraphImpl { + MethodPAG srcmpag; + Set> loads; + Set> stores; + + public SMPAG(MethodPAG srcmpag) { + this.srcmpag = srcmpag; + init(); + } + + private void init() { + loads = new HashSet<>(); + stores = new HashSet<>(); + QueueReader reader = srcmpag.getInternalReader().clone(); + UniqueQueue workList = new UniqueQueue<>(); + Set visit = new HashSet<>(); + while (reader.hasNext()) { + qilin.core.pag.Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + this.addEdge(from, to); // ASSIGN + } else if (to instanceof FieldRefNode) { + this.addEdge(from, to); // STORE + } // local-global : A.f = a; + + + } else if (from instanceof AllocNode) { + this.addEdge(from, to); // NEW + } else if (from instanceof FieldRefNode) { + this.addEdge(from, to); // LOAD + } else { // global-local + workList.add(to); + } + } + while (!workList.isEmpty()) { + Node curr = workList.poll(); + visit.add(curr); + if (this.predsOf(curr).isEmpty()) { + for (Node next : this.succsOf(curr)) { + if (!visit.contains(next)) { + workList.add(next); + } + this.preds.get(next).remove(curr); + } + if (this.succs.containsKey(curr)) { + this.succs.get(curr).clear(); + } + } + } + + // initialize stores and loads + for (Node node : this.allNodes()) { + if (node instanceof FieldRefNode) { + for (Node from : this.predsOf(node)) { + stores.add(new Pair<>(node, from)); + } + for (Node to : this.succsOf(node)) { + loads.add(new Pair<>(to, node)); + } + } + } + } + + // + public Set> getStores() { + return stores; + } + + // + public Set> getLoads() { + return loads; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java new file mode 100644 index 00000000000..d62f39124ae --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java @@ -0,0 +1,70 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +import qilin.core.pag.Node; + +import java.util.Objects; + +/* + * Transition edges used in define our DFAs. + * */ +public class TranEdge { + private final Node src; + private final Node dst; + private final DFA.TranCond tranCond; + + public TranEdge(Node s, Node d, DFA.TranCond tran) { + this.src = s; + this.dst = d; + this.tranCond = tran; + } + + public Node getSource() { + return src; + } + + public Node getTarget() { + return dst; + } + + public DFA.TranCond getTranCond() { + return tranCond; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TranEdge tranEdge = (TranEdge) o; + return Objects.equals(src, tranEdge.src) && + Objects.equals(dst, tranEdge.dst) && + tranCond == tranEdge.tranCond; + } + + @Override + public int hashCode() { + return Objects.hash(src, dst, tranCond); + } + + @Override + public String toString() { + return src + "\n\t--" + tranCond + "-->\n\t" + dst; + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java new file mode 100644 index 00000000000..92f68f1fa8c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java @@ -0,0 +1,33 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.conch; + +public enum Trilean { + TRUE, FALSE, UNKNOWN; + + public static Trilean OR(Trilean x1, Trilean x2) { + if (x1 == TRUE || x2 == TRUE) { + return TRUE; + } else if (x1 == UNKNOWN || x2 == UNKNOWN) { + return UNKNOWN; + } else { + return FALSE; + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java new file mode 100644 index 00000000000..585feb7432a --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -0,0 +1,203 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.dd; + +import qilin.util.PTAUtils; +import soot.*; +import soot.jimple.*; + +/* + * features and formulas used in "Precise and Scalable Points-to Analysis via Data-Driven + * Context Tunneling" (OOPSLA 2018). + * */ +public class CtxTunnelingFeaturesTrueTable { + private final boolean[] f = new boolean[24]; + + public CtxTunnelingFeaturesTrueTable(SootMethod sm) { + String sig = sm.getSignature(); + // the 10 atomic signature features. + this.f[1] = sig.contains("java"); + this.f[2] = sig.contains("lang"); + this.f[3] = sig.contains("sun"); + this.f[4] = sig.contains("()"); + this.f[5] = sig.contains("void"); + this.f[6] = sig.contains("security"); + this.f[7] = sig.contains("int"); + this.f[8] = sig.contains("util"); + this.f[9] = sig.contains("String"); + this.f[10] = sig.contains("init"); + // 13 additional features (a bit complex). + this.f[11] = containedInNestedClass(sm); + this.f[12] = sm.getParameterCount() > 1; + + Body body = PTAUtils.getMethodBody(sm); + this.f[15] = body.getLocalCount() > 0; + int heapAllocCnt = 0; + for (Unit unit : body.getUnits()) { + if (unit instanceof AssignStmt assignStmt) { + Value left = assignStmt.getLeftOp(); + if (left instanceof Local) { + Value right = assignStmt.getRightOp(); + if (right instanceof Local) { + this.f[14] = true; + } else if (right instanceof NewExpr || right instanceof NewArrayExpr || right instanceof NewMultiArrayExpr) { + heapAllocCnt++; + } else if (right instanceof InvokeExpr) { + if (right instanceof StaticInvokeExpr) { + this.f[17] = true; + } else if (right instanceof VirtualInvokeExpr || right instanceof InterfaceInvokeExpr) { + this.f[18] = true; + } + } else if (right instanceof ArrayRef) { + this.f[13] = true; + } + } else if (left instanceof InstanceFieldRef) { + this.f[16] = true; + } + } else if (unit instanceof InvokeStmt invokeStmt) { + InvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof StaticInvokeExpr) { + this.f[17] = true; + } else if (expr instanceof VirtualInvokeExpr || expr instanceof InterfaceInvokeExpr) { + this.f[18] = true; + } + } + + } + this.f[19] = sm.isStatic(); + this.f[20] = heapAllocCnt == 1; + this.f[21] = sig.contains("Object"); + this.f[22] = heapAllocCnt >= 1; // note, the original implementation is >=1 not > 1 which is conflict with the paper. + this.f[23] = sm.getDeclaringClass().getMethods().size() > 20; // their artifact uses 20 as the threshold. + } + + public boolean containedInNestedClass(SootMethod sm) { + SootClass sc = sm.getDeclaringClass(); + return sc.toString().contains("$"); + } + + // corresponding to the Tunneling predicate in its original implementation. + public boolean cfaFormula2() { + boolean subF1 = !f[3] && !f[6] && !f[9] && f[14] && f[15] && !f[18] && !f[19] && !f[23]; + boolean subF2 = f[1] && !f[3] && !f[4] && f[7] && !f[9] && f[12] && f[14] && f[15] && !f[16] && !f[19] && !f[21]; + boolean subF3 = f[1] && !f[2] && !f[3] && !f[6] && !f[9] && f[11] && !f[13] && f[14] && f[15] && !f[16] + && !f[17] && !f[19] && !f[20] && !f[21] && !f[22] && !f[23]; + return subF1 || subF2 || subF3; + } + + // corresponding to the TunnelingM in its original implementation. + public boolean cfaFormula1() { + boolean subF1 = f[1] && !f[2] && !f[3] && f[4] && f[5] && !f[6] && !f[7] && f[8] && f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && !f[22] && f[23]; + + boolean subF2 = !f[6] && f[8] && !f[10] && !f[11] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[22]; + + boolean subF3 = f[1] && f[2] && !f[3] && !f[4] && !f[6] && f[8] && !f[9] && !f[10] && !f[11] && f[12] && f[14] + && f[15] && !f[16] && f[17] && f[18] && f[19] && !f[20] && f[21] && !f[22] && f[23]; + return subF1 || subF2 || subF3; + } + + public boolean objFormula2() { + boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[14] && f[15] && !f[19]; + boolean subF2 = f[1] && f[2] && f[3] && !f[4] && f[5] && f[6] && !f[7] && !f[8] && f[9] && f[10] && !f[11] + && f[12] && !f[13] && f[14] && f[15] && f[16] && f[17] && f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + return subF1 || subF2; + } + + public boolean objFormula1() { + boolean subF1 = !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] && !f[11] && !f[12] + && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; + + boolean subF2 = f[1] && !f[2] && !f[3] && f[4] && !f[5] && !f[6] && !f[7] && !f[9] && !f[10] && !f[11] && !f[12] + && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && !f[23]; + + boolean subF3 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] + && f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; + + boolean subF4 = f[1] && f[2] && !f[3] && !f[4] && !f[5] && !f[6] && !f[7] && f[8] && !f[10] && !f[11] && !f[12] + && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && f[21] && f[23]; + return subF1 || subF2 || subF3 || subF4; + } + + public boolean typeFormula2() { + boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[14] && f[15] && !f[19] && !f[23]; + boolean subF2 = f[1] && f[2] && !f[5] && !f[7] && !f[8] && f[9] && !f[10] && !f[11] && f[14] + && f[15] && !f[16] && f[17] && !f[19] && !f[20] && f[22] && !f[23]; + boolean subF3 = f[3] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && !f[11] && !f[13] && f[14] && f[15] + && f[18] && !f[19] && !f[20] && !f[22] && f[23]; + + boolean subF4 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] + && !f[11] && f[14] && f[15] && f[16] && !f[17] && !f[19] && !f[20] && !f[21]; + + boolean subF5 = !f[1] && !f[2] && !f[3] && !f[4] && !f[6] && f[7] && !f[9] && !f[11] && f[12] + && !f[13] && f[14] && f[15] && !f[17] && !f[19] && !f[20] && !f[21] && !f[23]; + return subF1 || subF2 || subF3 || subF4 || subF5; + } + + public boolean typeFormula1() { + boolean subF1 = f[1] && !f[2] && !f[3] && !f[6] && !f[7] && f[8] && !f[9] && !f[10] && !f[11] + && !f[12] && f[14] && f[15] && !f[16] && !f[17] && !f[19] && f[20] && f[22]; + + boolean subF2 = f[1] && !f[2] && !f[3] && f[4] && f[5] && !f[6] && !f[7] && f[8] && !f[9] && f[10] && !f[11] + && !f[12] && !f[13] && !f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + + boolean subF3 = f[1] && f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] && !f[11] + && f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + + boolean subF4 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[21] && !f[18] && f[20] && f[22] && !f[23]; + + boolean subF5 = !f[1] && !f[2] && !f[3] && !f[4] && !f[5] && !f[6] && f[7] && !f[8] && !f[9] && !f[10] && !f[11] + && f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + + boolean subF6 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && !f[9] + && f[8] && f[10] && !f[11] && f[12] && !f[13] && f[14] && f[15] && f[16] + && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; + + boolean subF7 = !f[1] && !f[2] && f[3] && f[4] && f[5] && !f[6] && !f[7] && !f[8] + && !f[9] && f[10] && !f[11] && !f[12] && !f[13] && !f[14] && f[15] && !f[16] + && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && f[22] && !f[23]; + + boolean subF8 = !f[4] && !f[9] && !f[10] && !f[11] && f[13] && f[14] && f[15] && !f[16] && f[18] && f[22]; + + boolean subF9 = f[1] && !f[2] && !f[3] && f[4] && !f[5] && !f[6] && !f[7] && f[8] && !f[9] && !f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + + boolean subF10 = !f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[9] + && !f[11] && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[19] && !f[21] && f[22]; + return subF1 || subF2 || subF3 || subF4 || subF5 || subF6 || subF7 || subF8 || subF9 || subF10; + } + + public boolean hybridFormula2() { + boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[15] && !f[23]; + boolean subF2 = f[1] && !f[3] && !f[4] && !f[6] && f[8] && !f[9] && !f[10] + && !f[11] && f[14] && f[15] && !f[16] && f[19]; + boolean subF3 = f[2] && !f[3] && f[4] && !f[5] && !f[6] && f[8] && !f[9] && !f[11] && !f[13] + && f[14] && f[15] && !f[16] && f[17] && !f[18] && !f[19] && !f[20] && f[23]; + return subF1 || subF2 || subF3; + } + + public boolean hybridFormula1() { + boolean subF1 = f[1] && !f[2] && !f[3] && f[4] && !f[6] && !f[8] && !f[9] && !f[11] && !f[13] + && f[14] && f[15] && !f[17] && !f[19] && f[20] && !f[21] && f[22]; + boolean subF2 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] && + !f[13] && !f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; + return subF1 || subF2; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java new file mode 100644 index 00000000000..bad5177c403 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java @@ -0,0 +1,95 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.dd; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldValNode; +import qilin.core.pag.LocalVarNode; +import qilin.parm.ctxcons.CallsiteCtxConstructor; +import qilin.parm.ctxcons.HybObjCtxConstructor; +import qilin.parm.ctxcons.ObjCtxConstructor; +import qilin.parm.ctxcons.TypeCtxConstructor; +import qilin.parm.select.CtxSelector; +import soot.Context; +import soot.SootMethod; + +import java.util.HashMap; +import java.util.Map; + +public class DataDrivenSelector extends CtxSelector { + private final Map m2ftt = new HashMap<>(); + private final Class mClass; + + public DataDrivenSelector(Class mClass) { + this.mClass = mClass; + } + + private FeaturesTrueTable findOrCreateFeaturesTrueTable(SootMethod sm) { + return m2ftt.computeIfAbsent(sm, k -> new FeaturesTrueTable(sm)); + } + + @Override + public Context select(SootMethod m, Context context) { + FeaturesTrueTable ftt = findOrCreateFeaturesTrueTable(m); + int i = 0; + if (mClass == HybObjCtxConstructor.class) { + if (ftt.hybrid2objFormula2()) { + i = 2; + } else if (ftt.hybrid2objFormula1()) { + i = 1; + } + } else if (mClass == ObjCtxConstructor.class) { + if (ftt.twoObjFormula2()) { + i = 2; + } else if (ftt.twoObjFormula1()) { + i = 1; + } + } else if (mClass == CallsiteCtxConstructor.class) { + if (ftt.twoCFAFormula2()) { + i = 2; + } else if (ftt.twoCFAFormula1()) { + i = 1; + } + } else if (mClass == TypeCtxConstructor.class) { + if (ftt.twoTypeFormula2()) { + i = 2; + } else if (ftt.twoTypeFormula1()) { + i = 1; + } + } else { + throw new RuntimeException("unsupport data-driven pointer analysis!"); + } + return contextTailor(context, i); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return context; + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return context; + } + + @Override + public Context select(AllocNode heap, Context context) { + return context; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java new file mode 100644 index 00000000000..da07066824d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -0,0 +1,139 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.dd; + +import qilin.util.PTAUtils; +import soot.Body; +import soot.SootMethod; +import soot.Unit; +import soot.jimple.*; + +/* + * features and formulas used in "Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017)" + * */ +public class FeaturesTrueTable { + private final boolean[] features = new boolean[26]; + + public FeaturesTrueTable(SootMethod sm) { + String sig = sm.getSignature(); + this.features[1] = sig.contains("java"); + this.features[2] = sig.contains("lang"); + this.features[3] = sig.contains("sun"); + this.features[4] = sig.contains("()"); + this.features[5] = sig.contains("void"); + this.features[6] = sig.contains("security"); + this.features[7] = sig.contains("int"); + this.features[8] = sig.contains("util"); + this.features[9] = sig.contains("String"); + this.features[10] = sig.contains("init"); + Body body = PTAUtils.getMethodBody(sm); + for (Unit unit : body.getUnits()) { + if (unit instanceof AssignStmt) { + this.features[11] = true; + } else if (unit instanceof IdentityStmt) { + this.features[12] = true; + } else if (unit instanceof InvokeStmt) { + this.features[13] = true; + } else if (unit instanceof ReturnStmt) { + this.features[14] = true; + } else if (unit instanceof ThrowStmt) { + this.features[15] = true; + } else if (unit instanceof BreakpointStmt) { + this.features[16] = true; + } else if (unit instanceof EnterMonitorStmt) { + this.features[17] = true; + } else if (unit instanceof ExitMonitorStmt) { + this.features[18] = true; + } else if (unit instanceof GotoStmt) { + this.features[19] = true; + } else if (unit instanceof IfStmt) { + this.features[20] = true; + } else if (unit instanceof LookupSwitchStmt) { + this.features[21] = true; + } else if (unit instanceof NopStmt) { + this.features[22] = true; + } else if (unit instanceof RetStmt) { + this.features[23] = true; + } else if (unit instanceof ReturnVoidStmt) { + this.features[24] = true; + } else if (unit instanceof TableSwitchStmt) { + this.features[25] = true; + } + } + } + + // the following two are for hybrid 2-object-sensitive pointer analysis. + public boolean hybrid2objFormula2() { + return features[1] && !features[3] && !features[6] && features[8] && !features[9] && !features[16] + && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] + && !features[22] && !features[23] && !features[24] && !features[25]; + } + + public boolean hybrid2objFormula1() { + boolean subF1 = features[1] && !features[3] && !features[4] && features[6] && !features[7] && !features[8] && !features[9] && + !features[15] && !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] + && !features[22] && !features[23] && !features[24] && !features[25]; + boolean subF2 = !features[3] && !features[4] && !features[7] && !features[8] && !features[9] && features[10] && features[11] && + features[12] && features[13] && !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && + !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; + boolean subF3 = !features[3] && !features[9] && features[13] && features[14] && features[15] && !features[16] && !features[17] + && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; + boolean subF4 = features[1] && features[2] && !features[3] && features[4] && !features[5] && !features[6] && !features[7] && !features[8] + && !features[9] && !features[10] && !features[13] && !features[15] && !features[16] && !features[17] && !features[18] + && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; + return subF1 || subF2 || subF3 || subF4; + } + + public boolean twoObjFormula2() { + return hybrid2objFormula2(); + } + + public boolean twoObjFormula1() { + boolean subF1 = features[1] && features[2] && !features[3] && !features[6] && !features[7] && !features[8] && !features[9] && + !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && + !features[23] && !features[24] && !features[25]; + boolean subF2 = !features[1] && !features[2] && features[5] && features[8] && !features[9] && features[11] && features[12] && !features[14] + && !features[15] && !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && + !features[23] && !features[24] && !features[25]; + boolean subF3 = !features[3] && !features[4] && !features[7] && !features[8] && !features[9] && features[10] && features[11] && features[12] && + !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && + !features[23] && !features[24] && !features[25]; + return subF1 || subF2 || subF3; + } + + public boolean twoTypeFormula2() { + return hybrid2objFormula2(); + } + + public boolean twoTypeFormula1() { + return features[1] && features[2] && !features[3] && !features[6] && !features[7] && !features[8] && !features[9] && !features[15] && + !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && + !features[23] && !features[24] && !features[25]; + } + + public boolean twoCFAFormula2() { + return features[1] && !features[6] && !features[7] && features[11] && features[12] && features[13] && !features[16] && !features[17] && !features[18] + && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; + } + + public boolean twoCFAFormula1() { + return features[1] && features[2] && !features[7] && !features[16] && !features[17] && !features[18] + && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java new file mode 100644 index 00000000000..4b0eac23b04 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java @@ -0,0 +1,68 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.dd; + +import qilin.core.pag.CallSite; +import qilin.core.pag.ContextAllocNode; +import qilin.parm.ctxcons.*; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; + +import java.util.HashMap; +import java.util.Map; + +public class TunnelingConstructor implements CtxConstructor { + private final CtxConstructor ctxCons; + private final Map m2ftt = new HashMap<>(); + + private CtxTunnelingFeaturesTrueTable findOrCreateTunnelingFeaturesTrueTable(SootMethod sm) { + return m2ftt.computeIfAbsent(sm, k -> new CtxTunnelingFeaturesTrueTable(sm)); + } + + public TunnelingConstructor(CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + } + + @Override + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + CtxTunnelingFeaturesTrueTable ctftt1 = findOrCreateTunnelingFeaturesTrueTable(caller.method()); + CtxTunnelingFeaturesTrueTable ctftt2 = findOrCreateTunnelingFeaturesTrueTable(target); + if (ctxCons instanceof CallsiteCtxConstructor) { + if (ctftt1.cfaFormula1() || ctftt2.cfaFormula2()) { + return caller.context(); + } + } else if (ctxCons instanceof TypeCtxConstructor) { + if (ctftt1.typeFormula1() || ctftt2.typeFormula2()) { + return caller.context(); + } + } else if (ctxCons instanceof ObjCtxConstructor) { + if (ctftt1.objFormula1() || ctftt2.objFormula2()) { + return caller.context(); + } + } else if (ctxCons instanceof HybObjCtxConstructor) { + if (ctftt1.hybridFormula1() || ctftt2.hybridFormula2()) { + return caller.context(); + } + } else { + throw new RuntimeException("unsupported context constructor for tunneling: " + ctxCons.getClass()); + } + return ctxCons.constructCtx(caller, receiverNode, callSite, target); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/data-driven/README.md b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/data-driven/README.md new file mode 100644 index 00000000000..e64ef7008f9 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/data-driven/README.md @@ -0,0 +1,5 @@ +# References + +1. [Data-driven context-sensitivity for points-to analysis](https://dl.acm.org/doi/abs/10.1145/3133924) + +2. [Artifact Link](https://github.com/kupl/Data-Driven-Pointsto-Analysis) \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/tunneling/README.md b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/tunneling/README.md new file mode 100644 index 00000000000..8dac19e44fb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/tunneling/README.md @@ -0,0 +1,5 @@ +# References + +1. [Precise and Scalable Points-to Analysis via Data-Driven Context Tunneling](https://dl.acm.org/doi/10.1145/3276510) + +2. [Artifact Link](https://dl.acm.org/do/10.1145/3276931/full/) \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java new file mode 100644 index 00000000000..54465868d11 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java @@ -0,0 +1,62 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.eagle; + +import qilin.core.pag.AllocNode; +import qilin.util.PTAUtils; + +/** + * Original Graph Node(sparkNode) expanded bidirectinally + */ +public class BNode { + public Object sparkNode; + public Boolean forward; + public int level; + public Boolean cs; + + public boolean entryCS() { + if (this.cs) + return false; + return this.cs = true; + } + + public BNode(Object origin, Boolean forward) { + this.sparkNode = origin; + this.forward = forward; + this.cs = false; + this.level = 0; + } + + public Object getIR() { + return PTAUtils.getIR(sparkNode); + } + + boolean isHeapPlus() { + return sparkNode instanceof AllocNode && this.forward; + } + + boolean isHeapMinus() { + return sparkNode instanceof AllocNode && !this.forward; + } + + @Override + public String toString() { + return sparkNode + "," + forward; + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java new file mode 100644 index 00000000000..c34d656a647 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -0,0 +1,381 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.eagle; + +import qilin.core.PTA; +import qilin.core.PointsToAnalysis; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; +import qilin.util.Util; +import qilin.util.queue.UniqueQueue; +import soot.RefLikeType; +import soot.SootMethod; +import soot.Unit; +import soot.Value; +import soot.jimple.*; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.queue.QueueReader; + +import java.util.*; +import java.util.stream.Collectors; + +// implementation of Eagle (OOPSLA'19). +public class Eagle { + protected Map> sparkNode2BNode = new HashMap<>(); + // fields for storage + public Set allocs = new HashSet<>(); + public Set allocIs = new HashSet<>(); + public Map> outEdges = new HashMap<>(); + protected Map> balancedOutEdges = new HashMap<>(); + + private int new_count = 0; + private int assign_count = 0; + protected int store_count = 0; + private int load_count = 0; + private int balance_count = 0; + private int hstore_count = 0; + private int hload_count = 0; + private int total_nodes_count = 0; + private int total_edges_count = 0; + + public void dumpCount() { + System.out.println("#NEW:" + new_count); + System.out.println("#ASSIGN:" + assign_count); + System.out.println("#STORE:" + store_count); + System.out.println("#LOAD:" + load_count); + System.out.println("#HSTORE:" + hstore_count); + System.out.println("#HLOAD:" + hload_count); + System.out.println("#BALANCE:" + balance_count); + } + + public Collection getNodes() { + return sparkNode2BNode.values().stream().flatMap(subMap -> subMap.values().stream()) + .collect(Collectors.toSet()); + } + + public Collection getSparkNodes() { + return sparkNode2BNode.values().stream().flatMap(subMap -> subMap.values().stream()).map(gn -> gn.sparkNode) + .collect(Collectors.toSet()); + } + + public BNode getBNode(Object origin, Boolean forward) { + Map subMap = sparkNode2BNode.computeIfAbsent(origin, k -> new HashMap<>()); + if (subMap.containsKey(forward)) { + return subMap.get(forward); + } else { + BNode ret = new BNode(origin, forward); + subMap.put(forward, ret); + total_nodes_count++; + return ret; + } + } + + protected void addNormalEdge(BNode from, BNode to) { + Set m = outEdges.computeIfAbsent(from, k -> new HashSet<>()); + m.add(to); + total_edges_count++; + } + + public boolean addBalancedEdge(BNode from, BNode to) { + boolean ret = Util.addToMap(balancedOutEdges, from, to); + balance_count++; + total_edges_count++; + return ret; + } + + public void addNewEdge(AllocNode from, LocalVarNode to) { + BNode fromE = getBNode(from, true), toE = getBNode(to, true); + addNormalEdge(fromE, toE); + BNode toEI = getBNode(to, false), fromEI = getBNode(from, false); + addNormalEdge(toEI, fromEI); + + new_count++; + allocs.add(fromE); + allocIs.add(fromEI); + } + + public void addAssignEdge(LocalVarNode from, LocalVarNode to) { + BNode fromE = getBNode(from, true), toE = getBNode(to, true); + addNormalEdge(fromE, toE); + BNode toEI = getBNode(to, false), fromEI = getBNode(from, false); + addNormalEdge(toEI, fromEI); + + assign_count++; + } + + public void addStoreEdge(LocalVarNode from, LocalVarNode base) { + BNode fromE = getBNode(from, true), baseEI = getBNode(base, false); + addNormalEdge(fromE, baseEI); + BNode baseE = getBNode(base, true), fromEI = getBNode(from, false); + addNormalEdge(baseE, fromEI); + + store_count++; + } + + public void addLoadEdge(LocalVarNode base, LocalVarNode to) { + BNode baseE = getBNode(base, true), toE = getBNode(to, true); + addNormalEdge(baseE, toE); + BNode toEI = getBNode(to, false), baseEI = getBNode(base, false); + addNormalEdge(toEI, baseEI); + + load_count++; + } + + public void addHstoreEdge(Object from, AllocNode baseObj) { + BNode fromE = getBNode(from, true), baseObjE = getBNode(baseObj, true); + addNormalEdge(fromE, baseObjE); + BNode baseObjEI = getBNode(baseObj, false), fromEI = getBNode(from, false); + addNormalEdge(baseObjEI, fromEI); + allocIs.add(baseObjEI); + allocs.add(baseObjE); + hstore_count++; + } + + public void addHloadEdge(AllocNode baseObj, Object to) { + BNode baseObjEI = getBNode(baseObj, false), toE = getBNode(to, true); + addNormalEdge(baseObjEI, toE); + BNode toEI = getBNode(to, false), baseObjE = getBNode(baseObj, true); + addNormalEdge(toEI, baseObjE); + allocIs.add(baseObjEI); + allocs.add(baseObjE); + hload_count++; + } + + public int totalEdgesCount() { + return total_edges_count; + } + + public int totalNodesCount() { + return total_nodes_count; + } + + public Set getAllOutEdges(BNode node) { + Set ret = new HashSet<>(getOutEdges(node)); + if (balancedOutEdges.containsKey(node)) { + ret.addAll(balancedOutEdges.get(node)); + } + return ret; + } + + public Collection getOutEdges(BNode node) { + return outEdges.getOrDefault(node, Collections.emptySet()); + } + + public boolean reachValidReceiverObject(BNode from, BNode to) { + BNode fromEI = getBNode(to.sparkNode, false); + if (from.sparkNode instanceof Field || from.sparkNode instanceof ArrayElement) { + return getOutEdges(fromEI).contains(from); + } + return true; + } + + // eagle propagate + protected boolean enterCS(BNode node) { + return node.entryCS(); + } + + public Map contxtLengthAnalysis() { + Queue workList = new UniqueQueue<>(); + Set matchedObjects = new HashSet<>(); + // start from all "parameter/field" node + for (BNode heapNode : allocIs) { + for (BNode dst : getOutEdges(heapNode)) { + dst.cs = true; + workList.add(dst); + } + } + while (!workList.isEmpty()) { + BNode node = workList.poll(); + for (BNode dst : getAllOutEdges(node)) { + if (dst.isHeapPlus() && !node.isHeapMinus()) { + if (reachValidReceiverObject(node, dst)) { + if (matchedObjects.add(dst.sparkNode)) { // add balanced edges + BNode fromEI = getBNode(dst.sparkNode, false); + addBalancedEdge(fromEI, dst, workList); + } + } + } else { + if (enterCS(dst)) { + workList.add(dst); + } + } + } + } + Map ret = new HashMap<>(); + getSparkNodes().forEach(sparkNode -> { + BNode node = getBNode(sparkNode, true); + BNode nodeInv = getBNode(sparkNode, false); + ret.put(sparkNode, node.cs && nodeInv.cs ? 1 : 0); + }); + return ret; + } + + protected void addBalancedEdge(BNode from, BNode to, Queue workList) { + if (addBalancedEdge(from, to)) { + if (from.cs) { + workList.add(from);// add src of the balanced edges to worklist + } + } + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + protected void addParamEdges(AllocNode o, LocalVarNode thisRef, LocalVarNode[] parms, LocalVarNode mret, LocalVarNode mThrow) { + this.addHloadEdge(o, thisRef); + for (VarNode parm : parms) { + if (parm != null) { + this.addHloadEdge(o, parm); + } + } + if (mret != null) { + this.addHstoreEdge(mret, o); + } + if (mThrow != null) { + this.addHstoreEdge(mThrow, o); + } + } + + public void buildGraph(PTA prePTA) { + PAG prePAG = prePTA.getPag(); + // calculate points-to set for "This" pointer in each static method. + Map> pts = PTAUtils.calcStaticThisPTS(prePTA); + + CallGraph callGraph = prePTA.getCallGraph(); + for (SootMethod method : prePTA.getNakedReachableMethods()) { + if (method.isPhantom()) { + continue; + } + MethodPAG srcmpag = prePAG.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + // add local edges + if (PTAUtils.isFakeMainMethod(method)) { + // special treatment for fake main + this.addNewEdge(prePTA.getRootNode(), thisRef); + } + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + } // local-global + + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + } // global-local + } + // add exception edges that added dynamically during the pre-analysis. + srcmpag.getExceptionEdges().forEach((k, vs) -> { + for (Node v : vs) { + this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); + } + }); + // add para edges + int numParms = method.getParameterCount(); + LocalVarNode[] parms = new LocalVarNode[numParms]; + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof RefLikeType) { + parms[i] = (LocalVarNode) srcnf.caseParm(i); + } + } + LocalVarNode mret = method.getReturnType() instanceof RefLikeType ? (LocalVarNode) srcnf.caseRet() : null; + LocalVarNode throwFinal = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); + if (method.isStatic()) { + pts.getOrDefault(thisRef, Collections.emptySet()).forEach(a -> { + addParamEdges(a, thisRef, parms, mret, throwFinal); + }); + } else { + PointsToSet thisPts = prePTA.reachingObjects(thisRef).toCIPointsToSet(); + for (Iterator it = thisPts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + addParamEdges(n, thisRef, parms, mret, throwFinal); + } + } + + // add invoke edges + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + continue; + args[i] = arg; + } + LocalVarNode retDest = null; + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + retDest = prePAG.findLocalVarNode(dest); + } + } + LocalVarNode receiver; + if (ie instanceof InstanceInvokeExpr iie) { + receiver = prePAG.findLocalVarNode(iie.getBase()); + } else { + // static call + receiver = thisRef; + } + for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + for (int i = 0; i < numArgs; i++) { + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) + continue; + ValNode argNode = prePAG.findValNode(args[i]); + if (argNode instanceof LocalVarNode) { + this.addStoreEdge((LocalVarNode) argNode, receiver); + } + } + if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { + this.addLoadEdge(receiver, retDest); + } + LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); + this.addLoadEdge(receiver, stmtThrowNode); + this.addStoreEdge(receiver, receiver);// do not move this out of loop + } + } + } + + // add field edges + prePAG.getContextFields().forEach(contextField -> { + AllocNode base = contextField.getBase(); + SparkField field = contextField.getField(); + if (!prePAG.simpleInvLookup(contextField).isEmpty()) { + this.addHloadEdge(base, field); + } + if (!prePAG.simpleLookup(contextField).isEmpty()) { + this.addHstoreEdge(field, base); + } + }); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java new file mode 100644 index 00000000000..4c0bfa3be45 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java @@ -0,0 +1,136 @@ +package qilin.pta.toolkits.mahjong; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.Node; +import qilin.pta.toolkits.mahjong.automata.DFA; +import qilin.pta.toolkits.mahjong.automata.DFAEquivalenceChecker; +import qilin.pta.toolkits.mahjong.automata.DFAFactory; +import qilin.pta.toolkits.mahjong.automata.DFAState; +import qilin.pta.toolkits.common.FieldPointstoGraph; +import qilin.util.UnionFindSet; +import soot.Type; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * @author Tian Tan + * @author Yue Li + * refactered by Dongjie He. + */ +public class HeapAbstraction { + + private final FieldPointstoGraph fpg; + private final DFAFactory dfaFactory; + private final DFAEquivalenceChecker dfaEqChecker; + + /** + * This map would be manipulated by multiple threads + * thus it should be concurrent hashmap. + */ + private Map canMerged; + + public HeapAbstraction(FieldPointstoGraph fpg) { + this.fpg = fpg; + this.dfaFactory = new DFAFactory(fpg); + this.dfaEqChecker = new DFAEquivalenceChecker(); + } + + public Map computeMergedObjectMap() { + UnionFindSet uf = modelHeap(); + return convertToMap(uf.getDisjointSets()); + } + + /** + * Modeling the heap by checking the equivalence of automata. + */ + private UnionFindSet modelHeap() { + canMerged = new ConcurrentHashMap<>(); + Set allObjs = fpg.getAllObjs(); + UnionFindSet uf = new UnionFindSet<>(allObjs); + // group the objects by their types + Map> groupedObjs = allObjs.stream() + .collect(Collectors.groupingBy(Node::getType, Collectors.toSet())); + groupedObjs.entrySet().parallelStream().forEach(entry -> { + DFAMap dfaMap = new DFAMap(); + Set objs = entry.getValue().stream().filter(o -> canBeMerged(o, dfaMap)).collect(Collectors.toSet()); + for (AllocNode o1 : objs) { + for (AllocNode o2 : objs) { + if (o1.getNumber() <= o2.getNumber() && !uf.isConnected(o1, o2)) { + if (canBeMerged(o1, o2, dfaMap)) { + uf.union(o1, o2); + } + } + } + } + }); + return uf; + } + + /** + * @param o1 + * @param o2 + * @return whether o1 and o2 can be merged. + */ + private boolean canBeMerged(AllocNode o1, AllocNode o2, DFAMap dfaMap) { + if (o1 == o2) { + return true; + } + DFA dfa1 = dfaMap.retrieveDFA(o1); + DFA dfa2 = dfaMap.retrieveDFA(o2); + return dfaEqChecker.isEquivalent(dfa1, dfa2); + } + + /** + * @param o + * @return whether o can be merged with other objects. + */ + private boolean canBeMerged(AllocNode o, DFAMap dfaMap) { + if (!canMerged.containsKey(o)) { + boolean result = true; + // Check whether the types of objects pointed (directly/indirectly) + // by o are unique. + DFA dfa = dfaMap.retrieveDFA(o); + for (DFAState s : dfa.getStates()) { + if (dfa.outputOf(s).size() > 1) { + // Types pointed (directly/indirectly) by o are not unique. + result = false; + break; + } + } + canMerged.put(o, result); + } + return canMerged.get(o); + } + + private static Map convertToMap(Collection> objModel) { + Map map = new HashMap<>(); + objModel.forEach(objs -> { + AllocNode rep = selectRepresentative(objs); + objs.forEach(obj -> map.put(obj, rep)); + }); + return map; + } + + private static AllocNode selectRepresentative(Set objs) { + return objs.stream().findFirst().get(); + } + + /** + * During equivalence check, each thread holds a DFAMap which contains + * the DFA of the objects of the type. After comparison, the DFAMap + * and its containing DFA will be released to save memory space. + */ + private class DFAMap { + private final Map dfaMap = new HashMap<>(); + + private DFA retrieveDFA(AllocNode o) { + return dfaMap.computeIfAbsent(o, k -> dfaFactory.getDFA(o)); + } + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java new file mode 100644 index 00000000000..4e1eedbf247 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java @@ -0,0 +1,68 @@ +package qilin.pta.toolkits.mahjong; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.pta.toolkits.common.FieldPointstoGraph; +import qilin.util.Stopwatch; + +import java.util.Collection; +import java.util.Map; + +/** + * @author Tian Tan + * @author Yue Li + */ +public class Mahjong { + public static void run(PTA pta, Map heapModelMap) { + FieldPointstoGraph fpg = buildFPG(pta); + System.out.print("Creating heap abstraction ... "); + Stopwatch mahjongTimer = Stopwatch.newAndStart("Mahjong"); + HeapAbstraction heapAbs = new HeapAbstraction(fpg); + Map mom = heapAbs.computeMergedObjectMap(); + mahjongTimer.stop(); + System.out.println(mahjongTimer); + outputStatistics(fpg, mom); + + System.out.print("Writing Mahjong heap abstraction ...\n"); + writeMergedObjectMap(mom, heapModelMap); + } + + public static FieldPointstoGraph buildFPG(PTA pta) { + System.out.print("Building FPG (Field Points-to Graph) ... "); + Stopwatch fpgTimer = Stopwatch.newAndStart("FPG Construction"); + FieldPointstoGraph fpg = new FieldPointstoGraph(pta); + fpgTimer.stop(); + System.out.println(fpgTimer); + return fpg; + } + + public static void outputStatistics(FieldPointstoGraph fpg, Map mom) { + int nObj = (int) mom.keySet().stream().distinct().count(); + int nObjMahjong = (int) mom.values().stream().distinct().count(); + System.out.println("-----------------------------------------------------------"); + System.out.printf("%d objects in the allocation-site heap abstraction.\n", nObj); + System.out.printf("%d objects in the Mahjong heap abstraction.\n", nObjMahjong); + System.out.println("-----------------------------------------------------------"); + + int nType = (int) fpg.getAllObjs().stream().map(AllocNode::getType).distinct().count(); + int nField = (int) fpg.getAllObjs().stream().map(fpg::outFieldsOf).flatMap(Collection::stream).distinct().count(); + int nObj2 = fpg.getAllObjs().size(); + // int nObjMahjong = model.size(); + + System.out.println("-----------------------------------------------------------"); + System.out.println("In the FPG (allocation-site heap abstraction), there are:"); + System.out.printf("%10d types\n", nType); + System.out.printf("%10d fields\n", nField); + System.out.printf("%10d objects\n", nObj2); + System.out.println("In the Mahjong heap abstraction, there are:"); + System.out.printf("%10d objects\n", nObjMahjong); + System.out.println("-----------------------------------------------------------"); + } + + private static void writeMergedObjectMap(Map mom, Map heapModelMap) { + mom.forEach((heap, mergedHeap) -> { + heapModelMap.put(heap.getNewExpr(), mergedHeap.getNewExpr()); + }); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java new file mode 100644 index 00000000000..58f2d1ecbfb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java @@ -0,0 +1,74 @@ +package qilin.pta.toolkits.mahjong.automata; + +import soot.Type; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +/** + * @author Tian Tan + * @author Yue Li + *

+ * refactered by Dongjie He. + */ +public class DFA { + + private Set states, allStates; + private final DFAState q0; + + static final DFAState deadState = new DFAState(); + + public DFA(DFAState q0) { + this.q0 = q0; + } + + /** + * @return Set of states. Does not contains dead state. + */ + public Set getStates() { + if (states == null) { + computeStates(); + } + return states; + } + + /** + * @return Set of all states including dead state. + */ + public Set getAllStates() { + if (allStates == null) { + computeStates(); + } + return allStates; + } + + private void computeStates() { + Queue queue = new LinkedList<>(); + queue.add(q0); + states = new HashSet<>(); + while (!queue.isEmpty()) { + DFAState s = queue.poll(); + if (!states.contains(s)) { + states.add(s); + queue.addAll(s.getNextMap().values()); + } + } + allStates = new HashSet<>(states); + allStates.add(deadState); + } + + public DFAState getStartState() { + return q0; + } + + public static DFAState getDeadState() { + return deadState; + } + + public Set outputOf(DFAState s) { + return s.getOutput(); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java new file mode 100644 index 00000000000..a5ac0c4975c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java @@ -0,0 +1,105 @@ +package qilin.pta.toolkits.mahjong.automata; + +import qilin.util.Pair; +import qilin.util.UnionFindSet; +import soot.Type; +import soot.jimple.spark.pag.SparkField; + +import java.util.Collection; +import java.util.Set; +import java.util.Stack; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Tian Tan + * @author Yue Li + */ +public class DFAEquivalenceChecker { + + /** + * Check the equivalence of input automata by Hopcroft-Karp algorithm + * with minor modifications. + * + * @param dfa1 + * @param dfa2 + * @return whether dfa1 and dfa2 are equivalent + */ + public boolean isEquivalent(DFA dfa1, DFA dfa2) { + CombinedDFA dfa = new CombinedDFA(dfa1, dfa2); + Set combinedStates = dfa.getStates(); + UnionFindSet uf = new UnionFindSet<>(combinedStates); + Stack> stack = new Stack<>(); + + DFAState s1 = dfa1.getStartState(); + DFAState s2 = dfa2.getStartState(); + uf.union(s1, s2); + stack.push(new Pair<>(s1, s2)); + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + DFAState q1 = pair.getFirst(); + DFAState q2 = pair.getSecond(); + Stream.concat(dfa.outEdgesOf(q1).stream(), dfa.outEdgesOf(q2).stream()).forEach(field -> { + DFAState r1 = uf.find(q1.nextState(field)); + DFAState r2 = uf.find(q2.nextState(field)); + if (r1 != r2) { + uf.union(r1, r2); + stack.push(new Pair<>(r1, r2)); + } + }); + } + Collection> mergedStateSets = uf.getDisjointSets(); + return validate(dfa, mergedStateSets); + } + + + /** + * @param dfa + * @param mergedStateSets + * @return true if every state set contains no different output + * (i.e., types) + */ + private boolean validate(CombinedDFA dfa, Collection> mergedStateSets) { + for (Set set : mergedStateSets) { + int minSize = set.stream() + .mapToInt(s -> dfa.outputOf(s).size()) + .min() + .getAsInt(); + long unionSize = set.stream() + .flatMap(s -> dfa.outputOf(s).stream()) + .distinct() + .count(); + if (unionSize > minSize) { + return false; + } + } + return true; + } + + + private static class CombinedDFA { + + DFA dfa1, dfa2; + + private CombinedDFA(DFA dfa1, DFA dfa2) { + this.dfa1 = dfa1; + this.dfa2 = dfa2; + } + + private Set getStates() { + return Stream + .concat(dfa1.getAllStates().stream(), dfa2.getAllStates().stream()) + .collect(Collectors.toSet()); + } + + private Set outEdgesOf(DFAState s) { + return s.outEdges(); + } + + private Set outputOf(DFAState s) { + return s.getOutput(); + } + + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java new file mode 100644 index 00000000000..7fc1098883b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java @@ -0,0 +1,102 @@ +package qilin.pta.toolkits.mahjong.automata; + +import qilin.core.pag.AllocNode; +import qilin.pta.toolkits.common.FieldPointstoGraph; +import soot.Type; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Tian Tan + * @author Yue Li + */ +public class DFAFactory { + + private final FieldPointstoGraph fpg; + + private Map, DFAState> stateMap; + private Set states, visited; + + public DFAFactory(FieldPointstoGraph fpg) { + this.fpg = fpg; + buildAllDFA(); + } + + public DFA getDFA(AllocNode obj) { + DFAState q0 = stateMap.get(Collections.singleton(obj)); + return new DFA(q0); + } + + private void buildAllDFA() { + stateMap = new HashMap<>(); + states = new HashSet<>(); + visited = new HashSet<>(); + fpg.getAllObjs().forEach(this::buildDFA); + } + + /** + * Perform subset construction algorithm to convert an NFA + * to a DFA. If a set of NFA states are merged to an existing + * DFA state, then reused the existing DFA state instead of creating + * an equivalent new one. + * + * @param obj the start state (object) of the DFA + */ + private void buildDFA(AllocNode obj) { + Set q0Set = Collections.singleton(obj); + if (!stateMap.containsKey(q0Set)) { + NFA nfa = new NFA(obj, fpg); + DFAState startState = getDFAState(q0Set, nfa); + Queue worklist = new LinkedList<>(); + states.add(startState); + worklist.add(startState); + while (!worklist.isEmpty()) { + DFAState s = worklist.poll(); + if (!visited.contains(s)) { + visited.add(s); + Set fields = fields(nfa, s.getObjects()); + fields.forEach(f -> { + Set nextNFAStates = move(nfa, s.getObjects(), f); + DFAState nextState = getDFAState(nextNFAStates, nfa); + if (!states.contains(nextState)) { + states.add(nextState); + worklist.add(nextState); + } + addTransition(s, f, nextState); + }); + } + } + } + } + + private DFAState getDFAState(Set objs, NFA nfa) { + if (!stateMap.containsKey(objs)) { + Set output = objs.stream() + .map(nfa::outputOf) + .collect(Collectors.toSet()); + stateMap.put(objs, new DFAState(objs, output)); + } + return stateMap.get(objs); + } + + private Set move(NFA nfa, Set objs, SparkField f) { + return objs.stream() + .map(obj -> nfa.nextStates(obj, f)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + private Set fields(NFA nfa, Set objs) { + return objs.stream() + .map(nfa::outEdgesOf) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + private void addTransition(DFAState s, SparkField f, DFAState nextState) { + s.addTransition(f, nextState); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java new file mode 100644 index 00000000000..329979293a1 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java @@ -0,0 +1,91 @@ +package qilin.pta.toolkits.mahjong.automata; + +import qilin.core.pag.AllocNode; +import soot.Type; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Tian Tan + * @author Yue Li + */ +public class DFAState { + + private final Set objs; + private final Set output; + private final Map nextMap; + + private boolean hasHashCode = false; + private int hashCode; + + public DFAState() { + this.objs = Collections.emptySet(); + this.output = Collections.emptySet(); + this.nextMap = new HashMap<>(); + } + + public DFAState(Set objs, Set output) { + this.objs = objs; + this.output = output; + this.nextMap = new HashMap<>(); + } + + public Set getObjects() { + return objs; + } + + public Set getOutput() { + return output; + } + + void addTransition(SparkField f, DFAState nextState) { + nextMap.put(f, nextState); + } + + Map getNextMap() { + return nextMap; + } + + DFAState nextState(SparkField f) { + return nextMap.getOrDefault(f, DFA.getDeadState()); + } + + Set outEdges() { + return nextMap.keySet(); + } + + /** + * Cache hash code. + */ + @Override + public int hashCode() { + if (!hasHashCode) { + hashCode = objs.hashCode(); + hasHashCode = true; + } + return hashCode; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof DFAState anoDFAState)) { + return false; + } + return getObjects().equals(anoDFAState.getObjects()); + } + + @Override + public String toString() { + return getObjects().stream() + .map(obj -> obj == null ? "null" : String.valueOf(obj.getNumber())) + .sorted() + .collect(Collectors.toCollection(LinkedHashSet::new)) + .toString(); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java new file mode 100644 index 00000000000..40bc237de4c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java @@ -0,0 +1,88 @@ +package qilin.pta.toolkits.mahjong.automata; + +import qilin.core.pag.AllocNode; +import qilin.pta.toolkits.common.FieldPointstoGraph; +import soot.Type; +import soot.jimple.spark.pag.SparkField; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; + +/** + * @author Tian Tan + * @author Yue Li + */ +public class NFA { + + private static final AllocNode deadState = null; + + private final AllocNode q0; + private final FieldPointstoGraph fpg; + + public NFA(AllocNode q0, FieldPointstoGraph fpg) { + this.q0 = q0; + this.fpg = fpg; + } + + /** + * This method on-the-fly computes set of states. + * + * @return Set of states. Does not contains dead state. + */ + public Set getStates() { + Set states = new HashSet<>(); + Stack stack = new Stack<>(); + stack.push(q0); + while (!stack.isEmpty()) { + AllocNode s = stack.pop(); + if (!states.contains(s)) { + states.add(s); + outEdgesOf(s).forEach(field -> { + nextStates(s, field).stream() + .filter(obj -> !states.contains(obj)) + .forEach(stack::push); + }); + } + } + return states; + } + + public AllocNode getStartState() { + return q0; + } + + public AllocNode getDeadState() { + return deadState; + } + + public Set nextStates(AllocNode obj, SparkField f) { + if (isDeadState(obj) || !fpg.hasFieldPointer(obj, f)) { + return Collections.singleton(deadState); + } else { + return fpg.pointsTo(obj, f); + } + } + + public boolean isDeadState(AllocNode obj) { + return obj == deadState; + } + + public Set outEdgesOf(AllocNode obj) { + if (isDeadState(obj)) { + return Collections.emptySet(); + } else { + return fpg.outFieldsOf(obj); + } + } + + public Type outputOf(AllocNode obj) { + if (isDeadState(obj)) { + return null; + } else { + return obj.getType(); + } + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/gpl-3.0.txt b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/gpl-3.0.txt new file mode 100644 index 00000000000..f288702d2fa --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java new file mode 100644 index 00000000000..11a34a16313 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java @@ -0,0 +1,60 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.selectx; + +import qilin.core.pag.Node; + +import java.util.Set; +import java.util.stream.Stream; + +public abstract class BNode { + public Node sparkNode; + /** + * visited is not overrided by para: this represents value flows in *any* contexts, + * this can avoid unmatched exit without missing exit from inner alloc or global + */ + private boolean visited = false; + + BNode(Node origin) { + this.sparkNode = origin; + } + + public void reset() { + visited = false; + } + + public boolean isVisited() { + return this.visited; + } + + public boolean setVisited() { + if (visited) + return false; + return visited = true; + } + + public abstract boolean addOutEdge(BNode to); + + public abstract Stream forwardTargets(); + + @Override + public String toString() { + return this.getClass().toString() + " : " + sparkNode.toString(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java new file mode 100644 index 00000000000..69e13466309 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java @@ -0,0 +1,59 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.selectx; + +import java.util.*; +import java.util.stream.Stream; + +import qilin.core.pag.GlobalVarNode; + +public class G extends BNode { + public static Map g2GN = new HashMap<>(); + public static Map g2GP = new HashMap<>(); + + public static G v(GlobalVarNode origin, boolean positive) { + if (positive) { + return g2GP.computeIfAbsent(origin, k -> new G(origin, true)); + } else { + return g2GN.computeIfAbsent(origin, k -> new G(origin, false)); + } + } + + private final Set outLs = new HashSet<>(); + private final boolean positive; + + G(GlobalVarNode origin, boolean positive) { + super(origin); + this.positive = positive; + } + + public boolean addOutEdge(L toE) { + return outLs.add(toE); + } + + @Override + public boolean addOutEdge(BNode toE) { + return addOutEdge((L) toE); + } + + @Override + public Stream forwardTargets() { + return outLs.stream(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java new file mode 100644 index 00000000000..784a198b99e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java @@ -0,0 +1,64 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.selectx; + +import qilin.core.pag.Node; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; + + +/** + * local nodes + */ +public abstract class I extends BNode { + private final Set outIs = new HashSet<>(); + protected Set paras = new HashSet<>(); + + I(Node origin) { + super(origin); + } + + public void clearParas() { + this.paras.clear(); + } + + boolean update(I another) { + return this.paras.addAll(another.paras); + } + + public boolean addOutEdge(I to) { + return outIs.add(to); + } + + @Override + public boolean addOutEdge(BNode toE) { + return addOutEdge((I) toE); + } + + @Override + public Stream forwardTargets() { + return outIs.stream(); + } + + public Set getOutTargets() { + return this.outIs; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java new file mode 100644 index 00000000000..4998e5885c7 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java @@ -0,0 +1,107 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.selectx; + +import qilin.core.pag.LocalVarNode; +import qilin.util.Util; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +/** + * locals + */ +public class L extends I { + public static Map l2LN = new HashMap<>(); + public static Map l2LP = new HashMap<>(); + + public static L v(LocalVarNode origin, boolean positive) { + if (positive) { + return l2LP.computeIfAbsent(origin, k -> new L(origin, positive)); + } else { + return l2LN.computeIfAbsent(origin, k -> new L(origin, positive)); + } + } + + private final Set outGs = new HashSet<>(); + private final boolean positive; + private final Map> outEntryEdges = new HashMap<>(); + private final Map> outExitEdges = new HashMap<>(); + private final Map> inEntryEdges = new HashMap<>(); + + L(LocalVarNode origin, boolean positive) { + super(origin); + this.positive = positive; + } + + public boolean addOutEdge(G to) { + return outGs.add(to); + } + + public Stream getOutGs() { + return outGs.stream(); + } + + @Override + public boolean addOutEdge(BNode toE) { + if (toE instanceof G) + return addOutEdge((G) toE); + return super.addOutEdge(toE); + } + + public boolean addOutEntryEdge(int i, L toE) { + return Util.addToMap(outEntryEdges, i, toE); + } + + public boolean addOutExitEdge(int i, L toE) { + return Util.addToMap(outExitEdges, i, toE); + } + + public Set getOutEntryEdges() { + return outEntryEdges.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + } + + public Set>> getOutExitEdges() { + return outExitEdges.entrySet(); + } + + public boolean addInEntryEdge(int i, L fromE) { + return Util.addToMap(inEntryEdges, i, fromE); + } + + public Set getInEntryEdges(int i) { + return inEntryEdges.getOrDefault(i, Collections.emptySet()); + } + + @Override + public Stream forwardTargets() { + Stream exits = outExitEdges.values().stream().flatMap(Collection::stream); + Stream outs = Stream.concat(exits, outGs.stream()); + return Stream.concat(outs, super.forwardTargets()); + } + + /* + * inverse operation: inv(l-) = l+ and inv(l+) = l-. + * */ + public L inv() { + return L.v((LocalVarNode) sparkNode, !positive); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java new file mode 100644 index 00000000000..dd77fd99ff5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.selectx; + +import qilin.core.pag.AllocNode; + +import java.util.HashMap; +import java.util.Map; + +public class O extends I { + public static Map o2O = new HashMap<>(); + + public static O v(AllocNode origin) { + return o2O.computeIfAbsent(origin, k -> new O(origin)); + } + + public O(AllocNode origin) { + super(origin); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java new file mode 100644 index 00000000000..f4189f255e4 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -0,0 +1,321 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.selectx; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import qilin.core.PTA; +import qilin.core.PointsToAnalysis; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import soot.*; +import soot.jimple.*; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.queue.QueueReader; + +public class Selectx { + private final PTA prePTA; + private final PAG prePAG; + private final Set sparkFields = new HashSet<>(); + + public Selectx(PTA pta) { + this.prePTA = pta; + this.prePAG = pta.getPag(); + buildGraph(); + } + + public void addNewEdge(AllocNode from, LocalVarNode to) { + O fromE = O.v(from); + L toE = L.v(to, true); + fromE.addOutEdge(toE); + L toEI = L.v(to, false); + toEI.addOutEdge(fromE); + } + + public void addAssignEdge(LocalVarNode from, LocalVarNode to) { + L fromE = L.v(from, true), toE = L.v(to, true); + fromE.addOutEdge(toE); + L fromEI = L.v(from, false), toEI = L.v(to, false); + toEI.addOutEdge(fromEI); + } + + public void addEntryEdge(LocalVarNode from, LocalVarNode to, CallSite callSite) { + int i = getCallSiteNumber(callSite); + + L fromE = L.v(from, true), toE = L.v(to, true); + if (fromE.addOutEntryEdge(i, toE)) { + toE.addInEntryEdge(i, fromE); + L fromEI = L.v(from, false), toEI = L.v(to, false); + toEI.addOutExitEdge(i, fromEI); + } + } + + public void addExitEdge(LocalVarNode from, LocalVarNode to, CallSite callSite) { + int i = getCallSiteNumber(callSite); + + L fromE = L.v(from, true), toE = L.v(to, true); + if (fromE.addOutExitEdge(i, toE)) { + L fromEI = L.v(from, false), toEI = L.v(to, false); + toEI.addOutEntryEdge(i, fromEI); + fromEI.addInEntryEdge(i, toEI); + } + } + + public void addStoreEdge(LocalVarNode from, LocalVarNode base) { + L fromE = L.v(from, true), baseE = L.v(base, true); + L fromEI = L.v(from, false), baseEI = L.v(base, false); + fromE.addOutEdge(baseEI); + baseE.addOutEdge(fromEI); + } + + public void addStaticStoreEdge(LocalVarNode from, GlobalVarNode to) { + L fromE = L.v(from, true); + G toE = G.v(to, true); + fromE.addOutEdge(toE); + L fromEI = L.v(from, false); + G toEI = G.v(to, false); + toEI.addOutEdge(fromEI); + } + + public void addStaticLoadEdge(GlobalVarNode from, LocalVarNode to) { + G fromE = G.v(from, true); + L toE = L.v(to, true); + fromE.addOutEdge(toE); + G fromEI = G.v(from, false); + L toEI = L.v(to, false); + toEI.addOutEdge(fromEI); + } + + private void propagate(Set workList, Set paraWorkList) { + while (!workList.isEmpty() || !paraWorkList.isEmpty()) { + while (!workList.isEmpty()) { + BNode node = workList.iterator().next(); + workList.remove(node); + node.forwardTargets().filter(BNode::setVisited).forEach(workList::add); + if (node instanceof L l) { + l.getOutEntryEdges().stream().filter(tgt -> tgt.paras.add(tgt)).forEach(paraWorkList::add); + } + } + while (!paraWorkList.isEmpty()) { + I node = paraWorkList.iterator().next(); + paraWorkList.remove(node); + // para propagation. + node.getOutTargets().stream().filter(i -> i.update(node)).forEach(paraWorkList::add); + if (node instanceof L l) { + l.getOutGs().filter(BNode::setVisited).forEach(workList::add); + l.getOutEntryEdges().stream().filter(tgt -> tgt.paras.add(tgt)).forEach(paraWorkList::add); + for (Map.Entry> entry : l.getOutExitEdges()) { + Integer i = entry.getKey(); + Set tgts = entry.getValue(); + l.paras.stream().flatMap(para -> para.getInEntryEdges(i).stream()).forEach(arg -> { + tgts.forEach(tgt -> { + if (arg.addOutEdge(tgt)) { //add match edge + if (arg.isVisited() && tgt.setVisited()) { + workList.add(tgt); + } + if (tgt.update(arg)) { + paraWorkList.add(tgt); + } + } + }); + }); + } + } + } // para while + } // outer while + } + + private void resetNodes() { + // reset nodes' visited state + G.g2GN.values().forEach(BNode::reset); + G.g2GP.values().forEach(BNode::reset); + L.l2LN.values().forEach(BNode::reset); + L.l2LP.values().forEach(BNode::reset); + O.o2O.values().forEach(BNode::reset); + // clear paras + L.l2LN.values().forEach(I::clearParas); + L.l2LP.values().forEach(I::clearParas); + O.o2O.values().forEach(I::clearParas); + } + + public Map process() { + System.out.print("cs2 propogating ..."); + long time = System.currentTimeMillis(); + + Set workList = new HashSet<>(); + Set paraWorkList = new HashSet<>(); + + //forward processing... + O.o2O.values().forEach(o -> { + o.setVisited(); + workList.add(o); + }); + propagate(workList, paraWorkList); + + //record and reset... + Set entryO = O.o2O.values().stream().filter(o -> !o.paras.isEmpty()).collect(Collectors.toSet()); + Set entryL = Stream.concat(L.l2LP.values().stream(), L.l2LN.values().stream()) + .filter(l -> !l.paras.isEmpty()).collect(Collectors.toSet()); + resetNodes(); + + //backward processing... + L.l2LN.values().forEach(ln -> { + ln.setVisited(); + workList.add(ln); + }); + propagate(workList, paraWorkList); + + System.out.println((System.currentTimeMillis() - time) / 1000 + "s"); + + Map ret = new HashMap<>(); + entryO.forEach(o -> { + if (!o.paras.isEmpty()) { + ret.put(o.sparkNode, 1); + } else { + ret.put(o.sparkNode, 0); + } + }); + entryL.forEach(l -> { + if (!l.inv().paras.isEmpty()) { + ret.put(l.sparkNode, 1); + } else { + ret.put(l.sparkNode, 0); + } + }); + this.sparkFields.forEach(f -> { + ret.put(f, 1); + }); + return ret; + } + + + Map call2Number = new HashMap<>(); + int totalCallsites = 0; + + int getCallSiteNumber(CallSite callsite) { + Integer oldNumber = call2Number.get(callsite); + if (oldNumber != null) { + return oldNumber; + } + totalCallsites++; + call2Number.put(callsite, totalCallsites); + return totalCallsites; + } + + + private void buildGraph() { + for (SootMethod method : prePTA.getNakedReachableMethods()) { + if (method.isPhantom()) { + continue; + } + MethodPAG srcmpag = prePAG.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + } else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + this.sparkFields.add(fr.getField()); + } else { // local-global + assert to instanceof GlobalVarNode; + this.addStaticStoreEdge((LocalVarNode) from, (GlobalVarNode) to); + } + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + // load edge is treated as assign. + this.addAssignEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + this.sparkFields.add(fr.getField()); + } else { + assert (from instanceof GlobalVarNode); + this.addStaticLoadEdge((GlobalVarNode) from, (LocalVarNode) to); + } + } + + // add exception edges that added dynamically during the pre-analysis. + srcmpag.getExceptionEdges().forEach((k, vs) -> { + for (Node v : vs) { + this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); + } + }); + + // add invoke edges + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + CallSite callSite = new CallSite(u); + InvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + continue; + } + args[i] = arg; + } + LocalVarNode retDest = null; + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + retDest = prePAG.findLocalVarNode(dest); + } + } + LocalVarNode receiver = null; + if (ie instanceof InstanceInvokeExpr iie) { + receiver = prePAG.findLocalVarNode(iie.getBase()); + } + for (Iterator it = prePTA.getCallGraph().edgesOutOf(u); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + for (int i = 0; i < numArgs; i++) { + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) { + continue; + } + LocalVarNode parm = (LocalVarNode) tgtnf.caseParm(i); + this.addEntryEdge((LocalVarNode) srcnf.getNode(args[i]), parm, callSite); + } + if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { + LocalVarNode ret = (LocalVarNode) tgtnf.caseRet(); + this.addExitEdge(ret, retDest, callSite); + } + LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); + LocalVarNode throwFinal = prePAG.findLocalVarNode(new Parm(tgtmtd, PointsToAnalysis.THROW_NODE)); + if (throwFinal != null) { + this.addExitEdge(throwFinal, stmtThrowNode, callSite); + } + if (receiver != null) { + LocalVarNode thisRef = (LocalVarNode) tgtnf.caseThis(); + this.addEntryEdge(receiver, thisRef, callSite); + } + } + } + } // reachable methods. + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java new file mode 100644 index 00000000000..0a9fa49aa2c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -0,0 +1,294 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import qilin.core.PTA; +import qilin.core.PointsToAnalysis; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.util.Pair; +import qilin.util.queue.UniqueQueue; +import soot.RefLikeType; +import soot.SootMethod; +import soot.Unit; +import soot.Value; +import soot.jimple.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.queue.QueueReader; + +import java.util.*; + +public abstract class AbstractMVFG { + public static Map method2VFG = new HashMap<>(); + protected final PTA prePTA; + protected final OCG hg; + protected final SootMethod method; + protected final Set sparkNodes = new HashSet<>(); + protected final Set csNodes = new HashSet<>(); + protected final Map> outEdges = new HashMap<>(); + protected final Map> inEdges = new HashMap<>(); + + protected int total_edge_count = 0; + + public static AbstractMVFG findMethodVFG(SootMethod method) { + return method2VFG.getOrDefault(method, null); + } + + public AbstractMVFG(PTA prePTA, OCG hg, SootMethod method) { + this.prePTA = prePTA; + this.hg = hg; + this.method = method; + } + + public Collection getAllNodes() { + return sparkNodes; + } + + public int getTotalNodeCount() { + return sparkNodes.size(); + } + + public int getTotalEdgeCount() { + return total_edge_count; + } + + public Collection getCSNodes() { + return csNodes; + } + + protected void addNormalEdge(TranEdge edge) { + sparkNodes.add(edge.getSource()); + sparkNodes.add(edge.getTarget()); + total_edge_count++; + outEdges.computeIfAbsent(edge.getSource(), k -> new HashSet<>()).add(edge); + inEdges.computeIfAbsent(edge.getTarget(), k -> new HashSet<>()).add(edge); + } + + protected void addNewEdge(AllocNode from, LocalVarNode to) { + TranEdge newEdge = new TranEdge(from, to, DFA.TranCond.NEW); + addNormalEdge(newEdge); + TranEdge newInvEdge = new TranEdge(to, from, DFA.TranCond.INEW); + addNormalEdge(newInvEdge); + } + + protected void addCSLikelyEdge(AllocNode heap) { + TranEdge csLikelyEdge = new TranEdge(heap, heap, DFA.TranCond.CSLIKELY); + addNormalEdge(csLikelyEdge); + } + + protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { + TranEdge assignEdge = new TranEdge(from, to, DFA.TranCond.ASSIGN); + addNormalEdge(assignEdge); + TranEdge assignInvEdge = new TranEdge(to, from, DFA.TranCond.IASSIGN); + addNormalEdge(assignInvEdge); + } + + protected void addStoreEdge(LocalVarNode from, LocalVarNode base) { + TranEdge storeEdge = new TranEdge(from, base, DFA.TranCond.STORE); + addNormalEdge(storeEdge); + TranEdge storeInvEdge = new TranEdge(base, from, DFA.TranCond.ISTORE); + addNormalEdge(storeInvEdge); + } + + protected void addLoadEdge(LocalVarNode base, LocalVarNode to) { + TranEdge loadEdge = new TranEdge(base, to, DFA.TranCond.LOAD); + addNormalEdge(loadEdge); + TranEdge loadInvEdge = new TranEdge(to, base, DFA.TranCond.ILOAD); + addNormalEdge(loadInvEdge); + } + + protected void buildVFG() { + CallGraph callGraph = prePTA.getCallGraph(); + PAG pag = prePTA.getPag(); + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + } // local-global + + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + if (hg.isCSLikely((AllocNode) from)) { + this.addCSLikelyEdge((AllocNode) from); + } + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + } // global-local + + } + // add exception edges that added dynamically during the pre-analysis. + srcmpag.getExceptionEdges().forEach((k, vs) -> { + for (Node v : vs) { + this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); + } + }); + + // add invoke edges + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + continue; + args[i] = arg; + } + LocalVarNode retDest = null; + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + retDest = pag.findLocalVarNode(dest); + } + } + LocalVarNode receiver; + if (ie instanceof InstanceInvokeExpr iie) { + receiver = pag.findLocalVarNode(iie.getBase()); + } else { + // static call + receiver = thisRef; + } + + Set targets = new HashSet<>(); + for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + targets.add(tgtmtd); + } + if (!targets.isEmpty()) { + for (int i = 0; i < numArgs; i++) { + if (args[i] == null) + continue; + ValNode argNode = pag.findValNode(args[i]); + if (argNode instanceof LocalVarNode && satisfyAddingStoreCondition(i, targets)) { + this.addStoreEdge((LocalVarNode) argNode, receiver); + } + } + if (retDest != null && retDest.getType() instanceof RefLikeType) { + if (statisfyAddingLoadCondition(targets)) { + this.addLoadEdge(receiver, retDest); + } + } + if (statisfyAddingLoadCondition(targets)) { + LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); + this.addLoadEdge(receiver, stmtThrowNode); + } + if (satisfyAddingStoreCondition(PointsToAnalysis.THIS_NODE, targets)) { + this.addStoreEdge(receiver, receiver); + } + } + } + + // add param and return edges + addNormalEdge(new TranEdge(thisRef, thisRef, DFA.TranCond.PARAM)); + addNormalEdge(new TranEdge(thisRef, thisRef, DFA.TranCond.IPARAM)); + + int numParms = method.getParameterCount(); + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof RefLikeType) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); + addNormalEdge(new TranEdge(param, param, DFA.TranCond.IPARAM)); + } + } + if (method.getReturnType() instanceof RefLikeType) { + LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); + addStoreEdge(mret, thisRef); + } + LocalVarNode mThrow = pag.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); + if (mThrow != null) { + addStoreEdge(mThrow, thisRef); + } + } + + protected abstract boolean statisfyAddingLoadCondition(Set targets); + + protected abstract boolean satisfyAddingStoreCondition(int paramIndex, Set targets); + + /* + * Algorithm1: x \in R(flow) \cap R(iflow). + * more efficient. + * */ + public void computeNodesInPrecisionLossPatterns() { + Queue> workList = new UniqueQueue<>(); + Map> state2nodes = new HashMap<>(); + MethodPAG srcmpag = prePTA.getPag().getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + + // initialize worklist + int numParms = method.getParameterCount(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + Set startState = state2nodes.computeIfAbsent(DFA.State.S, k -> new HashSet<>()); + startState.add(thisRef); + workList.add(new Pair<>(thisRef, DFA.State.S)); + + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof RefLikeType) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + startState.add(param); + workList.add(new Pair<>(param, DFA.State.S)); + } + } + if (method.getReturnType() instanceof RefLikeType) { + LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); + startState.add(mret); + workList.add(new Pair<>(mret, DFA.State.S)); + } + LocalVarNode mThrow = (LocalVarNode) srcnf.caseMethodThrow(); + startState.add(mThrow); + workList.add(new Pair<>(mThrow, DFA.State.S)); + + // propagate + while (!workList.isEmpty()) { + Pair pair = workList.poll(); + Object currNode = pair.getFirst(); + DFA.State currState = pair.getSecond(); + for (TranEdge e : outEdges.getOrDefault(currNode, Collections.emptySet())) { + Object target = e.getTarget(); + DFA.TranCond tranCond = e.getTranCond(); + DFA.State nextState = DFA.nextState(currState, tranCond); + if (nextState != DFA.State.ERROR) { + Set stateNodes = state2nodes.computeIfAbsent(nextState, k -> new HashSet<>()); + if (stateNodes.add(target)) { + workList.add(new Pair<>(target, nextState)); + } + } + } + } + // collect cs nodes. + Set flowNodes = state2nodes.getOrDefault(DFA.State.FLOW, Collections.emptySet()); + Set iflowNodes = state2nodes.getOrDefault(DFA.State.IFLOW, Collections.emptySet()); + for (Object sparkNode : sparkNodes) { + if (flowNodes.contains(sparkNode) && iflowNodes.contains(sparkNode)) { + csNodes.add(sparkNode); + } + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java new file mode 100644 index 00000000000..d4145828d00 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java @@ -0,0 +1,58 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class DFA { + public enum State { + S, FLOW, IFLOW, E, ERROR; + } + + public enum TranCond { + PARAM, IPARAM, ASSIGN, IASSIGN, LOAD, ILOAD, STORE, ISTORE, NEW, INEW, CSLIKELY; + } + + private static final Map> transitionFunc = new HashMap<>(); + + static { + Map mS = transitionFunc.computeIfAbsent(State.S, k -> new HashMap<>()); + mS.put(TranCond.PARAM, State.FLOW); + + Map mFlow = transitionFunc.computeIfAbsent(State.FLOW, k -> new HashMap<>()); + mFlow.put(TranCond.ASSIGN, State.FLOW); + mFlow.put(TranCond.LOAD, State.FLOW); + mFlow.put(TranCond.STORE, State.IFLOW); + mFlow.put(TranCond.ISTORE, State.IFLOW); + mFlow.put(TranCond.NEW, State.FLOW); + + Map mIFlow = transitionFunc.computeIfAbsent(State.IFLOW, k -> new HashMap<>()); + mIFlow.put(TranCond.IASSIGN, State.IFLOW); + mIFlow.put(TranCond.ILOAD, State.IFLOW); + mIFlow.put(TranCond.IPARAM, State.E); + mIFlow.put(TranCond.INEW, State.IFLOW); + mIFlow.put(TranCond.CSLIKELY, State.FLOW); + } + + public static State nextState(State curr, TranCond tranCond) { + return transitionFunc.getOrDefault(curr, Collections.emptyMap()).getOrDefault(tranCond, State.ERROR); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java new file mode 100644 index 00000000000..4efabcd814d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java @@ -0,0 +1,69 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import qilin.util.graph.DirectedGraph; +import qilin.util.graph.DirectedGraphImpl; +import soot.SootMethod; +import soot.jimple.toolkits.callgraph.CallGraph; + +import java.util.Collection; + +public class MethodLevelCallGraph implements DirectedGraph { + private final CallGraph callGraph; + private final DirectedGraphImpl mcg; + + public MethodLevelCallGraph(CallGraph callGraph) { + this.callGraph = callGraph; + this.mcg = new DirectedGraphImpl<>(); + init(); + } + + private void init() { + callGraph.iterator().forEachRemaining(edge -> { + SootMethod src = edge.getSrc().method(); + SootMethod tgt = edge.getTgt().method(); + if (src != null && tgt != null) { + mcg.addEdge(src, tgt); + } else { + if (src != null) { + mcg.addNode(src); + } + if (tgt != null) { + mcg.addNode(tgt); + } + } + }); + } + + @Override + public Collection allNodes() { + return mcg.allNodes(); + } + + @Override + public Collection predsOf(SootMethod n) { + return mcg.predsOf(n); + } + + @Override + public Collection succsOf(final SootMethod n) { + return mcg.succsOf(n); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java new file mode 100644 index 00000000000..9a4f564be7c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java @@ -0,0 +1,45 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import qilin.core.PTA; +import soot.SootMethod; + +import java.util.Set; + +public class MethodVFG extends AbstractMVFG { + public static AbstractMVFG findOrCreateMethodVFG(PTA prePTA, SootMethod method, OCG hg) { + return method2VFG.computeIfAbsent(method, k -> new MethodVFG(prePTA, method, hg)); + } + + public MethodVFG(PTA prePTA, SootMethod method, OCG hg) { + super(prePTA, hg, method); + buildVFG(); + } + + @Override + protected boolean statisfyAddingLoadCondition(Set targets) { + return true; + } + + @Override + protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { + return true; + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java new file mode 100644 index 00000000000..f3ecde8894c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -0,0 +1,96 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import qilin.core.PTA; +import qilin.core.PointsToAnalysis; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.MethodPAG; +import qilin.core.pag.Node; +import qilin.util.graph.MergedNode; +import soot.RefLikeType; +import soot.SootMethod; + +import java.util.Set; + +public class ModularMVFG extends AbstractMVFG { + public static AbstractMVFG findOrCreateMethodVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode sccNode) { + return method2VFG.computeIfAbsent(method, k -> new ModularMVFG(prePTA, method, hg, sccNode)); + } + + private final MergedNode sccNode; + + public ModularMVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode sccNode) { + super(prePTA, hg, method); + this.sccNode = sccNode; + buildVFG(); + } + + @Override + protected boolean statisfyAddingLoadCondition(Set targets) { + for (SootMethod tgtmtd : targets) { + // the target method is in the same scc with current method. + if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { + return true; + } + if (!(tgtmtd.getReturnType() instanceof RefLikeType)) { + continue; + } + MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); + AbstractMVFG tgtVfg = method2VFG.get(tgtmtd); + assert tgtVfg != null; + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + Node ret = tgtnf.caseRet(); + if (tgtVfg.getCSNodes().contains(ret)) { + return true; + } + } + return false; + } + + + protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { + for (SootMethod tgtmtd : targets) { + // the target method is in the same scc with current method. + if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { + return true; + } + MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); + AbstractMVFG tgtVfg = method2VFG.get(tgtmtd); + assert tgtVfg != null; + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + LocalVarNode parm; + if (paramIndex == PointsToAnalysis.THIS_NODE) { + parm = (LocalVarNode) tgtnf.caseThis(); + } else { + if (tgtmtd.getParameterType(paramIndex) instanceof RefLikeType) { + parm = (LocalVarNode) tgtnf.caseParm(paramIndex); + } else { + continue; + } + } + if (tgtVfg.getCSNodes().contains(parm)) { + return true; + } + } + return false; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java new file mode 100644 index 00000000000..18d34f64b07 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -0,0 +1,261 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.pta.PTAConfig; +import qilin.util.PTAUtils; +import soot.*; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; + +// Object Containment Graph +public class OCG { + public final PTA pta; + protected final Map> pts; + public Map nodes; + private int total_node_count = 0; + private int total_edge_count = 0; + + public OCG(PTA pta) { + this.pta = pta; + this.pts = PTAUtils.calcStaticThisPTS(pta); + this.nodes = new HashMap<>(); + buildGraph(); + } + + protected void buildGraph() { + PAG pag = pta.getPag(); + pag.getAllocNodes().forEach(this::findOrCreate); + pag.getContextFields().forEach(contextField -> { + AllocNode base = contextField.getBase(); + if (base instanceof ConstantNode) { + return; + } + + SparkField f = contextField.getField(); + if (f.getType() instanceof ArrayType at) { + if (at.baseType instanceof PrimType) { + return; + } + } + PointsToSet pts = pta.reachingObjects(contextField).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + if (n instanceof ConstantNode) { + continue; + } + addEdge(findOrCreate(base), findOrCreate(n)); + } + }); + } + + public Collection allNodes() { + return nodes.values(); + } + + public int getTotalNodeCount() { + return total_node_count; + } + + public int getTotalEdgeCount() { + return total_edge_count; + } + + /** + * (1) case1: objects on OCG have successors but does not have predecessors. + * (1-1) factorys + * (1-2) normal uses. + * (2) case2: objects on OCG does not have successors. + * (2-1) no predecessors. + * (2-2) have predecessors. + * (3) othercase: objects on OCG have successors and predecessors. + */ + public void stat() { + int case1 = 0; + int total_factory = 0; + int case1_factory = 0; + int case1_normal = 0; + int case2 = 0; + int case2_noPred = 0; + int case2_hasPred = 0; + int otherCase = 0; + for (OCGNode node : nodes.values()) { + if (node.successors.size() == 0) { + case2++; + if (node.predecessors.size() == 0) { + case2_noPred++; + } else { + case2_hasPred++; + } + if (isFactoryObject(node.ir)) { + total_factory++; + } + } else if (node.predecessors.size() == 0) { + case1++; + if (isFactoryObject(node.ir)) { + case1_factory++; + // System.out.println(((AllocNode) node.ir).toString2()); + } else { + case1_normal++; + } + } else { + if (isFactoryObject(node.ir)) { + total_factory++; + } + otherCase++; + } + } + + System.out.println("#case1:" + case1); + System.out.println("#total_factory:" + total_factory); + System.out.println("#case1_factory:" + case1_factory); + System.out.println("#case1_normal:" + case1_normal); + System.out.println("#case2:" + case2); + System.out.println("#case2_noPred:" + case2_noPred); + System.out.println("#case2_hasPred:" + case2_hasPred); + System.out.println("#othercase:" + otherCase); + } + + private OCGNode findOrCreate(AllocNode ir) { + if (nodes.containsKey(ir)) { + return nodes.get(ir); + } else { + total_node_count++; + OCGNode ret = new OCGNode(ir); + nodes.put(ir, ret); + return ret; + } + } + + private boolean isNewTop(OCGNode node) { + return node.predecessors.isEmpty() && !isFactoryObject(node.ir); + } + + private boolean isNewBottom(OCGNode node) { + return node.successors.isEmpty(); + } + + public boolean isTop(AllocNode heap) { + return !nodes.containsKey(heap) || isNewTop(findOrCreate(heap)); + } + + public boolean isBottom(AllocNode heap) { + return !nodes.containsKey(heap) || isNewBottom(findOrCreate(heap)); + } + + private boolean isNotTopAndBottom(OCGNode node) { + return !isNewBottom(node) && !isNewTop(node); + } + + public boolean isCSLikely(AllocNode allocNode) { + OCGNode node = this.nodes.getOrDefault(allocNode, null); + if (node == null) { + return false; + } else { + return node.cslikely; + } + } + + public void run() { + int[] a = new int[2]; + System.out.println(PTAConfig.v().turnerConfig); + for (OCGNode node : nodes.values()) { + PTAConfig.TurnerConfig hgConfig = PTAConfig.v().turnerConfig; + if (hgConfig == PTAConfig.TurnerConfig.PHASE_TWO) { + node.cslikely = true; + } else { + node.cslikely = isNotTopAndBottom(node); + } + if (node.cslikely) { + a[1]++; + } else { + a[0]++; + } + + } + for (int i = 0; i < 2; ++i) { + System.out.println("#level " + i + ": " + a[i]); + } + stat(); + } + + protected void addEdge(OCGNode pre, OCGNode succ) { + total_edge_count++; + pre.addSucc(succ); + succ.addPred(pre); + } + + public static class OCGNode { + public final AllocNode ir; + public Set successors; + public Set predecessors; + public boolean cslikely; + + public OCGNode(AllocNode ir) { + this.ir = ir; + this.cslikely = false; + this.successors = new HashSet<>(); + this.predecessors = new HashSet<>(); + } + + @Override + public String toString() { + return ir.toString(); + } + + public void addSucc(OCGNode node) { + this.successors.add(node); + } + + public void addPred(OCGNode node) { + this.predecessors.add(node); + } + } + + /** + * patterns in case1: (1) create one object and never return out of the method. + * (2) create one object and then return out (factory). + */ + boolean isFactoryObject(AllocNode heap) { + SootMethod method = heap.getMethod(); + if (method == null) { + return false; + } + Type retType = method.getReturnType(); + if (!(retType instanceof RefLikeType)) { + return false; + } + if (retType instanceof ArrayType at) { + if (at.baseType instanceof PrimType) { + return false; + } + } + MethodPAG methodPAG = pta.getPag().getMethodPAG(method); + MethodNodeFactory factory = methodPAG.nodeFactory(); + Node retNode = factory.caseRet(); + PointsToSet pts = pta.reachingObjects(retNode).toCIPointsToSet(); + return pts.contains(heap); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java new file mode 100644 index 00000000000..f1a8ebb41e7 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java @@ -0,0 +1,60 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import java.util.Objects; + +public class TranEdge { + private final Object src; + private final Object dst; + private final DFA.TranCond tranCond; + + public TranEdge(Object s, Object d, DFA.TranCond tran) { + this.src = s; + this.dst = d; + this.tranCond = tran; + } + + public Object getSource() { + return src; + } + + public Object getTarget() { + return dst; + } + + public DFA.TranCond getTranCond() { + return tranCond; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TranEdge tranEdge = (TranEdge) o; + return Objects.equals(src, tranEdge.src) && + Objects.equals(dst, tranEdge.dst) && + tranCond == tranEdge.tranCond; + } + + @Override + public int hashCode() { + return Objects.hash(src, dst, tranCond); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java new file mode 100644 index 00000000000..fd65911cd11 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java @@ -0,0 +1,232 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.turner; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.core.pag.PAG; +import qilin.pta.PTAConfig; +import qilin.util.graph.MergedNode; +import qilin.util.graph.SCCMergedGraph; +import qilin.util.graph.TopologicalSorter; +import soot.SootMethod; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class Turner { + protected OCG ocg; + private int total_node_count = 0; + private int total_edge_count = 0; + private final PTA prePTA; + private final int k; + private final int hk; + public static boolean isModular = false; + + public Turner(int k, PTA pta) { + this.k = k; + this.hk = k - 1; + this.prePTA = pta; + if (isModular) { + System.out.println("Turner with modularization ..."); + } else { + System.out.println("Turner ..."); + } + } + + //////////////////////////////////////////////////////////////////////// + public Map contxtLengthAnalysis() { + this.ocg = new OCG(prePTA); + ocg.run(); + mergeNodeAndEdgeCount(ocg.getTotalNodeCount(), ocg.getTotalEdgeCount()); + // compute level for variables in methods + Set nodes = ConcurrentHashMap.newKeySet(); + Collection reachables = prePTA.getNakedReachableMethods(); + if (isModular) { + MethodLevelCallGraph mcg = new MethodLevelCallGraph(prePTA.getCallGraph()); + final SCCMergedGraph mg = new SCCMergedGraph<>(mcg); + mystat(mg); + final TopologicalSorter> topoSorter = new TopologicalSorter<>(); + topoSorter.sort(mg, true).forEach(node -> { + for (SootMethod method : node.getContent()) { + nodes.addAll(computeCtxLevelForVariables(method, node)); + } + }); + } else { + reachables.forEach(method -> { + nodes.addAll(computeCtxLevelForVariables(method)); + }); + } + // collect nodes and their level + Map ret1 = new HashMap<>(); + // compute level for variables/objects + reachables.forEach(method -> { + AbstractMVFG mvfg = MethodVFG.findMethodVFG(method); + if (mvfg != null) { + for (Object obj : mvfg.getAllNodes()) { + if (nodes.contains(obj)) { + ret1.put(obj, obj instanceof AllocNode ? hk : k); + } else { + ret1.put(obj, 0); + } + } + } + }); + // compute level for fields, In our paper, we do not mention this part + // as it does not hurt too much efficiency. + PAG pag = prePTA.getPag(); + Set fields = new HashSet<>(); + Set readSet = new HashSet<>(); + Set writeSet = new HashSet<>(); + + pag.getContextFields().forEach(contextField -> { + SparkField field = contextField.getField(); + fields.add(field); + if (!pag.simpleInvLookup(contextField).isEmpty()) { + writeSet.add(field); + } + if (!pag.simpleLookup(contextField).isEmpty()) { + readSet.add(field); + } + }); + + for (SparkField f : fields) { + int x = 0; + this.total_node_count += 1; + if (writeSet.contains(f) && readSet.contains(f)) { + x = k; + } + ret1.put(f, x); + } + Map ret = new HashMap<>(ret1); + if (PTAConfig.v().turnerConfig == PTAConfig.TurnerConfig.PHASE_ONE) { + Map ret2 = new HashMap<>(); + ret1.forEach((w, v) -> { + if (w instanceof AllocNode) { + ret2.put(w, ocg.isCSLikely((AllocNode) w) ? hk : 0); + } else { + ret2.put(w, k); + } + }); + ret = ret2; + } + System.out.println("#Node:" + this.total_node_count); + System.out.println("#Edge:" + this.total_edge_count); + statObjInOCG(ret); + return ret; + } + + private void statObjInOCG(Map ret) { + int cibyocg = 0; + int cibydfa = 0; + int csobj = 0; + int tops = 0; + int bottoms = 0; + int topandbottoms = 0; + for (AllocNode o : prePTA.getPag().getAllocNodes()) { + if (!this.ocg.isCSLikely(o)) { + cibyocg++; + } else if (ret.containsKey(o) && ret.get(o) > 0) { + csobj++; + } else { + cibydfa++; + } + if (this.ocg.isTop(o)) { + tops++; + } + if (this.ocg.isBottom(o)) { + bottoms++; + } + if (this.ocg.isTop(o) && this.ocg.isBottom(o)) { + topandbottoms++; + } + } + System.out.println("#CIByOCG:" + cibyocg); + System.out.println("#CIByDFA:" + cibydfa); + System.out.println("#CSOBJ:" + csobj); + System.out.println("#CITOP:" + tops); + System.out.println("#CIBOT:" + bottoms); + System.out.println("#CITOPBOT:" + topandbottoms); + } + + private Collection computeCtxLevelForVariables(SootMethod method) { + if (method.isPhantom()) { + return Collections.emptySet(); + } else { + AbstractMVFG mvfg = MethodVFG.findOrCreateMethodVFG(prePTA, method, ocg); + mvfg.computeNodesInPrecisionLossPatterns(); + mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); + return mvfg.getCSNodes(); + } + } + + private Collection computeCtxLevelForVariables(SootMethod method, MergedNode sccNode) { + if (method.isPhantom()) { + return Collections.emptySet(); + } else { + AbstractMVFG mvfg = ModularMVFG.findOrCreateMethodVFG(prePTA, method, ocg, sccNode); + mvfg.computeNodesInPrecisionLossPatterns(); + mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); + return mvfg.getCSNodes(); + } + } + + private void mergeNodeAndEdgeCount(int nodeCnt, int edgeCnt) { + this.total_node_count += nodeCnt; + this.total_edge_count += edgeCnt; + } + + private void mystat(SCCMergedGraph scccg) { + int sccCnt = scccg.allNodes().size(); + int sccCntGtW = 0; + int maxScc = 0; + double avgScc = 0.0; + double avgSccGtW = 0.0; + for (MergedNode scc : scccg.allNodes()) { + int sccSize = scc.getContent().size(); + if (sccSize > maxScc) { + maxScc = sccSize; + } + avgScc += sccSize; + if (sccSize > 1) { + ++sccCntGtW; + avgSccGtW += sccSize; + } + } + avgScc /= sccCnt; + avgSccGtW /= sccCntGtW; + int[] dist = new int[maxScc + 1]; + for (MergedNode scc : scccg.allNodes()) { + int sccSize = scc.getContent().size(); + dist[sccSize]++; + } + System.out.println("#scc count:" + sccCnt); + System.out.println("#scc count (exclude singleton):" + sccCntGtW); + System.out.println("Average scc size:" + avgScc); + System.out.println("Average scc size(exclude singleton):" + avgSccGtW); + System.out.println("Maximum scc size:" + maxScc); + System.out.println("Scc size distribution (size, count):"); + for (int i = 0; i <= maxScc; ++i) { + if (dist[i] > 0) { + System.out.println(i + "," + dist[i]); + } + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java new file mode 100644 index 00000000000..2434032e006 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java @@ -0,0 +1,87 @@ +package qilin.pta.toolkits.zipper; + +public class Global { + private static boolean debug = false; + private static String flow = null; + private static boolean enableWrappedFlow = true; + private static boolean enableUnwrappedFlow = true; + private static boolean isExpress = false; + public static final int UNDEFINE = -1; + private static int tst = UNDEFINE; + private static int thread = UNDEFINE; + private static float expressThreshold = 0.05f; + + public static void setDebug(final boolean debug) { + Global.debug = debug; + } + + public static boolean isDebug() { + return Global.debug; + } + + public static String getFlow() { + return Global.flow; + } + + public static void setFlow(String flow) { + Global.flow = flow; + } + + public static boolean isEnableWrappedFlow() { + return Global.enableWrappedFlow; + } + + public static void setEnableWrappedFlow(boolean enableWrappedFlow) { + Global.enableWrappedFlow = enableWrappedFlow; + } + + public static boolean isEnableUnwrappedFlow() { + return Global.enableUnwrappedFlow; + } + + public static void setEnableUnwrappedFlow(boolean enableUnwrappedFlow) { + Global.enableUnwrappedFlow = enableUnwrappedFlow; + } + + public static boolean isExpress() { + return Global.isExpress; + } + + public static void setExpress(final boolean isExpress) { + Global.isExpress = isExpress; + } + + public static int getTST() { + return Global.tst; + } + + public static void setTST(int tst) { + Global.tst = tst; + } + + public static int getThread() { + return thread; + } + + public static void setThread(int thread) { + Global.thread = thread; + } + + public static float getExpressThreshold() { + return expressThreshold; + } + + public static void setExpressThreshold(float expressThreshold) { + Global.expressThreshold = expressThreshold; + } + + private static boolean listContext = false; + + public static boolean isListContext() { + return listContext; + } + + public static void setListContext(boolean listContext) { + Global.listContext = listContext; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java new file mode 100644 index 00000000000..2b9bb933eed --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java @@ -0,0 +1,59 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.toolkits.zipper; + +import qilin.core.PTA; +import qilin.pta.toolkits.zipper.analysis.Zipper; +import qilin.util.ANSIColor; +import qilin.util.Stopwatch; +import soot.SootMethod; + +import java.util.Comparator; +import java.util.Set; + +public class Main { + + public static void run(PTA pta, Set zipperPCMOutput) { + int numThreads = Runtime.getRuntime().availableProcessors(); + Global.setThread(numThreads); + Global.setExpress(false); + String zipperStr = Global.isExpress() ? "Zipper-e" : "Zipper"; + System.out.println(ANSIColor.BOLD + ANSIColor.YELLOW + zipperStr + " starts ..." + ANSIColor.RESET); + String flows = Global.getFlow() != null ? Global.getFlow() : "Direct+Wrapped+Unwrapped"; + System.out.println("Precision loss patterns: " + ANSIColor.BOLD + ANSIColor.GREEN + flows + ANSIColor.RESET); + Zipper.outputNumberOfClasses(pta); + Stopwatch zipperTimer = Stopwatch.newAndStart("Zipper Timer"); + Zipper zipper = new Zipper(pta); + Set pcm = zipper.analyze(); + zipperTimer.stop(); + System.out.print(ANSIColor.BOLD + ANSIColor.YELLOW + zipperStr + " finishes, analysis time: " + ANSIColor.RESET); + System.out.print(ANSIColor.BOLD + ANSIColor.GREEN); + System.out.printf("%.2fs", zipperTimer.elapsed()); + System.out.println(ANSIColor.RESET); + + System.out.println("Writing Zipper precision-critical methods ...\n"); + System.out.println(); + writeZipperResults(pcm, zipperPCMOutput); + } + + private static void writeZipperResults(final Set results, final Set outputSet) { + results.stream().sorted(Comparator.comparing(Object::toString)).forEach(outputSet::add); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/ReadMe.txt b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/ReadMe.txt new file mode 100644 index 00000000000..f1ad774f9dc --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/ReadMe.txt @@ -0,0 +1,6 @@ +Get its source from https://github.com/silverbullettt/zipper.git +Commit: b83b0382580eed3e93e88b9bc07cfe27c2c2af01 +Replace original Obj with AllocNode; +Replace original Variable with VarNode; +Replace original Method/InstanceMethod/StaticMethod with SootMethod; +Replace original Field with SparkField; \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java new file mode 100644 index 00000000000..29c07f3f609 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java @@ -0,0 +1,184 @@ +package qilin.pta.toolkits.zipper.analysis; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.AllocNode; +import qilin.core.pag.VarNode; +import qilin.core.sets.PointsToSet; +import qilin.pta.toolkits.common.OAG; +import qilin.pta.toolkits.zipper.Global; +import qilin.util.collect.SetFactory; +import qilin.util.graph.MergedNode; +import qilin.util.graph.SCCMergedGraph; +import qilin.util.graph.TopologicalSorter; +import soot.SootMethod; +import soot.Type; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * For each object o, this class compute the set of methods + * which o could potentially be their context element. + *

+ * Conversely, for each method m, this class compute the + * set of objects which could potentially be its context element. + */ +public class PotentialContextElement { + private final PTA pta; + // This map maps each object to the methods invoked on it. + // For instance methods, they are the methods whose receiver is the object. + // For static methods, they are the methods reachable from instance methods. + private Map> invokedMethods; + private Map> obj2invokedMethods; + private final Map> typePCEMethods; + private final Map> pceOfMap; + + private final OAG oag; + private final Map> typeAllocatees; + private final Map> allocateeMap; + + PotentialContextElement(final PTA pta, final OAG oag) { + this.pta = pta; + this.oag = oag; + this.typePCEMethods = new ConcurrentHashMap<>(); + this.obj2invokedMethods = new ConcurrentHashMap<>(); + this.pceOfMap = new ConcurrentHashMap<>(); + this.typeAllocatees = new ConcurrentHashMap<>(); + this.allocateeMap = new ConcurrentHashMap<>(); + this.init(oag); + } + + public Set PCEMethodsOf(final AllocNode obj) { + return this.pceOfMap.getOrDefault(obj, Collections.emptySet()); + } + + /** + * @param type + * @return PCE methods of the objects of given type. + */ + public Set PCEMethodsOf(final Type type) { + if (!this.typePCEMethods.containsKey(type)) { + final Set methods = ConcurrentHashMap.newKeySet(); + pta.getPag().getAllocNodes().stream(). + filter(o -> o.getType().equals(type)). + forEach(obj -> methods.addAll(this.PCEMethodsOf(obj))); + this.typePCEMethods.put(type, methods); + } + return this.typePCEMethods.getOrDefault(type, Collections.emptySet()); + } + + /** + * Compute PCE methods for each objects. + */ + private void init(final OAG oag) { + final SCCMergedGraph mg = new SCCMergedGraph<>(oag); + final TopologicalSorter> topoSorter = new TopologicalSorter<>(); + final SetFactory setFactory = new SetFactory<>(); + final SetFactory setFactory2 = new SetFactory<>(); + this.buildMethodsInvokedOnObjects(); + this.invokedMethods = new HashMap<>(); + topoSorter.sort(mg, true).forEach(node -> { + final Set methods = ConcurrentHashMap.newKeySet(); + methods.addAll(setFactory.get(this.getPCEMethods(node, mg))); + final Set allocatees = ConcurrentHashMap.newKeySet(); + allocatees.addAll(setFactory2.get(this.getAllocatees(node, mg))); + node.getContent().forEach(obj -> { + pceOfMap.put(obj, methods); + allocateeMap.put(obj, allocatees); + }); + }); + this.invokedMethods = null; + if (Global.isDebug()) { + this.computePCEObjects(); + } + + oag.allNodes().forEach(obj -> { + final Type type = obj.getType(); + this.typeAllocatees.putIfAbsent(type, new HashSet<>()); + this.typeAllocatees.get(type).addAll(this.allocateesOf(obj)); + }); + } + + private Set getAllocatees(final MergedNode node, final SCCMergedGraph mg) { + final Set allocatees = new HashSet<>(); + mg.succsOf(node).forEach(n -> { + // direct allocatees + allocatees.addAll(n.getContent()); + // indirect allocatees, here, it does not require to traverse all heaps in n.getContent() + // because of lines 104-107. + final AllocNode o = n.getContent().iterator().next(); + allocatees.addAll(this.allocateesOf(o)); + }); + final AllocNode obj = node.getContent().iterator().next(); + if (node.getContent().size() > 1 || oag.succsOf(obj).contains(obj)) { + // The merged node is a true SCC + allocatees.addAll(node.getContent()); + } + return allocatees; + } + + private Set allocateesOf(final AllocNode obj) { + return this.allocateeMap.getOrDefault(obj, Collections.emptySet()); + } + + public Set allocateesOf(final Type type) { + return this.typeAllocatees.getOrDefault(type, Collections.emptySet()); + } + + private Set getPCEMethods(final MergedNode node, final SCCMergedGraph mg) { + final Set methods = new HashSet<>(); + mg.succsOf(node).forEach(n -> { + final AllocNode o2 = n.getContent().iterator().next(); + methods.addAll(this.PCEMethodsOf(o2)); + }); + node.getContent().forEach(o -> methods.addAll(this.invokedMethodsOf(o))); + return methods; + } + + public Set methodsInvokedOn(final AllocNode obj) { + return this.obj2invokedMethods.getOrDefault(obj, Collections.emptySet()); + } + + private void buildMethodsInvokedOnObjects() { + this.obj2invokedMethods = new HashMap<>(); + pta.getNakedReachableMethods().stream().filter(m -> !m.isStatic()).forEach(instMtd -> { + MethodNodeFactory mthdNF = pta.getPag().getMethodPAG(instMtd).nodeFactory(); + VarNode thisVar = mthdNF.caseThis(); + PointsToSet pts = pta.reachingObjects(thisVar).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode obj = it.next(); + obj2invokedMethods.computeIfAbsent(obj, k -> new HashSet<>()).add(instMtd); + } + }); + } + + private Set invokedMethodsOf(final AllocNode obj) { + if (!this.invokedMethods.containsKey(obj)) { + final Set methods = new HashSet<>(); + final Queue queue = new LinkedList<>(this.methodsInvokedOn(obj)); + while (!queue.isEmpty()) { + final SootMethod method = queue.poll(); + methods.add(method); + pta.getCallGraph().edgesOutOf(method).forEachRemaining(edge -> { + SootMethod callee = edge.getTgt().method(); + if (callee.isStatic() && !methods.contains(callee)) { + queue.offer(callee); + } + }); + } + this.invokedMethods.put(obj, methods); + } + return this.invokedMethods.get(obj); + } + + private void computePCEObjects() { + final Map> pceObjs = new HashMap<>(); + pta.getPag().getAllocNodes().forEach(obj -> this.PCEMethodsOf(obj).forEach(method -> { + if (!pceObjs.containsKey(method)) { + pceObjs.put(method, new HashSet<>()); + } + pceObjs.get(method).add(obj); + })); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java new file mode 100644 index 00000000000..06f061d6f04 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java @@ -0,0 +1,312 @@ +package qilin.pta.toolkits.zipper.analysis; + +import qilin.core.PTA; +import qilin.core.pag.*; +import qilin.pta.toolkits.common.OAG; +import qilin.pta.toolkits.common.ToolUtil; +import qilin.pta.toolkits.zipper.Global; +import qilin.pta.toolkits.zipper.flowgraph.FlowAnalysis; +import qilin.pta.toolkits.zipper.flowgraph.ObjectFlowGraph; +import qilin.util.ANSIColor; +import qilin.util.Stopwatch; +import qilin.util.graph.ConcurrentDirectedGraphImpl; +import soot.RefType; +import soot.SootMethod; +import soot.Type; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static qilin.util.ANSIColor.color; + +/** + * Main class of Zipper, which computes precision-critical methods + * in the program being analyzed. + */ +public class Zipper { + private final PTA pta; + private final PotentialContextElement pce; + private final ObjectFlowGraph ofg; + private final AtomicInteger analyzedClasses = new AtomicInteger(0); + private final AtomicInteger totalPFGNodes = new AtomicInteger(0); + private final AtomicInteger totalPFGEdges = new AtomicInteger(0); + private final ConcurrentDirectedGraphImpl overallPFG = new ConcurrentDirectedGraphImpl<>(); + private final Map methodPts; + private final Map> pcmMap = new ConcurrentHashMap<>(1024); + + public Zipper(PTA pta) { + this.pta = pta; + OAG oag = new OAG(pta); + oag.build(); + System.out.println("#OAG:" + oag.allNodes().size()); + this.pce = new PotentialContextElement(pta, oag); + this.ofg = buildObjectFlowGraph(); + this.methodPts = getMethodPointsToSize(); + } + + public static void outputNumberOfClasses(PTA pta) { + int nrClasses = (int) pta.getPag().getAllocNodes().stream() + .map(AllocNode::getType) + .distinct() + .count(); + System.out.println("#classes: " + ANSIColor.BOLD + ANSIColor.GREEN + nrClasses + ANSIColor.RESET); + System.out.println(); + } + + public int numberOfOverallPFGNodes() { + return overallPFG.allNodes().size(); + } + + public int numberOfOverallPFGEdges() { + int nrEdges = 0; + for (Node node : overallPFG.allNodes()) { + nrEdges += overallPFG.succsOf(node).size(); + } + return nrEdges; + } + + public ObjectFlowGraph buildObjectFlowGraph() { + Stopwatch ofgTimer = Stopwatch.newAndStart("Object Flow Graph Timer"); + System.out.println("Building OFG (Object Flow Graph) ... "); + ObjectFlowGraph ofg = new ObjectFlowGraph(pta); + ofgTimer.stop(); + System.out.println(ofgTimer); + outputObjectFlowGraphSize(ofg); + return ofg; + } + + public static void outputObjectFlowGraphSize(ObjectFlowGraph ofg) { + int nrNodes = ofg.allNodes().size(); + int nrEdges = 0; + for (Node node : ofg.allNodes()) { + nrEdges += ofg.outEdgesOf(node).size(); + } + + System.out.println("#nodes in OFG: " + ANSIColor.BOLD + ANSIColor.GREEN + nrNodes + ANSIColor.RESET); + System.out.println("#edges in OFG: " + ANSIColor.BOLD + ANSIColor.GREEN + nrEdges + ANSIColor.RESET); + System.out.println(); + } + + /** + * @return set of precision-critical methods in the program + */ + public Set analyze() { + reset(); + System.out.println("Building PFGs (Pollution Flow Graphs) and computing precision-critical methods ..."); + List types = pta.getPag().getAllocNodes().stream() + .map(AllocNode::getType) + .distinct() + .sorted(Comparator.comparing(Type::toString)) + .filter(t -> t instanceof RefType) + .map(t -> (RefType) t) + .collect(Collectors.toList()); + if (Global.getThread() == Global.UNDEFINE) { + computePCM(types); + } else { + computePCMConcurrent(types, Global.getThread()); + } + System.out.println("#avg. nodes in PFG: " + ANSIColor.BOLD + ANSIColor.GREEN + + Math.round(totalPFGNodes.floatValue() / analyzedClasses.get()) + ANSIColor.RESET); + System.out.println("#avg. edges in PFG: " + ANSIColor.BOLD + ANSIColor.GREEN + + Math.round(totalPFGEdges.floatValue() / analyzedClasses.get()) + ANSIColor.RESET); + System.out.println("#Node:" + totalPFGNodes.intValue()); + System.out.println("#Edge:" + totalPFGEdges.intValue()); + System.out.println("#Node2:" + numberOfOverallPFGNodes()); + System.out.println("#Edge2:" + numberOfOverallPFGEdges()); + System.out.println(); + + Set pcm = collectAllPrecisionCriticalMethods(pcmMap, + computePCMThreshold()); + System.out.println("#Precision-critical methods: " + ANSIColor.BOLD + ANSIColor.GREEN + pcm.size() + ANSIColor.RESET); + return pcm; + } + + private void computePCM(List types) { + FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); + types.forEach(type -> analyze(type, fa)); + } + + private void computePCMConcurrent(List types, int nThread) { + ExecutorService executorService = Executors.newFixedThreadPool(nThread); + types.forEach(type -> + executorService.execute(() -> { + FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); + analyze(type, fa); + })); + executorService.shutdown(); + try { + executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + /** + * @param type + * @param fa Compute the set of precision-critical methods for a class/type and add these methods + * to the pcm collection. + */ + private void analyze(RefType type, FlowAnalysis fa) { + if (Global.isDebug()) { + System.out.println("----------------------------------------"); + } + // System.out.println(color(YELLOW, "Zipper: analyzing ") + type); + + // Obtain all methods of type (including inherited methods) + Set ms = pta.getPag().getAllocNodes().stream(). + filter(o -> o.getType().equals(type)) + .map(pce::methodsInvokedOn) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + if (type.toString().equals("java.util.HashMap")) { + System.out.println("ssssss"); + } + // Obtain IN methods + Set inms = ms.stream() + .filter(m -> !m.isPrivate()) + .filter(m -> ToolUtil.getParameters(pta.getPag(), m).stream() + .anyMatch(p -> !pta.reachingObjects(p).toCIPointsToSet().isEmpty())) + .collect(Collectors.toSet()); + + // Obtain OUT methods + Set outms = new HashSet<>(); + ms.stream() + .filter(m -> !m.isPrivate()) + .filter(m -> ToolUtil.getRetVars(pta.getPag(), m).stream() + .anyMatch(r -> !pta.reachingObjects(r).toCIPointsToSet().isEmpty())) + .forEach(outms::add); + + // OUT methods of inner classes and special access$ methods + // are also considered as the OUT methods of current type + pce.PCEMethodsOf(type).stream() + .filter(m -> !m.isPrivate() && !m.isStatic()) + .filter(m -> ToolUtil.isInnerType( + m.getDeclaringClass().getType(), type)) + .forEach(outms::add); + pce.PCEMethodsOf(type).stream() + .filter(m -> !m.isPrivate() && !m.isStatic()) + .filter(m -> m.getDeclaringClass().getType().equals(type) + && m.toString().contains("access$")) + .forEach(outms::add); + + if (Global.isDebug()) { + System.out.println(color(ANSIColor.YELLOW, "In methods:")); + inms.stream() + .sorted(Comparator.comparing(SootMethod::toString)) + .forEach(m -> System.out.println(" " + m)); + System.out.println(color(ANSIColor.YELLOW, "Out methods:")); + outms.stream() + .sorted(Comparator.comparing(SootMethod::toString)) + .forEach(m -> System.out.println(" " + m)); + } + + fa.initialize(type, inms, outms); + inms.forEach(fa::analyze); + Set flowNodes = fa.getFlowNodes(); + Set precisionCriticalMethods = getPrecisionCriticalMethods(type, flowNodes); + if (Global.isDebug()) { + if (!precisionCriticalMethods.isEmpty()) { + System.out.println(color(ANSIColor.BLUE, "Flow found: ") + type); + } + } + mergeAnalysisResults(type, fa.numberOfPFGNodes(), fa.numberOfPFGEdges(), precisionCriticalMethods); + mergeSinglePFG(fa.getPFG()); + fa.clear(); + } + + private void mergeSinglePFG(ConcurrentDirectedGraphImpl pfg) { + for (Node node : pfg.allNodes()) { + this.overallPFG.addNode(node); + for (Node succ : pfg.succsOf(node)) { + this.overallPFG.addEdge(node, succ); + } + } + } + + private void mergeAnalysisResults(Type type, int nrPFGNodes, int nrPFGEdges, Set precisionCriticalMethods) { + analyzedClasses.incrementAndGet(); + totalPFGNodes.addAndGet(nrPFGNodes); + totalPFGEdges.addAndGet(nrPFGEdges); + pcmMap.put(type, new ArrayList<>(precisionCriticalMethods)); + } + + private Set collectAllPrecisionCriticalMethods( + Map> pcmMap, int pcmThreshold) { + System.out.println("PCM Threshold:" + pcmThreshold); + Set pcm = new HashSet<>(); + pcmMap.forEach((type, pcms) -> { + if (Global.isExpress() && + getAccumulativePointsToSetSize(pcms) > pcmThreshold) { + System.out.println("type: " + type + ", accumulativePTSize: " + getAccumulativePointsToSetSize(pcms)); + return; + } + pcm.addAll(pcms); + }); + return pcm; + } + + private int computePCMThreshold() { + // Use points-to size of whole program as denominator + int totalPTSSize = 0; + for (ValNode var : pta.getPag().getValNodes()) { + if (var instanceof VarNode varNode) { +// Collection pts = ToolUtil.pointsToSetOf(pta, varNode); + totalPTSSize += pta.reachingObjects(varNode).toCIPointsToSet().size(); + } + } + return (int) (Global.getExpressThreshold() * totalPTSSize); + } + + private Set getPrecisionCriticalMethods(Type type, Set nodes) { + return nodes.stream() + .map(this::node2ContainingMethod) + .filter(Objects::nonNull) + .filter(pce.PCEMethodsOf(type)::contains) + .collect(Collectors.toSet()); + } + + private SootMethod node2ContainingMethod(Node node) { + if (node instanceof LocalVarNode lvn) { + return lvn.getMethod(); + } else { + ContextField ctxField = (ContextField) node; + return ctxField.getBase().getMethod(); + } + } + + private void reset() { + analyzedClasses.set(0); + totalPFGNodes.set(0); + totalPFGEdges.set(0); + pcmMap.clear(); + } + + private Map getMethodPointsToSize() { + Map results = new HashMap<>(); + for (ValNode valnode : pta.getPag().getValNodes()) { + if (!(valnode instanceof LocalVarNode lvn)) { + continue; + } + SootMethod inMethod = lvn.getMethod(); + int ptSize = ToolUtil.pointsToSetSizeOf(pta, lvn); + if (results.containsKey(inMethod)) { + int oldValue = results.get(inMethod); + results.replace(inMethod, oldValue, oldValue + ptSize); + } else { + results.put(inMethod, ptSize); + } + } + return results; + } + + private long getAccumulativePointsToSetSize(Collection methods) { + return methods.stream() + .mapToInt(methodPts::get) + .sum(); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java new file mode 100644 index 00000000000..2f1b0262ca3 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java @@ -0,0 +1,19 @@ +package qilin.pta.toolkits.zipper.cases; + +// NO IN , NO OUT, CASE 4. +public class CaseA { + static class A { + Object f; + } + + A create() { + return new A(); + } + + void foo() { + Object o = new Object(); + A a = create(); + a.f = o; + o = a.f; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java new file mode 100644 index 00000000000..0d3084bb9ad --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java @@ -0,0 +1,25 @@ +package qilin.pta.toolkits.zipper.cases; + +// No Out, case 2 +public class CaseB { + static class A { + Object f; + + void bar(Object q) { + this.f = q; + } + } + + void foo() { + Object oy = new Object(); + Object oz = new Object(); + + A a = new A(); + a.bar(oy); + Object o = a.f; + +// A a1 = new A(); +// a1.bar(oz); +// Object o1 = a1.f; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java new file mode 100644 index 00000000000..9a8eb9a75a8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java @@ -0,0 +1,35 @@ +package qilin.pta.toolkits.zipper.cases; + +public class CaseC { + static class A { + Object f; + } + + A f; + + // case 2; + CaseC() { + A a = new A(); + this.f = a; + } + + // does not consider this_variable. + A getF() { + A r = this.f; + return r; + } + + void foo() { + Object o1 = new Object(); + CaseC c1 = new CaseC(); + A a1 = c1.getF(); + a1.f = o1; + Object o1x = a1.f; + +// Object o2 = new Object(); +// CaseC c2 = new CaseC(); +// A a2 = c2.getF(); +// a2.f = o2; +// Object o2x = a2.f; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java new file mode 100644 index 00000000000..f799dccea5c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java @@ -0,0 +1,21 @@ +package qilin.pta.toolkits.zipper.cases; + +public class CaseD { + static class A { + Object f, g; + } + + Object id(Object p) { + A a = new A(); + a.f = p; + Object r = a.f; + return r; + } + + Object fakeId(Object p) { + A a = new A(); + a.f = p; + a.g = new Object(); + return a.g; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java new file mode 100644 index 00000000000..4bad0783246 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java @@ -0,0 +1,59 @@ +package qilin.pta.toolkits.zipper.flowgraph; + +import qilin.core.pag.Node; + +import java.util.Objects; + +public class Edge { + private final Kind kind; + private final Node source; + private final Node target; + private final int hashCode; + + public Edge(final Kind kind, final Node source, final Node target) { + this.kind = kind; + this.source = source; + this.target = target; + this.hashCode = Objects.hash(kind, source, target); + } + + public Kind getKind() { + return this.kind; + } + + public Node getSource() { + return this.source; + } + + public Node getTarget() { + return this.target; + } + + @Override + public String toString() { + return this.kind + ": " + this.source + " --> " + this.target; + } + + @Override + public int hashCode() { + return this.hashCode; + } + + @Override + public boolean equals(final Object other) { + if (this.isOFGEdge()) { + return this == other; + } + if (this == other) { + return true; + } + if (!(other instanceof final Edge otherEdge)) { + return false; + } + return this.kind.equals(otherEdge.kind) && this.source.equals(otherEdge.source) && this.target.equals(otherEdge.target); + } + + private boolean isOFGEdge() { + return this.kind != Kind.WRAPPED_FLOW && this.kind != Kind.UNWRAPPED_FLOW; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java new file mode 100644 index 00000000000..9bfa4814b67 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -0,0 +1,269 @@ +package qilin.pta.toolkits.zipper.flowgraph; + +import qilin.core.PTA; +import qilin.core.pag.*; +import qilin.pta.toolkits.common.ToolUtil; +import qilin.pta.toolkits.zipper.Global; +import qilin.pta.toolkits.zipper.analysis.PotentialContextElement; +import qilin.util.ANSIColor; +import qilin.util.graph.ConcurrentDirectedGraphImpl; +import qilin.util.graph.Reachability; +import soot.*; +import soot.jimple.AssignStmt; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.Stmt; + +import java.util.*; +import java.util.stream.Collectors; + +import static qilin.util.ANSIColor.color; + +public class FlowAnalysis { + private final PTA pta; + private final PotentialContextElement pce; + private final ObjectFlowGraph objectFlowGraph; + + private Type currentType; + private Set inVars; + private Set outNodes; + private Set visitedNodes; + private Map> wuEdges; + private ConcurrentDirectedGraphImpl pollutionFlowGraph; + private Reachability reachability; + + public FlowAnalysis(PTA pta, + PotentialContextElement pce, + ObjectFlowGraph ofg) { + this.pta = pta; + this.pce = pce; + this.objectFlowGraph = ofg; + } + + public void initialize(Type type, Set inms, Set outms) { + currentType = type; + inVars = inms.stream() + .map(m -> ToolUtil.getParameters(pta.getPag(), m)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + outNodes = outms.stream() + .map(m -> ToolUtil.getRetVars(pta.getPag(), m)) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + visitedNodes = new HashSet<>(); + wuEdges = new HashMap<>(); + pollutionFlowGraph = new ConcurrentDirectedGraphImpl<>(); + reachability = new Reachability<>(pollutionFlowGraph); + } + + public void analyze(SootMethod startMethod) { + for (VarNode param : ToolUtil.getParameters(pta.getPag(), startMethod)) { + if (param != null) { + dfs(param); + } else { + if (Global.isDebug()) { + System.out.println(param + " is absent in the flow graph."); + } + } + } + + if (Global.isDebug()) { + Set outMethods = new HashSet<>(); + for (VarNode param : ToolUtil.getParameters(pta.getPag(), startMethod)) { + if (param != null) { + for (Node outNode : outNodes) { + if (reachability.reachableNodesFrom(param).contains(outNode)) { + LocalVarNode outVarNode = (LocalVarNode) outNode; + outMethods.add(outVarNode.getMethod()); + } + } + } + } + System.out.println(color(ANSIColor.GREEN, "In method: ") + startMethod); + System.out.println(color(ANSIColor.GREEN, "Out methods: ") + outMethods); + } + } + + public Set getFlowNodes() { + Set results = new HashSet<>(); + for (Node outNode : outNodes) { + if (pollutionFlowGraph.allNodes().contains(outNode)) { + results.addAll(reachability.nodesReach(outNode)); + } + } + return results; + } + + public int numberOfPFGNodes() { + return pollutionFlowGraph.allNodes().size(); + } + + public int numberOfPFGEdges() { + int nrEdges = 0; + for (Node node : pollutionFlowGraph.allNodes()) { + nrEdges += pollutionFlowGraph.succsOf(node).size(); + } + return nrEdges; + } + + public ConcurrentDirectedGraphImpl getPFG() { + return pollutionFlowGraph; + } + + public void clear() { + currentType = null; + inVars = null; + outNodes = null; + visitedNodes = null; + wuEdges = null; + pollutionFlowGraph = null; + reachability = null; + } + + // a bit more complicated than the algorithm in TOPLAS'20 + private void dfs(Node node) { + if (Global.isDebug()) { + System.out.println(color(ANSIColor.BLUE, "Node ") + node); + } + if (visitedNodes.contains(node)) { // node has been visited + if (Global.isDebug()) { + System.out.println(color(ANSIColor.RED, "Visited node: ") + node); + } + } else { + visitedNodes.add(node); + pollutionFlowGraph.addNode(node); + // add unwrapped flow edges + if (Global.isEnableUnwrappedFlow()) { + if (node instanceof VarNode var) { + Collection varPts = pta.reachingObjects(var).toCIPointsToSet().toCollection(); + // Optimization: approximate unwrapped flows to make + // Zipper and pointer analysis run faster + pta.getCgb().getReceiverToSitesMap() + .getOrDefault(var, Collections.emptySet()) + .forEach(vcs -> { + Stmt callsiteStmt = (Stmt) vcs.getUnit(); + InvokeExpr invo = callsiteStmt.getInvokeExpr(); + if (!(invo instanceof InstanceInvokeExpr)) { + return; + } + if (callsiteStmt instanceof AssignStmt assignStmt) { + Value lv = assignStmt.getLeftOp(); + if (!(lv.getType() instanceof RefLikeType)) { + return; + } + final VarNode to = (VarNode) pta.getPag().findValNode(lv); + if (outNodes.contains(to)) { + for (VarNode inVar : inVars) { + if (!Collections.disjoint(pta.reachingObjects(inVar).toCIPointsToSet().toCollection(), varPts)) { + Edge unwrappedEdge = new Edge(Kind.UNWRAPPED_FLOW, node, to); + addWUEdge(node, unwrappedEdge); + break; + } + } + } + } + }); + } + } + List nextEdges = new ArrayList<>(); + for (Edge edge : outEdgesOf(node)) { + switch (edge.getKind()) { + case LOCAL_ASSIGN, UNWRAPPED_FLOW -> { + nextEdges.add(edge); + } + case INTERPROCEDURAL_ASSIGN, INSTANCE_LOAD, WRAPPED_FLOW -> { + // next must be a variable + LocalVarNode next = (LocalVarNode) edge.getTarget(); + SootMethod inMethod = next.getMethod(); + // Optimization: filter out some potential spurious flows due to + // the imprecision of context-insensitive pre-analysis, which + // helps improve the performance of Zipper and pointer analysis. + if (pce.PCEMethodsOf(currentType).contains(inMethod)) { + nextEdges.add(edge); + } + } + case INSTANCE_STORE -> { + ContextField next = (ContextField) edge.getTarget(); + AllocNode base = next.getBase(); + if (base.getType().equals(currentType)) { + // add wrapped flow edges to this variable + if (Global.isEnableWrappedFlow()) { + methodsInvokedOn(currentType).stream() + .map(m -> ToolUtil.getThis(pta.getPag(), m)) // filter this variable of native methods + .map(n -> new Edge(Kind.WRAPPED_FLOW, next, n)) + .forEach(e -> addWUEdge(next, e)); + } + nextEdges.add(edge); + } else if (pce.allocateesOf(currentType).contains(base)) { + // Optimization, similar as above. + if (Global.isEnableWrappedFlow()) { + Set r = new HashSet<>(); + AllocNode mBase = (AllocNode) pta.parameterize(base, pta.emptyContext()); + pta.getPag().allocLookup(mBase).forEach(v -> { + if (v instanceof ContextVarNode cvn) { + if (cvn.base() instanceof LocalVarNode lvn) { + if (!lvn.isThis()) { + r.add(lvn); + } + } + } + }); + Iterator it = r.iterator(); + if (it.hasNext()) { + Node assigned = r.iterator().next(); + if (assigned != null) { + Edge e = new Edge(Kind.WRAPPED_FLOW, next, assigned); + addWUEdge(next, e); + } + } + } + nextEdges.add(edge); + } + } + default -> { + throw new RuntimeException("Unknown edge: " + edge); + } + } + } + for (Edge nextEdge : nextEdges) { + Node nextNode = nextEdge.getTarget(); + pollutionFlowGraph.addEdge(node, nextNode); + dfs(nextNode); + } + } + } + + private void addWUEdge(Node sourceNode, Edge edge) { + wuEdges.computeIfAbsent(sourceNode, k -> new HashSet<>()).add(edge); + } + + private Collection methodsInvokedOn(Type type) { + return pta.getPag().getAllocNodes() + .stream().filter(o -> o.getType().equals(type)) + .map(pce::methodsInvokedOn).flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + + /** + * @param node + * @return out edges of node from OFG, and wuEdges, if present + */ + private Set outEdgesOf(Node node) { + Set outEdges = objectFlowGraph.outEdgesOf(node); + if (wuEdges.containsKey(node)) { + outEdges = new HashSet<>(outEdges); + outEdges.addAll(wuEdges.get(node)); + } + return outEdges; + } + + private void outputPollutionFlowGraphSize() { + int nrNodes = pollutionFlowGraph.allNodes().size(); + int nrEdges = 0; + for (Node node : pollutionFlowGraph.allNodes()) { + nrEdges += pollutionFlowGraph.succsOf(node).size(); + } + System.out.printf("#Size of PFG of %s: %d nodes, %d edges.\n", currentType, nrNodes, nrEdges); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java new file mode 100644 index 00000000000..753f7cd9bae --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java @@ -0,0 +1,11 @@ +package qilin.pta.toolkits.zipper.flowgraph; + +import qilin.core.pag.Node; + +import java.util.Set; + +public interface IObjectFlowGraph { + Set outEdgesOf(final Node p0); + + Set allNodes(); +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java new file mode 100644 index 00000000000..1acca6aabc7 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java @@ -0,0 +1,10 @@ +package qilin.pta.toolkits.zipper.flowgraph; + +public enum Kind { + LOCAL_ASSIGN, + INTERPROCEDURAL_ASSIGN, + INSTANCE_LOAD, + INSTANCE_STORE, + WRAPPED_FLOW, + UNWRAPPED_FLOW; +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java new file mode 100644 index 00000000000..2be92fdf076 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java @@ -0,0 +1,124 @@ +package qilin.pta.toolkits.zipper.flowgraph; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.pta.toolkits.zipper.Global; +import soot.SootMethod; +import soot.Value; +import soot.jimple.*; + +import java.util.*; + +public class ObjectFlowGraph implements IObjectFlowGraph { + private final PTA pta; + private Map> outEdges; + + public ObjectFlowGraph(PTA pta) { + this.pta = pta; + init(); + } + + @Override + public Set outEdgesOf(Node node) { + return outEdges.getOrDefault(node, Collections.emptySet()); + } + + @Override + public Set allNodes() { + return outEdges.keySet(); + } + + private boolean localVarBase(ValNode valNode) { + if (valNode instanceof ContextVarNode cvn) { + return cvn.base() instanceof LocalVarNode; + } else { + return valNode instanceof LocalVarNode; + } + } + + private LocalVarNode fetchLocalVar(ValNode valNode) { + if (valNode instanceof ContextVarNode cvn) { + if (cvn.base() instanceof LocalVarNode) { + return (LocalVarNode) cvn.base(); + } + } else if (valNode instanceof LocalVarNode) { + return (LocalVarNode) valNode; + } + return null; + } + + private LocalVarNode fetchVar(ValNode valNode) { + if (valNode instanceof ContextVarNode cvn) { + VarNode base = cvn.base(); + if (base instanceof LocalVarNode lvn) { + return lvn; + } + } else if (valNode instanceof LocalVarNode lvn) { + return lvn; + } + return null; + } + + public void addOutEdge(final Edge e) { + outEdges.computeIfAbsent(e.getSource(), k -> new HashSet<>()).add(e); + } + + private void init() { + outEdges = new HashMap<>(); + + pta.getPag().getSimple().forEach((s, ts) -> { + if (localVarBase(s)) { + ts.forEach(t -> { + if (localVarBase(t)) { + LocalVarNode toNode = fetchVar(t); + LocalVarNode fromNode = fetchVar(s); + if (fetchLocalVar(s).isInterProcSource()) { + addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, toNode)); + } else { + if (fetchLocalVar(t).isInterProcTarget()) { + if (!fetchLocalVar(t).isThis()) { + addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, toNode)); + } + } else { + addOutEdge(new Edge(Kind.LOCAL_ASSIGN, fromNode, toNode)); + } + } + } else if (t instanceof ContextField ctxField) { + LocalVarNode varNode = fetchVar(s); + addOutEdge(new Edge(Kind.INSTANCE_STORE, varNode, ctxField)); + } + }); + } else if (s instanceof ContextField ctxField) { + ts.forEach(t -> { + assert localVarBase(t); + LocalVarNode varNode = fetchVar(t); + addOutEdge(new Edge(Kind.INSTANCE_LOAD, ctxField, varNode)); + }); + } + }); + + pta.getCallGraph().forEach(e -> { + Stmt callsite = e.srcStmt(); + SootMethod caller = e.src(); + if (caller != null) { + SootMethod callee = e.tgt(); + if (!callee.isStatic()) { + MethodNodeFactory calleeNF = pta.getPag().getMethodPAG(callee).nodeFactory(); + LocalVarNode thisVar = (LocalVarNode) calleeNF.caseThis(); + InvokeExpr ie = callsite.getInvokeExpr(); + Value base = null; + if (ie instanceof InstanceInvokeExpr iie) { + base = iie.getBase(); + } + if (base != null) { + LocalVarNode fromNode = (LocalVarNode) pta.getPag().findValNode(base); + addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, thisVar)); + } + } + } else if (Global.isDebug()) { + System.out.println("Null caller of: " + callsite); + } + }); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/mit.txt b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/mit.txt new file mode 100644 index 00000000000..dc47550a578 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/mit.txt @@ -0,0 +1,24 @@ +The MIT License + +Copyright (C) 2018 Yue Li, Tian Tan, Anders Møller, Yannis Smaragdakis + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java new file mode 100644 index 00000000000..7b7b3fa5499 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java @@ -0,0 +1,65 @@ +package qilin.pta.tools; + +import qilin.CoreConfig; +import qilin.core.CorePTA; +import qilin.core.builder.CallGraphBuilder; +import qilin.core.pag.PAG; +import qilin.core.solver.Propagator; +import qilin.core.solver.Solver; +import qilin.stat.IEvaluator; +import qilin.stat.PTAEvaluator; +import qilin.stat.SimplifiedEvaluator; +import qilin.util.PTAUtils; + +public abstract class BasePTA extends CorePTA { + protected IEvaluator evaluator; + + public BasePTA() { +// this.evaluator = new PTAEvaluator(this); + this.evaluator = new SimplifiedEvaluator(this); + } + + public IEvaluator evaluator() { + return this.evaluator; + } + + @Override + protected PAG createPAG() { + return new PAG(this); + } + + @Override + protected CallGraphBuilder createCallGraphBuilder() { + return new CallGraphBuilder(this); + } + + @Override + public Propagator getPropagator() { + return new Solver(this); + } + + @Override + public void run() { + evaluator.begin(); + pureRun(); + evaluator.end(); + dumpStats(); + System.out.println(evaluator()); + } + + protected void dumpStats() { + if (CoreConfig.v().getOutConfig().dumppts) { + PTAUtils.dumpPts(this, !CoreConfig.v().getOutConfig().dumplibpts); + } + if (CoreConfig.v().getOutConfig().dumpCallGraph) { + PTAUtils.dumpCallGraph(getCallGraph(), false); +// PTAUtils.dumpSlicedCallGraph(getCallGraph(), +// parameterize(PTAScene.v().getMethod(""), emptyContext())); + } + if (CoreConfig.v().getOutConfig().dumppag) { + PTAUtils.dumpPAG(pag, "pag"); +// PTAUtils.dumpMPAGs(this, "mpags"); + PTAUtils.dumpNodeNames("nodeNames"); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java new file mode 100644 index 00000000000..d825cae2ac8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java @@ -0,0 +1,72 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.CtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.BeanSelector; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.pta.PTAConfig; +import qilin.pta.StagedPTA; +import qilin.pta.toolkits.bean.Bean; +import qilin.util.Stopwatch; + +import java.util.HashMap; +import java.util.Map; + +/* + * refer to "Making k-Object-Sensitive Pointer Analysis More Precise with Still k-Limiting" (SAS'16) + * */ +public class BeanPTA extends StagedPTA { + // currently, we only support k = 2 and hk = 1; + // [current heap, [allocator heap, [heap ctx, new ctx]]] only for B-2obj; + Map>> beanNexCtxMap = new HashMap<>(); + + public BeanPTA(CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new BeanSelector(pag, beanNexCtxMap); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + prePTA = new Spark(); + System.out.println("bean ..."); + } + + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + Stopwatch beanTimer = Stopwatch.newAndStart("Bean"); + Bean.run(prePTA, beanNexCtxMap); + beanTimer.stop(); + System.out.println(beanTimer); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java new file mode 100644 index 00000000000..1bdf094bb70 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java @@ -0,0 +1,51 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.CallsiteCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.parm.select.UniformSelector; +import qilin.pta.PTAConfig; + +/* + * refer to "Two approaches to interprocedural data flow analysis" (PFA 1981) + * */ + +public class CallSiteSensPTA extends BasePTA { + + public CallSiteSensPTA(int k, int hk) { + this.ctxCons = new CallsiteCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("k-callsite PTA ..."); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java new file mode 100644 index 00000000000..b43824e9783 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java @@ -0,0 +1,56 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.CtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.pta.PTAConfig; +import qilin.pta.toolkits.dd.DataDrivenSelector; +/* + * Support Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017): + * https://doi.org/10.1145/3133924 + * The limitation of this paper is that it only support a flavour of context sensitivity with k = 2. + * k > 2 will costs more time (which is often unbearable) for training. + * The length of heap context is k - 1 by default, where k is a fixed number (i.e., 2) + * We use the same formula presented in the paper. However, our evaluation does not show the same effectiveness + * as claimed in the paper. Maybe we should retrain the formulas in our framework. + * */ + +public class DataDrivenPTA extends BasePTA { + + public DataDrivenPTA(CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new DataDrivenSelector(ctxCons.getClass()); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("data-driven ..."); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java new file mode 100644 index 00000000000..4f422c95d0b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java @@ -0,0 +1,163 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.core.solver.Propagator; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.DebloatingSelector; +import qilin.parm.select.PipelineSelector; +import qilin.pta.PTAConfig; +import qilin.pta.StagedPTA; +import qilin.pta.toolkits.conch.Conch; +import qilin.stat.IEvaluator; +import qilin.util.Stopwatch; +import soot.*; +import soot.jimple.spark.pag.SparkField; + +import java.util.HashSet; +import java.util.Set; + +/* + * refer to "Context Debloating for Object-Sensitive Pointer Analysis" (ASE'21) + * */ +public class DebloatedPTA extends StagedPTA { + protected BasePTA basePTA; + protected Set ctxDepHeaps = new HashSet<>(); + + /* + * The debloating approach is currently for object-sensitive PTA only. + * Thus the base PTA should be k-OBJ, Zipper-OBJ or Eagle-OBJ. + * */ + public DebloatedPTA(BasePTA basePTA) { + this.basePTA = basePTA; + CtxSelector debloatingSelector = new DebloatingSelector(ctxDepHeaps); + basePTA.setContextSelector(new PipelineSelector(basePTA.ctxSelector(), debloatingSelector)); + if (basePTA instanceof StagedPTA stagedPTA) { + this.prePTA = stagedPTA.getPrePTA(); + } else { + this.prePTA = new Spark(); + } + System.out.println("debloating ...."); + } + + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + Stopwatch conchTimer = Stopwatch.newAndStart("Conch"); + Conch hc = new Conch(prePTA); + hc.runClassifier(); + this.ctxDepHeaps.addAll(hc.ctxDependentHeaps()); + System.out.println(); + conchTimer.stop(); + System.out.println(conchTimer); + } + + @Override + protected void mainAnalysis() { + if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { + System.out.println("selective pta starts!"); + basePTA.run(); + } + } + + @Override + public Propagator getPropagator() { + return basePTA.getPropagator(); + } + + @Override + public Node parameterize(Node n, Context context) { + return basePTA.parameterize(n, context); + } + + @Override + public MethodOrMethodContext parameterize(SootMethod method, Context context) { + return basePTA.parameterize(method, context); + } + + @Override + public AllocNode getRootNode() { + return basePTA.getRootNode(); + } + + @Override + public IEvaluator evaluator() { + return basePTA.evaluator(); + } + + @Override + public Context emptyContext() { + return basePTA.emptyContext(); + } + + @Override + public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + return basePTA.createCalleeCtx(caller, receiverNode, callSite, target); + } + + @Override + public PointsToSet reachingObjectsInternal(PointsToSet s, SparkField f) { + return basePTA.reachingObjectsInternal(s, f); + } + + @Override + public PointsToSet reachingObjects(Local l) { + return basePTA.reachingObjects(l); + } + + @Override + public PointsToSet reachingObjects(Node n) { + return basePTA.reachingObjects(n); + } + + @Override + public PointsToSet reachingObjects(Context c, Local l) { + return basePTA.reachingObjects(c, l); + } + + @Override + public PointsToSet reachingObjects(SootField f) { + return basePTA.reachingObjects(f); + } + + @Override + public PointsToSet reachingObjects(PointsToSet s, SootField f) { + return basePTA.reachingObjects(s, f); + } + + @Override + public PointsToSet reachingObjects(Local l, SootField f) { + return basePTA.reachingObjects(l, f); + } + + @Override + public PointsToSet reachingObjects(Context c, Local l, SootField f) { + return basePTA.reachingObjects(c, l, f); + } + + @Override + public PointsToSet reachingObjectsOfArrayElement(PointsToSet s) { + return basePTA.reachingObjectsOfArrayElement(s); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java new file mode 100644 index 00000000000..952a6e92fca --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java @@ -0,0 +1,122 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.core.pag.AllocNode; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.Parm; +import qilin.pta.toolkits.eagle.Eagle; +import qilin.util.Pair; +import qilin.util.Stopwatch; +import soot.Local; +import soot.jimple.Expr; +import soot.jimple.NewArrayExpr; +import soot.jimple.Stmt; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.Map; + +/* + * refer to "Precision-Preserving Yet Fast Object-Sensitive Pointer Analysis with Partial Context Sensitivity" (OOPSLA'19) + * and "Eagle: CFL-Reachability-based Precision-Preserving Acceleration of Object-Sensitive Pointer Analysis with Partial Context Sensitivity" + * (TOSEM'21) + * */ +public class EaglePTA extends PartialObjSensPTA { + public EaglePTA(int ctxLen) { + super(ctxLen); + System.out.println("Eagle ...."); + } + + @Override + protected Map calculatingNode2Length() { + Stopwatch timer = Stopwatch.newAndStart("TransGraph Construction"); + Eagle eagle = new Eagle(); + eagle.buildGraph(prePTA); + timer.stop(); + System.out.println(timer); + Stopwatch eagleTimer = Stopwatch.newAndStart("Eagle Selection"); + Map ret = eagle.contxtLengthAnalysis(); + eagleTimer.stop(); + System.out.println(eagleTimer); + eagle.dumpCount(); +// try { +// writeToFile(ret); +// } catch (FileNotFoundException e) { +// System.out.println("no file exists for dumping eagle selected partial heaps/variables."); +// } + System.out.println("#Node:" + eagle.totalNodesCount()); + System.out.println("#Edge:" + eagle.totalEdgesCount()); + return ret; + } + + protected void writeToFile(Map partialResults) throws FileNotFoundException { + final char EOL = '\n'; + String insensVarFile = "InsensitiveVar.facts"; + String insensHeapFile = "InsensitiveHeap.facts"; + PrintWriter varWriter = new PrintWriter(insensVarFile); + PrintWriter heapWriter = new PrintWriter(insensHeapFile); + partialResults.forEach((k, v) -> { + if (v > 0) { + return; + } + if (k instanceof AllocNode heap) { + if (heap.getMethod() == null) { + return; + } + String newExpr = heap.getNewExpr().toString(); + if (heap.getNewExpr() instanceof NewArrayExpr nae) { + newExpr = "new " + nae.getBaseType().toString() + "[]"; + } + String heapSig = heap.getMethod().toString() + "/" + newExpr; + heapWriter.write(heapSig); + heapWriter.write(EOL); + } else if (k instanceof LocalVarNode lvn) { + Object variable = lvn.getVariable(); + String varName = variable.toString(); + if (variable instanceof Parm parm) { + if (parm.isThis()) { + varName = "@this"; + } else if (parm.isReturn()) { + return; + } else if (parm.isThrowRet()) { + return; + } else { + varName = "@parameter" + parm.getIndex(); + } + } else if (variable instanceof Local) { + + } else if (variable instanceof Stmt) { + return; + } else if (variable instanceof Expr) { + return; + } else if (variable instanceof Pair) { + return; + } else { + return; + } + String varSig = lvn.getMethod().toString() + "/" + varName; + varWriter.write(varSig); + varWriter.write(EOL); + } + }); + varWriter.close(); + heapWriter.close(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java new file mode 100644 index 00000000000..1ef7cef9008 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java @@ -0,0 +1,51 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.HybObjCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.parm.select.UniformSelector; +import qilin.pta.PTAConfig; + +/** + * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) + */ +public class HybridObjectSensPTA extends BasePTA { + + public HybridObjectSensPTA(int k, int hk) { + this.ctxCons = new HybObjCtxConstructor(); + CtxSelector us = new UniformSelector(k + 1, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("Hybrid k-OBJ ..."); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java new file mode 100644 index 00000000000..34db6856bde --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java @@ -0,0 +1,51 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.HybTypeCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.parm.select.UniformSelector; +import qilin.pta.PTAConfig; + +/** + * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) + */ + +public class HybridTypeSensPTA extends BasePTA { + + public HybridTypeSensPTA(int k, int hk) { + this.ctxCons = new HybTypeCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("Hybrid k-type ..."); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java new file mode 100644 index 00000000000..965a33d9813 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java @@ -0,0 +1,77 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.CtxConstructor; +import qilin.parm.heapabst.MahjongAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.DebloatingSelector; +import qilin.parm.select.PipelineSelector; +import qilin.parm.select.UniformSelector; +import qilin.pta.PTAConfig; +import qilin.pta.StagedPTA; +import qilin.pta.toolkits.mahjong.Mahjong; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/* + * refer to "Efficient and Precise Points-to Analysis: Modeling the Heap by Merging Equivalent Automata" (PLDI'17) + * */ +public class MahjongPTA extends StagedPTA { + protected final Map heapModelMap = new HashMap<>(); + public Set mergedHeap = new HashSet<>(); + public Set csHeap = new HashSet<>(); + + public MahjongPTA(int k, int hk, CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new UniformSelector(k, hk); + CtxSelector ds = new DebloatingSelector(csHeap); + this.ctxSel = new PipelineSelector(us, ds); + this.heapAbst = new MahjongAbstractor(pag, mergedHeap, heapModelMap); + System.out.println("Mahjong ..."); + } + + @Override + protected void preAnalysis() { + PTAConfig.v().getPtaConfig().mergeHeap = false; + prePTA.pureRun(); + + Mahjong.run(prePTA, heapModelMap); + heapModelMap.forEach((origin, merged) -> { + if (pag.findAllocNode(origin) == null || pag.findAllocNode(merged) == null) { + return; + } + if (pag.findAllocNode(origin).getType() != pag.findAllocNode(merged).getType()) { + return; + } + if (!csHeap.add(merged)) { + mergedHeap.add(merged); + } + }); + csHeap.removeAll(mergedHeap); + System.out.println("#MERGE HEAP (not-single):" + mergedHeap.size()); + System.out.println("#NON-MERGED HEAP (single):" + csHeap.size()); + for (Object mh : mergedHeap) { + System.out.println(mh); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java new file mode 100644 index 00000000000..aaa9010bd48 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java @@ -0,0 +1,50 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.ObjCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.parm.select.UniformSelector; +import qilin.pta.PTAConfig; + +/* + * refer to "Parameterized object sensitivity for points-to analysis for Java" (TSE'05) + * */ +public class ObjectSensPTA extends BasePTA { + public ObjectSensPTA(int k, int hk) { + this.ctxCons = new ObjCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + System.out.println(".... Heuristic..."); + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("k-OBJ ..."); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java new file mode 100644 index 00000000000..83a3aa47b92 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -0,0 +1,192 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.core.CorePTA; +import qilin.core.pag.*; +import qilin.parm.ctxcons.CallsiteCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.*; +import qilin.pta.PTAConfig; +import qilin.pta.StagedPTA; +import qilin.util.PTAUtils; +import qilin.util.Stopwatch; +import soot.*; +import soot.jimple.*; +import soot.util.queue.QueueReader; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public abstract class PartialCallSiteSensPTA extends StagedPTA { + protected Set csnodes = new HashSet<>(); + protected Set csmethods = new HashSet<>(); + protected CorePTA prePTA; + protected PAG prePAG; + + // just for stats + Set PCSM = new HashSet<>(); + Set CSM = new HashSet<>(); + + public PartialCallSiteSensPTA(int ctxLen) { + this.ctxCons = new CallsiteCtxConstructor(); + CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + this.prePTA = new Spark(); + this.prePAG = prePTA.getPag(); + } + + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + select(); + extraStats(); + } + + protected abstract Map calculatingNode2Length(); + + // =========context selector============= + protected void select() { + Stopwatch preTimer = Stopwatch.newAndStart("pre-analysis"); + Map ret = calculatingNode2Length(); + ret.forEach((sparkNode, l) -> { + if (l > 0) { + csnodes.add(PTAUtils.getIR(sparkNode)); + } + SootMethod method = null; + if (sparkNode instanceof LocalVarNode) { + method = ((LocalVarNode) sparkNode).getMethod(); + } else if (sparkNode instanceof AllocNode allocNode) { + method = allocNode.getMethod(); + } + + if (method != null) { + if (l == 0) { + PCSM.add(method); + } else { + CSM.add(method); + } + } + }); + PCSM.retainAll(CSM); + CSM.removeAll(PCSM); + csmethods.addAll(CSM); + csmethods.addAll(PCSM); + System.out.println("#CSNODES:" + csnodes.size()); + System.out.println("#CSMETHODS:" + csmethods.size()); + preTimer.stop(); + System.out.println(preTimer); + } + + protected void extraStats() { + int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + SootMethod method = momc.method(); + Set nodes = new HashSet<>(); + if (method.isPhantom()) { + return; + } + MethodPAG srcmpag = pag.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + nodes.add(((VarNode) from).getVariable()); + } else if (from instanceof AllocNode) { + nodes.add(((AllocNode) from).getNewExpr()); + } else if (from instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + + if (to instanceof LocalVarNode) { + nodes.add(((VarNode) to).getVariable()); + } else if (to instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + } + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + InvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + continue; + } + nodes.add(arg); + } + + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + nodes.add(dest); + } + } + if (ie instanceof InstanceInvokeExpr iie) { + Value base = iie.getBase(); + if (base instanceof Local) { + nodes.add(base); + } + } + } + for (Object o : nodes) { + int index = 0; + if (csnodes.contains(o)) { + index = 1; + } + if (index != 0) { + PCN[0]++; + } else { + NPCN[0]++; + } + totalN[0]++; + } + RM[0]++; + } + RM[0]--; // For the FakeMain method. + System.out.println("#ReachableMethod:" + RM[0]); + System.out.println("#FCSM:" + CSM.size()); + System.out.println("#PCSM:" + PCSM.size()); + System.out.println("#CIM:" + (RM[0] - PCSM.size() - CSM.size())); + System.out.println("#CIN: " + NPCN[0]); + System.out.println("#CSN: " + PCN[0]); + System.out.println("totalN: " + totalN[0]); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java new file mode 100644 index 00000000000..7767fcd4cd8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -0,0 +1,194 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.core.pag.*; +import qilin.parm.ctxcons.ObjCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PartialVarSelector; +import qilin.parm.select.PipelineSelector; +import qilin.pta.PTAConfig; +import qilin.pta.StagedPTA; +import qilin.util.PTAUtils; +import qilin.util.Stopwatch; +import soot.*; +import soot.jimple.*; +import soot.util.queue.QueueReader; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public abstract class PartialObjSensPTA extends StagedPTA { + protected Set csnodes = new HashSet<>(); + protected Set csmethods = new HashSet<>(); + protected PAG prePAG; + + // just for stats + Set PCSM = new HashSet<>(); + Set CSM = new HashSet<>(); + + public PartialObjSensPTA(int ctxLen) { + this.ctxCons = new ObjCtxConstructor(); + CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + this.prePTA = new Spark(); + this.prePAG = prePTA.getPag(); + } + + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + select(); + extraStats(); + } + + protected abstract Map calculatingNode2Length(); + + // =========context selector============= + protected void select() { + Stopwatch preTimer = Stopwatch.newAndStart("pre-analysis"); + Map ret = calculatingNode2Length(); + ret.forEach((sparkNode, l) -> { + if (l > 0) { + csnodes.add(PTAUtils.getIR(sparkNode)); + } + SootMethod method = null; + if (sparkNode instanceof LocalVarNode) { + method = ((LocalVarNode) sparkNode).getMethod(); + } else if (sparkNode instanceof AllocNode allocNode) { + method = allocNode.getMethod(); + } + + if (method != null) { + if (l == 0) { + PCSM.add(method); + } else { + CSM.add(method); + } + } + }); + PCSM.retainAll(CSM); + CSM.removeAll(PCSM); + csmethods.addAll(CSM); + csmethods.addAll(PCSM); + System.out.println("#CSNODES:" + csnodes.size()); + System.out.println("#CSMETHODS:" + csmethods.size()); + preTimer.stop(); + System.out.println(preTimer); + } + + protected void extraStats() { + int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + SootMethod method = momc.method(); + Set nodes = new HashSet<>(); + if (method.isPhantom()) { + return; + } + MethodPAG srcmpag = pag.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + nodes.add(((VarNode) from).getVariable()); + } else if (from instanceof AllocNode) { + nodes.add(((AllocNode) from).getNewExpr()); + } else if (from instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + + if (to instanceof LocalVarNode) { + nodes.add(((VarNode) to).getVariable()); + } else if (to instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + } + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + InvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + continue; + } + nodes.add(arg); + } + + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + nodes.add(dest); + } + } + if (ie instanceof InstanceInvokeExpr iie) { + Value base = iie.getBase(); + if (base instanceof Local) { + nodes.add(base); + } + } + } + for (Object o : nodes) { + int index = 0; + if (csnodes.contains(o)) { + index = 1; + } + if (index != 0) { + PCN[0]++; + } else { + NPCN[0]++; + } + totalN[0]++; + } +// System.out.println(method); + RM[0]++; + } + RM[0]--; // For the FakeMain method. + System.out.println("#ReachableMethod:" + RM[0]); + System.out.println("#FCSM:" + CSM.size()); + System.out.println("#PCSM:" + PCSM.size()); + System.out.println("#CIM:" + (RM[0] - PCSM.size() - CSM.size())); + System.out.println("#CIN: " + NPCN[0]); + System.out.println("#CSN: " + PCN[0]); + System.out.println("totalN: " + totalN[0]); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java new file mode 100644 index 00000000000..3640b614914 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.pta.toolkits.selectx.Selectx; + +import java.util.Map; + +public class SelectxPTA extends PartialCallSiteSensPTA { + + public SelectxPTA(int ctxLen) { + super(ctxLen); + System.out.println("selectx ... "); + } + + //=========context selector============= + + @Override + protected Map calculatingNode2Length() { + System.out.print("Construct transPAG..."); + long time = System.currentTimeMillis(); + + prePAG = prePTA.getPag(); + Selectx selectx = new Selectx(prePTA); + + System.out.println((System.currentTimeMillis() - time) / 1000 + "s"); + + System.out.println("Propagate.."); + return selectx.process(); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java new file mode 100644 index 00000000000..da0a21fb2fb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.InsensCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.InsenSelector; +import qilin.pta.PTAConfig; + +/* + * refer to "Scaling Java Points-To Analysis using SPARK" (CC'03) + * */ +public class Spark extends BasePTA { + public Spark() { + this.ctxCons = new InsensCtxConstructor(); + this.ctxSel = new InsenSelector(); + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("Context-Insensitive ..."); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java new file mode 100644 index 00000000000..dc02e2a5f15 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java @@ -0,0 +1,52 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.CtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.parm.select.UniformSelector; +import qilin.pta.PTAConfig; +import qilin.pta.toolkits.dd.TunnelingConstructor; + +/* + * This class support context tunneling from the paper "Precise and Scalable Points-to Analysis via Data-Driven + * Context Tunneling" (OOPSLA 2018). We reuse the trained formula from the paper. However, our evaluation does + * not show the claimed effectiveness. Maybe we should train the benchmarks to get new formulas? + * */ +public class TunnelingPTA extends BasePTA { + public TunnelingPTA(CtxConstructor ctxCons, int k, int hk) { + this.ctxCons = new TunnelingConstructor(ctxCons); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("context-tunneling ..."); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java new file mode 100644 index 00000000000..cb159f3397c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java @@ -0,0 +1,42 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.pta.toolkits.turner.Turner; + +import java.util.Map; + +/* + * refer to "Accelerating Object-Sensitive Pointer Analysis by Exploiting Object Containment and Reachability" (ECOOP'21) + * */ +public class TurnerPTA extends PartialObjSensPTA { + private final int k; + + public TurnerPTA(int k) { + super(k); + this.k = k; + System.out.println("Turner ..."); + } + + @Override + protected Map calculatingNode2Length() { + Turner turner = new Turner(k, prePTA); + return turner.contxtLengthAnalysis(); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java new file mode 100644 index 00000000000..022996b4743 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java @@ -0,0 +1,50 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.parm.ctxcons.TypeCtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PipelineSelector; +import qilin.parm.select.UniformSelector; +import qilin.pta.PTAConfig; + +/* + * refer to "Pick Your Contexts Well: Understanding Object-Sensitivity" (PLDI'11) + * */ +public class TypeSensPTA extends BasePTA { + + public TypeSensPTA(int k, int hk) { + this.ctxCons = new TypeCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("k-type ..."); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java new file mode 100644 index 00000000000..dd06b534f69 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -0,0 +1,159 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.core.pag.*; +import qilin.parm.ctxcons.CtxConstructor; +import qilin.parm.heapabst.AllocSiteAbstractor; +import qilin.parm.heapabst.HeuristicAbstractor; +import qilin.parm.select.CtxSelector; +import qilin.parm.select.HeuristicSelector; +import qilin.parm.select.PartialMethodLvSelector; +import qilin.parm.select.PipelineSelector; +import qilin.pta.PTAConfig; +import qilin.pta.StagedPTA; +import qilin.pta.toolkits.zipper.Main; +import qilin.util.Stopwatch; +import soot.*; +import soot.jimple.*; +import soot.util.queue.QueueReader; + +import java.util.HashSet; +import java.util.Set; + +/* + * refer to "Precision-Guided Context Sensitivity for Pointer Analysis" (OOPSLA'18) + * and "A Principled Approach to Selective Context Sensitivity for Pointer Analysis" (TOPLAS'20) + * */ +public class ZipperPTA extends StagedPTA { + private final Set PCMs = new HashSet<>(); + + /* + * Zipper support object-sensitivity, callsite-sensitivity by using corresponding + * context-constructor. + * */ + public ZipperPTA(int k, int hk, CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new PartialMethodLvSelector(k, hk, PCMs); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + this.prePTA = new Spark(); + } + + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + Stopwatch zipperTimer = Stopwatch.newAndStart("Zipper"); + Main.run(prePTA, PCMs); + zipperTimer.stop(); + System.out.println(zipperTimer); + extraStats(); + } + + protected void extraStats() { + int[] RM = new int[1], PCN = new int[1], NPCN = new int[1]; + int[] totalN = new int[1]; + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + SootMethod method = momc.method(); + Set nodes = new HashSet<>(); + + if (method.isPhantom()) { + return; + } + MethodPAG srcmpag = pag.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + nodes.add(((VarNode) from).getVariable()); + } else if (from instanceof AllocNode) { + nodes.add(((AllocNode) from).getNewExpr()); + } else if (from instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + + if (to instanceof LocalVarNode) { + nodes.add(((VarNode) to).getVariable()); + } else if (to instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + } + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + InvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + continue; + } + nodes.add(arg); + } + + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + nodes.add(dest); + } + } + if (ie instanceof InstanceInvokeExpr iie) { + Value base = iie.getBase(); + if (base instanceof Local) { + nodes.add(base); + } + } + } + + if (PCMs.contains(method)) { + PCN[0] += nodes.size(); + } else { + NPCN[0] += nodes.size(); + } + RM[0]++; + + totalN[0] += nodes.size(); + } + RM[0]--; // For the FakeMain method. + System.out.println("#ReachableMethod:" + RM[0]); + System.out.println("#FCSM:" + PCMs.size()); + System.out.println("#PCSM:0"); + System.out.println("#CIM:" + (RM[0] - PCMs.size())); + System.out.println("#CIN: " + NPCN[0]); + System.out.println("#CSN: " + PCN[0]); + System.out.println("totalN: " + totalN[0]); + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/AbstractStat.java b/sootup.qilin/src/main/java/qilin/stat/AbstractStat.java new file mode 100644 index 00000000000..bafb994e668 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/AbstractStat.java @@ -0,0 +1,23 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +public interface AbstractStat { + void export(Exporter exporter); +} diff --git a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java new file mode 100644 index 00000000000..f8fb91bf805 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java @@ -0,0 +1,73 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.PTAScene; +import soot.SootClass; +import soot.SootMethod; + +import java.util.Set; +import java.util.stream.Collectors; + +public class BenchmarkStat implements AbstractStat { + private final PTA pta; + + private int classes = 0; + private int appClasses = 0; + private int phantomClasses = 0; + private int libClasses = 0; + private Set reachableClasses; + private Set reachableAppClasses; + int libReachableClasses = 0; + + public BenchmarkStat(PTA pta) { + this.pta = pta; + init(); + } + + private void init() { + reachableClasses = pta.getNakedReachableMethods().stream().map(SootMethod::getDeclaringClass) + .collect(Collectors.toSet()); + reachableAppClasses = reachableClasses.stream().filter(SootClass::isApplicationClass) + .collect(Collectors.toSet()); + + classes = PTAScene.v().getClasses().size(); + appClasses = PTAScene.v().getApplicationClasses().size(); + phantomClasses = PTAScene.v().getPhantomClasses().size(); + libClasses = classes - appClasses - phantomClasses; + libReachableClasses = (reachableClasses.size() - reachableAppClasses.size() - 1); // -FakeMain + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Class:", String.valueOf(classes)); + exporter.collectMetric("#Appclass:", String.valueOf(appClasses)); + exporter.collectMetric("#Libclass:", String.valueOf(libClasses)); + exporter.collectMetric("#Phantomclass:", String.valueOf(phantomClasses)); + exporter.collectMetric("#Class(reachable):", String.valueOf(reachableClasses.size())); + exporter.collectMetric("#Appclass(reachable):", String.valueOf(reachableAppClasses.size())); + exporter.collectMetric("#Libclass(reachable):", String.valueOf(libReachableClasses)); + + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpClassTypes(PTAScene.v().getClasses()); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java new file mode 100644 index 00000000000..cb30261f5dc --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -0,0 +1,198 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.builder.FakeMainFactory; +import qilin.core.pag.ContextVarNode; +import qilin.core.pag.LocalVarNode; +import soot.MethodOrMethodContext; +import soot.SootMethod; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class CallGraphStat implements AbstractStat { + private final PTA pta; + + private final Set reachableMethods = new HashSet<>(); + private int reachableStatic = 0; + private final Set reachableParameterizedMethods = new HashSet<>(); + private final Set reachableAppParameterizedMethods = new HashSet<>(); + private final Set reachableAppMethods = new HashSet<>(); + private int reachableAppStatic = 0; + private int CSCallEdges = 0; + private int CSStaticToStatic = 0; + private int CSStaticToInstance = 0; + private int CSInstanceToStatic = 0; + private int CSInstancetoInstance = 0; + private int CSApp2lib = 0; + private int CSApp2app = 0; + private int CSLib2lib = 0; + private int CSLib2app = 0; + private int CICallEdges = 0; + private int CIApp2lib = 0; + private int CIApp2app = 0; + private int CILib2lib = 0; + private int CILib2app = 0; + private int CIStaticToStatic = 0; + private int CIStaticToInstance = 0; + private int CIInstanceToStatic = 0; + private int CIInstancetoInstance = 0; + + public CallGraphStat(PTA pta) { + this.pta = pta; + init(); + } + + private void init() { + CallGraph csCallGraph = pta.getCgb().getCallGraph(); + CSCallEdges = csCallGraph.size(); + for (final MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + final SootMethod m = momc.method(); + boolean toApp = m.getDeclaringClass().isApplicationClass(); + reachableParameterizedMethods.add(momc); + reachableMethods.add(m); +// if (m.toString().equals("")) { +// System.out.println(PTAUtils.getMethodBody(m)); +// } + + if (toApp) { + reachableAppParameterizedMethods.add(momc); + reachableAppMethods.add(momc.method()); + } + + for (Iterator iterator = csCallGraph.edgesInto(momc); iterator.hasNext(); ) { + Edge e = iterator.next(); + final SootMethod srcm = e.getSrc().method(); + boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); + if (fromApp && toApp) { + CSApp2app++; + } else if (fromApp) { + CSApp2lib++; + } else if (!toApp) { + CSLib2lib++; + } else { + CSLib2app++; + } + if (e.src().isStatic()) { + if (e.isStatic()) { + CSStaticToStatic++; + } else { + CSStaticToInstance++; + } + } else if (e.isStatic()) { + CSInstanceToStatic++; + } else { + CSInstancetoInstance++; + } + } + } + CallGraph ciCallGraph = pta.getCallGraph(); + CICallEdges = ciCallGraph.size(); + for (SootMethod sm : reachableMethods) { + boolean toApp = sm.getDeclaringClass().isApplicationClass(); + if (sm.isStatic()) { + reachableStatic++; + if (toApp) { + reachableAppStatic++; + } + } + for (Iterator iterator = ciCallGraph.edgesInto(sm); iterator.hasNext(); ) { + Edge e = iterator.next(); + final SootMethod srcm = e.getSrc().method(); +// if (sm.toString().equals("")) { +// System.out.println("from:" + srcm); +// } + boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); + if (fromApp && toApp) { + CIApp2app++; + } else if (fromApp) { + CIApp2lib++; + } else if (!toApp) { + CILib2lib++; + } else { + CILib2app++; + } + + if (e.src().isStatic()) { + if (e.isStatic()) { + CIStaticToStatic++; + } else { + CIStaticToInstance++; + } + } else if (e.isStatic()) { + CIInstanceToStatic++; + } else { + CIInstancetoInstance++; + } + } + } + } + + private long thisReceiverCount() { + return pta.getCgb().getReceiverToSitesMap().entrySet().stream() + .filter(e -> e.getKey() instanceof ContextVarNode) + .filter(e -> e.getKey().base() instanceof LocalVarNode) + .filter(e -> ((LocalVarNode) e.getKey().base()).isThis()).count(); + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Method (Static):", String.valueOf(PTAScene.v().getMethodNumberer().size() - 1));// -fakeMain + exporter.collectMetric("#Reachable Method (CI):", String.valueOf(reachableMethods.size() - 1));// -fakeMain + exporter.collectMetric("\t#Reachable-Static Method (CI):", String.valueOf(reachableStatic - 1));// -fakeMain + exporter.collectMetric("#Reachable Method (CS):", String.valueOf(reachableParameterizedMethods.size() - 1));// -fakeMain + exporter.collectMetric("#Reachable App Method (CI):", String.valueOf(reachableAppMethods.size())); + exporter.collectMetric("\t#Reachable-App-Static Method (CI):", String.valueOf(reachableAppStatic)); + exporter.collectMetric("#Reachable App Method (CS):", String.valueOf(reachableAppParameterizedMethods.size())); + exporter.collectMetric("#Call Edge(CI):", String.valueOf(CICallEdges - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("\t#Static-Static Call Edge(CI):", String.valueOf(CIStaticToStatic - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("\t#Static-Instance Call Edge(CI):", String.valueOf(CIStaticToInstance)); + exporter.collectMetric("\t#Instance-Static Call Edge(CI):", String.valueOf(CIInstanceToStatic)); + exporter.collectMetric("\t#Instance-Instance Call Edge(CI):", String.valueOf(CIInstancetoInstance)); + exporter.collectMetric("\t#Application-Application Call Edge(CI):", String.valueOf(CIApp2app)); + exporter.collectMetric("\t#Application-Library Call Edge(CI):", String.valueOf(CIApp2lib)); + exporter.collectMetric("\t#Library-Application Call Edge(CI):", String.valueOf(CILib2app)); + exporter.collectMetric("\t#Library-Library Call Edge(CI):", String.valueOf(CILib2lib)); + exporter.collectMetric("#Call Edge(CS):", String.valueOf(CSCallEdges - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("\t#Static-Static Call Edge(CS):", String.valueOf(CSStaticToStatic - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("\t#Static-Instance Call Edge(CS):", String.valueOf(CSStaticToInstance)); + exporter.collectMetric("\t#Instance-Static Call Edge(CS):", String.valueOf(CSInstanceToStatic)); + exporter.collectMetric("\t#Instance-Instance Call Edge(CS):", String.valueOf(CSInstancetoInstance)); + exporter.collectMetric("\t#Application-Application Call Edge(CS):", String.valueOf(CSApp2app)); + exporter.collectMetric("\t#Application-Library Call Edge(CS):", String.valueOf(CSApp2lib)); + exporter.collectMetric("\t#Library-Application Call Edge(CS):", String.valueOf(CSLib2app)); + exporter.collectMetric("\t#Library-Library Call Edge(CS):", String.valueOf(CSLib2lib)); + exporter.collectMetric("#receivers:", String.valueOf(pta.getCgb().getReceiverToSitesMap().size())); + exporter.collectMetric("\t#thisreceivers:", String.valueOf(thisReceiverCount())); + exporter.collectMetric("#avg p2s size for virtualcalls:", String.valueOf((CSCallEdges - CSStaticToStatic - CSInstanceToStatic) + * 1.0 / pta.getCgb().getReceiverToSitesMap().size())); + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpReachableMethods(reachableMethods); + exporter.dumpAppReachableMethods(reachableAppMethods); + exporter.dumpInsensCallGraph(pta.getCallGraph()); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java new file mode 100644 index 00000000000..ad206904c8e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -0,0 +1,296 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.Parm; +import qilin.core.sets.PointsToSet; +import qilin.util.Util; +import soot.SootClass; +import soot.SootMethod; +import soot.Type; +import soot.jimple.AssignStmt; +import soot.jimple.CastExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.*; + +public class Exporter { + private final String metrics = "Metrics.csv"; + private final String staticFPTs = "StaticFieldPointsTo.csv"; + + private static final int STATLENGTH = 50; + private final StringBuffer report = new StringBuffer(); + + public void addLine(String str) { + report.append(str).append('\n'); + } + + private String makeUp(String string) { + final String makeUpString = " "; + String tmp = ""; + for (int i = 0; i < Math.max(0, STATLENGTH - string.length()); ++i) { + tmp = tmp.concat(makeUpString); + } +// StringBuilder ret = new StringBuilder(); +// ret.append(makeUpString.repeat(Math.max(0, STATLENGTH - string.length()))); + return string + tmp; + } + + public void collectMetric(String desc, String value) { + addLine(makeUp(desc) + value); + } + + private String getFilePath(String fileName) { + String finalPath = CoreConfig.v().getOutConfig().outDir; + finalPath = finalPath + File.separator + CoreConfig.v().getAppConfig().MAIN_CLASS + File.separator + CoreConfig.v().getPtaConfig().ptaName + File.separator; + File file = new File(finalPath); + if (!file.exists()) { + file.mkdirs(); + } + finalPath = finalPath + fileName; + return finalPath; + } + + private void dumpMethods(Collection methods, String fileName) { + StringBuilder builder = new StringBuilder(); + for (SootMethod sm : methods) { + String sig = sm.getSignature(); + sig = Util.stripQuotes(sig); + builder.append(sig); + builder.append("\n"); + } + String finalPath = getFilePath(fileName); + Util.writeToFile(finalPath, builder.toString()); + } + + public void dumpReachableMethods(Collection reachables) { + String reachMethods = "Reachable.csv"; + dumpMethods(reachables, reachMethods); + } + + public void dumpAppReachableMethods(Collection appReachables) { + String appReachMethods = "AppReachable.csv"; + dumpMethods(appReachables, appReachMethods); + } + + public void dumpSingleCallMethods(Collection singleCallMs) { + String singleCalls = "SingleCallMethods.csv"; + dumpMethods(singleCallMs, singleCalls); + } + + public void dumpSingleReceiverMethods(Collection singleReceiverMs) { + String singleReceivers = "SingleReceiverMethods.csv"; + dumpMethods(singleReceiverMs, singleReceivers); + } + + public void dumpSingleCallSingleReceiverMethods(Collection singleCallSingleReceiverMs) { + String singleCallSingleReceivers = "SingleCallSingleReceiverMethods.csv"; + dumpMethods(singleCallSingleReceiverMs, singleCallSingleReceivers); + } + + public void dumpClassTypes(Collection classes) { + StringBuilder builder = new StringBuilder(); + for (SootClass sc : classes) { + builder.append(sc.getName()); + builder.append("\n"); + } + String classTypes = "ClassType.csv"; + String finalPath = getFilePath(classTypes); + Util.writeToFile(finalPath, builder.toString()); + } + + public void dumpPolyCalls(Map polys) { + StringBuilder builder = new StringBuilder(); + for (InvokeExpr ie : polys.keySet()) { + SootMethod tgt = ie.getMethod(); + String polySig = polys.get(ie).getSignature() + "/" + tgt.getDeclaringClass() + "." + tgt.getName() + "\n"; + builder.append(polySig); + } + String polyCalls = "PolyCalls.csv"; + String finalPath = getFilePath(polyCalls); + Util.writeToFile(finalPath, builder.toString()); + } + + public void dumpMayFailCasts(Map> casts) { + StringBuilder builder = new StringBuilder(); + for (SootMethod sm : casts.keySet()) { + for (Stmt stmt : casts.get(sm)) { + AssignStmt as = (AssignStmt) stmt; + CastExpr ce = (CastExpr) as.getRightOp(); + final Type targetType = ce.getCastType(); + builder.append(sm.toString()); + builder.append("\t"); + builder.append(targetType.toString()); + builder.append("\t"); + builder.append(sm).append("/").append(ce.getOp().toString()); + builder.append("\t"); + builder.append(sm).append("/").append(as.getLeftOp().toString()); + builder.append("\n"); + } + } + String mayFailCasts = "MayFailCasts.csv"; + String finalPath = getFilePath(mayFailCasts); + Util.writeToFile(finalPath, builder.toString()); + } + + public void dumpMethodThrowPointsto(Map m2pts) { + String methodThrowPts = "MethodThrowPointsTo.csv"; + String finalPath = getFilePath(methodThrowPts); + try { + File mfile = new File(finalPath); + mfile.delete(); + mfile.createNewFile(); + BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); + for (SootMethod sm : m2pts.keySet()) { + PointsToSet pts = m2pts.get(sm).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + StringBuilder builder = new StringBuilder(); + builder.append(n.toString()); + builder.append("\t"); + String sig = Util.stripQuotes(sm.getSignature()); + builder.append(sig); + builder.append("\n"); + try { + writer.write(builder.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + writer.flush(); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void dumpInsensCallGraph(CallGraph ciCallGraph) { + String insensCallGraphEdges = "InsensCallGraphEdges.csv"; + String finalPath = getFilePath(insensCallGraphEdges); + try { + File mfile = new File(finalPath); + mfile.delete(); + mfile.createNewFile(); + BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); + for (Edge edge : ciCallGraph) { + String srcSig = Util.stripQuotes(edge.src().getSignature()); + String dstSig = Util.stripQuotes(edge.tgt().getSignature()); + String str = edge.srcStmt() + " in method " + srcSig + "\t" + dstSig + "\n"; + writer.write(str); + } + writer.flush(); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void dumpReachableLocalVars(Collection lvns) { + StringBuilder builder = new StringBuilder(); + for (LocalVarNode lvn : lvns) { + String varName = getDoopVarName(lvn); + builder.append(varName).append("\n"); + } + String insensReachVars = "InsensReachVars.csv"; + String finalPath = getFilePath(insensReachVars); + Util.writeToFile(finalPath, builder.toString()); + } + + public void dumpReachableLocalVarsNoNative(Collection lvns) { + StringBuilder builder = new StringBuilder(); + for (LocalVarNode lvn : lvns) { + String varName = getDoopVarName(lvn); + builder.append(varName).append("\n"); + } + String insensReachVars = "InsensReachVarsNoNatives.csv"; + String finalPath = getFilePath(insensReachVars); + Util.writeToFile(finalPath, builder.toString()); + } + + private String getDoopVarName(LocalVarNode lvn) { + SootMethod m = lvn.getMethod(); + Object v = lvn.getVariable(); + String varName = v.toString(); + if (v instanceof Parm parm) { + if (parm.isThis()) { + varName = "@this"; + } else if (parm.isReturn()) { + + } else if (parm.isThrowRet()) { + + } else { + varName = "@parameter" + parm.getIndex(); + } + } + return m.getSignature() + "/" + varName; + } + + public void dumpInsensPointsTo(Collection lvns, PTA pta) { + String insensVarPTs = "InsensVarPointsTo.csv"; + String finalPath = getFilePath(insensVarPTs); + try { + File mfile = new File(finalPath); + mfile.delete(); + mfile.createNewFile(); + BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); + for (LocalVarNode lvn : lvns) { + String varName = getDoopVarName(lvn); + final Set callocSites = new HashSet<>(); + PointsToSet cpts = pta.reachingObjects(lvn).toCIPointsToSet(); + for (Iterator it = cpts.iterator(); it.hasNext(); ) { + AllocNode heap = it.next(); + callocSites.add(heap); + } + for (AllocNode heap : callocSites) { + String str = heap.getNewExpr() + "\t" + varName + "\n"; + if (heap.getMethod() != null) { + str = heap.getMethod() + "/" + heap.getNewExpr() + "\t" + varName + "\n"; + } + writer.write(str); + } + } + writer.flush(); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String report() { + String tmp = report.toString(); + if (CoreConfig.v().getOutConfig().dumpStats) { + String statistics = "Statistics.txt"; + String finalPath = getFilePath(statistics); + Util.writeToFile(finalPath, tmp); + } + return tmp; + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java new file mode 100644 index 00000000000..dc69afbb9d8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java @@ -0,0 +1,9 @@ +package qilin.stat; + +public interface IEvaluator { + int GB = 1024 * 1024 * 1024; + + void begin(); + + void end(); +} diff --git a/sootup.qilin/src/main/java/qilin/stat/PAGStat.java b/sootup.qilin/src/main/java/qilin/stat/PAGStat.java new file mode 100644 index 00000000000..d2989a25dcd --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/PAGStat.java @@ -0,0 +1,80 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.core.PTA; +import qilin.core.pag.*; + +import java.util.Map; +import java.util.Set; + +public class PAGStat implements AbstractStat { + private final PTA pta; + private final PAG pag; + + private int newEdges = 0; // v = new O; + private int simpleEdges = 0; // include assign, global_assign, and o.f assign. + private int hloadEdges = 0; // v = o.f; + private int hstoreEdges = 0; // o.f = v; + private int storeEdges = 0; // v.f = v; + private int loadEdges = 0; // v = v.f; + + public PAGStat(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + init(); + } + + private void init() { + for (Set s : pag.getAlloc().values()) { + newEdges += s.size(); + } + for (Map.Entry> e : pag.getSimple().entrySet()) { + Set tagets = e.getValue(); + int nt = tagets.size(); + simpleEdges += nt; + if (e.getKey() instanceof ContextField) { + hloadEdges += nt; + } else { + for (ValNode v : tagets) { + if (v instanceof ContextField) { + hstoreEdges++; + } + } + } + } + for (Map.Entry> s : pag.getStoreInv().entrySet()) { + storeEdges += s.getValue().size(); + } + for (Map.Entry> s : pag.getLoad().entrySet()) { + loadEdges += s.getValue().size(); + } + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Alloc-pag-edge:", String.valueOf(newEdges)); + exporter.collectMetric("#Simple-pag-edge:", String.valueOf(simpleEdges)); + exporter.collectMetric("\t#Local-to-Local:", String.valueOf((simpleEdges - hloadEdges - hstoreEdges))); + exporter.collectMetric("\t#Field-to-Local:", String.valueOf(hloadEdges)); + exporter.collectMetric("\t#Local-to-Field:", String.valueOf(hstoreEdges)); + exporter.collectMetric("#Store-pag-edge:", String.valueOf(storeEdges)); + exporter.collectMetric("#Load-pag-edge:", String.valueOf(loadEdges)); + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java new file mode 100644 index 00000000000..d19a9131657 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java @@ -0,0 +1,113 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.CoreConfig; +import qilin.core.PTA; + +/** + * Gather stats on the performance and precision of a PTA run. + *

+ * Each new run of the PTA will over-write stats + *

+ * - Wall time (sec) - Memory (max, current) before and after - Reachable + * methods (context and no-context) - Total reachable casts - Reachable casts + * that may fail - Call graph edges - Context sensitive call graph edges - Total + * reachable virtual call sites - Polymorphic virtual call sites (sites with >1 + * target methods) - Number of pointers (local and global) - Total points to + * sets size (local and global) context insensitive (convert to alloc site) + */ +public class PTAEvaluator implements IEvaluator { + protected final RuntimeStat runtimeStat; + protected final Exporter exporter; + protected final PTA pta; + + public PTAEvaluator(PTA pta) { + this.pta = pta; + runtimeStat = new RuntimeStat(); + exporter = new Exporter(); + } + + /** + * Note the start of a qilin.pta run. + */ + @Override + public void begin() { + Runtime runtime = Runtime.getRuntime();// Getting the runtime reference + // from system + exporter.addLine(" ====== Memory Usage ======"); + exporter.collectMetric("Used Memory Before:", (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB");// Print + // used memory + exporter.collectMetric("Free Memory Before:", runtime.freeMemory() / GB + " GB");// Print free memory + exporter.collectMetric("Total Memory Before:", runtime.totalMemory() / GB + " GB");// Print total available memory + exporter.collectMetric("Max Memory Before:", runtime.maxMemory() / GB + " GB");// Print Maximum available memory + exporter.collectMetric("Analysis: ", CoreConfig.v().getPtaConfig().ptaName); + runtimeStat.begin(); + } + + protected PointsToStat createPointsToStat() { + return new PointsToStat(pta); + } + + /** + * Note the end of a qilin.pta run. + */ + @Override + public void end() { + // done with processing + runtimeStat.end(); + /** + * all method reachable from the harness main + */ + PAGStat pagStat = new PAGStat(pta); + BenchmarkStat benchmarkStat = new BenchmarkStat(pta); + CallGraphStat callGraphStat = new CallGraphStat(pta); + TypeClientStat typeClientStat = new TypeClientStat(pta); + PointsToStat ptsStat = createPointsToStat(); + YummyStat yummyStat = new YummyStat(pta); + runtimeStat.export(exporter); + // memory stats + Runtime runtime = Runtime.getRuntime();// Getting the runtime reference + // from system + exporter.collectMetric("Used Memory After:", (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB");// Print + // used memory + exporter.collectMetric("Free Memory After:", runtime.freeMemory() / GB + " GB");// Print free memory + exporter.collectMetric("Total Memory After:", runtime.totalMemory() / GB + " GB");// Print total available memory + exporter.collectMetric("Max Memory After:", runtime.maxMemory() / GB + " GB");// Print Maximum available memory + exporter.addLine(" ====== Yummy ======"); + yummyStat.export(exporter); + exporter.addLine(" ====== Call Graph ======"); + callGraphStat.export(exporter); + exporter.addLine(" ====== Statements ======"); + typeClientStat.export(exporter); + exporter.addLine(" ====== Nodes ======"); + ptsStat.export(exporter); + exporter.addLine(" ====== Assignments ======"); + pagStat.export(exporter); + exporter.addLine(" ====== Classes ======"); + benchmarkStat.export(exporter); + + } + + @Override + public String toString() { + return exporter.report(); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java new file mode 100644 index 00000000000..3ff9a9d5459 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -0,0 +1,293 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; +import soot.*; + +import java.util.*; + +public class PointsToStat implements AbstractStat { + private final PTA pta; + private final PAG pag; + private int contextCnt = 0; + private double avgCtxPerMthd = 0.0; + + private int ciAllocs = 0; + private int csAllocs = 0; + private int totalGlobalPointers = 0; + private int totalGlobalPointsToCi = 0; + private int totalGlobalPointsToCs = 0; + private int appGlobalPointers = 0; + private int appGlobalPointsToCi = 0; + private int appGlobalPointsToCs = 0; + private int totalLocalPointersCi = 0; + private int totalLocalPointersCs = 0; + private int totalLocalCiToCi = 0; + private int totalLocalCiToCs = 0; + private int totalLocalCsToCi = 0; + private int totalLocalCsToCs = 0; + private int appLocalPointersCi = 0; + private int appLocalPointersCs = 0; + private int appLocalCiToCi = 0; + private int appLocalCiToCs = 0; + private int appLocalCsToCi = 0; + private int appLocalCsToCs = 0; + private int totalFieldPointsToCs = 0; + private int methodThrowCnt = 0; + + private final Map methodThrowPts; + private final Set mLocalVarNodes = new HashSet<>(); + private int ptsCnt = 0; + private int varCnt = 0; + private final Set mLocalVarNodesNoNative = new HashSet<>(); + private int ptsCntNoNative = 0; + private int varCntNoNative = 0; + + public PointsToStat(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + methodThrowPts = new HashMap<>(); + init(); + } + + private final Set handledNatives = Set.of( + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ); + + protected Set getPointsToNewExpr(PointsToSet pts) { + final Set allocSites = new HashSet<>(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + allocSites.add(n.getNewExpr()); + } + return allocSites; + } + + private void init() { + ciAllocs = pag.getAllocNodes().size(); + csAllocs = pag.getAlloc().keySet().size(); + // globals + for (SootField global : pag.getGlobalPointers()) { + try { + if (!global.isStatic()) + continue; + GlobalVarNode gvn = pag.findGlobalVarNode(global); + boolean app = gvn.getDeclaringClass().isApplicationClass(); + + totalGlobalPointers++; + if (app) { + appGlobalPointers++; + } + + PointsToSet pts = pta.reachingObjects(gvn); + final Set allocSites = getPointsToNewExpr(pts); + + totalGlobalPointsToCi += allocSites.size(); + totalGlobalPointsToCs += pts.size(); + if (app) { + appGlobalPointsToCi += allocSites.size(); + appGlobalPointsToCs += pts.size(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + // locals exclude Exceptions + for (Local local : pag.getLocalPointers()) { + try { + Collection varNodes = pag.getVarNodes(local); + LocalVarNode lvn = pag.findLocalVarNode(local); + if (local.toString().contains("intermediate/")) { + continue; + } + mLocalVarNodes.add(lvn); + if (!handledNatives.contains(lvn.getMethod().toString())) { + mLocalVarNodesNoNative.add(lvn); + } + boolean app = lvn.getMethod().getDeclaringClass().isApplicationClass(); + totalLocalPointersCi++; + if (app) { + appLocalPointersCi++; + } + + totalLocalPointersCs += varNodes.size(); + if (app) { + appLocalPointersCs += varNodes.size(); + } + + PointsToSet pts = pta.reachingObjects(local); + final Set allocSites = getPointsToNewExpr(pts); + + totalLocalCiToCi += allocSites.size(); + totalLocalCiToCs += pts.size(); + if (app) { + appLocalCiToCi += allocSites.size(); + appLocalCiToCs += pts.size(); + } + + for (VarNode cvn : varNodes) { + PointsToSet cpts = pta.reachingObjects(cvn); + final Set callocSites = getPointsToNewExpr(cpts); + totalLocalCsToCi += callocSites.size(); + totalLocalCsToCs += cpts.size(); + if (app) { + appLocalCsToCi += callocSites.size(); + appLocalCsToCs += cpts.size(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // field points-to + for (ContextField cfvn : pag.getContextFields()) { + totalFieldPointsToCs += cfvn.getP2Set().size(); + } + + // stat context. + Map> mpag2contexts = pag.getMethod2ContextsMap(); + int[] cnts = new int[2]; + mpag2contexts.forEach((k, v) -> { + cnts[0]++; + cnts[1] += v.size(); + }); + contextCnt = cnts[1]; + avgCtxPerMthd = cnts[1] * 1.0 / cnts[0]; + + // stat method throw points-to. + for (SootMethod sm : pta.getNakedReachableMethods()) { + Node mThrow = pag.getMethodPAG(sm).nodeFactory().caseMethodThrow(); + PointsToSet pts = pta.reachingObjects(mThrow); + if (!pts.isEmpty()) { + methodThrowCnt++; + methodThrowPts.put(sm, pts); + } + } + + // stat avg pts. + for (SootMethod sm : pta.getNakedReachableMethods()) { + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory mnf = mpag.nodeFactory(); + if (!sm.isStatic()) { + mLocalVarNodes.add((LocalVarNode) mnf.caseThis()); + if (!handledNatives.contains(sm.toString())) { + mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseThis()); + } + } + for (int i = 0; i < sm.getParameterCount(); ++i) { + Type mType = sm.getParameterType(i); + if (mType instanceof RefLikeType) { + mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); + if (!handledNatives.contains(sm.toString())) { + mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseParm(i)); + } + } + } + } + Set tmp = new HashSet<>(); + for (LocalVarNode lvn : mLocalVarNodes) { + SootMethod sm = lvn.getMethod(); + if (PTAUtils.isFakeMainMethod(sm)) { + tmp.add(lvn); + continue; + } + PointsToSet cpts = pta.reachingObjects(lvn); + final Set callocSites = getPointsToNewExpr(cpts); + if (callocSites.size() > 0) { + ptsCnt += callocSites.size(); + varCnt++; + if (!handledNatives.contains(sm.toString())) { + ptsCntNoNative += callocSites.size(); + varCntNoNative++; + } + } else { + tmp.add(lvn); + } + } + mLocalVarNodes.removeAll(tmp); + mLocalVarNodesNoNative.removeAll(tmp); + System.out.println("PTS relation:" + ptsCnt); + System.out.println("VAR CNT:" + varCnt); + System.out.println("AVG PTS: " + (ptsCnt * 1.0 / varCnt)); + System.out.println("PTS relation (no native):" + ptsCntNoNative); + System.out.println("VAR CNT (no native):" + varCntNoNative); + System.out.println("AVG PTS (no native): " + (ptsCntNoNative * 1.0 / varCntNoNative)); + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Context:", String.valueOf(contextCnt)); + exporter.collectMetric("#Avg Context per Method:", String.valueOf(avgCtxPerMthd)); + exporter.collectMetric("#Method with Throw Pointer-to:", String.valueOf(methodThrowCnt)); + + exporter.collectMetric("#Alloc Node(CI): ", String.valueOf(ciAllocs)); + exporter.collectMetric("#Alloc Node(CS): ", String.valueOf(csAllocs)); + + exporter.collectMetric("#Global CS Pointer-to Relation:", String.valueOf(totalGlobalPointsToCs)); + exporter.collectMetric("#Local CS Pointer-to Relation:", String.valueOf(totalLocalCsToCs)); + exporter.collectMetric("#Field CS Pointer-to Relation:", String.valueOf(totalFieldPointsToCs)); + + exporter.collectMetric("#Global Pointer (lib + app):", String.valueOf(totalGlobalPointers)); + exporter.collectMetric("#Global Avg Points-To Target(CI):", String.valueOf(((double) totalGlobalPointsToCi) / ((double) totalGlobalPointers))); + exporter.collectMetric("#Global Avg Points-To Target(CS):", String.valueOf(((double) totalGlobalPointsToCs) / ((double) totalGlobalPointers))); + exporter.collectMetric("#App Global Pointer:", String.valueOf(appGlobalPointers)); + exporter.collectMetric("#App Global Avg Points-To Target(CI):", String.valueOf(((double) appGlobalPointsToCi) / ((double) appGlobalPointers))); + exporter.collectMetric("#App Global Avg Points-To Target(CS):", String.valueOf(((double) appGlobalPointsToCs) / ((double) appGlobalPointers))); + exporter.collectMetric("#Avg Points-to Target(CI):", String.valueOf(((double) ptsCnt) / (varCnt))); + exporter.collectMetric("#Avg Points-to Target without Native Var(CI):", String.valueOf(((double) ptsCntNoNative) / (varCntNoNative))); + exporter.collectMetric("#Local Pointer (lib + app):", String.valueOf(totalLocalPointersCi)); + exporter.collectMetric("#Local Avg Points-To Target(CI):", String.valueOf(((double) totalLocalCiToCi) / ((double) totalLocalPointersCi))); + exporter.collectMetric("#Local Avg Points-To Target(CS):", String.valueOf(((double) totalLocalCiToCs) / ((double) totalLocalPointersCi))); + exporter.collectMetric("#App Local Pointer:", String.valueOf(appLocalPointersCi)); + exporter.collectMetric("#App Local Avg Points-To Target(CI):", String.valueOf(((double) appLocalCiToCi) / ((double) appLocalPointersCi))); + exporter.collectMetric("#App Local Avg Points-To Target(CS):", String.valueOf(((double) appLocalCiToCs) / ((double) appLocalPointersCi))); + exporter.collectMetric("#Context Local Pointer (lib + app):", String.valueOf(totalLocalPointersCs)); + exporter.collectMetric("#Context Local Avg Points-To Target(CI):", String.valueOf(((double) totalLocalCsToCi) / ((double) totalLocalPointersCs))); + exporter.collectMetric("#Context Local Avg Points-To Target(CS):", String.valueOf(((double) totalLocalCsToCs) / ((double) totalLocalPointersCs))); + exporter.collectMetric("#App Context Local Pointer:", String.valueOf(appLocalPointersCs)); + exporter.collectMetric("#App Context Local Avg Points-To Target(CI):", String.valueOf(((double) appLocalCsToCi) / ((double) appLocalPointersCs))); + exporter.collectMetric("#App Context Local Avg Points-To Target(CS):", String.valueOf(((double) appLocalCsToCs) / ((double) appLocalPointersCs))); + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpMethodThrowPointsto(methodThrowPts); + exporter.dumpReachableLocalVars(mLocalVarNodes); + exporter.dumpReachableLocalVarsNoNative(mLocalVarNodesNoNative); + exporter.dumpInsensPointsTo(mLocalVarNodes, pta); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java b/sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java new file mode 100644 index 00000000000..4aa963a0ea7 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import java.util.Date; + +public class RuntimeStat implements AbstractStat { + private Date startTime; + private long elapsedTime; + + public void begin() { + startTime = new Date(); + } + + public void end() { + Date endTime = new Date(); + elapsedTime = endTime.getTime() - startTime.getTime(); + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("Time (sec):", String.valueOf(((double) elapsedTime) / 1000.0)); + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java new file mode 100644 index 00000000000..ea56dcd1ed6 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -0,0 +1,183 @@ +package qilin.stat; + +import qilin.core.PTA; +import qilin.core.builder.FakeMainFactory; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; +import qilin.util.Stopwatch; +import soot.*; +import soot.jimple.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; + +import java.util.*; + +public class SimplifiedEvaluator implements IEvaluator { + protected final PTA pta; + protected final Exporter exporter; + protected Stopwatch stopwatch; + + public SimplifiedEvaluator(PTA pta) { + this.pta = pta; + exporter = new Exporter(); + } + + @Override + public void begin() { + stopwatch = Stopwatch.newAndStart("PTA evaluator"); + } + + @Override + public void end() { + stopwatch.stop(); + exporter.collectMetric("Time (sec):", String.valueOf(((double) stopwatch.elapsed()))); + exporter.collectMetric("#Reachable Method (CI):", String.valueOf(pta.getNakedReachableMethods().size() - 1)); + CallGraph ciCallGraph = pta.getCallGraph(); + exporter.collectMetric("#Call Edge(CI):", String.valueOf(ciCallGraph.size() - FakeMainFactory.implicitCallEdges)); + + CallGraph callGraph = pta.getCallGraph(); + + // loop over all reachable method's statement to find casts, local + // references, virtual call sites + Set reachableMethods = new HashSet<>(); + for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + final SootMethod sm = momc.method(); + reachableMethods.add(sm); + } + int totalPolyCalls = 0; + int totalCastsMayFail = 0; + for (SootMethod sm : reachableMethods) { + // All the statements in the method + for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { + Stmt st = (Stmt) unit; + // virtual calls + if (st.containsInvokeExpr()) { + InvokeExpr ie = st.getInvokeExpr(); + if (!(ie instanceof StaticInvokeExpr)) { + // Virtual, Special or Instance + // have to check target soot method, cannot just + // count edges + Set targets = new HashSet<>(); + for (Iterator it = callGraph.edgesOutOf(st); it.hasNext(); ) + targets.add(it.next().tgt()); + if (targets.size() > 1) { + totalPolyCalls++; + } + } + } else if (st instanceof AssignStmt) { + Value rhs = ((AssignStmt) st).getRightOp(); + Value lhs = ((AssignStmt) st).getLeftOp(); + if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { + final Type targetType = ((CastExpr) rhs).getCastType(); + Value v = ((CastExpr) rhs).getOp(); + if (!(v instanceof Local)) { + continue; + } + boolean fails = false; + Collection pts = pta.reachingObjects((Local) v).toCollection(); + for (Node n : pts) { + if (fails) { + break; + } + fails = !PTAUtils.castNeverFails(n.getType(), targetType); + } + if (fails) { + totalCastsMayFail++; + } + } + } + } + } + exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail)); + exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls)); + + ptsStat(); + } + + private void ptsStat() { + int ptsCntNoNative = 0; + int varCntNoNative = 0; + PAG pag = pta.getPag(); + // locals exclude Exceptions + for (Local local : pag.getLocalPointers()) { + try { + LocalVarNode lvn = pag.findLocalVarNode(local); + if (local.toString().contains("intermediate/")) { + continue; + } + mLocalVarNodes.add(lvn); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // stat avg pts. + for (SootMethod sm : pta.getNakedReachableMethods()) { + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory mnf = mpag.nodeFactory(); + if (!sm.isStatic()) { + mLocalVarNodes.add((LocalVarNode) mnf.caseThis()); + } + for (int i = 0; i < sm.getParameterCount(); ++i) { + Type mType = sm.getParameterType(i); + if (mType instanceof RefLikeType) { + mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); + } + } + } + Set tmp = new HashSet<>(); + for (LocalVarNode lvn : mLocalVarNodes) { + SootMethod sm = lvn.getMethod(); + if (PTAUtils.isFakeMainMethod(sm)) { + tmp.add(lvn); + continue; + } + final Set callocSites = getPointsToNewExpr(pta.reachingObjects(lvn)); + if (callocSites.size() > 0) { + if (!handledNatives.contains(sm.toString())) { + ptsCntNoNative += callocSites.size(); + varCntNoNative++; + } + } else { + tmp.add(lvn); + } + } + mLocalVarNodes.removeAll(tmp); + + exporter.collectMetric("#Avg Points-to Target without Native Var(CI):", String.valueOf(((double) ptsCntNoNative) / (varCntNoNative))); + } + + private final Set handledNatives = Set.of( + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ); + + private final Set mLocalVarNodes = new HashSet<>(); + + protected Set getPointsToNewExpr(PointsToSet pts) { + final Set allocSites = new HashSet<>(); + for (AllocNode n : pts.toCollection()) { + allocSites.add(n.getNewExpr()); + } + return allocSites; + } + + @Override + public String toString() { + return exporter.report(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java new file mode 100644 index 00000000000..4386eca2762 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -0,0 +1,155 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.builder.FakeMainFactory; +import qilin.core.pag.AllocNode; +import qilin.util.PTAUtils; +import soot.*; +import soot.jimple.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; + +import java.util.*; + +public class TypeClientStat implements AbstractStat { + private final PTA pta; + + private int totalCasts = 0; + private int appCasts = 0; + private int totalCastsMayFail = 0; + private int appCastsMayFail = 0; + private int totalVirtualCalls = 0; + private int appVirtualCalls = 0; + private int totalPolyCalls = 0; + private int appPolyCalls = 0; + private int totalStaticCalls = 0; + private int totalPolyCallTargets = 0; + private int unreachable = 0; + private final Map polyCalls = new HashMap<>(); + private final Map> mayFailCasts = new HashMap<>(); + + public TypeClientStat(PTA pta) { + this.pta = pta; + init(); + } + + private void init() { + CallGraph callGraph = pta.getCallGraph(); + + // loop over all reachable method's statement to find casts, local + // references, virtual call sites + Set reachableMethods = new HashSet<>(); + for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + final SootMethod sm = momc.method(); + reachableMethods.add(sm); + } + + for (SootMethod sm : reachableMethods) { + boolean app = sm.getDeclaringClass().isApplicationClass(); + + // All the statements in the method + for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { + Stmt st = (Stmt) unit; + + // virtual calls + if (st.containsInvokeExpr()) { + InvokeExpr ie = st.getInvokeExpr(); + if (ie instanceof StaticInvokeExpr) { + totalStaticCalls++; + } else {// Virtual, Special or Instance + totalVirtualCalls++; + if (app) { + appVirtualCalls++; + } + // have to check target soot method, cannot just + // count edges + Set targets = new HashSet<>(); + + for (Iterator it = callGraph.edgesOutOf(st); it.hasNext(); ) + targets.add(it.next().tgt()); + if (targets.size() == 0) { + unreachable++; + } + if (targets.size() > 1) { + totalPolyCallTargets += targets.size(); + totalPolyCalls++; + polyCalls.put(ie, sm); + if (app) { + appPolyCalls++; + } + } + } + } else if (st instanceof AssignStmt) { + Value rhs = ((AssignStmt) st).getRightOp(); + Value lhs = ((AssignStmt) st).getLeftOp(); + if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { + final Type targetType = ((CastExpr) rhs).getCastType(); + Value v = ((CastExpr) rhs).getOp(); + if (!(v instanceof Local)) { + continue; + } + totalCasts++; + if (app) { + appCasts++; + } + boolean fails = false; + Collection pts = pta.reachingObjects((Local) v).toCollection(); + for (AllocNode n : pts) { + if (fails) { + break; + } + fails = !PTAUtils.castNeverFails(n.getType(), targetType); + } + + if (fails) { + totalCastsMayFail++; + mayFailCasts.computeIfAbsent(sm, k -> new HashSet<>()).add(st); + if (app) { + appCastsMayFail++; + } + } + } + } + } + } + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Cast (Total):", String.valueOf(totalCasts)); + exporter.collectMetric("#Cast (AppOnly):", String.valueOf(appCasts)); + exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail)); + exporter.collectMetric("#May Fail Cast (AppOnly):", String.valueOf(appCastsMayFail)); + exporter.collectMetric("#Static Call Site(Total):", String.valueOf(totalStaticCalls - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("#Virtual Call Site(Total):", String.valueOf(totalVirtualCalls)); + exporter.collectMetric("#Virtual Call Site(AppOnly):", String.valueOf(appVirtualCalls)); + exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls)); + exporter.collectMetric("#Virtual Call Site(Polymorphic AppOnly):", String.valueOf(appPolyCalls)); + exporter.collectMetric("#Virtual Call Site(Unreachable):", String.valueOf(unreachable)); + exporter.collectMetric("#Avg Poly Call Targets:", String.valueOf(1.0 * totalPolyCallTargets / totalPolyCalls)); + + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpPolyCalls(polyCalls); + exporter.dumpMayFailCasts(mayFailCasts); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java new file mode 100644 index 00000000000..040caedfe1f --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -0,0 +1,104 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.sets.PointsToSet; +import soot.MethodOrMethodContext; +import soot.SootMethod; +import soot.Unit; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class YummyStat implements AbstractStat { + private final PTA pta; + private long singleCallCnt; + private long singleReceiverCnt; + private long singleCallSingleReceiverCnt; + private final Set singleCalls = new HashSet<>(); + private final Set singleReceivers = new HashSet<>(); + private final Set singleCallSingleReceivers = new HashSet<>(); + + public YummyStat(PTA pta) { + this.pta = pta; + init(); + } + + private void init() { + Map> target2callsites = new HashMap<>(); + CallGraph ciCallGraph = pta.getCallGraph(); + for (Edge edge : ciCallGraph) { + Unit callUnit = edge.srcUnit(); + SootMethod target = edge.tgt(); + if (callUnit != null && target != null) { + target2callsites.computeIfAbsent(target, k -> new HashSet<>()).add(callUnit); + } + } + + target2callsites.entrySet().stream() + .filter(e -> e.getValue().size() == 1) + .map(Map.Entry::getKey).filter(m -> !m.isStatic()) + .forEach(singleCalls::add); + + singleCallCnt = singleCalls.size(); + + + Set instanceReachables = new HashSet<>(); + for (final MethodOrMethodContext momc : pta.getReachableMethods()) { + SootMethod method = momc.method(); + if (!method.isPhantom() && !method.isStatic()) { + instanceReachables.add(method); + } + } + + for (SootMethod method : instanceReachables) { + MethodNodeFactory nf = pta.getPag().getMethodPAG(method).nodeFactory(); + PointsToSet pts = pta.reachingObjects(nf.caseThis()).toCIPointsToSet(); + int ptSize = pts.size(); + if (ptSize == 1) { + singleReceivers.add(method); + } + } + + singleReceiverCnt = singleReceivers.size(); + + singleCalls.stream().filter(singleReceivers::contains).forEach(singleCallSingleReceivers::add); + singleCallSingleReceiverCnt = singleCallSingleReceivers.size(); + } + + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Single-Call Methods:", String.valueOf(singleCallCnt)); + exporter.collectMetric("#Single-Receiver Methods:", String.valueOf(singleReceiverCnt)); + exporter.collectMetric("#Single-Call-Single-Receiver Methods:", String.valueOf(singleCallSingleReceiverCnt)); + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpSingleCallMethods(singleCalls); + exporter.dumpSingleReceiverMethods(singleReceivers); + exporter.dumpSingleCallSingleReceiverMethods(singleCallSingleReceivers); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/ANSIColor.java b/sootup.qilin/src/main/java/qilin/util/ANSIColor.java new file mode 100644 index 00000000000..8c4c8655f54 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/ANSIColor.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +public class ANSIColor { + public static final String RESET = "\u001b[0m"; + public static final String BOLD = "\u001b[1m"; + public static final String BLACK = "\u001b[30m"; + public static final String RED = "\u001b[31m"; + public static final String GREEN = "\u001b[32m"; + public static final String YELLOW = "\u001b[33m"; + public static final String BLUE = "\u001b[34m"; + public static final String PURPLE = "\u001b[35m"; + public static final String CYAN = "\u001b[36m"; + public static final String WHITE = "\u001b[37m"; + public static final String BG_BLACK = "\u001b[40m"; + + public static String color(final String color, final String s) { + return color + s + RESET; + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/DataFactory.java b/sootup.qilin/src/main/java/qilin/util/DataFactory.java new file mode 100644 index 00000000000..d9fde14c613 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/DataFactory.java @@ -0,0 +1,35 @@ +package qilin.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DataFactory { + public static List createList() { + return new ArrayList<>(); +// return new CopyOnWriteArrayList<>(); + } + + public static Set createSet() { + return new HashSet<>(); +// return ConcurrentHashMap.newKeySet(); + } + + public static Set createSet(int initCapacity) { + return new HashSet<>(initCapacity); +// return ConcurrentHashMap.newKeySet(initCapacity); + } + + public static Map createMap() { + return new HashMap<>(); +// return new ConcurrentHashMap<>(); + } + + public static Map createMap(int initCapacity) { + return new HashMap<>(initCapacity); +// return new ConcurrentHashMap<>(initCapacity); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java b/sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java new file mode 100644 index 00000000000..5ee60e47e64 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java @@ -0,0 +1,79 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +import oshi.SystemInfo; +import oshi.software.os.OSProcess; +import oshi.software.os.OperatingSystem; + +import java.util.Timer; +import java.util.TimerTask; + +public class MemoryWatcher extends Timer { + private final long pid; + private final String name; + private final long[] maxMemory; + + public MemoryWatcher(long pid, String name) { + this.pid = pid; + this.name = name; + this.maxMemory = new long[1]; + } + + private TimerTask task; + + public void start() { + this.maxMemory[0] = 0; + task = new TimerTask() { + @Override + public void run() { + SystemInfo si = new SystemInfo(); + OperatingSystem os = si.getOperatingSystem(); + OSProcess process = os.getProcess((int) pid); + long mem = process.getResidentSetSize(); + if (mem > maxMemory[0]) { + maxMemory[0] = mem; + } + } + }; + schedule(task, 0, 100); + } + + public void stop() { + task.cancel(); + this.cancel(); + } + + public double inKiloByte() { + return maxMemory[0] / 1024.0; + } + + public double inMegaByte() { + return maxMemory[0] / (1024.0 * 1024.0); + } + + public double inGigaByte() { + return maxMemory[0] / (1024.0 * 1024.0 * 1024.0); + } + + @Override + public String toString() { + return String.format("%s consumed memory: %.2f MB", this.name, this.inMegaByte()); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java new file mode 100644 index 00000000000..3b7ec14b7ad --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -0,0 +1,856 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import qilin.CoreConfig; +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.VirtualCalls; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.context.ContextElement; +import qilin.core.context.ContextElements; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import qilin.core.sets.PointsToSetInternal; +import qilin.util.queue.ChunkedQueue; +import qilin.util.queue.QueueReader; +import qilin.util.queue.UniqueQueue; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; +import sootup.core.types.NullType; +import sootup.core.types.Type; + +import java.io.*; +import java.net.URL; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public final class PTAUtils { + private static final Logger logger = LoggerFactory.getLogger(PTAUtils.class); + static final String output_dir = CoreConfig.v().getOutConfig().outDir; + static Map nodes = new TreeMap<>(); + private static final ClassType clRunnable = RefType.v("java.lang.Runnable"); + + public static Map> calcStaticThisPTS(PTA pta) { + Map> pts = new HashMap<>(); + Set workList = new HashSet<>(); + PAG pag = pta.getPag(); + // add all instance methods which potentially contain static call + for (SootMethod method : pta.getNakedReachableMethods()) { + if (PTAUtils.isFakeMainMethod(method) || !method.isPhantom() && !method.isStatic()) { + MethodPAG srcmpag = pag.getMethodPAG(method); + LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); + final PointsToSet other = pta.reachingObjects(thisRef).toCIPointsToSet(); + + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { + for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + LocalVarNode tgtThisRef = (LocalVarNode) tgtnf.caseThis(); + // create "THIS" ptr for static method + Set addTo = pts.computeIfAbsent(tgtThisRef, k -> new HashSet<>()); + boolean returnValue = false; + for (Iterator itx = other.iterator(); itx.hasNext(); ) { + AllocNode node = itx.next(); + if (addTo.add(node)) { + returnValue = true; + } + } + if (returnValue) { + workList.add(tgtmtd); + } + } + } + } + } + } + while (!workList.isEmpty()) { + SootMethod method = workList.iterator().next(); + workList.remove(method); + MethodPAG srcmpag = pag.getMethodPAG(method); + LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); + final Set other = pts.computeIfAbsent(thisRef, k -> new HashSet<>()); + + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { + for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + LocalVarNode tgtThisRef = (LocalVarNode) tgtnf.caseThis(); + // create "THIS" ptr for static method + Set addTo = pts.computeIfAbsent(tgtThisRef, k -> new HashSet<>()); + if (addTo.addAll(other)) { + workList.add(tgtmtd); + } + } + } + } + } + return pts; + } + + public static Object getIR(Object sparkNode) { + if (sparkNode instanceof VarNode) { + return ((VarNode) sparkNode).getVariable(); + } else if (sparkNode instanceof AllocNode) { + return ((AllocNode) sparkNode).getNewExpr(); + } else {// sparkField? + return sparkNode; + } + } + + public static boolean mustAlias(PTA pta, VarNode v1, VarNode v2) { + PointsToSet v1pts = pta.reachingObjects(v1).toCIPointsToSet(); + PointsToSet v2pts = pta.reachingObjects(v2).toCIPointsToSet(); + return v1pts.pointsToSetEquals(v2pts); + } + + public static void printPts(PTA pta, PointsToSet pts) { + final StringBuffer ret = new StringBuffer(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + ret.append("\t").append(n).append("\n"); + } + System.out.print(ret); + } + + /** + * dump callgraph to sootoutput/callgraph.dot + */ + public static void dumpCallGraph(Iterable callgraph, boolean appOnly) { + String filename = "callgraph"; + DotGraph canvas = setDotGraph(filename); + + int mn = -1; + Set methodSet = new HashSet<>(); + List methodList = new ArrayList<>(); + + for (Edge edge : callgraph) { + ContextMethod srcmtd = edge.getSrc(); + if (appOnly && !srcmtd.method().getDeclaringClass().isApplicationClass()) + continue; + ContextMethod dstmtd = edge.getTgt(); + String srcName = srcmtd.toString(); + + if (methodSet.add(srcName)) { + canvas.drawNode(srcName).setLabel("" + ++mn); + methodList.add(mn, srcName); + } + String dstName = dstmtd.toString(); + + if (methodSet.add(dstName)) { + canvas.drawNode(dstName).setLabel("" + ++mn); + methodList.add(mn, dstName); + } + canvas.drawEdge(srcName, dstName); + } + + plotDotGraph(canvas, filename); + try { + PrintWriter out = new PrintWriter(new File(output_dir, "callgraphnodes")); + for (int i = 0; i < methodList.size(); i++) + out.println(i + ":" + methodList.get(i)); + out.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + /** + * slice a callgrph, put nodes &edges related to method into set1&set2 + */ + private static void slice(CallGraph callgraph, ContextMethod method, Set set1, + Set set2) { + for (Iterator it = callgraph.edgesInto(method); it.hasNext(); ) { + Edge edge = it.next(); + set2.add(edge); + ContextMethod src = edge.getSrc(); + if (set1.add(src)) + slice(callgraph, src, set1, set2); + } + + } + + /** + * dump callgraph strench to method + */ + public static void dumpSlicedCallGraph(CallGraph callgraph, ContextMethod method) { + Set tgts = new HashSet<>(); + Set edges = new HashSet<>(); + tgts.add(method); + slice(callgraph, method, tgts, edges); + + dumpCallGraph(edges, false); + } + + /** + * dump callgraph from entry to the method + */ + public static void dumpSlicedCallGraph2(CallGraph callgraph, ContextMethod method) { + Set edges = new HashSet<>(); + Set visited = new HashSet<>(); + Queue queue = new UniqueQueue<>(); + queue.add(method); + while (!queue.isEmpty()) { + ContextMethod front = queue.poll(); + for (Iterator it = callgraph.edgesInto(front); it.hasNext(); ) { + Edge edge = it.next(); + ContextMethod src = edge.getSrc(); + if (visited.add(src)) { + queue.add(src); + edges.add(edge); + break; + } + } + } + dumpCallGraph(edges, false); + } + + public static boolean isUnresolved(Type type) { + if (type instanceof ArrayType at) { + type = at.getArrayElementType(); + } + if (!(type instanceof ClassType rt)) + return false; + if (!rt.hasSootClass()) { + return true; + } + SootClass cl = rt.getSootClass(); + return cl.resolvingLevel() < SootClass.HIERARCHY; + } + + public static boolean castNeverFails(Type src, Type dst) { + if (dst == null) + return true; + if (dst == src) + return true; + if (src == null) + return false; + if (dst.equals(src)) + return true; + if (src instanceof NullType) + return true; +// if (src instanceof AnySubType) +// return true; + if (dst instanceof NullType) + return false; +// if (dst instanceof AnySubType) +// throw new RuntimeException("oops src=" + src + " dst=" + dst); + return PTAScene.v().getOrMakeFastHierarchy().canStoreType(src, dst); + } + + public static QueueReader dispatch(Type type, VirtualCallSite site) { + final ChunkedQueue targetsQueue = new ChunkedQueue<>(); + final QueueReader targets = targetsQueue.reader(); + if (site.kind() == Kind.THREAD && !PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, clRunnable)) { + return targets; + } + ContextMethod container = site.container(); + if (site.iie() instanceof JSpecialInvokeExpr sie && site.kind() != Kind.THREAD) { + SootMethod target = VirtualCalls.v().resolveSpecial(sie, site.subSig(), container.method()); + // if the call target resides in a phantom class then + // "target" will be null, simply do not add the target in that case + if (target != null) { + targetsQueue.add(target); + } + } else { + Type mType = site.recNode().getType(); + VirtualCalls.v().resolve(type, mType, site.subSig(), container.method(), targetsQueue); + } + return targets; + } + + public static boolean addWithTypeFiltering(PointsToSetInternal pts, Type type, Node node) { + if (PTAUtils.castNeverFails(node.getType(), type)) { + return pts.add(node.getNumber()); + } + return false; + } + + /** + * dump pts to sootoutput/pts + */ + public static void dumpPts(PTA pta, boolean appOnly) { + try { + PrintWriter file = new PrintWriter(new File(output_dir, "pts.txt")); + file.println("Points-to results:"); + for (final ValNode vn : pta.getPag().getValNodes()) { + if (!(vn instanceof VarNode)) { + continue; + } + SootClass clz = null; + if (vn instanceof LocalVarNode) { + SootMethod sm = ((LocalVarNode) vn).getMethod(); + if (sm != null) { + clz = sm.getDeclaringClass(); + } + } else if (vn instanceof GlobalVarNode gvn) { + clz = gvn.getDeclaringClass(); + } else if (vn instanceof ContextVarNode cv) { + VarNode varNode = cv.base(); + if (varNode instanceof LocalVarNode cvbase) { + clz = cvbase.getMethod().getDeclaringClass(); + } else if (varNode instanceof GlobalVarNode gvn) { + clz = gvn.getDeclaringClass(); + } + } + if (appOnly && clz != null && !clz.isApplicationClass()) { + continue; + } + + String label = getNodeLabel(vn); + nodes.put("[" + label + "]", vn); + file.print(label + " -> {"); + PointsToSet p2set = pta.reachingObjects(vn); + + if (p2set == null || p2set.isEmpty()) { + file.print(" empty }\n"); + continue; + } + for (Iterator it = p2set.iterator(); it.hasNext(); ) { + Node n = it.next(); + label = getNodeLabel(n); + nodes.put("[" + label + "]", n); + file.print(" "); + file.print(label); + } + file.print(" }\n"); + } + dumpNodeNames(file); + file.close(); + } catch (IOException e) { + throw new RuntimeException("Couldn't dump solution." + e); + } + } + + public static void slicePAG(AllocNode allocNode, PAG pag, String filename) { + Map> edges = new HashMap<>(); + Queue queue = new UniqueQueue<>(); + Set tov = pag.allocLookup(allocNode); + edges.computeIfAbsent(allocNode, k -> new HashSet<>()).addAll(tov); + queue.addAll(tov); + Set visited = new HashSet<>(tov); + while (!queue.isEmpty()) { + ValNode front = queue.poll(); + Set tovx = pag.simpleLookup(front); + Set toex = edges.computeIfAbsent(front, k -> new HashSet<>()); + for (ValNode vn : tovx) { + if (toex.add(vn)) { + queue.add(vn); + visited.add(vn); + } + } + } + DotGraph canvas = setDotGraph("hello"); + edges.forEach((n, elements) -> { + drawNode(canvas, n); + elements.forEach(element -> { + drawNode(canvas, element); + drawEdge(canvas, n, element, "black"); + }); + }); + canvas.plot(filename); + for (Node n : visited) { + System.out.println(n); + } + } + + public static void dumpMPAG(PAG pag, SootMethod method) { + String filename = method.getSignature() + ".dot"; + DotGraph canvas = setDotGraph(filename); + QueueReader reader = pag.getMethodPAG(method).getInternalReader().clone(); + while (reader.hasNext()) { + Node src = reader.next(); + Node dst = reader.next(); + drawNode(canvas, src); + drawNode(canvas, dst); + String color = src instanceof AllocNode ? "green" : // alloc + src instanceof FieldRefNode ? "red" : // load + dst instanceof FieldRefNode ? "blue" : // store + "black"; // simple + drawEdge(canvas, src, dst, color); + } + plotDotGraph(canvas, filename); + } + + /** + * dump mPAGs to sootoutput/@filename.dot + */ + public static void dumpMPAGs(PTA pta, String filename) { + DotGraph canvas = setDotGraph(filename); + for (SootMethod m : pta.getNakedReachableMethods()) { + QueueReader reader = pta.getPag().getMethodPAG(m).getInternalReader().clone(); + while (reader.hasNext()) { + Node src = reader.next(); + Node dst = reader.next(); + drawNode(canvas, src); + drawNode(canvas, dst); + String color = src instanceof AllocNode ? "green" : // alloc + src instanceof FieldRefNode ? "red" : // load + dst instanceof FieldRefNode ? "blue" : // store + "black"; // simple + drawEdge(canvas, src, dst, color); + } + } + plotDotGraph(canvas, filename); + } + + /** + * dump pag to sootoutput/@filename.dot + */ + public static void dumpPAG(PAG pag, String filename) { + DotGraph canvas = setDotGraph(filename); + + // draw edges + drawPAGMap(canvas, pag.getAlloc(), "green"); + drawPAGMap(canvas, pag.getSimple(), "black"); + drawInvPAGMap(canvas, pag.getStoreInv(), "blue"); + drawPAGMap(canvas, pag.getLoad(), "red"); + // collect nodes. + Set nodes = new HashSet<>(); + pag.getAlloc().forEach((k, v) -> { + nodes.add(k); + nodes.addAll(v); + }); + pag.getSimple().forEach((k, v) -> { + nodes.add(k); + nodes.addAll(v); + }); + pag.getStoreInv().forEach((k, v) -> { + nodes.add(k); + nodes.addAll(v); + }); + pag.getLoad().forEach((k, v) -> { + nodes.add(k); + nodes.addAll(v); + }); + // draw nodes. + nodes.forEach(node -> drawNode(canvas, node)); + plotDotGraph(canvas, filename); + } + + private static void plotDotGraph(DotGraph canvas, String filename) { + canvas.plot(output_dir + "/" + filename + ".dot"); + } + + private static DotGraph setDotGraph(String fileName) { + DotGraph canvas = new DotGraph(fileName); + canvas.setNodeShape(DotGraphConstants.NODE_SHAPE_BOX); + canvas.setGraphLabel(fileName); + return canvas; + } + + public static String getNodeLabel(Node node) { + int num = node.getNumber(); + if (node instanceof LocalVarNode) + return "L" + num; + else if (node instanceof ContextVarNode) { + return "L" + num; + } else if (node instanceof GlobalVarNode) + return "G" + num; + else if (node instanceof ContextField) + return "OF" + num; + else if (node instanceof FieldRefNode) + return "VF" + num; + else if (node instanceof AllocNode) + return "O" + num; + else + throw new RuntimeException("no such node type exists!"); + } + + private static void drawNode(DotGraph canvas, Node node) { + DotGraphNode dotNode = canvas.drawNode(node.toString()); + dotNode.setLabel("[" + getNodeLabel(node) + "]"); + nodes.put("[" + getNodeLabel(node) + "]", node); + } + + private static void drawEdge(DotGraph canvas, Node src, Node dst, String color) { + canvas.drawEdge(src.toString(), dst.toString()).setAttribute("color", color); + } + + private static void dumpNodeNames(PrintWriter file) { + nodes.forEach((l, n) -> file.println(l + n)); + } + + public static void dumpNodeNames(String fileName) { + try { + PrintWriter out = new PrintWriter(new File(output_dir, fileName)); + dumpNodeNames(out); + out.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + private static void drawPAGMap(DotGraph canvas, Map> map, String color) { + map.forEach((n, elements) -> { + elements.forEach(element -> { + drawEdge(canvas, n, element, color); + }); + }); + } + + private static void drawInvPAGMap(DotGraph canvas, Map> map, String color) { + map.forEach((n, elements) -> { + elements.forEach(element -> { + drawEdge(canvas, element, n, color); + }); + }); + } + + public static boolean isThrowable(Type type) { + if (type instanceof ClassType) { + return PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, RefType.v("java.lang.Throwable")); + } + return false; + } + + public static boolean subtypeOfAbstractStringBuilder(Type t) { + if (!(t instanceof ClassType rt)) { + return false; + } + String s = rt.toString(); + return (s.equals("java.lang.StringBuffer") || s.equals("java.lang.StringBuilder")); + } + + public static boolean supportFinalize(AllocNode heap) { + NumberedString sigFinalize = PTAScene.v().getSubSigNumberer().findOrAdd("void finalize()"); + Type type = heap.getType(); + if (type instanceof ClassType refType && type != RefType.v("java.lang.Object")) { + SootMethod finalizeMethod = VirtualCalls.v().resolveNonSpecial(refType, sigFinalize); + if (finalizeMethod != null && finalizeMethod.toString().equals("")) { + return false; + } + return finalizeMethod != null; + } + return false; + } + + public static Context plusplusOp(AllocNode heap) { + ContextElement[] array; + int s; + if (heap instanceof ContextAllocNode csHeap) { + ContextElements ctxElems = (ContextElements) csHeap.context(); + int ms = ctxElems.size(); + ContextElement[] oldArray = ctxElems.getElements(); + array = new ContextElement[ms + 1]; + array[0] = csHeap.base(); + System.arraycopy(oldArray, 0, array, 1, ms); + s = ms + 1; + } else { + array = new ContextElement[1]; + array[0] = heap; + s = 1; + } + return new ContextElements(array, s); + } + + public static boolean isFakeMainMethod(SootMethod method) { + String sig = ""; + return method.getSignature().equals(sig); + } + + /** + * comma separated list of classes in which no matter what the length of k + * for object sensitivity, we want to limit the depth of the object + * sensitivity to 0. Also add subclasses of each + */ + private static final String[] NO_CONTEXT = {"java.lang.Throwable", "java.lang.StringBuffer", "java.lang.StringBuilder"}; + private static Set ignoreList = null; + + /** + * Install no context list for classes given plus all subclasses. + */ + private static void initEmptyHeapContextTypes() { + if (ignoreList == null) { + ignoreList = new HashSet<>(); + Hierarchy hierarchy = new Hierarchy(); + for (String str : NO_CONTEXT) { + SootClass clz = PTAScene.v().getSootClass(str); + if (clz.isInterface()) { + for (SootClass child : hierarchy.getSubinterfacesOfIncluding(clz)) { + if (child != null) { + ignoreList.add(child); + } + } + } else { + for (SootClass child : hierarchy.getSubclassesOfIncluding(clz)) { + if (child != null) { + ignoreList.add(child); + } + } + } + } + } + } + + public static boolean isOfPrimitiveBaseType(AllocNode heap) { + if (heap.getType() instanceof ArrayType arrayType) { + return arrayType.getBaseType() instanceof PrimType; + } + return false; + } + + public static boolean isPrimitiveArrayType(Type type) { + if (type instanceof ArrayType arrayType) { + return arrayType.getArrayElementType() instanceof PrimType; + } + return false; + } + + /** + * Limit heap context to 0 for these AllocNodes of types in ignoreList. + * We set heaps of StringBuilder/StringBuffer/Throwable types to be context-insensitive just like that in Doop. + * refers to library/string-constants.logic in doop. + */ + public static boolean enforceEmptyContext(AllocNode probe) { + // primitive array objects should be context-insenstive. + if (probe.getType() instanceof ArrayType arrayType) { + if (arrayType.getArrayElementType() instanceof PrimType) { + return true; + } + } + // shortcircuit below computation + initEmptyHeapContextTypes(); + if (!ignoreList.isEmpty()) { + // check if the type that is allocated should never has context + // because it is on the ignore List + SootClass allocated = getSootClass(probe.getType()); + // first check if on the no context list, that trumps all + return ignoreList.contains(allocated); + } + return false; + } + + /** + * Write the jimple file for clz. ParentDir is the absolute path of parent + * directory. + */ + public static void writeJimple(String parentDir, SootClass clz) { + + File packageDirectory = new File( + parentDir + File.separator + clz.getType().getPackageName().toString().replace(".", File.separator)); + + try { + packageDirectory.mkdirs(); + OutputStream streamOut = new FileOutputStream( + packageDirectory + File.separator + clz.getName() + ".jimple"); + PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut)); + Printer.v().printTo(clz, writerOut); + writerOut.flush(); + writerOut.close(); + streamOut.close(); + + } catch (Exception e) { + logger.error("Error writing jimple to file {}", clz, e); + } + } + + public static void dumpJimple(String outputDir) { + for (SootClass clz : PTAScene.v().getLibraryClasses()) { + writeJimple(outputDir, clz); + } + for (SootClass clz : PTAScene.v().getApplicationClasses()) { + writeJimple(outputDir, clz); + } + } + + /** + * Given a file name with separators, convert them in to . so it is a legal + * class name. modified: Ammonia: handle .* not only .class + */ + public static String fromFileToClass(String name) { + return name.substring(0, name.lastIndexOf('.')).replace(File.separatorChar, '.'); + } + + /** + * Given a jarFile, return a list of the classes contained in the jarfile with . + * replacing /. + */ + public static List getClassesFromJar(JarFile jarFile) { + LinkedList classes = new LinkedList<>(); + Enumeration allEntries = jarFile.entries(); + + while (allEntries.hasMoreElements()) { + JarEntry entry = allEntries.nextElement(); + String name = entry.getName(); + if (!name.endsWith(".class")) { + continue; + } + + String clsName = name.substring(0, name.length() - 6).replace('/', '.'); + classes.add(clsName); + } + return classes; + } + + public static String findMainFromMetaInfo(String appPath) { + String mainClass = null; + try { + JarFile jar = new JarFile(appPath); + Enumeration allEntries = jar.entries(); + while (allEntries.hasMoreElements()) { + JarEntry entry = allEntries.nextElement(); + String name = entry.getName(); + if (!name.endsWith(".MF")) { + continue; + } + String urlstring = "jar:file:" + appPath + "!/" + name; + URL url = new URL(urlstring); + Scanner scanner = new Scanner(url.openStream()); + while (scanner.hasNext()) { + String string = scanner.next(); + if ("Main-Class:".equals(string) && scanner.hasNext()) { + mainClass = scanner.next(); + break; + } + } + if (mainClass == null) { + System.out.println("cannot find meta info."); + } + scanner.close(); + jar.close(); + break; + } + } catch (IOException e) { + System.out.println("cannot find meta info."); + } + return mainClass; + } + + public static SootClass getSootClass(Type type) { + SootClass allocated = null; + if (type instanceof RefType) { + allocated = ((RefType) type).getSootClass(); + } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof RefType) { + allocated = ((RefType) ((ArrayType) type).getArrayElementType()).getSootClass(); + } + return allocated; + } + + private static final Map methodToBody = DataFactory.createMap(); + + public static Body getMethodBody(SootMethod m) { + Body body = methodToBody.get(m); + if (body == null) { + synchronized (PTAUtils.class) { + if (body == null) { + if (m.isConcrete()) { + body = m.getBody(); + } else { + body = Body.builder().setMethodSignature(m.getSignature()).build(); + } + methodToBody.putIfAbsent(m, body); + } + } + } + return body; + } + + public static boolean isEmptyArray(AllocNode heap) { + Object var = heap.getNewExpr(); + if (var instanceof NewArrayExpr nae) { + Value sizeVal = nae.getSize(); + if (sizeVal instanceof IntConstant size) { + return size.value == 0; + } + } + return false; + } + + public static LocalVarNode paramToArg(PAG pag, Stmt invokeStmt, MethodPAG srcmpag, VarNode pi) { + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); + Parm mPi = (Parm) pi.getVariable(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + LocalVarNode receiver; + if (ie instanceof AbstractInstanceInvokeExpr iie) { + receiver = pag.findLocalVarNode(iie.getBase()); + } else { + // static call + receiver = thisRef; + } + if (mPi.isThis()) { + return receiver; + } else if (mPi.isReturn()) { + if (invokeStmt instanceof JAssignStmt assignStmt) { + Value mR = assignStmt.getLeftOp(); + return (LocalVarNode) pag.findValNode(mR); + } else { + return null; + } + } else if (mPi.isThrowRet()) { + return srcnf.makeInvokeStmtThrowVarNode(invokeStmt, srcmpag.getMethod()); + } + // Normal formal parameters. + Value arg = ie.getArg(mPi.getIndex()); + if (arg == null) { + return null; + } else { + return pag.findLocalVarNode(arg); + } + } + + /* + * We use this method to replace EntryPoints.v().clinitsOf() because it is infested with bugs. + * */ + public static Set clinitsOf(SootClass cl) { + Set ret = new HashSet<>(); + Set visit = new HashSet<>(); + Queue worklist = new UniqueQueue<>(); + SootClass curr = cl; + while (curr != null) { + worklist.add(curr); + curr = (SootClass) curr.getSuperclass().get(); + } + while (!worklist.isEmpty()) { + SootClass sc = worklist.poll(); + if (visit.add(sc)) { + worklist.addAll(sc.getInterfaces()); + } + } + for (SootClass sc : visit) { + final SootMethod initStart = sc.getMethod(Scene.v().getSubSigNumberer().findOrAdd("void ()")); + if (initStart != null) { + ret.add(initStart); + } + } + return ret; + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/util/Pair.java b/sootup.qilin/src/main/java/qilin/util/Pair.java new file mode 100644 index 00000000000..d511f939dd3 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/Pair.java @@ -0,0 +1,59 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +import java.util.Objects; + +public class Pair { + + private final T1 first; + private final T2 second; + + public Pair(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + public T1 getFirst() { + return first; + } + + public T2 getSecond() { + return second; + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Pair anoPair) { + return Objects.equals(first, anoPair.first) && Objects.equals(second, anoPair.second); + } + return false; + } + + @Override + public String toString() { + return "<" + first + ", " + second + ">"; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/util/Stopwatch.java b/sootup.qilin/src/main/java/qilin/util/Stopwatch.java new file mode 100644 index 00000000000..2e21ab93f46 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/Stopwatch.java @@ -0,0 +1,71 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +public class Stopwatch { + private final String name; + private long elapsedTime; + private long startTime; + private boolean inCounting; + + public static Stopwatch newAndStart(final String name) { + Stopwatch stopwatch = new Stopwatch(name); + stopwatch.start(); + return stopwatch; + } + + private Stopwatch(final String name) { + this.elapsedTime = 0L; + this.inCounting = false; + this.name = name; + } + + private void start() { + if (!this.inCounting) { + this.inCounting = true; + this.startTime = System.currentTimeMillis(); + } + } + + public void stop() { + if (this.inCounting) { + this.elapsedTime += System.currentTimeMillis() - this.startTime; + this.inCounting = false; + } + } + + public float elapsed() { + return this.elapsedTime / 1000.0f; + } + + public void reset() { + this.elapsedTime = 0L; + this.inCounting = false; + } + + public void restart() { + reset(); + start(); + } + + @Override + public String toString() { + return String.format("%s elapsed time: %.2fs", this.name, this.elapsed()); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/Triple.java b/sootup.qilin/src/main/java/qilin/util/Triple.java new file mode 100644 index 00000000000..c8d84403d87 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/Triple.java @@ -0,0 +1,65 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +import java.util.Objects; + +public class Triple { + private final T1 first; + private final T2 second; + private final T3 third; + + public Triple(final T1 first, final T2 second, final T3 third) { + this.first = first; + this.second = second; + this.third = third; + } + + public T1 getFirst() { + return this.first; + } + + public T2 getSecond() { + return this.second; + } + + public T3 getThird() { + return this.third; + } + + @Override + public int hashCode() { + return Objects.hash(this.first, this.second, this.third); + } + + @Override + public boolean equals(final Object o) { + if (o instanceof final Triple anoTriple) { + return Objects.equals(this.first, anoTriple.first) && Objects.equals(this.second, anoTriple.second) + && Objects.equals(this.third, anoTriple.third); + } + return false; + } + + @Override + public String toString() { + return "<" + this.first + ", " + this.second + ", " + + this.third + ">"; + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/UnionFindSet.java b/sootup.qilin/src/main/java/qilin/util/UnionFindSet.java new file mode 100644 index 00000000000..aa364ec46a4 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/UnionFindSet.java @@ -0,0 +1,93 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class UnionFindSet { + private final Map entries; + private int nrsets; + + public UnionFindSet(final Collection elems) { + this.entries = new HashMap<>(); + elems.forEach(elem -> this.entries.put(elem, new Entry(elem))); + this.nrsets = this.entries.size(); + } + + public boolean union(final E e1, final E e2) { + final Entry root1 = this.findRoot(this.entries.get(e1)); + final Entry root2 = this.findRoot(this.entries.get(e2)); + if (root1 == root2) { + return false; + } + if (root1.rank < root2.rank) { + root1.parent = root2; + } else if (root1.rank > root2.rank) { + root2.parent = root1; + } else { + root2.parent = root1; + ++root2.rank; + } + --this.nrsets; + return true; + } + + public boolean isConnected(final E e1, final E e2) { + final Entry root1 = this.findRoot(this.entries.get(e1)); + final Entry root2 = this.findRoot(this.entries.get(e2)); + return root1 == root2; + } + + public E find(final E e) { + final Entry ent = this.findRoot(this.entries.get(e)); + return ent.elem; + } + + public int numberOfSets() { + return this.nrsets; + } + + public Collection> getDisjointSets() { + return this.entries.keySet().stream() + .collect(Collectors.groupingBy(this::find, Collectors.toSet())).values(); + } + + private Entry findRoot(final Entry ent) { + if (ent.parent != ent) { + ent.parent = this.findRoot(ent.parent); + } + return ent.parent; + } + + private class Entry { + private final E elem; + private Entry parent; + private int rank; + + private Entry(final E elem) { + this.elem = elem; + this.parent = this; + this.rank = 0; + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/Util.java b/sootup.qilin/src/main/java/qilin/util/Util.java new file mode 100644 index 00000000000..325c959f18f --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/Util.java @@ -0,0 +1,92 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class Util { + private static final Logger logger = LoggerFactory.getLogger(Util.class); + + public static byte[] toUtf8(String s) { + try { + ByteArrayOutputStream bs = new ByteArrayOutputStream(s.length()); + DataOutputStream d = new DataOutputStream(bs); + d.writeUTF(s); + return bs.toByteArray(); + } catch (IOException e) { + logger.debug("Some sort of IO exception in toUtf8 with " + s); + } + return null; + } + + public static boolean addToMap(Map> map, K key, V value) { + return map.computeIfAbsent(key, k -> DataFactory.createSet()).add(value); + } + + public static boolean removeFromMap(Map> map, K key, V value) { + if (!map.containsKey(key)) { + return false; + } + return map.get(key).remove(value); + } + + public static void add(Map map, T name, String... aliases) { + for (String alias : aliases) { + map.put(alias, name); + } + } + + public static String[] concat(String[] a, String[] b) { + String[] c = new String[a.length + b.length]; + System.arraycopy(a, 0, c, 0, a.length); + System.arraycopy(b, 0, c, a.length, b.length); + return c; + } + + public static void writeToFile(String file, String content) { + try { + File mfile = new File(file); + if (!mfile.exists()) { + System.out.println(file); + mfile.createNewFile(); + } + FileWriter writer = new FileWriter(mfile); + writer.write(content); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private final static Pattern qPat = Pattern.compile("'"); + + public static String stripQuotes(CharSequence s) { + return qPat.matcher(s).replaceAll(""); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java b/sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java new file mode 100644 index 00000000000..0b2f866cb56 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.collect; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class SetFactory { + private final Map, Set> sets; + + public SetFactory() { + this.sets = new HashMap<>(); + } + + public Set get(final Set set) { + if (!this.sets.containsKey(set)) { + this.sets.put(set, set); + } + return this.sets.get(set); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java b/sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java new file mode 100644 index 00000000000..c271d4cb046 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java @@ -0,0 +1,63 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class ConcurrentDirectedGraphImpl implements DirectedGraph { + protected Set nodes; + protected Map> preds; + protected Map> succs; + + public ConcurrentDirectedGraphImpl() { + this.nodes = ConcurrentHashMap.newKeySet(); + this.preds = new ConcurrentHashMap<>(); + this.succs = new ConcurrentHashMap<>(); + } + + public void addNode(final N node) { + this.nodes.add(node); + } + + public void addEdge(final N from, final N to) { + this.addNode(from); + this.addNode(to); + this.preds.computeIfAbsent(to, k -> ConcurrentHashMap.newKeySet()).add(from); + this.succs.computeIfAbsent(from, k -> ConcurrentHashMap.newKeySet()).add(to); + } + + @Override + public Collection allNodes() { + return this.nodes; + } + + @Override + public Collection predsOf(final N n) { + return this.preds.getOrDefault(n, Collections.emptySet()); + } + + @Override + public Collection succsOf(final N n) { + return this.succs.getOrDefault(n, Collections.emptySet()); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java new file mode 100644 index 00000000000..f2f26e44107 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java @@ -0,0 +1,55 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; +import java.util.stream.Collectors; + +public interface DirectedGraph { + Collection allNodes(); + + Collection predsOf(final N p); + + Collection succsOf(final N p); + + /* no cache, very slow.*/ + default Collection computeReachableNodes(N source) { + Set reachableNodes = new HashSet<>(); + Stack stack = new Stack<>(); + stack.push(source); + while (!stack.isEmpty()) { + N node = stack.pop(); + if (reachableNodes.add(node)) { + stack.addAll(succsOf(node)); + } + } + return reachableNodes; + } + + default Collection computeRootNodes() { + return allNodes().stream().filter(node -> predsOf(node).size() == 0).collect(Collectors.toSet()); + } + + default Collection computeTailNodes() { + return allNodes().stream().filter(node -> succsOf(node).size() == 0).collect(Collectors.toSet()); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java new file mode 100644 index 00000000000..c56e7526c7e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java @@ -0,0 +1,59 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.*; + +public class DirectedGraphImpl implements DirectedGraph { + protected Set nodes; + protected Map> preds; + protected Map> succs; + + public DirectedGraphImpl() { + this.nodes = new HashSet<>(); + this.preds = new HashMap<>(); + this.succs = new HashMap<>(); + } + + public void addNode(final N node) { + this.nodes.add(node); + } + + public void addEdge(final N from, final N to) { + this.addNode(from); + this.addNode(to); + this.preds.computeIfAbsent(to, k -> new HashSet<>()).add(from); + this.succs.computeIfAbsent(from, k -> new HashSet<>()).add(to); + } + + @Override + public Collection allNodes() { + return this.nodes; + } + + @Override + public Collection predsOf(final N n) { + return this.preds.getOrDefault(n, Collections.emptySet()); + } + + @Override + public Collection succsOf(final N n) { + return this.succs.getOrDefault(n, Collections.emptySet()); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java b/sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java new file mode 100644 index 00000000000..446a18e6261 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java @@ -0,0 +1,65 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class MergedNode { + private Set> preds; + private Set> succs; + private final Set content; + + public MergedNode(final Collection content) { + this.content = new HashSet<>(content); + } + + public void addPred(final MergedNode pred) { + if (this.preds == null) { + this.preds = new HashSet<>(4); + } + this.preds.add(pred); + } + + public Set> getPreds() { + return (this.preds == null) ? Collections.emptySet() : this.preds; + } + + public void addSucc(final MergedNode succ) { + if (this.succs == null) { + this.succs = new HashSet<>(4); + } + this.succs.add(succ); + } + + public Set> getSuccs() { + return (this.succs == null) ? Collections.emptySet() : this.succs; + } + + public Set getContent() { + return this.content; + } + + @Override + public String toString() { + return this.content.toString(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java b/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java new file mode 100644 index 00000000000..75dc1771121 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java @@ -0,0 +1,76 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class Reachability { + private final DirectedGraph graph; + private final Map> reachableNodes; + private final Map> reachToNodes; + + public Reachability(final DirectedGraph graph) { + this.reachableNodes = new HashMap<>(); + this.reachToNodes = new HashMap<>(); + this.graph = graph; + } + + public Set reachableNodesFrom(final N source) { + if (!this.reachableNodes.containsKey(source)) { + final Set visited = new HashSet<>(); + final Deque stack = new ArrayDeque<>(); + stack.push(source); + while (!stack.isEmpty()) { + final N node = stack.pop(); + visited.add(node); + this.graph.succsOf(node).stream().filter(n -> !visited.contains(n)).forEach(stack::push); + } + this.reachableNodes.put(source, visited); + } + return this.reachableNodes.get(source); + } + + public Set nodesReach(final N target) { + if (!this.reachToNodes.containsKey(target)) { + final Set visited = new HashSet<>(); + final Deque stack = new ArrayDeque<>(); + stack.push(target); + while (!stack.isEmpty()) { + final N node = stack.pop(); + visited.add(node); + this.graph.predsOf(node).stream().filter(n -> !visited.contains(n)).forEach(stack::push); + } + this.reachToNodes.put(target, visited); + } + return this.reachToNodes.get(target); + } + + public Set passedNodes(final N source, final N target) { + final Set reachableFromSource = this.reachableNodesFrom(source); + final Set reachToTarget = this.nodesReach(target); + final Set ret = new HashSet<>(reachableFromSource); + ret.retainAll(reachToTarget); + return ret; + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java b/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java new file mode 100644 index 00000000000..6856417ab22 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java @@ -0,0 +1,68 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class SCCMergedGraph implements DirectedGraph> { + private Set> nodes; + private final Map> nodeMap = new HashMap<>(); + + public SCCMergedGraph(final DirectedGraph graph) { + this.init(graph); + } + + public MergedNode getMergedNode(N contentNode) { + return nodeMap.get(contentNode); + } + + @Override + public Collection> allNodes() { + return this.nodes; + } + + @Override + public Collection> predsOf(final MergedNode node) { + return node.getPreds(); + } + + @Override + public Collection> succsOf(final MergedNode node) { + return node.getSuccs(); + } + + private void init(final DirectedGraph graph) { + this.nodes = new HashSet<>(); + final StronglyConnectedComponents scc = new StronglyConnectedComponents<>(graph); + scc.getComponents().forEach(component -> { + final MergedNode node2 = new MergedNode<>(component); + component.forEach(n -> nodeMap.put(n, node2)); + this.nodes.add(node2); + }); + this.nodes.forEach(node -> node.getContent().stream().map(graph::succsOf).flatMap(Collection::stream) + .map(nodeMap::get).filter(succ -> succ != node).forEach(succ -> { + node.addSucc(succ); + succ.addPred(node); + })); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java b/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java new file mode 100644 index 00000000000..521da7517e1 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java @@ -0,0 +1,102 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +public class StronglyConnectedComponents { + private final List> componentList; + private final List> trueComponentList; + private int index; + private Map indexForNode; + private Map lowlinkForNode; + private Stack stack; + private DirectedGraph graph; + + public StronglyConnectedComponents(final DirectedGraph graph) { + this.componentList = new ArrayList<>(); + this.trueComponentList = new ArrayList<>(); + this.index = 0; + this.graph = graph; + this.stack = new Stack<>(); + this.indexForNode = new HashMap<>(); + this.lowlinkForNode = new HashMap<>(); + for (final N node : graph.allNodes()) { + if (!this.indexForNode.containsKey(node)) { + this.recurse(node); + } + } + this.validate(graph, this.componentList); + this.indexForNode = null; + this.lowlinkForNode = null; + this.stack = null; + this.graph = null; + } + + public List> getComponents() { + return this.componentList; + } + + public List> getTrueComponents() { + return this.trueComponentList; + } + + private void recurse(final N node) { + this.indexForNode.put(node, this.index); + this.lowlinkForNode.put(node, this.index); + ++this.index; + this.stack.push(node); + for (final N succ : this.graph.succsOf(node)) { + if (!this.indexForNode.containsKey(succ)) { + this.recurse(succ); + this.lowlinkForNode.put(node, Math.min(this.lowlinkForNode.get(node), this.lowlinkForNode.get(succ))); + } else { + if (!this.stack.contains(succ)) { + continue; + } + this.lowlinkForNode.put(node, Math.min(this.lowlinkForNode.get(node), this.indexForNode.get(succ))); + } + } + if (this.lowlinkForNode.get(node) == (int) this.indexForNode.get(node)) { + final List scc = new ArrayList<>(); + N v2; + do { + v2 = this.stack.pop(); + scc.add(v2); + } while (node != v2); + this.componentList.add(scc); + if (scc.size() > 1) { + this.trueComponentList.add(scc); + } else { + final N n = scc.get(0); + if (this.graph.succsOf(n).contains(n)) { + this.trueComponentList.add(scc); + } + } + } + } + + private void validate(final DirectedGraph graph, final List> SCCs) { + assert graph.allNodes().size() == SCCs.stream().mapToInt(List::size).sum(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java b/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java new file mode 100644 index 00000000000..85d2db37a3d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java @@ -0,0 +1,66 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class TopologicalSorter { + private DirectedGraph graph; + private List sortedList; + private Set visited; + + public List sort(final DirectedGraph graph) { + return this.sort(graph, false); + } + + public List sort(final DirectedGraph graph, final boolean reverse) { + this.initialize(graph); + graph.allNodes().stream().filter(n -> graph.succsOf(n).isEmpty()).forEach(this::visit); + List result = this.sortedList; + if (reverse) { + Collections.reverse(result); + } + this.clear(); + return result; + } + + private void initialize(final DirectedGraph graph) { + this.graph = graph; + this.sortedList = new LinkedList<>(); + this.visited = new HashSet<>(); + } + + private void visit(final N node) { + if (!this.visited.contains(node)) { + this.visited.add(node); + this.graph.predsOf(node).forEach(this::visit); + this.sortedList.add(node); + } + } + + private void clear() { + this.graph = null; + this.sortedList = null; + this.visited = null; + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/Tree.java b/sootup.qilin/src/main/java/qilin/util/graph/Tree.java new file mode 100644 index 00000000000..d146fddfacb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/Tree.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.Collection; + +public interface Tree { + N getRoot(); + + Collection getLeaves(); + + boolean isALeaf(N n); + + Collection getAllNodes(); + + int size(); + + N parentOf(N n); + + Collection childrenOf(N n); +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java b/sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java new file mode 100644 index 00000000000..2d40f351dcd --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java @@ -0,0 +1,93 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class TreeImpl implements Tree { + Map> data2Node; + TreeNode root; + + public TreeImpl() { + this.data2Node = new HashMap<>(); + } + + @Override + public N getRoot() { + if (root == null) { + for (TreeNode n : data2Node.values()) { + if (n.isRoot()) { + root = n; + break; + } + } + } + return root != null ? root.getElem() : null; + } + + @Override + public Collection getLeaves() { + return getAllNodes().stream().filter(this::isALeaf).collect(Collectors.toSet()); + } + + @Override + public boolean isALeaf(N o) { + return data2Node.containsKey(o) && data2Node.get(o).isLeaf(); + } + + @Override + public Collection getAllNodes() { + return data2Node.keySet(); + } + + public Collection> getAllTreeNodes() { + return data2Node.values(); + } + + @Override + public int size() { + return data2Node.size(); + } + + @Override + public N parentOf(N o) { + return data2Node.containsKey(o) ? data2Node.get(o).getParent().getElem() : null; + } + + @Override + public Collection childrenOf(N o) { + if (data2Node.containsKey(o)) { + TreeNode node = data2Node.get(o); + return node.getChildren().stream().map(TreeNode::getElem).collect(Collectors.toSet()); + } + return Collections.emptySet(); + } + + public boolean addTreeEdge(N parent, N child) { + TreeNode p = data2Node.computeIfAbsent(parent, k -> new TreeNode<>(parent)); + TreeNode c = data2Node.computeIfAbsent(child, k -> new TreeNode<>(child)); + boolean f = p.addChild(c); + c.setParent(p); + return f; + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java b/sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java new file mode 100644 index 00000000000..3d991d6891f --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java @@ -0,0 +1,61 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.graph; + +import java.util.HashSet; +import java.util.Set; + +public class TreeNode { + private final D elem; + private TreeNode parent; + private final Set> children; + + public TreeNode(D e) { + this.elem = e; + this.children = new HashSet<>(); + } + + public D getElem() { + return elem; + } + + public TreeNode getParent() { + return parent; + } + + public boolean isLeaf() { + return this.children.isEmpty(); + } + + public boolean isRoot() { + return this.parent == null; + } + + public void setParent(TreeNode parent) { + this.parent = parent; + } + + public Set> getChildren() { + return children; + } + + public boolean addChild(TreeNode child) { + return this.children.add(child); + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/package.html b/sootup.qilin/src/main/java/qilin/util/package.html new file mode 100644 index 00000000000..38bdbd94acd --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/package.html @@ -0,0 +1,27 @@ + + +Soot utility classes + +Generally useful utility classes for Soot. + + diff --git a/sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java b/sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java new file mode 100644 index 00000000000..03c7af54f57 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java @@ -0,0 +1,98 @@ +package qilin.util.queue; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary + * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not + * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the + * QueueReader was created. + * + * @author Ondrej Lhotak + */ +@SuppressWarnings("unchecked") +public class ChunkedQueue { + + protected static final Object NULL_CONST = new Object(); + protected static final Object DELETED_CONST = new Object(); + + protected static final int LENGTH = 60; + protected Object[] q; + protected int index; + + public ChunkedQueue() { + q = new Object[LENGTH]; + index = 0; + } + + /** Add an object to the queue. */ + public void add(E o) { + if (o == null) { + o = (E) NULL_CONST; + } + if (index == LENGTH - 1) { + Object[] temp = new Object[LENGTH]; + q[index] = temp; + q = temp; + index = 0; + } + q[index++] = o; + } + + /** Create reader which will read objects from the queue. */ + public QueueReader reader() { + return new QueueReader((E[]) q, index); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + boolean isFirst = true; + + int idx = index; + Object[] curArray = q; + while (idx < curArray.length) { + Object curObj = curArray[idx]; + if (curObj == null) { + break; + } + if (isFirst) { + isFirst = false; + } else { + sb.append(", "); + } + if (curObj instanceof Object[]) { + curArray = (Object[]) curObj; + idx = 0; + } else { + sb.append(curObj.toString()); + idx++; + } + } + sb.append("]"); + return sb.toString(); + } + +} + diff --git a/sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java b/sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java new file mode 100644 index 00000000000..8fea82b164b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java @@ -0,0 +1,194 @@ +package qilin.util.queue; + +import java.util.Collection; +import java.util.Collections; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.NoSuchElementException; + +/** + * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary + * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not + * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the + * QueueReader was created. + * + * @author Ondrej Lhotak + */ +public class QueueReader implements java.util.Iterator { + protected E[] q; + protected int index; + + protected QueueReader(E[] q, int index) { + this.q = q; + this.index = index; + } + + /** + * Returns (and removes) the next object in the queue, or null if there are none. + */ + @SuppressWarnings("unchecked") + public E next() { + Object ret = null; + do { + if (q[index] == null) { + throw new NoSuchElementException(); + } + if (index == q.length - 1) { + q = (E[]) q[index]; + index = 0; + if (q[index] == null) { + throw new NoSuchElementException(); + } + } + ret = q[index]; + if (ret == ChunkedQueue.NULL_CONST) { + ret = null; + } + index++; + } while (skip(ret)); + return (E) ret; + } + + protected boolean skip(Object ret) { + return ret == ChunkedQueue.DELETED_CONST; + } + + /** Returns true iff there is currently another object in the queue. */ + @SuppressWarnings("unchecked") + public boolean hasNext() { + do { + E ret = q[index]; + if (ret == null) { + return false; + } + if (index == q.length - 1) { + q = (E[]) ret; + index = 0; + if (q[index] == null) { + return false; + } + } + if (skip(ret)) { + index++; + } else { + return true; + } + } while (true); + } + + /** + * Removes an element from the underlying queue. This operation can only delete elements that have not yet been consumed by + * this reader. + * + * @param o + * The element to remove + */ + public void remove(E o) { + if (o instanceof Invalidable) { + ((Invalidable) o).invalidate(); + return; + } + remove(Collections.singleton(o)); + } + + /** + * Removes elements from the underlying queue. This operation can only delete elements that have not yet been consumed by + * this reader. + * + * @param toRemove + * The elements to remove + */ + @SuppressWarnings("unchecked") + public void remove(Collection toRemove) { + boolean allInvalidable = true; + for (E o : toRemove) { + if (!(o instanceof Invalidable)) { + allInvalidable = false; + continue; + } + + ((Invalidable) o).invalidate(); + } + if (allInvalidable) { + return; + } + int idx = 0; + Object[] curQ = q; + while (curQ[idx] != null) { + // Do we need to switch to a new list? + if (idx == curQ.length - 1) { + curQ = (E[]) curQ[idx]; + idx = 0; + } + + // Is this the element to delete? + if (toRemove.contains(curQ[idx])) { + curQ[idx] = ChunkedQueue.DELETED_CONST; + } + + // Next element + idx++; + } + } + + @SuppressWarnings("unchecked") + public void remove() { + q[index - 1] = (E) ChunkedQueue.DELETED_CONST; + } + + public QueueReader clone() { + return new QueueReader(q, index); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + boolean isFirst = true; + + int idx = index; + Object[] curArray = q; + while (idx < curArray.length) { + Object curObj = curArray[idx]; + if (curObj == null) { + break; + } + if (isFirst) { + isFirst = false; + } else { + sb.append(", "); + } + if (curObj instanceof Object[]) { + curArray = (Object[]) curObj; + idx = 0; + } else { + sb.append(curObj.toString()); + idx++; + } + } + sb.append("]"); + return sb.toString(); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java b/sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java new file mode 100644 index 00000000000..3aaa6892632 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java @@ -0,0 +1,137 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.util.queue; + +import java.util.*; + +public class UniqueQueue implements Queue { + private final Set set; + private final Queue queue; + + public UniqueQueue() { + this.set = new HashSet<>(); + this.queue = new LinkedList<>(); + } + + @Override + public boolean add(T t) { + if (set.contains(t)) { + return false; + } else { + set.add(t); + queue.add(t); + return true; + } + } + + @Override + public void clear() { + set.clear(); + queue.clear(); + } + + @Override + public boolean offer(T t) { + return add(t); + } + + @Override + public T remove() { + return poll(); + } + + @Override + public T poll() { + T t = queue.poll(); + if (t != null) { + set.remove(t); + } + return t; + } + + @Override + public T peek() { + return queue.peek(); + } + + @Override + public int size() { + return set.size(); + } + + @Override + public boolean isEmpty() { + return set.isEmpty(); + } + + @Override + public boolean contains(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + throw new UnsupportedOperationException(); + } + + @Override + public Object[] toArray() { + throw new UnsupportedOperationException(); + } + + @Override + public T1[] toArray(T1[] t1s) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(Collection collection) { + boolean ret = false; + for (T t : collection) { + ret |= add(t); + } + return ret; + } + + @Override + public boolean removeAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public T element() { + throw new UnsupportedOperationException(); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/util/queue/package.html b/sootup.qilin/src/main/java/qilin/util/queue/package.html new file mode 100644 index 00000000000..2eb0b82ce6b --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/util/queue/package.html @@ -0,0 +1,27 @@ + + +Soot queue classes + +An efficient queue implementation to be used generally within Soot. + + From a971159954431a034f004af85890c85ab96ba89e Mon Sep 17 00:00:00 2001 From: Dongjie He Date: Tue, 27 Dec 2022 03:40:17 +1100 Subject: [PATCH 002/145] update sootup.qilin --- .../java/qilin/core/ArtificialMethod.java | 44 +++++++-------- .../src/main/java/qilin/core/CorePTA.java | 7 ++- .../src/main/java/qilin/core/PTA.java | 12 ++-- .../src/main/java/qilin/core/PTAScene.java | 7 ++- .../qilin/core/builder/ExceptionHandler.java | 2 +- .../JavaIoFileSystemGetFileSystemNative.java | 4 -- .../natives/JavaIoFileSystemListNative.java | 8 +-- .../natives/JavaLangObjectCloneNative.java | 8 ++- ...efFinalizerInvokeFinalizeMethodNative.java | 5 +- .../core/natives/JavaLangReflectArrayGet.java | 7 ++- .../core/natives/JavaLangReflectArraySet.java | 4 +- .../JavaLangSystemArraycopyNative.java | 4 +- .../natives/JavaLangSystemSetErr0Native.java | 4 +- .../natives/JavaLangSystemSetIn0Native.java | 4 +- .../natives/JavaLangSystemSetOut0Native.java | 4 +- .../natives/JavaLangThreadCurrentThread.java | 8 +-- .../natives/JavaLangThreadStart0Native.java | 4 +- ...ityAccessControllerDoPrivilegedNative.java | 8 ++- ...ontrollerDoPrivileged_ExceptionNative.java | 8 ++- .../java/qilin/core/natives/NativeMethod.java | 6 +- .../core/natives/NativeMethodDriver.java | 4 +- .../parm/ctxcons/CallsiteCtxConstructor.java | 8 +-- .../qilin/parm/ctxcons/CtxConstructor.java | 8 +-- .../parm/ctxcons/HybTypeCtxConstructor.java | 8 +-- .../parm/ctxcons/InsensCtxConstructor.java | 8 +-- .../qilin/parm/ctxcons/ObjCtxConstructor.java | 8 +-- .../parm/ctxcons/TypeCtxConstructor.java | 8 +-- .../parm/heapabst/HeuristicAbstractor.java | 6 +- .../parm/heapabst/MahjongAbstractor.java | 4 +- .../java/qilin/parm/select/BeanSelector.java | 4 +- .../java/qilin/parm/select/CtxSelector.java | 4 +- .../qilin/parm/select/DebloatingSelector.java | 4 +- .../parm/select/FullMethodLvSelector.java | 4 +- .../qilin/parm/select/HeuristicSelector.java | 4 +- .../java/qilin/parm/select/InsenSelector.java | 4 +- .../parm/select/PartialMethodLvSelector.java | 4 +- .../qilin/parm/select/PartialVarSelector.java | 4 +- .../qilin/parm/select/PipelineSelector.java | 4 +- .../qilin/parm/select/UniformSelector.java | 4 +- .../java/qilin/parm/select/VarLvSelector.java | 4 +- .../toolkits/common/FieldPointstoGraph.java | 2 +- .../java/qilin/pta/toolkits/common/OAG.java | 7 ++- .../qilin/pta/toolkits/common/ToolUtil.java | 14 ++--- .../pta/toolkits/conch/AbstractConch.java | 8 +-- .../qilin/pta/toolkits/conch/AbstractPAG.java | 13 ++--- .../java/qilin/pta/toolkits/conch/Conch.java | 41 +++++++------- .../toolkits/conch/DepOnParamAnalysis.java | 8 +-- .../pta/toolkits/conch/LeakAnalysis.java | 4 +- .../java/qilin/pta/toolkits/conch/SMPAG.java | 2 +- .../dd/CtxTunnelingFeaturesTrueTable.java | 44 ++++++++++----- .../pta/toolkits/dd/DataDrivenSelector.java | 4 +- .../pta/toolkits/dd/FeaturesTrueTable.java | 56 +++++++++++-------- .../pta/toolkits/dd/TunnelingConstructor.java | 8 +-- .../java/qilin/pta/toolkits/eagle/Eagle.java | 39 ++++++------- .../pta/toolkits/mahjong/HeapAbstraction.java | 2 +- .../pta/toolkits/mahjong/automata/DFA.java | 2 +- .../automata/DFAEquivalenceChecker.java | 4 +- .../toolkits/mahjong/automata/DFAFactory.java | 4 +- .../toolkits/mahjong/automata/DFAState.java | 4 +- .../pta/toolkits/mahjong/automata/NFA.java | 4 +- .../qilin/pta/toolkits/selectx/Selectx.java | 35 ++++++------ .../pta/toolkits/turner/AbstractMVFG.java | 40 ++++++------- .../toolkits/turner/MethodLevelCallGraph.java | 2 +- .../qilin/pta/toolkits/turner/MethodVFG.java | 2 +- .../pta/toolkits/turner/ModularMVFG.java | 8 +-- .../java/qilin/pta/toolkits/turner/OCG.java | 12 ++-- .../qilin/pta/toolkits/turner/Turner.java | 4 +- .../java/qilin/pta/toolkits/zipper/Main.java | 2 +- .../analysis/PotentialContextElement.java | 4 +- .../pta/toolkits/zipper/analysis/Zipper.java | 22 ++++---- .../pta/toolkits/zipper/cases/CaseA.java | 19 ------- .../pta/toolkits/zipper/cases/CaseB.java | 25 --------- .../pta/toolkits/zipper/cases/CaseC.java | 35 ------------ .../pta/toolkits/zipper/cases/CaseD.java | 21 ------- .../zipper/flowgraph/FlowAnalysis.java | 23 ++++---- .../zipper/flowgraph/ObjectFlowGraph.java | 12 ++-- .../java/qilin/pta/tools/DebloatedPTA.java | 10 ++-- .../main/java/qilin/pta/tools/EaglePTA.java | 12 ++-- .../pta/tools/PartialCallSiteSensPTA.java | 37 ++++++------ .../qilin/pta/tools/PartialObjSensPTA.java | 40 ++++++------- .../main/java/qilin/pta/tools/ZipperPTA.java | 37 ++++++------ .../main/java/qilin/stat/BenchmarkStat.java | 3 +- .../main/java/qilin/stat/CallGraphStat.java | 10 ++-- .../src/main/java/qilin/stat/Exporter.java | 37 ++++++------ .../main/java/qilin/stat/PointsToStat.java | 9 ++- .../java/qilin/stat/SimplifiedEvaluator.java | 35 +++++++----- .../main/java/qilin/stat/TypeClientStat.java | 37 +++++++----- .../src/main/java/qilin/stat/YummyStat.java | 12 ++-- 88 files changed, 527 insertions(+), 552 deletions(-) delete mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java delete mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java delete mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java delete mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index 8560f2bf2ce..d17af3804f2 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -31,10 +31,6 @@ import sootup.core.jimple.common.ref.IdentityRef; import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JParameterRef; -import sootup.core.jimple.common.ref.JThisRef; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JIdentityStmt; -import sootup.core.jimple.common.stmt.JReturnStmt; import sootup.core.model.Body; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; @@ -50,7 +46,7 @@ public abstract class ArtificialMethod { protected IdentifierFactory identifierFactory; protected SootMethod method; protected Body body; - protected Value thisLocal; + protected Local thisLocal; protected Local[] paraLocals; protected int paraStart; protected int localStart; @@ -58,9 +54,8 @@ public abstract class ArtificialMethod { protected Value getThis() { if (thisLocal == null) { ClassType type = method.getDeclaringClassType(); - Value thisRef = new JThisRef(type); thisLocal = getLocal(type, 0); - addIdentity(thisLocal, thisRef); + addIdentity(thisLocal, Jimple.newThisRef(type)); } return thisLocal; } @@ -129,10 +124,10 @@ protected Value getArrayRef(Value base) { * add an instance invocation receiver.sig(args) */ protected void addInvoke(Value receiver, String sig, Immediate... args) { - MethodSignature methodRef = PTAScene.v().getMethod(sig).getSignature(); + MethodSignature msig = identifierFactory.parseMethodSignature(sig); List argsL = Arrays.asList(args); - AbstractInvokeExpr invoke = methodRef.getDeclaringClass().isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, methodRef, argsL) - : Jimple.newVirtualInvokeExpr((Local) receiver, methodRef, argsL); + AbstractInvokeExpr invoke = msig.getDeclaringClass().isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) + : Jimple.newVirtualInvokeExpr((Local) receiver, msig, argsL); body.getUnits().add(Jimple.newInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo())); } @@ -141,12 +136,12 @@ protected void addInvoke(Value receiver, String sig, Immediate... args) { * * @return rx */ - protected Value getInvoke(Value receiver, String sig, Value... args) { - SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); - List argsL = Arrays.asList(args); - Value invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) - : new JVirtualInvokeExpr(receiver, methodRef, argsL); - Value rx = getNextLocal(methodRef.getReturnType()); + protected Value getInvoke(Value receiver, String sig, Immediate... args) { + MethodSignature msig = identifierFactory.parseMethodSignature(sig); + List argsL = Arrays.asList(args); + Value invoke = methodRef.getDeclaringClass().isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) + : Jimple.newVirtualInvokeExpr((Local) receiver, msig, argsL); + Value rx = getNextLocal(msig.getType()); addAssign(rx, invoke); return rx; } @@ -154,10 +149,10 @@ protected Value getInvoke(Value receiver, String sig, Value... args) { /** * add a static invocation sig(args) */ - protected void addInvoke(String sig, Value... args) { - SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); - List argsL = Arrays.asList(args); - body.getUnits().add(new JInvokeStmt(new JStaticInvokeExpr(methodRef, argsL))); + protected void addInvoke(String sig, Immediate... args) { + MethodSignature msig = identifierFactory.parseMethodSignature(sig); + List argsL = Arrays.asList(args); + body.getUnits().add(Jimple.newInvokeStmt(Jimple.newStaticInvokeExpr(msig, argsL), StmtPositionInfo.createNoStmtPositionInfo())); } /** @@ -165,12 +160,11 @@ protected void addInvoke(String sig, Value... args) { * * @return rx */ - protected Value getInvoke(String sig, Value... args) { + protected Value getInvoke(String sig, Immediate... args) { MethodSignature msig = identifierFactory.parseMethodSignature(sig); - SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); - List argsL = Arrays.asList(args); - Value rx = getNextLocal(methodRef.getReturnType()); - addAssign(rx, new JStaticInvokeExpr(methodRef, argsL)); + List argsL = Arrays.asList(args); + Value rx = getNextLocal(msig.getType()); + addAssign(rx, Jimple.newStaticInvokeExpr(msig, argsL)); return rx; } diff --git a/sootup.qilin/src/main/java/qilin/core/CorePTA.java b/sootup.qilin/src/main/java/qilin/core/CorePTA.java index fc2abd458ff..a04ea55ec54 100644 --- a/sootup.qilin/src/main/java/qilin/core/CorePTA.java +++ b/sootup.qilin/src/main/java/qilin/core/CorePTA.java @@ -18,12 +18,13 @@ package qilin.core; +import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.solver.Propagator; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.HeapAbstractor; import qilin.parm.select.CtxSelector; -import soot.*; +import sootup.core.model.SootMethod; /* * This represents a parameterized PTA which could be concreted to many pointer analyses. @@ -55,7 +56,7 @@ public HeapAbstractor heapAbstractor() { public abstract Propagator getPropagator(); @Override - public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context createCalleeCtx(ContextMethod caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { return ctxCons.constructCtx(caller, (ContextAllocNode) receiverNode, callSite, target); } @@ -110,7 +111,7 @@ protected ContextAllocNode parameterize(AllocNode node, Context context) { * Finds or creates the ContextMethod for method and context. */ @Override - public MethodOrMethodContext parameterize(SootMethod method, Context context) { + public ContextMethod parameterize(SootMethod method, Context context) { Context ctx = ctxSel.select(method, context); return pag.makeContextMethod(ctx, method); } diff --git a/sootup.qilin/src/main/java/qilin/core/PTA.java b/sootup.qilin/src/main/java/qilin/core/PTA.java index 564e3a45cef..fddbc420817 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTA.java +++ b/sootup.qilin/src/main/java/qilin/core/PTA.java @@ -20,6 +20,7 @@ import qilin.core.builder.CallGraphBuilder; import qilin.core.builder.ExceptionHandler; +import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.*; import qilin.core.sets.PointsToSet; @@ -27,9 +28,10 @@ import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.HeapAbstractor; import qilin.parm.select.CtxSelector; -import soot.*; -import soot.jimple.spark.pag.SparkField; import soot.jimple.toolkits.callgraph.CallGraph; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; import java.util.Collection; import java.util.HashSet; @@ -82,7 +84,7 @@ public CallGraph getCallGraph() { return callGraph; } - public Collection getReachableMethods() { + public Collection getReachableMethods() { return cgb.getReachableMethods(); } @@ -100,13 +102,13 @@ public Collection getNakedReachableMethods() { public abstract Node parameterize(Node n, Context context); - public abstract MethodOrMethodContext parameterize(SootMethod method, Context context); + public abstract ContextMethod parameterize(SootMethod method, Context context); public abstract AllocNode getRootNode(); public abstract Context emptyContext(); - public abstract Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target); + public abstract Context createCalleeCtx(ContextMethod caller, AllocNode receiverNode, CallSite callSite, SootMethod target); public abstract HeapAbstractor heapAbstractor(); diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java index 2becfa9b1e7..bf53d72cb54 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTAScene.java +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -20,11 +20,16 @@ import qilin.core.builder.FakeMainFactory; import qilin.util.DataFactory; -import soot.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.util.Chain; import soot.util.IterableNumberer; import soot.util.StringNumberer; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index 7ef0aefcadb..5f793be172b 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -34,7 +34,7 @@ import java.util.*; public class ExceptionHandler { - protected final Map> throwNodeToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); + protected final Map> throwNodeToSites = DataFactory.createMap(1000); protected PTA pta; protected PAG pag; diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index 72a3c1ec335..a84249c104e 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -18,10 +18,6 @@ package qilin.core.natives; -import soot.RefType; -import soot.SootMethod; -import soot.Value; - public class JavaIoFileSystemGetFileSystemNative extends NativeMethod { public JavaIoFileSystemGetFileSystemNative(SootMethod method) { super(method); diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java index 9aa887897a7..462c483bec2 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -18,9 +18,9 @@ package qilin.core.natives; -import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaIoFileSystemListNative extends NativeMethod { public JavaIoFileSystemListNative(SootMethod method) { @@ -37,6 +37,6 @@ public void simulate() { Value elem = getNew(RefType.v("java.lang.String")); // addInvoke(elem, "()>"); addAssign(getArrayRef(arrLocal), elem); - addReturn(arrLocal); + addReturn((Immediate) arrLocal); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java index 2015305c614..f2a586570ce 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java @@ -18,8 +18,10 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; + +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangObjectCloneNative extends NativeMethod { @@ -33,7 +35,7 @@ public JavaLangObjectCloneNative(SootMethod method) { */ public void simulate() { Value r0 = getThis(); - addReturn(r0); + addReturn((Immediate) r0); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java index 88c109910de..8321a0a9938 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java @@ -18,8 +18,9 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; + +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangRefFinalizerInvokeFinalizeMethodNative extends NativeMethod { public JavaLangRefFinalizerInvokeFinalizeMethodNative(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index 829f8bab37a..15e94b9853f 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -20,8 +20,9 @@ import soot.ArrayType; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; /* * @@ -38,6 +39,6 @@ void simulate() { Value arrayRef = getArrayRef(arrayBase); Value ret = getNextLocal(RefType.v("java.lang.Object")); addAssign(ret, arrayRef); - addReturn(ret); + addReturn((Immediate) ret); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java index c608b635fc8..b5ca730795c 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -20,8 +20,8 @@ import soot.ArrayType; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; /* * handle diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java index f03dcfc9c81..6a19deb4f6a 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -20,8 +20,8 @@ import soot.ArrayType; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; /* * This file will be temporarily discarded. Yes, it is correct but need one more level of context. diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java index 84d5f0786e5..632ebf1cbfc 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangSystemSetErr0Native extends NativeMethod { public JavaLangSystemSetErr0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java index e6d36202de4..d427bca5444 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangSystemSetIn0Native extends NativeMethod { public JavaLangSystemSetIn0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java index 203a5f0ce0f..ff8ac0a358f 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangSystemSetOut0Native extends NativeMethod { public JavaLangSystemSetOut0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java index c8eda289ed1..a7c7c0d52fd 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -19,9 +19,9 @@ package qilin.core.natives; import qilin.core.PTAScene; -import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangThreadCurrentThread extends NativeMethod { JavaLangThreadCurrentThread(SootMethod method) { @@ -33,6 +33,6 @@ void simulate() { Value lv = getNextLocal(RefType.v("java.lang.Thread")); Value rv = PTAScene.v().getFieldCurrentThread(); addAssign(lv, rv); - addReturn(lv); + addReturn((Immediate) lv); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java index c1dd4da9507..be330b7d483 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java @@ -19,8 +19,8 @@ package qilin.core.natives; import qilin.core.PTAScene; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangThreadStart0Native extends NativeMethod { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java index 3ff7f9d4c31..f4c5c0d845d 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java @@ -17,8 +17,10 @@ */ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; + +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaSecurityAccessControllerDoPrivilegedNative extends NativeMethod { public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { @@ -34,6 +36,6 @@ public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { public void simulate() { Value r0 = getPara(0); Value r1 = getInvoke(r0, ""); - addReturn(r1); + addReturn((Immediate) r1); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java index dee72f7f120..12a3fff3684 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java @@ -18,8 +18,10 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; + +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaSecurityAccessControllerDoPrivileged_ExceptionNative extends NativeMethod { public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod method) { @@ -35,6 +37,6 @@ public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod metho public void simulate() { Value r0 = getPara(0); Value r1 = getInvoke(r0, ""); - addReturn(r1); + addReturn((Immediate) r1); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java index d54d470b0a5..b94cbcb1b02 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java @@ -20,8 +20,8 @@ import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootMethod; public abstract class NativeMethod extends ArtificialMethod { @@ -29,7 +29,7 @@ public abstract class NativeMethod extends ArtificialMethod { this.method = method; this.body = PTAUtils.getMethodBody(method); int paraCount = method.getParameterCount(); - paraLocals = new Value[paraCount]; + paraLocals = new Local[paraCount]; this.paraStart = method.isStatic() ? 0 : 1; this.localStart = this.paraStart + paraCount; } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java index aaa70916b69..5be8c9372b5 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java @@ -19,14 +19,14 @@ package qilin.core.natives; import qilin.core.PTAScene; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class NativeMethodDriver { public void buildNative(SootMethod method) { if (!PTAScene.v().nativeBuilt.add(method)) { return; } - String sig = method.getSignature(); + String sig = method.getSignature().toString(); switch (sig) { case "": case "": diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java index 5309b88908b..34d7297f2f7 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java @@ -18,18 +18,18 @@ package qilin.parm.ctxcons; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import soot.Context; -import soot.MethodOrMethodContext; -import soot.SootMethod; +import qilin.core.pag.ContextMethod; +import sootup.core.model.SootMethod; public class CallsiteCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); assert callerContext instanceof ContextElements; ContextElements ctxElems = (ContextElements) callerContext; diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java index c7cb8e5a990..00afc962d49 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java @@ -18,16 +18,16 @@ package qilin.parm.ctxcons; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import soot.Context; -import soot.MethodOrMethodContext; -import soot.SootMethod; +import qilin.core.pag.ContextMethod; +import sootup.core.model.SootMethod; public interface CtxConstructor { - Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target); + Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target); Context emptyContext = new ContextElements(new ContextElement[0], 0); } \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java index 2e7cc3dbd5b..de3d83279b9 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java @@ -18,20 +18,20 @@ package qilin.parm.ctxcons; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.context.TypeContextElement; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import soot.Context; -import soot.MethodOrMethodContext; -import soot.SootMethod; +import qilin.core.pag.ContextMethod; +import sootup.core.model.SootMethod; // implementation of selective hybrid context...(Yannis pldi'13) public class HybTypeCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); if (receiverNode == null) { // static invoke assert callerContext instanceof ContextElements; diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java index cdd393d9b10..c38bb569cc2 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java @@ -18,16 +18,16 @@ package qilin.parm.ctxcons; +import qilin.core.context.Context; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import soot.Context; -import soot.MethodOrMethodContext; -import soot.SootMethod; +import qilin.core.pag.ContextMethod; +import sootup.core.model.SootMethod; public class InsensCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { return emptyContext; } } diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java index 8b7131df7bb..e60e680242a 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java @@ -18,19 +18,19 @@ package qilin.parm.ctxcons; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import soot.Context; -import soot.MethodOrMethodContext; -import soot.SootMethod; +import qilin.core.pag.ContextMethod; +import sootup.core.model.SootMethod; // implementation of obj context...(Ana Tosem'05) public class ObjCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); if (receiverNode == null) { // static invoke return callerContext; diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java index 6cf034383e4..fd9a4212770 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java @@ -18,21 +18,21 @@ package qilin.parm.ctxcons; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.context.TypeContextElement; import qilin.core.pag.AllocNode; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import soot.Context; -import soot.MethodOrMethodContext; -import soot.SootMethod; +import qilin.core.pag.ContextMethod; +import sootup.core.model.SootMethod; // implementation of type context...(Yannis popl'11) public class TypeCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); if (receiverNode == null) { // static invoke return callerContext; diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java index ed388baa161..7012af0fc28 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -23,7 +23,9 @@ import qilin.core.pag.PAG; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.*; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; import java.util.Set; @@ -42,7 +44,7 @@ public AllocNode abstractHeap(AllocNode heap) { Type type = heap.getType(); SootMethod m = heap.getMethod(); if (mergedTypes.contains(type) || (PTAUtils.isThrowable(type) && mergedTypes.add(type))) { - return pag.makeAllocNode(MergedNewExpr.v((RefLikeType) type), type, null); + return pag.makeAllocNode(MergedNewExpr.v((ReferenceType) type), type, null); } else { return heap; } diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java index 1f3ffe1689d..e822f6c5030 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java @@ -21,8 +21,8 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.Map; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java index ec804562d98..cab87611402 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java @@ -18,14 +18,14 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.PAG; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java index c549881c9d4..766925d6a99 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java @@ -18,14 +18,14 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public abstract class CtxSelector { public abstract Context select(SootMethod m, Context context); diff --git a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java index 83476653680..767fe94534a 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java index 0244781aaa9..db8658c1087 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java index ec0479c0238..ea17428fbd1 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java @@ -18,13 +18,13 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; import qilin.util.PTAUtils; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class HeuristicSelector extends CtxSelector { diff --git a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java index ead5ce4c20e..ee3e6a3b454 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class InsenSelector extends CtxSelector { @Override diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java index e81c93d89b3..6091252820c 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java index d5f7a5af813..7abf7e0ea8b 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java index 4528c0a8523..632c92c2285 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; /* * A pipeline context selector which selects context by firstly using ctxSelA and then ctxSelB. diff --git a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java index c3ee0b8fc05..ae5d14fdac6 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class UniformSelector extends CtxSelector { private final int k; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java index d8f0b02bcf2..c02537bd9f8 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java index 2dc40e83df9..37e6d39b0a5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java @@ -21,8 +21,8 @@ import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; +import qilin.core.pag.SparkField; import qilin.core.sets.PointsToSet; -import soot.jimple.spark.pag.SparkField; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java index 4f497cb5201..400611c66c9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java @@ -23,11 +23,12 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.MethodPAG; +import qilin.core.pag.Node; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.graph.DirectedGraph; -import soot.SootMethod; -import soot.util.queue.QueueReader; +import qilin.util.queue.QueueReader; +import sootup.core.model.SootMethod; import java.util.*; @@ -114,7 +115,7 @@ protected void buildOAG() { MethodPAG srcmpag = pta.getPag().getMethodPAG(method); MethodNodeFactory srcnf = srcmpag.nodeFactory(); LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - QueueReader reader = srcmpag.getInternalReader().clone(); + QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { qilin.core.pag.Node from = reader.next(), to = reader.next(); if (from instanceof AllocNode tgt) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index e542c95bfe6..7d74ac3f064 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -19,14 +19,12 @@ package qilin.pta.toolkits.common; import qilin.core.PTA; -import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.PAG; import qilin.core.pag.VarNode; -import soot.RefLikeType; -import soot.RefType; -import soot.SootClass; -import soot.SootMethod; +import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.core.types.ReferenceType; import java.util.Collections; import java.util.HashSet; @@ -42,7 +40,7 @@ public static Set getParameters(PAG pag, SootMethod m) { MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); Set ret = new HashSet<>(); for (int i = 0; i < m.getParameterCount(); ++i) { - if (m.getParameterType(i) instanceof RefLikeType) { + if (m.getParameterType(i) instanceof ReferenceType) { qilin.core.pag.VarNode param = mthdNF.caseParm(i); ret.add(param); } @@ -52,7 +50,7 @@ public static Set getParameters(PAG pag, SootMethod m) { public static Set getRetVars(PAG pag, SootMethod m) { MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); - if (m.getReturnType() instanceof RefLikeType) { + if (m.getReturnType() instanceof ReferenceType) { VarNode ret = mthdNF.caseRet(); return Collections.singleton(ret); } @@ -68,7 +66,7 @@ public static int pointsToSetSizeOf(final PTA pta, VarNode var) { * @param pOuter potential outer class * @return whether pInner is an inner class of pOuter */ - public static boolean isInnerType(final RefType pInner, RefType pOuter) { + public static boolean isInnerType(final ClassType pInner, ClassType pOuter) { final String pInnerStr = pInner.toString(); while (!pInnerStr.startsWith(pOuter.toString() + "$")) { SootClass sc = pOuter.getSootClass(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java index 5af968d47c5..0da0a2d208a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java @@ -24,10 +24,8 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.ArrayType; -import soot.PrimType; -import soot.SootMethod; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; import java.util.*; @@ -173,7 +171,7 @@ private boolean primitiveField(SparkField f) { * here, we let primitive array as primitive type as that in Turner. * this wont hurt precision of clients. * */ - return at.baseType instanceof PrimType; + return at.getBaseType() instanceof PrimType; } else return f.getType().toString().equals(s); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java index 514c5841096..76e44cdf230 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -24,11 +24,10 @@ import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; -import soot.RefLikeType; -import soot.SootMethod; -import soot.jimple.Stmt; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.util.queue.QueueReader; +import qilin.util.queue.QueueReader; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.Collection; import java.util.Collections; @@ -101,12 +100,12 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); addParamEdge(param); } } - if (method.getReturnType() instanceof RefLikeType) { + if (method.getReturnType() instanceof ReferenceType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); addReturnEdge(mret); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index deaad929bfe..0a792a483cf 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -24,14 +24,13 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.SootMethod; -import soot.Unit; -import soot.Value; -import soot.jimple.InvokeExpr; -import soot.jimple.InvokeStmt; -import soot.jimple.SpecialInvokeExpr; -import soot.jimple.Stmt; -import soot.jimple.spark.pag.SparkField; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.stmt.JInvokeStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; import java.util.*; import java.util.stream.Collectors; @@ -69,15 +68,16 @@ private SootMethod findInvokedConstructorOf(AllocNode heap) { SootMethod containingMethod = heap.getMethod(); MethodPAG cmpag = pag.getMethodPAG(containingMethod); MethodNodeFactory nodeFactory = cmpag.nodeFactory(); - for (Unit unit : cmpag.getInvokeStmts()) { - if (unit instanceof InvokeStmt invokeStmt) { - InvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof SpecialInvokeExpr iie) { + for (Stmt stmt : cmpag.getInvokeStmts()) { + if (stmt instanceof JInvokeStmt invokeStmt) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); PointsToSet v1pts = pta.reachingObjects(baseNode); - SootMethod target = iie.getMethod(); - if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && target.isConstructor()) { + MethodSignature targetSig = iie.getMethodSignature(); + SootMethod target = null; + if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && targetSig.isConstructor()) { return target; } } @@ -90,10 +90,10 @@ private SootMethod findInvokedConstructorOf(SootMethod outerInit) { MethodPAG cmpag = pag.getMethodPAG(outerInit); MethodNodeFactory nodeFactory = cmpag.nodeFactory(); VarNode thisNode = nodeFactory.caseThis(); - for (Unit unit : cmpag.getInvokeStmts()) { - if (unit instanceof InvokeStmt invokeStmt) { - InvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof SpecialInvokeExpr iie) { + for (Stmt stmt : cmpag.getInvokeStmts()) { + if (stmt instanceof JInvokeStmt invokeStmt) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); SootMethod target = iie.getMethod(); @@ -124,9 +124,8 @@ private ArrayList recoverConstructorChain(SootMethod sm, AllocNode h private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMethod curr, SootMethod caller) { MethodPAG cmpag = pag.getMethodPAG(caller); Set ret = new HashSet<>(); - for (Unit unit : cmpag.getInvokeStmts()) { - Stmt stmt = (Stmt) unit; - if (!(stmt.getInvokeExpr() instanceof SpecialInvokeExpr)) { + for (Stmt stmt : cmpag.getInvokeStmts()) { + if (!(stmt.getInvokeExpr() instanceof JSpecialInvokeExpr)) { continue; } SootMethod target = stmt.getInvokeExpr().getMethod(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index b99aaefd3f5..c140c2c5a2b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -22,10 +22,10 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.jimple.AssignStmt; -import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.Collections; import java.util.Iterator; @@ -119,7 +119,7 @@ public void run() { MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); MethodNodeFactory srcnf = srcmpag.nodeFactory(); Stmt invokeStmt = (Stmt) edge.srcUnit(); - if (invokeStmt instanceof AssignStmt assignStmt) { + if (invokeStmt instanceof JAssignStmt assignStmt) { VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); if (sourceParam instanceof LocalVarNode pj) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java index dcee2a57e59..3d1b300cea0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -21,9 +21,9 @@ import qilin.core.PTA; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.Collections; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java index 67719f67d54..8a3452e712f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java @@ -21,8 +21,8 @@ import qilin.core.pag.*; import qilin.util.Pair; import qilin.util.graph.DirectedGraphImpl; +import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import soot.util.queue.QueueReader; import java.util.HashSet; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index 585feb7432a..d5bdb0b2e14 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -19,8 +19,22 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import soot.*; -import soot.jimple.*; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JNewMultiArrayExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootMethod; /* * features and formulas used in "Precise and Scalable Points-to Analysis via Data-Driven @@ -30,7 +44,7 @@ public class CtxTunnelingFeaturesTrueTable { private final boolean[] f = new boolean[24]; public CtxTunnelingFeaturesTrueTable(SootMethod sm) { - String sig = sm.getSignature(); + String sig = sm.getSignature().toString(); // the 10 atomic signature features. this.f[1] = sig.contains("java"); this.f[2] = sig.contains("lang"); @@ -49,32 +63,32 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm) { Body body = PTAUtils.getMethodBody(sm); this.f[15] = body.getLocalCount() > 0; int heapAllocCnt = 0; - for (Unit unit : body.getUnits()) { - if (unit instanceof AssignStmt assignStmt) { + for (Stmt stmt : body.getStmts()) { + if (stmt instanceof JAssignStmt assignStmt) { Value left = assignStmt.getLeftOp(); if (left instanceof Local) { Value right = assignStmt.getRightOp(); if (right instanceof Local) { this.f[14] = true; - } else if (right instanceof NewExpr || right instanceof NewArrayExpr || right instanceof NewMultiArrayExpr) { + } else if (right instanceof JNewExpr || right instanceof JNewArrayExpr || right instanceof JNewMultiArrayExpr) { heapAllocCnt++; - } else if (right instanceof InvokeExpr) { - if (right instanceof StaticInvokeExpr) { + } else if (right instanceof AbstractInvokeExpr) { + if (right instanceof JStaticInvokeExpr) { this.f[17] = true; - } else if (right instanceof VirtualInvokeExpr || right instanceof InterfaceInvokeExpr) { + } else if (right instanceof JVirtualInvokeExpr || right instanceof JInterfaceInvokeExpr) { this.f[18] = true; } - } else if (right instanceof ArrayRef) { + } else if (right instanceof JArrayRef) { this.f[13] = true; } - } else if (left instanceof InstanceFieldRef) { + } else if (left instanceof JInstanceFieldRef) { this.f[16] = true; } - } else if (unit instanceof InvokeStmt invokeStmt) { - InvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof StaticInvokeExpr) { + } else if (stmt instanceof JInvokeStmt invokeStmt) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JStaticInvokeExpr) { this.f[17] = true; - } else if (expr instanceof VirtualInvokeExpr || expr instanceof InterfaceInvokeExpr) { + } else if (expr instanceof JVirtualInvokeExpr || expr instanceof JInterfaceInvokeExpr) { this.f[18] = true; } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java index bad5177c403..7b63afb0391 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java @@ -18,6 +18,7 @@ package qilin.pta.toolkits.dd; +import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; @@ -26,8 +27,7 @@ import qilin.parm.ctxcons.ObjCtxConstructor; import qilin.parm.ctxcons.TypeCtxConstructor; import qilin.parm.select.CtxSelector; -import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.HashMap; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java index da07066824d..f5308c67ded 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -19,10 +19,23 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import soot.Body; -import soot.SootMethod; -import soot.Unit; -import soot.jimple.*; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JGotoStmt; +import sootup.core.jimple.common.stmt.JIdentityStmt; +import sootup.core.jimple.common.stmt.JIfStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; +import sootup.core.jimple.common.stmt.JNopStmt; +import sootup.core.jimple.common.stmt.JReturnStmt; +import sootup.core.jimple.common.stmt.JReturnVoidStmt; +import sootup.core.jimple.common.stmt.JThrowStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.jimple.javabytecode.stmt.JBreakpointStmt; +import sootup.core.jimple.javabytecode.stmt.JEnterMonitorStmt; +import sootup.core.jimple.javabytecode.stmt.JExitMonitorStmt; +import sootup.core.jimple.javabytecode.stmt.JRetStmt; +import sootup.core.jimple.javabytecode.stmt.JSwitchStmt; +import sootup.core.model.Body; +import sootup.core.model.SootMethod; /* * features and formulas used in "Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017)" @@ -31,7 +44,7 @@ public class FeaturesTrueTable { private final boolean[] features = new boolean[26]; public FeaturesTrueTable(SootMethod sm) { - String sig = sm.getSignature(); + String sig = sm.getSignature().toString(); this.features[1] = sig.contains("java"); this.features[2] = sig.contains("lang"); this.features[3] = sig.contains("sun"); @@ -43,37 +56,36 @@ public FeaturesTrueTable(SootMethod sm) { this.features[9] = sig.contains("String"); this.features[10] = sig.contains("init"); Body body = PTAUtils.getMethodBody(sm); - for (Unit unit : body.getUnits()) { - if (unit instanceof AssignStmt) { + for (Stmt stmt : body.getStmts()) { + if (stmt instanceof JAssignStmt) { this.features[11] = true; - } else if (unit instanceof IdentityStmt) { + } else if (stmt instanceof JIdentityStmt) { this.features[12] = true; - } else if (unit instanceof InvokeStmt) { + } else if (stmt instanceof JInvokeStmt) { this.features[13] = true; - } else if (unit instanceof ReturnStmt) { + } else if (stmt instanceof JReturnStmt) { this.features[14] = true; - } else if (unit instanceof ThrowStmt) { + } else if (stmt instanceof JThrowStmt) { this.features[15] = true; - } else if (unit instanceof BreakpointStmt) { + } else if (stmt instanceof JBreakpointStmt) { this.features[16] = true; - } else if (unit instanceof EnterMonitorStmt) { + } else if (stmt instanceof JEnterMonitorStmt) { this.features[17] = true; - } else if (unit instanceof ExitMonitorStmt) { + } else if (stmt instanceof JExitMonitorStmt) { this.features[18] = true; - } else if (unit instanceof GotoStmt) { + } else if (stmt instanceof JGotoStmt) { this.features[19] = true; - } else if (unit instanceof IfStmt) { + } else if (stmt instanceof JIfStmt) { this.features[20] = true; - } else if (unit instanceof LookupSwitchStmt) { + } else if (stmt instanceof JSwitchStmt) { this.features[21] = true; - } else if (unit instanceof NopStmt) { + this.features[25] = true; + } else if (stmt instanceof JNopStmt) { this.features[22] = true; - } else if (unit instanceof RetStmt) { + } else if (stmt instanceof JRetStmt) { this.features[23] = true; - } else if (unit instanceof ReturnVoidStmt) { + } else if (stmt instanceof JReturnVoidStmt) { this.features[24] = true; - } else if (unit instanceof TableSwitchStmt) { - this.features[25] = true; } } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java index 4b0eac23b04..e133fb3dcb4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java @@ -18,12 +18,12 @@ package qilin.pta.toolkits.dd; +import qilin.core.context.Context; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; +import qilin.core.pag.ContextMethod; import qilin.parm.ctxcons.*; -import soot.Context; -import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.HashMap; import java.util.Map; @@ -41,7 +41,7 @@ public TunnelingConstructor(CtxConstructor ctxCons) { } @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { CtxTunnelingFeaturesTrueTable ctftt1 = findOrCreateTunnelingFeaturesTrueTable(caller.method()); CtxTunnelingFeaturesTrueTable ctftt2 = findOrCreateTunnelingFeaturesTrueTable(target); if (ctxCons instanceof CallsiteCtxConstructor) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index c34d656a647..68e9e0c552d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -25,16 +25,18 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Util; +import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import soot.RefLikeType; -import soot.SootMethod; -import soot.Unit; -import soot.Value; -import soot.jimple.*; -import soot.jimple.spark.pag.SparkField; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; -import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.*; import java.util.stream.Collectors; @@ -301,11 +303,11 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); LocalVarNode[] parms = new LocalVarNode[numParms]; for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { parms[i] = (LocalVarNode) srcnf.caseParm(i); } } - LocalVarNode mret = method.getReturnType() instanceof RefLikeType ? (LocalVarNode) srcnf.caseRet() : null; + LocalVarNode mret = method.getReturnType() instanceof ReferenceType ? (LocalVarNode) srcnf.caseRet() : null; LocalVarNode throwFinal = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); if (method.isStatic()) { pts.getOrDefault(thisRef, Collections.emptySet()).forEach(a -> { @@ -320,26 +322,25 @@ else if (to instanceof FieldRefNode fr) { } // add invoke edges - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - InvokeExpr ie = s.getInvokeExpr(); + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { retDest = prePAG.findLocalVarNode(dest); } } LocalVarNode receiver; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } else { // static call @@ -349,14 +350,14 @@ else if (to instanceof FieldRefNode fr) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) continue; ValNode argNode = prePAG.findValNode(args[i]); if (argNode instanceof LocalVarNode) { this.addStoreEdge((LocalVarNode) argNode, receiver); } } - if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { + if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { this.addLoadEdge(receiver, retDest); } LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java index 4c0bfa3be45..35e4830c93d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java @@ -8,7 +8,7 @@ import qilin.pta.toolkits.mahjong.automata.DFAState; import qilin.pta.toolkits.common.FieldPointstoGraph; import qilin.util.UnionFindSet; -import soot.Type; +import sootup.core.types.Type; import java.util.Collection; import java.util.HashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java index 58f2d1ecbfb..a62de6109c7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java @@ -1,6 +1,6 @@ package qilin.pta.toolkits.mahjong.automata; -import soot.Type; +import sootup.core.types.Type; import java.util.HashSet; import java.util.LinkedList; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java index a5ac0c4975c..e038c8605fa 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; +import qilin.core.pag.SparkField; import qilin.util.Pair; import qilin.util.UnionFindSet; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; import java.util.Collection; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java index 7fc1098883b..69ec2ad74fd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; +import qilin.core.pag.SparkField; import qilin.pta.toolkits.common.FieldPointstoGraph; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java index 329979293a1..02e70604a48 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java @@ -1,8 +1,8 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import qilin.core.pag.SparkField; +import sootup.core.types.Type; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java index 40bc237de4c..067208c53a9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; +import qilin.core.pag.SparkField; import qilin.pta.toolkits.common.FieldPointstoGraph; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; import java.util.Collections; import java.util.HashSet; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index f4189f255e4..0f087bf12f4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -26,11 +26,16 @@ import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; -import soot.*; -import soot.jimple.*; -import soot.jimple.spark.pag.SparkField; +import qilin.util.queue.QueueReader; import soot.jimple.toolkits.callgraph.Edge; -import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; public class Selectx { private final PTA prePTA; @@ -264,29 +269,27 @@ private void buildGraph() { // add invoke edges MethodNodeFactory srcnf = srcmpag.nodeFactory(); - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - - CallSite callSite = new CallSite(u); - InvokeExpr ie = s.getInvokeExpr(); + for (final Stmt s : srcmpag.getInvokeStmts()) { + CallSite callSite = new CallSite(s); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { retDest = prePAG.findLocalVarNode(dest); } } LocalVarNode receiver = null; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } for (Iterator it = prePTA.getCallGraph().edgesOutOf(u); it.hasNext(); ) { @@ -295,13 +298,13 @@ private void buildGraph() { MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) { + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) { continue; } LocalVarNode parm = (LocalVarNode) tgtnf.caseParm(i); this.addEntryEdge((LocalVarNode) srcnf.getNode(args[i]), parm, callSite); } - if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { + if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { LocalVarNode ret = (LocalVarNode) tgtnf.caseRet(); this.addExitEdge(ret, retDest, callSite); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 0a9fa49aa2c..6eb873061d0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -23,15 +23,18 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.Pair; +import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import soot.RefLikeType; -import soot.SootMethod; -import soot.Unit; -import soot.Value; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; -import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.*; @@ -150,26 +153,25 @@ else if (to instanceof FieldRefNode fr) { }); // add invoke edges - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - InvokeExpr ie = s.getInvokeExpr(); + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { retDest = pag.findLocalVarNode(dest); } } LocalVarNode receiver; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = pag.findLocalVarNode(iie.getBase()); } else { // static call @@ -191,7 +193,7 @@ else if (to instanceof FieldRefNode fr) { this.addStoreEdge((LocalVarNode) argNode, receiver); } } - if (retDest != null && retDest.getType() instanceof RefLikeType) { + if (retDest != null && retDest.getType() instanceof ReferenceType) { if (statisfyAddingLoadCondition(targets)) { this.addLoadEdge(receiver, retDest); } @@ -212,13 +214,13 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); addNormalEdge(new TranEdge(param, param, DFA.TranCond.IPARAM)); } } - if (method.getReturnType() instanceof RefLikeType) { + if (method.getReturnType() instanceof ReferenceType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); addStoreEdge(mret, thisRef); } @@ -250,13 +252,13 @@ public void computeNodesInPrecisionLossPatterns() { workList.add(new Pair<>(thisRef, DFA.State.S)); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); startState.add(param); workList.add(new Pair<>(param, DFA.State.S)); } } - if (method.getReturnType() instanceof RefLikeType) { + if (method.getReturnType() instanceof ReferenceType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); startState.add(mret); workList.add(new Pair<>(mret, DFA.State.S)); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java index 4efabcd814d..e91354a5dd9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java @@ -20,8 +20,8 @@ import qilin.util.graph.DirectedGraph; import qilin.util.graph.DirectedGraphImpl; -import soot.SootMethod; import soot.jimple.toolkits.callgraph.CallGraph; +import sootup.core.model.SootMethod; import java.util.Collection; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java index 9a4f564be7c..b92a9ceb6b0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java @@ -19,7 +19,7 @@ package qilin.pta.toolkits.turner; import qilin.core.PTA; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java index f3ecde8894c..18ed2b167f8 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -25,8 +25,8 @@ import qilin.core.pag.MethodPAG; import qilin.core.pag.Node; import qilin.util.graph.MergedNode; -import soot.RefLikeType; -import soot.SootMethod; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.Set; @@ -50,7 +50,7 @@ protected boolean statisfyAddingLoadCondition(Set targets) { if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { return true; } - if (!(tgtmtd.getReturnType() instanceof RefLikeType)) { + if (!(tgtmtd.getReturnType() instanceof ReferenceType)) { continue; } MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); @@ -80,7 +80,7 @@ protected boolean satisfyAddingStoreCondition(int paramIndex, Set ta if (paramIndex == PointsToAnalysis.THIS_NODE) { parm = (LocalVarNode) tgtnf.caseThis(); } else { - if (tgtmtd.getParameterType(paramIndex) instanceof RefLikeType) { + if (tgtmtd.getParameterType(paramIndex) instanceof ReferenceType) { parm = (LocalVarNode) tgtnf.caseParm(paramIndex); } else { continue; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java index 18d34f64b07..642ea277058 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -24,8 +24,10 @@ import qilin.core.sets.PointsToSet; import qilin.pta.PTAConfig; import qilin.util.PTAUtils; -import soot.*; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; import java.util.*; @@ -55,7 +57,7 @@ protected void buildGraph() { SparkField f = contextField.getField(); if (f.getType() instanceof ArrayType at) { - if (at.baseType instanceof PrimType) { + if (at.getBaseType() instanceof PrimType) { return; } } @@ -243,11 +245,11 @@ boolean isFactoryObject(AllocNode heap) { return false; } Type retType = method.getReturnType(); - if (!(retType instanceof RefLikeType)) { + if (!(retType instanceof ReferenceType)) { return false; } if (retType instanceof ArrayType at) { - if (at.baseType instanceof PrimType) { + if (at.getBaseType() instanceof PrimType) { return false; } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java index fd65911cd11..3f45885e976 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java @@ -21,12 +21,12 @@ import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; +import qilin.core.pag.SparkField; import qilin.pta.PTAConfig; import qilin.util.graph.MergedNode; import qilin.util.graph.SCCMergedGraph; import qilin.util.graph.TopologicalSorter; -import soot.SootMethod; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; import java.util.*; import java.util.concurrent.ConcurrentHashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java index 2b9bb933eed..33cb0d39f99 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java @@ -22,7 +22,7 @@ import qilin.pta.toolkits.zipper.analysis.Zipper; import qilin.util.ANSIColor; import qilin.util.Stopwatch; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Comparator; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java index 29c07f3f609..ebc86bc094d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java @@ -11,8 +11,8 @@ import qilin.util.graph.MergedNode; import qilin.util.graph.SCCMergedGraph; import qilin.util.graph.TopologicalSorter; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java index 06f061d6f04..067dfff3acd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java @@ -10,9 +10,9 @@ import qilin.util.ANSIColor; import qilin.util.Stopwatch; import qilin.util.graph.ConcurrentDirectedGraphImpl; -import soot.RefType; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -98,12 +98,12 @@ public static void outputObjectFlowGraphSize(ObjectFlowGraph ofg) { public Set analyze() { reset(); System.out.println("Building PFGs (Pollution Flow Graphs) and computing precision-critical methods ..."); - List types = pta.getPag().getAllocNodes().stream() + List types = pta.getPag().getAllocNodes().stream() .map(AllocNode::getType) .distinct() .sorted(Comparator.comparing(Type::toString)) - .filter(t -> t instanceof RefType) - .map(t -> (RefType) t) + .filter(t -> t instanceof ClassType) + .map(t -> (ClassType) t) .collect(Collectors.toList()); if (Global.getThread() == Global.UNDEFINE) { computePCM(types); @@ -126,12 +126,12 @@ public Set analyze() { return pcm; } - private void computePCM(List types) { + private void computePCM(List types) { FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); types.forEach(type -> analyze(type, fa)); } - private void computePCMConcurrent(List types, int nThread) { + private void computePCMConcurrent(List types, int nThread) { ExecutorService executorService = Executors.newFixedThreadPool(nThread); types.forEach(type -> executorService.execute(() -> { @@ -151,7 +151,7 @@ private void computePCMConcurrent(List types, int nThread) { * @param fa Compute the set of precision-critical methods for a class/type and add these methods * to the pcm collection. */ - private void analyze(RefType type, FlowAnalysis fa) { + private void analyze(ClassType type, FlowAnalysis fa) { if (Global.isDebug()) { System.out.println("----------------------------------------"); } @@ -186,11 +186,11 @@ private void analyze(RefType type, FlowAnalysis fa) { pce.PCEMethodsOf(type).stream() .filter(m -> !m.isPrivate() && !m.isStatic()) .filter(m -> ToolUtil.isInnerType( - m.getDeclaringClass().getType(), type)) + m.getDeclaringClassType(), type)) .forEach(outms::add); pce.PCEMethodsOf(type).stream() .filter(m -> !m.isPrivate() && !m.isStatic()) - .filter(m -> m.getDeclaringClass().getType().equals(type) + .filter(m -> m.getDeclaringClassType().equals(type) && m.toString().contains("access$")) .forEach(outms::add); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java deleted file mode 100644 index 2f1b0262ca3..00000000000 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java +++ /dev/null @@ -1,19 +0,0 @@ -package qilin.pta.toolkits.zipper.cases; - -// NO IN , NO OUT, CASE 4. -public class CaseA { - static class A { - Object f; - } - - A create() { - return new A(); - } - - void foo() { - Object o = new Object(); - A a = create(); - a.f = o; - o = a.f; - } -} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java deleted file mode 100644 index 0d3084bb9ad..00000000000 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java +++ /dev/null @@ -1,25 +0,0 @@ -package qilin.pta.toolkits.zipper.cases; - -// No Out, case 2 -public class CaseB { - static class A { - Object f; - - void bar(Object q) { - this.f = q; - } - } - - void foo() { - Object oy = new Object(); - Object oz = new Object(); - - A a = new A(); - a.bar(oy); - Object o = a.f; - -// A a1 = new A(); -// a1.bar(oz); -// Object o1 = a1.f; - } -} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java deleted file mode 100644 index 9a8eb9a75a8..00000000000 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java +++ /dev/null @@ -1,35 +0,0 @@ -package qilin.pta.toolkits.zipper.cases; - -public class CaseC { - static class A { - Object f; - } - - A f; - - // case 2; - CaseC() { - A a = new A(); - this.f = a; - } - - // does not consider this_variable. - A getF() { - A r = this.f; - return r; - } - - void foo() { - Object o1 = new Object(); - CaseC c1 = new CaseC(); - A a1 = c1.getF(); - a1.f = o1; - Object o1x = a1.f; - -// Object o2 = new Object(); -// CaseC c2 = new CaseC(); -// A a2 = c2.getF(); -// a2.f = o2; -// Object o2x = a2.f; - } -} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java deleted file mode 100644 index f799dccea5c..00000000000 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java +++ /dev/null @@ -1,21 +0,0 @@ -package qilin.pta.toolkits.zipper.cases; - -public class CaseD { - static class A { - Object f, g; - } - - Object id(Object p) { - A a = new A(); - a.f = p; - Object r = a.f; - return r; - } - - Object fakeId(Object p) { - A a = new A(); - a.f = p; - a.g = new Object(); - return a.g; - } -} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java index 9bfa4814b67..39b29874e4a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -8,11 +8,14 @@ import qilin.util.ANSIColor; import qilin.util.graph.ConcurrentDirectedGraphImpl; import qilin.util.graph.Reachability; -import soot.*; -import soot.jimple.AssignStmt; -import soot.jimple.InstanceInvokeExpr; -import soot.jimple.InvokeExpr; -import soot.jimple.Stmt; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; import java.util.*; import java.util.stream.Collectors; @@ -142,14 +145,14 @@ private void dfs(Node node) { pta.getCgb().getReceiverToSitesMap() .getOrDefault(var, Collections.emptySet()) .forEach(vcs -> { - Stmt callsiteStmt = (Stmt) vcs.getUnit(); - InvokeExpr invo = callsiteStmt.getInvokeExpr(); - if (!(invo instanceof InstanceInvokeExpr)) { + Stmt callsiteStmt = vcs.getUnit(); + AbstractInvokeExpr invo = callsiteStmt.getInvokeExpr(); + if (!(invo instanceof AbstractInstanceInvokeExpr)) { return; } - if (callsiteStmt instanceof AssignStmt assignStmt) { + if (callsiteStmt instanceof JAssignStmt assignStmt) { Value lv = assignStmt.getLeftOp(); - if (!(lv.getType() instanceof RefLikeType)) { + if (!(lv.getType() instanceof ReferenceType)) { return; } final VarNode to = (VarNode) pta.getPag().findValNode(lv); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java index 2be92fdf076..3d9a2b47d30 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java @@ -4,9 +4,11 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.pta.toolkits.zipper.Global; -import soot.SootMethod; -import soot.Value; -import soot.jimple.*; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.*; @@ -106,9 +108,9 @@ private void init() { if (!callee.isStatic()) { MethodNodeFactory calleeNF = pta.getPag().getMethodPAG(callee).nodeFactory(); LocalVarNode thisVar = (LocalVarNode) calleeNF.caseThis(); - InvokeExpr ie = callsite.getInvokeExpr(); + AbstractInvokeExpr ie = callsite.getInvokeExpr(); Value base = null; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { base = iie.getBase(); } if (base != null) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java index 4f422c95d0b..734f56c6a54 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java @@ -18,6 +18,7 @@ package qilin.pta.tools; +import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.core.solver.Propagator; @@ -29,8 +30,9 @@ import qilin.pta.toolkits.conch.Conch; import qilin.stat.IEvaluator; import qilin.util.Stopwatch; -import soot.*; -import soot.jimple.spark.pag.SparkField; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; import java.util.HashSet; import java.util.Set; @@ -92,7 +94,7 @@ public Node parameterize(Node n, Context context) { } @Override - public MethodOrMethodContext parameterize(SootMethod method, Context context) { + public ContextMethod parameterize(SootMethod method, Context context) { return basePTA.parameterize(method, context); } @@ -112,7 +114,7 @@ public Context emptyContext() { } @Override - public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context createCalleeCtx(ContextMethod caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { return basePTA.createCalleeCtx(caller, receiverNode, callSite, target); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java index 952a6e92fca..69006afea65 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java @@ -24,10 +24,10 @@ import qilin.pta.toolkits.eagle.Eagle; import qilin.util.Pair; import qilin.util.Stopwatch; -import soot.Local; -import soot.jimple.Expr; -import soot.jimple.NewArrayExpr; -import soot.jimple.Stmt; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.common.expr.Expr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.stmt.Stmt; import java.io.FileNotFoundException; import java.io.PrintWriter; @@ -81,8 +81,8 @@ protected void writeToFile(Map partialResults) throws FileNotFo return; } String newExpr = heap.getNewExpr().toString(); - if (heap.getNewExpr() instanceof NewArrayExpr nae) { - newExpr = "new " + nae.getBaseType().toString() + "[]"; + if (heap.getNewExpr() instanceof JNewArrayExpr nae) { + newExpr = "new " + nae.getBaseType() + "[]"; } String heapSig = heap.getMethod().toString() + "/" + newExpr; heapWriter.write(heapSig); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index 83a3aa47b92..8724ac093af 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -28,9 +28,16 @@ import qilin.pta.StagedPTA; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.*; -import soot.jimple.*; -import soot.util.queue.QueueReader; +import qilin.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.HashSet; import java.util.Map; @@ -110,12 +117,12 @@ protected void select() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (ContextMethod momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); - if (method.isPhantom()) { - return; - } +// if (method.isPhantom()) { +// return; +// } MethodPAG srcmpag = pag.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -140,26 +147,24 @@ protected void extraStats() { } } } - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - - InvokeExpr ie = s.getInvokeExpr(); + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } nodes.add(arg); } - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { Value base = iie.getBase(); if (base instanceof Local) { nodes.add(base); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 7767fcd4cd8..f3923df26eb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -30,9 +30,15 @@ import qilin.pta.StagedPTA; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.*; -import soot.jimple.*; -import soot.util.queue.QueueReader; +import qilin.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.HashSet; import java.util.Map; @@ -111,12 +117,12 @@ protected void select() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (ContextMethod momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); - if (method.isPhantom()) { - return; - } +// if (method.isPhantom()) { +// return; +// } MethodPAG srcmpag = pag.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -141,30 +147,26 @@ protected void extraStats() { } } } - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - - InvokeExpr ie = s.getInvokeExpr(); + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } nodes.add(arg); } - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { Value base = iie.getBase(); - if (base instanceof Local) { - nodes.add(base); - } + nodes.add(base); } } for (Object o : nodes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index dd06b534f69..b0b72ec6235 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -30,9 +30,16 @@ import qilin.pta.StagedPTA; import qilin.pta.toolkits.zipper.Main; import qilin.util.Stopwatch; -import soot.*; -import soot.jimple.*; -import soot.util.queue.QueueReader; +import qilin.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.HashSet; import java.util.Set; @@ -80,13 +87,13 @@ protected void preAnalysis() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1]; int[] totalN = new int[1]; - for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (ContextMethod momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); - if (method.isPhantom()) { - return; - } +// if (method.isPhantom()) { +// return; +// } MethodPAG srcmpag = pag.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -111,26 +118,24 @@ protected void extraStats() { } } } - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - - InvokeExpr ie = s.getInvokeExpr(); + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } nodes.add(arg); } - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { Value base = iie.getBase(); if (base instanceof Local) { nodes.add(base); diff --git a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java index f8fb91bf805..eb7ca062137 100644 --- a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java @@ -21,8 +21,7 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; -import soot.SootClass; -import soot.SootMethod; +import sootup.core.model.SootClass; import java.util.Set; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index cb30261f5dc..810b04b3be8 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -22,12 +22,12 @@ import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.FakeMainFactory; +import qilin.core.pag.ContextMethod; import qilin.core.pag.ContextVarNode; import qilin.core.pag.LocalVarNode; -import soot.MethodOrMethodContext; -import soot.SootMethod; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.model.SootMethod; import java.util.HashSet; import java.util.Iterator; @@ -38,8 +38,8 @@ public class CallGraphStat implements AbstractStat { private final Set reachableMethods = new HashSet<>(); private int reachableStatic = 0; - private final Set reachableParameterizedMethods = new HashSet<>(); - private final Set reachableAppParameterizedMethods = new HashSet<>(); + private final Set reachableParameterizedMethods = new HashSet<>(); + private final Set reachableAppParameterizedMethods = new HashSet<>(); private final Set reachableAppMethods = new HashSet<>(); private int reachableAppStatic = 0; private int CSCallEdges = 0; @@ -69,7 +69,7 @@ public CallGraphStat(PTA pta) { private void init() { CallGraph csCallGraph = pta.getCgb().getCallGraph(); CSCallEdges = csCallGraph.size(); - for (final MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + for (final ContextMethod momc : pta.getCgb().getReachableMethods()) { final SootMethod m = momc.method(); boolean toApp = m.getDeclaringClass().isApplicationClass(); reachableParameterizedMethods.add(momc); diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index ad206904c8e..c5857b21878 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -25,15 +25,16 @@ import qilin.core.pag.Parm; import qilin.core.sets.PointsToSet; import qilin.util.Util; -import soot.SootClass; -import soot.SootMethod; -import soot.Type; -import soot.jimple.AssignStmt; -import soot.jimple.CastExpr; -import soot.jimple.InvokeExpr; -import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.core.types.Type; import java.io.BufferedWriter; import java.io.File; @@ -81,7 +82,7 @@ private String getFilePath(String fileName) { private void dumpMethods(Collection methods, String fileName) { StringBuilder builder = new StringBuilder(); for (SootMethod sm : methods) { - String sig = sm.getSignature(); + String sig = sm.getSignature().toString(); sig = Util.stripQuotes(sig); builder.append(sig); builder.append("\n"); @@ -126,11 +127,11 @@ public void dumpClassTypes(Collection classes) { Util.writeToFile(finalPath, builder.toString()); } - public void dumpPolyCalls(Map polys) { + public void dumpPolyCalls(Map polys) { StringBuilder builder = new StringBuilder(); - for (InvokeExpr ie : polys.keySet()) { - SootMethod tgt = ie.getMethod(); - String polySig = polys.get(ie).getSignature() + "/" + tgt.getDeclaringClass() + "." + tgt.getName() + "\n"; + for (AbstractInvokeExpr ie : polys.keySet()) { + MethodSignature tgtSig = ie.getMethodSignature(); + String polySig = polys.get(ie).getSignature() + "/" + tgtSig.getDeclClassType() + "." + tgtSig.getName() + "\n"; builder.append(polySig); } String polyCalls = "PolyCalls.csv"; @@ -142,16 +143,16 @@ public void dumpMayFailCasts(Map> casts) { StringBuilder builder = new StringBuilder(); for (SootMethod sm : casts.keySet()) { for (Stmt stmt : casts.get(sm)) { - AssignStmt as = (AssignStmt) stmt; - CastExpr ce = (CastExpr) as.getRightOp(); - final Type targetType = ce.getCastType(); + JAssignStmt as = (JAssignStmt) stmt; + JCastExpr ce = (JCastExpr) as.getRightOp(); + final Type targetType = ce.getType(); builder.append(sm.toString()); builder.append("\t"); - builder.append(targetType.toString()); + builder.append(targetType); builder.append("\t"); builder.append(sm).append("/").append(ce.getOp().toString()); builder.append("\t"); - builder.append(sm).append("/").append(as.getLeftOp().toString()); + builder.append(sm).append("/").append(as.getLeftOp()); builder.append("\n"); } } @@ -175,7 +176,7 @@ public void dumpMethodThrowPointsto(Map m2pts) { StringBuilder builder = new StringBuilder(); builder.append(n.toString()); builder.append("\t"); - String sig = Util.stripQuotes(sm.getSignature()); + String sig = Util.stripQuotes(sm.getSignature().toString()); builder.append(sig); builder.append("\n"); try { diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java index 3ff9a9d5459..84413d55fc3 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -21,10 +21,15 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; +import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; -import soot.*; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; import java.util.*; @@ -212,7 +217,7 @@ private void init() { } for (int i = 0; i < sm.getParameterCount(); ++i) { Type mType = sm.getParameterType(i); - if (mType instanceof RefLikeType) { + if (mType instanceof ReferenceType) { mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); if (!handledNatives.contains(sm.toString())) { mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseParm(i)); diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index ea56dcd1ed6..29df4b4d6ca 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -7,10 +7,18 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.*; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; import java.util.*; @@ -42,7 +50,7 @@ public void end() { // loop over all reachable method's statement to find casts, local // references, virtual call sites Set reachableMethods = new HashSet<>(); - for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + for (ContextMethod momc : pta.getCgb().getReachableMethods()) { final SootMethod sm = momc.method(); reachableMethods.add(sm); } @@ -50,12 +58,11 @@ public void end() { int totalCastsMayFail = 0; for (SootMethod sm : reachableMethods) { // All the statements in the method - for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { - Stmt st = (Stmt) unit; + for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { // virtual calls if (st.containsInvokeExpr()) { - InvokeExpr ie = st.getInvokeExpr(); - if (!(ie instanceof StaticInvokeExpr)) { + AbstractInvokeExpr ie = st.getInvokeExpr(); + if (!(ie instanceof JStaticInvokeExpr)) { // Virtual, Special or Instance // have to check target soot method, cannot just // count edges @@ -66,12 +73,12 @@ public void end() { totalPolyCalls++; } } - } else if (st instanceof AssignStmt) { - Value rhs = ((AssignStmt) st).getRightOp(); - Value lhs = ((AssignStmt) st).getLeftOp(); - if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { - final Type targetType = ((CastExpr) rhs).getCastType(); - Value v = ((CastExpr) rhs).getOp(); + } else if (st instanceof JAssignStmt) { + Value rhs = ((JAssignStmt) st).getRightOp(); + Value lhs = ((JAssignStmt) st).getLeftOp(); + if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { + final Type targetType = ((JCastExpr) rhs).getType(); + Value v = ((JCastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; } @@ -122,7 +129,7 @@ private void ptsStat() { } for (int i = 0; i < sm.getParameterCount(); ++i) { Type mType = sm.getParameterType(i); - if (mType instanceof RefLikeType) { + if (mType instanceof ReferenceType) { mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); } } diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index 4386eca2762..e0ae7993f9e 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -22,11 +22,20 @@ import qilin.core.PTA; import qilin.core.builder.FakeMainFactory; import qilin.core.pag.AllocNode; +import qilin.core.pag.ContextMethod; import qilin.util.PTAUtils; -import soot.*; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; +import sootup.core.types.Type; import java.util.*; @@ -44,7 +53,7 @@ public class TypeClientStat implements AbstractStat { private int totalStaticCalls = 0; private int totalPolyCallTargets = 0; private int unreachable = 0; - private final Map polyCalls = new HashMap<>(); + private final Map polyCalls = new HashMap<>(); private final Map> mayFailCasts = new HashMap<>(); public TypeClientStat(PTA pta) { @@ -58,7 +67,7 @@ private void init() { // loop over all reachable method's statement to find casts, local // references, virtual call sites Set reachableMethods = new HashSet<>(); - for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + for (ContextMethod momc : pta.getCgb().getReachableMethods()) { final SootMethod sm = momc.method(); reachableMethods.add(sm); } @@ -67,13 +76,11 @@ private void init() { boolean app = sm.getDeclaringClass().isApplicationClass(); // All the statements in the method - for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { - Stmt st = (Stmt) unit; - + for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { // virtual calls if (st.containsInvokeExpr()) { - InvokeExpr ie = st.getInvokeExpr(); - if (ie instanceof StaticInvokeExpr) { + AbstractInvokeExpr ie = st.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { totalStaticCalls++; } else {// Virtual, Special or Instance totalVirtualCalls++; @@ -98,12 +105,12 @@ private void init() { } } } - } else if (st instanceof AssignStmt) { - Value rhs = ((AssignStmt) st).getRightOp(); - Value lhs = ((AssignStmt) st).getLeftOp(); - if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { - final Type targetType = ((CastExpr) rhs).getCastType(); - Value v = ((CastExpr) rhs).getOp(); + } else if (st instanceof JAssignStmt) { + Value rhs = ((JAssignStmt) st).getRightOp(); + Value lhs = ((JAssignStmt) st).getLeftOp(); + if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { + final Type targetType = rhs.getType(); + Value v = ((JCastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; } diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java index 040caedfe1f..a6e3beed0b1 100644 --- a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -21,12 +21,12 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.ContextMethod; import qilin.core.sets.PointsToSet; -import soot.MethodOrMethodContext; -import soot.SootMethod; -import soot.Unit; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.HashMap; import java.util.HashSet; @@ -48,10 +48,10 @@ public YummyStat(PTA pta) { } private void init() { - Map> target2callsites = new HashMap<>(); + Map> target2callsites = new HashMap<>(); CallGraph ciCallGraph = pta.getCallGraph(); for (Edge edge : ciCallGraph) { - Unit callUnit = edge.srcUnit(); + Stmt callUnit = edge.srcUnit(); SootMethod target = edge.tgt(); if (callUnit != null && target != null) { target2callsites.computeIfAbsent(target, k -> new HashSet<>()).add(callUnit); @@ -67,7 +67,7 @@ private void init() { Set instanceReachables = new HashSet<>(); - for (final MethodOrMethodContext momc : pta.getReachableMethods()) { + for (final ContextMethod momc : pta.getReachableMethods()) { SootMethod method = momc.method(); if (!method.isPhantom() && !method.isStatic()) { instanceReachables.add(method); From 676a7ddad610fd63013b36e60c18b8ce9c08927a Mon Sep 17 00:00:00 2001 From: Dongjie He Date: Tue, 27 Dec 2022 14:58:43 +1100 Subject: [PATCH 003/145] update sootup.qilin --- .../common/expr/JNewMultiArrayExpr.java | 2 +- .../qilin/core/builder/FakeMainFactory.java | 3 + .../qilin/core/builder/MethodNodeFactory.java | 35 ++++++---- .../JavaIoFileSystemGetFileSystemNative.java | 10 ++- .../natives/JavaIoFileSystemListNative.java | 9 ++- .../core/natives/JavaLangReflectArrayGet.java | 9 +-- .../core/natives/JavaLangReflectArraySet.java | 7 +- .../JavaLangSystemArraycopyNative.java | 11 ++-- .../natives/JavaLangThreadCurrentThread.java | 3 +- .../java/qilin/core/pag/ArrayElement.java | 4 +- .../main/java/qilin/core/pag/MethodPAG.java | 18 ++++- .../src/main/java/qilin/core/pag/PAG.java | 12 ++-- .../src/main/java/qilin/core/pag/Parm.java | 3 +- .../core/reflection/ReflectionModel.java | 3 +- .../qilin/core/reflection/TamiflexModel.java | 66 +++++++++++-------- .../java/qilin/core/sets/PointsToSet.java | 4 +- .../core/sets/UnmodifiablePointsToSet.java | 6 +- .../parm/heapabst/HeuristicAbstractor.java | 7 +- 18 files changed, 138 insertions(+), 74 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java index 1be30ab14ce..acbea747fe9 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java @@ -106,7 +106,7 @@ public ArrayType getBaseType() { return baseType; } - public Value getSize(@Nonnull int index) { + public Immediate getSize(@Nonnull int index) { return sizes.get(index); } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index a069637031f..5c5cc4fe45c 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -21,6 +21,9 @@ import qilin.CoreConfig; import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; import java.util.ArrayList; import java.util.Collections; diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index cbe2779d350..20d86d917ea 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -24,6 +24,7 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Pair; +import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; @@ -47,13 +48,14 @@ import sootup.core.jimple.common.stmt.JReturnStmt; import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.Modifier; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; /** * @author Ondrej Lhotak @@ -141,7 +143,9 @@ protected void handleInvokeStmt(Stmt s) { } private void resolveClinit(JStaticFieldRef staticFieldRef) { - PTAUtils.clinitsOf(staticFieldRef.getField().getDeclaringClass()).forEach(mpag::addTriggeredClinit); + ClassType declClassType = staticFieldRef.getFieldSignature().getDeclClassType(); + SootClass sootClass = (SootClass) pag.getView().getClass(declClassType).get(); + PTAUtils.clinitsOf(sootClass).forEach(mpag::addTriggeredClinit); } /** @@ -213,7 +217,7 @@ private AllocNode caseNewExpr(JNewExpr ne) { } private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { - SootField sf = ifr.getField(); + SootField sf = (SootField) pag.getView().getField(ifr.getFieldSignature()).get(); // if (sf == null) { // sf = new SootField(ifr.getFieldSignature(), ifr.getType(), Modifier.PUBLIC); // sf.setNumber(Scene.v().getFieldNumberer().size()); @@ -226,7 +230,7 @@ private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { ArrayType type = (ArrayType) nmae.getType(); int pos = 0; - AllocNode prevAn = pag.makeAllocNode(new JNewArrayExpr(type, nmae.getSize(pos)), type, method); + AllocNode prevAn = pag.makeAllocNode(new JNewArrayExpr(type, nmae.getSize(pos), JavaIdentifierFactory.getInstance()), type, method); VarNode prevVn = pag.makeLocalVarNode(prevAn.getNewExpr(), prevAn.getType(), method); mpag.addInternalEdge(prevAn, prevVn); // new VarNode ret = prevVn; @@ -237,13 +241,13 @@ private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { } type = (ArrayType) t; ++pos; - Value sizeVal; + Immediate sizeVal; if (pos < nmae.getSizeCount()) { sizeVal = nmae.getSize(pos); } else { sizeVal = IntConstant.getInstance(1); } - AllocNode an = pag.makeAllocNode(new JNewArrayExpr(type, sizeVal), type, method); + AllocNode an = pag.makeAllocNode(new JNewArrayExpr(type, sizeVal, JavaIdentifierFactory.getInstance()), type, method); VarNode vn = pag.makeLocalVarNode(an.getNewExpr(), an.getType(), method); mpag.addInternalEdge(an, vn); // new mpag.addInternalEdge(vn, pag.makeFieldRefNode(prevVn, ArrayElement.v())); // store @@ -260,7 +264,7 @@ private VarNode caseCastExpr(JCastExpr ce) { } public VarNode caseThis() { - Type type = method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); + Type type = method.isStatic() ? JavaIdentifierFactory.getInstance().getType("java.lang.Object") : method.getDeclaringClassType(); VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THIS_NODE), type, method); ret.setInterProcTarget(); return ret; @@ -279,7 +283,7 @@ public VarNode caseRet() { } public VarNode caseMethodThrow() { - VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), RefType.v("java.lang.Throwable"), method); + VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), JavaIdentifierFactory.getInstance().getType("java.lang.Throwable"), method); ret.setInterProcSource(); return ret; } @@ -306,7 +310,7 @@ private VarNode caseParameterRef(JParameterRef pr) { } private VarNode caseStaticFieldRef(JStaticFieldRef sfr) { - return pag.makeGlobalVarNode(sfr.getField(), sfr.getType()); + return pag.makeGlobalVarNode(sfr.getFieldSignature(), sfr.getType()); } private Node caseNullConstant(NullConstant nr) { @@ -314,23 +318,26 @@ private Node caseNullConstant(NullConstant nr) { } private VarNode caseStringConstant(StringConstant sc) { + Type type = JavaIdentifierFactory.getInstance().getType("java.lang.String"); AllocNode stringConstantNode = pag.makeStringConstantNode(sc); - VarNode stringConstantVar = pag.makeGlobalVarNode(sc, RefType.v("java.lang.String")); + VarNode stringConstantVar = pag.makeGlobalVarNode(sc, type); mpag.addInternalEdge(stringConstantNode, stringConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), RefType.v("java.lang.String"), method); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), type, method); mpag.addInternalEdge(stringConstantVar, vn); return vn; } public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { - return pag.makeLocalVarNode(invoke, RefType.v("java.lang.Throwable"), method); + Type type = JavaIdentifierFactory.getInstance().getType("java.lang.Throwable"); + return pag.makeLocalVarNode(invoke, type, method); } final public VarNode caseClassConstant(ClassConstant cc) { + Type type = JavaIdentifierFactory.getInstance().getType("java.lang.Class"); AllocNode classConstant = pag.makeClassConstantNode(cc); - VarNode classConstantVar = pag.makeGlobalVarNode(cc, RefType.v("java.lang.Class")); + VarNode classConstantVar = pag.makeGlobalVarNode(cc, type); mpag.addInternalEdge(classConstant, classConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), RefType.v("java.lang.Class"), method); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), type, method); mpag.addInternalEdge(classConstantVar, vn); return vn; } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index a84249c104e..a50741b3774 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -18,6 +18,12 @@ package qilin.core.natives; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.java.core.JavaIdentifierFactory; + public class JavaIoFileSystemGetFileSystemNative extends NativeMethod { public JavaIoFileSystemGetFileSystemNative(SootMethod method) { super(method); @@ -31,8 +37,8 @@ public JavaIoFileSystemGetFileSystemNative(SootMethod method) { * only exists in old version of JDK(e.g., JDK6). */ public void simulate() { - Value newLocal0 = getNew(RefType.v("java.io.UnixFileSystem")); + Value newLocal0 = getNew((ClassType) JavaIdentifierFactory.getInstance().getType("java.io.UnixFileSystem")); addInvoke(newLocal0, "()>"); - addReturn(newLocal0); + addReturn((Immediate) newLocal0); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java index 462c483bec2..67bb0898334 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -18,9 +18,13 @@ package qilin.core.natives; +import sootup.core.IdentifierFactory; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.core.types.ReferenceType; +import sootup.java.core.JavaIdentifierFactory; public class JavaIoFileSystemListNative extends NativeMethod { public JavaIoFileSystemListNative(SootMethod method) { @@ -33,8 +37,9 @@ public JavaIoFileSystemListNative(SootMethod method) { * only exists in old JDK(e.g., JDK6). */ public void simulate() { - Value arrLocal = getNewArray(RefType.v("java.lang.String")); - Value elem = getNew(RefType.v("java.lang.String")); + IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); + Value arrLocal = getNewArray((ReferenceType) idFactory.getType("java.lang.String")); + Value elem = getNew((ClassType) idFactory.getType("java.lang.String")); // addInvoke(elem, "()>"); addAssign(getArrayRef(arrLocal), elem); addReturn((Immediate) arrLocal); diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index 15e94b9853f..d6880c29369 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -18,11 +18,11 @@ package qilin.core.natives; -import soot.ArrayType; -import soot.RefType; +import sootup.core.IdentifierFactory; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.java.core.JavaIdentifierFactory; /* * @@ -35,9 +35,10 @@ public class JavaLangReflectArrayGet extends NativeMethod { @Override void simulate() { - Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); + Value arrayBase = getPara(0, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); Value arrayRef = getArrayRef(arrayBase); - Value ret = getNextLocal(RefType.v("java.lang.Object")); + Value ret = getNextLocal(idFactory.getType("java.lang.Object")); addAssign(ret, arrayRef); addReturn((Immediate) ret); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java index b5ca730795c..070723a4fa9 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -18,10 +18,10 @@ package qilin.core.natives; -import soot.ArrayType; -import soot.RefType; +import sootup.core.IdentifierFactory; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.java.core.JavaIdentifierFactory; /* * handle @@ -34,7 +34,8 @@ public class JavaLangReflectArraySet extends NativeMethod { @Override void simulate() { - Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); + Value arrayBase = getPara(0, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); Value rightValue = getPara(2); Value arrayRef = getArrayRef(arrayBase); addAssign(arrayRef, rightValue); // a[] = b; diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java index 6a19deb4f6a..c100d8c8415 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -18,10 +18,10 @@ package qilin.core.natives; -import soot.ArrayType; -import soot.RefType; +import sootup.core.IdentifierFactory; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.java.core.JavaIdentifierFactory; /* * This file will be temporarily discarded. Yes, it is correct but need one more level of context. @@ -39,11 +39,12 @@ public JavaLangSystemArraycopyNative(SootMethod method) { public void simulate() { // Value srcArr = getPara(0); // Value dstArr = getPara(2); - Value srcArr = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); - Value dstArr = getPara(2, ArrayType.v(RefType.v("java.lang.Object"), 1)); + IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); + Value srcArr = getPara(0, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); + Value dstArr = getPara(2, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); Value src = getArrayRef(srcArr); Value dst = getArrayRef(dstArr); - Value temp = getNextLocal(RefType.v("java.lang.Object")); + Value temp = getNextLocal(idFactory.getType("java.lang.Object")); addAssign(temp, src); addAssign(dst, temp); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java index a7c7c0d52fd..d17c374712b 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -22,6 +22,7 @@ import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.java.core.JavaIdentifierFactory; public class JavaLangThreadCurrentThread extends NativeMethod { JavaLangThreadCurrentThread(SootMethod method) { @@ -30,7 +31,7 @@ public class JavaLangThreadCurrentThread extends NativeMethod { @Override void simulate() { - Value lv = getNextLocal(RefType.v("java.lang.Thread")); + Value lv = getNextLocal(JavaIdentifierFactory.getInstance().getType("java.lang.Thread")); Value rv = PTAScene.v().getFieldCurrentThread(); addAssign(lv, rv); addReturn((Immediate) lv); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java index d6b74fa2c2b..6af84842c5c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java @@ -18,8 +18,8 @@ package qilin.core.pag; -import soot.RefType; import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; /** * Represents an array element. @@ -50,6 +50,6 @@ public final void setNumber(int number) { } public Type getType() { - return RefType.v("java.lang.Object"); + return JavaIdentifierFactory.getInstance().getType("java.lang.Object"); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index 84975fa87a0..242382ed081 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -31,7 +31,12 @@ import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.core.views.View; +import sootup.java.core.JavaIdentifierFactory; import java.util.*; @@ -52,6 +57,7 @@ public class MethodPAG { */ private final Map> exceptionEdges = DataFactory.createMap(); protected MethodNodeFactory nodeFactory; + protected PAG pag; SootMethod method; /* * List[i-1] is wrappered in List[i]. @@ -63,6 +69,7 @@ public class MethodPAG { public final Map>> node2wrapperedTraps = DataFactory.createMap(); public MethodPAG(PAG pag, SootMethod m, Body body) { + this.pag = pag; this.method = m; this.nodeFactory = new MethodNodeFactory(pag, this); this.body = body; @@ -97,7 +104,10 @@ protected void build() { protected void buildNormal() { if (method.isStatic()) { - PTAUtils.clinitsOf(method.getDeclaringClass()).forEach(this::addTriggeredClinit); + View view = pag.getView(); + ClassType declClassType = method.getDeclaringClassType(); + SootClass declClass = (SootClass) view.getClass(declClassType).get(); + PTAUtils.clinitsOf(declClass).forEach(this::addTriggeredClinit); } for (Stmt unit : body.getStmts()) { try { @@ -167,7 +177,11 @@ private void addStmtTrap(Node src, Stmt stmt, Trap trap) { protected void addMiscEdges() { if (method.getSignature().equals("(java.lang.Object,java.lang.ref.ReferenceQueue)>")) { // Implements the special status of java.lang.ref.Reference just as in Doop (library/reference.logic). - JStaticFieldRef sfr = Jimple.newStaticFieldRef(RefType.v("java.lang.ref.Reference").getSootClass().getFieldByName("pending").makeRef()); + ClassType type = (ClassType) JavaIdentifierFactory.getInstance().getType("java.lang.ref.Reference"); + View view = pag.getView(); + SootClass sootClass = (SootClass) view.getClass(type).get(); + SootField sootField = (SootField) sootClass.getField("pending").get(); + JStaticFieldRef sfr = Jimple.newStaticFieldRef(sootField.getSignature()); addInternalEdge(nodeFactory.caseThis(), nodeFactory.getNode(sfr)); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index a60c480e68a..44dc038a21a 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -50,6 +50,7 @@ import sootup.core.model.SootMethod; import sootup.core.types.Type; import sootup.core.views.View; +import sootup.java.core.language.JavaJimple; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -123,6 +124,10 @@ public PAG(View view, PTA pta) { this.locals = DataFactory.createSet(100000); } + public View getView() { + return this.view; + } + public void setEdgeQueue(ChunkedQueue edgeQueue) { this.edgeQueue = edgeQueue; } @@ -319,7 +324,7 @@ public AllocNode makeAllocNode(Object newExpr, Type type, SootMethod m) { public AllocNode makeStringConstantNode(StringConstant sc) { StringConstant stringConstant = sc; if (!CoreConfig.v().getPtaConfig().stringConstants) { - stringConstant = StringConstant.v(PointsToAnalysis.STRING_NODE); + stringConstant = JavaJimple.getInstance().newStringConstant(PointsToAnalysis.STRING_NODE); } AllocNode ret = valToAllocNode.get(stringConstant); if (ret == null) { @@ -518,7 +523,7 @@ public ContextVarNode findContextVarNode(Local baseValue, Context context) { protected ReflectionModel createReflectionModel() { ReflectionModel model; if (CoreConfig.v().getAppConfig().REFLECTION_LOG != null && CoreConfig.v().getAppConfig().REFLECTION_LOG.length() > 0) { - model = new TamiflexModel(); + model = new TamiflexModel(view); } else { model = new NopReflectionModel(); } @@ -563,8 +568,7 @@ private void handleArrayCopy(SootMethod method) { if (s.containsInvokeExpr()) { AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); if (invokeExpr instanceof JStaticInvokeExpr sie) { - SootMethod sm = sie.getMethod(); - String sig = sm.getSignature(); + String sig = sie.getMethodSignature().toString(); if (sig.equals("")) { Value srcArr = sie.getArg(0); if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java index 38e0d7f0487..12b8c6aae9a 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java @@ -21,6 +21,7 @@ import qilin.core.PointsToAnalysis; import sootup.core.model.SootMethod; import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; import java.util.Objects; @@ -68,7 +69,7 @@ public Type getType() { if (index == PointsToAnalysis.RETURN_NODE) { return method.getReturnType(); } else if (index == PointsToAnalysis.THIS_NODE) { - return method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); + return method.isStatic() ? JavaIdentifierFactory.getInstance().getType("java.lang.Object") : method.getDeclaringClassType(); } return method.getParameterType(index); diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index 55f38f035d5..61cf207ab96 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; public abstract class ReflectionModel { @@ -73,7 +74,7 @@ public void buildReflection(SootMethod m) { return; } Map> newUnits = DataFactory.createMap(); - UnitPatchingChain units = PTAUtils.getMethodBody(m).getStmts(); + List units = PTAUtils.getMethodBody(m).getStmts(); for (final Stmt s : units) { if (s.containsInvokeExpr()) { newUnits.put(s, transform(s)); diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index e8f6152ce4d..7287939707b 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -22,6 +22,7 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; +import sootup.core.IdentifierFactory; import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; @@ -42,9 +43,13 @@ import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.signatures.FieldSignature; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import sootup.core.views.View; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.language.JavaJimple; import java.io.BufferedReader; import java.io.FileInputStream; @@ -57,9 +62,11 @@ */ public class TamiflexModel extends ReflectionModel { + protected View view; protected Map>> reflectionMap; - public TamiflexModel() { + public TamiflexModel(View view) { + this.view = view; reflectionMap = DataFactory.createMap(); parseTamiflexLog(CoreConfig.v().getAppConfig().REFLECTION_LOG, false); } @@ -73,8 +80,7 @@ Collection transformClassForName(Stmt s) { if (classForNames.containsKey(s)) { Collection fornames = classForNames.get(s); for (String clazz : fornames) { - Type refType = RefType.v(clazz); - ClassConstant cc = ClassConstant.fromType(refType); + ClassConstant cc = JavaJimple.getInstance().newClassConstant(clazz); if (s instanceof JAssignStmt jassign) { Value lvalue = jassign.getLeftOp(); ret.add(new JAssignStmt(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); @@ -97,10 +103,12 @@ protected Collection transformClassNewInstance(Stmt s) { Collection classNames = classNewInstances.get(s); for (String clsName : classNames) { SootClass cls = PTAScene.v().getSootClass(clsName); - if (cls.declaresMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()"))) { + MethodSubSignature msubsig = view.getIdentifierFactory().parseMethodSubSignature("void ()"); + Optional constrOpt = cls.getMethod(msubsig); + if (constrOpt.isPresent()) { JNewExpr newExpr = Jimple.newNewExpr(cls.getType()); ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); - SootMethod constructor = cls.getMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()")); + SootMethod constructor = constrOpt.get(); ret.add(Jimple.newInvokeStmt(Jimple.newSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), Collections.emptyList()), StmtPositionInfo.createNoStmtPositionInfo())); } } @@ -121,13 +129,12 @@ protected Collection transformContructorNewInstance(Stmt s) { Collection constructorSignatures = constructorNewInstances.get(s); AbstractInvokeExpr iie = s.getInvokeExpr(); Value args = iie.getArg(0); - JArrayRef arrayRef = new JArrayRef(args, IntConstant.getInstance(0), ); - Local arg = Jimple.newLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0), JavaIdentifierFactory.getInstance()); + Local arg = Jimple.newLocal("intermediate/" + arrayRef, JavaIdentifierFactory.getInstance().getType("java.lang.Object")); ret.add(Jimple.newAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); for (String constructorSignature : constructorSignatures) { SootMethod constructor = PTAScene.v().getMethod(constructorSignature); - SootClass cls = constructor.getDeclaringClass(); - JNewExpr newExpr = new JNewExpr(cls.getType()); + JNewExpr newExpr = new JNewExpr(constructor.getDeclaringClassType()); ret.add(Jimple.newAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); int argCount = constructor.getParameterCount(); List mArgs = new ArrayList<>(argCount); @@ -152,8 +159,9 @@ protected Collection transformMethodInvoke(Stmt s) { Value args = iie.getArg(1); Local arg = null; if (args.getType() instanceof ArrayType) { - JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0), ); - arg = Jimple.newLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); + JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0), idFactory); + arg = Jimple.newLocal("intermediate/" + arrayRef, idFactory.getType("java.lang.Object")); ret.add(Jimple.newAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); } @@ -194,14 +202,15 @@ protected Collection transformFieldSet(Stmt s) { Value base = iie.getArg(0); Value rValue = iie.getArg(1); for (String fieldSignature : fieldSignatures) { - SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + SootField field = (SootField) view.getField(fieldSig).get(); JFieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; - fieldRef = Jimple.newStaticFieldRef(field.getSignature()); + fieldRef = Jimple.newStaticFieldRef(fieldSig); } else { assert !(base instanceof NullConstant); - fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); + fieldRef = Jimple.newInstanceFieldRef((Local) base, fieldSig); } Stmt stmt = Jimple.newAssignStmt(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); ret.add(stmt); @@ -221,14 +230,15 @@ protected Collection transformFieldGet(Stmt s) { AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); for (String fieldSignature : fieldSignatures) { - SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + SootField field = (SootField) view.getField(fieldSig).get(); JFieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; - fieldRef = Jimple.newStaticFieldRef(field.getSignature()); + fieldRef = Jimple.newStaticFieldRef(fieldSig); } else { assert !(base instanceof NullConstant); - fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); + fieldRef = Jimple.newInstanceFieldRef((Local) base, fieldSig); } if (fieldRef.getType() instanceof ReferenceType) { Stmt stmt = Jimple.newAssignStmt(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); @@ -247,7 +257,7 @@ protected Collection transformArrayNewInstance(Stmt s) { Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); for (String arrayType : arrayTypes) { ArrayType at = (ArrayType) PTAScene.v().getTypeUnsafe(arrayType, true); - JNewArrayExpr newExpr = new JNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1), ); + JNewArrayExpr newExpr = new JNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1), view.getIdentifierFactory()); if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); ret.add(Jimple.newAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); @@ -261,15 +271,16 @@ Collection transformArrayGet(Stmt s) { Collection ret = DataFactory.createSet(); AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); + IdentifierFactory idFactory = view.getIdentifierFactory(); if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); Value arrayRef = null; if (base.getType() instanceof ArrayType) { - arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0), ); - } else if (base.getType() == RefType.v("java.lang.Object")) { - Local local = Jimple.newLocal("intermediate/" + base, ArrayType.v(RefType.v("java.lang.Object"), 1)); + arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0), idFactory); + } else if (base.getType() == idFactory.getType("java.lang.Object")) { + Local local = Jimple.newLocal("intermediate/" + base, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); ret.add(Jimple.newAssignStmt(local, base, StmtPositionInfo.createNoStmtPositionInfo())); - arrayRef = new JArrayRef(local, IntConstant.getInstance(0), ); + arrayRef = new JArrayRef(local, IntConstant.getInstance(0), idFactory); } if (arrayRef != null) { ret.add(Jimple.newAssignStmt(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); @@ -285,7 +296,7 @@ Collection transformArraySet(Stmt s) { Value base = iie.getArg(0); if (base.getType() instanceof ArrayType) { Value from = iie.getArg(2); - Value arrayRef = new JArrayRef(base, IntConstant.v(0)); + Value arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0), view.getIdentifierFactory()); ret.add(Jimple.newAssignStmt(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); } return ret; @@ -375,9 +386,10 @@ private Collection inferSourceMethod(String inClzDotMthd) { } SootClass sootClass = PTAScene.v().getSootClass(inClassStr); Set ret = DataFactory.createSet(); - for (SootMethod m : sootClass.getMethods()) { - if (m.isConcrete() && m.getName().equals(inMethodStr)) { - ret.add(m); + for (Object m: sootClass.getMethods()) { + SootMethod sm = (SootMethod) m; + if (sm.isConcrete() && sm.getName().equals(inMethodStr)) { + ret.add(sm); } } return ret; diff --git a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java index e608a16a634..e70092569d4 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java @@ -19,8 +19,8 @@ package qilin.core.sets; import qilin.core.pag.AllocNode; -import soot.Type; -import soot.jimple.ClassConstant; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.types.Type; import java.util.Collection; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java index cefd6f3b0ca..a1aa81fbc89 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java @@ -6,8 +6,10 @@ import qilin.core.pag.Node; import qilin.core.pag.StringConstantNode; import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.model.SootClass; import sootup.core.types.ClassType; import sootup.core.types.Type; +import sootup.core.views.View; import java.util.*; @@ -45,7 +47,9 @@ public Set possibleTypes() { public void visit(Node n) { Type t = n.getType(); if (t instanceof ClassType rt) { - if (rt.getSootClass().isAbstract()) { + View view = pta.getPag().getView(); + SootClass sootClass = (SootClass) view.getClass(rt).get(); + if (sootClass.isAbstract()) { return; } } diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java index 7012af0fc28..58c781bb4e9 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -23,9 +23,11 @@ import qilin.core.pag.PAG; import qilin.util.DataFactory; import qilin.util.PTAUtils; +import sootup.core.IdentifierFactory; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; import java.util.Set; @@ -35,8 +37,9 @@ public class HeuristicAbstractor implements HeapAbstractor { public HeuristicAbstractor(PAG pag) { this.pag = pag; - mergedTypes.add(RefType.v("java.lang.StringBuffer")); - mergedTypes.add(RefType.v("java.lang.StringBuilder")); + IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); + mergedTypes.add(idFactory.getType("java.lang.StringBuffer")); + mergedTypes.add(idFactory.getType("java.lang.StringBuilder")); } @Override From c304e2b1385ea0846ee45d08417c00f845595db7 Mon Sep 17 00:00:00 2001 From: Dongjie He Date: Tue, 27 Dec 2022 20:23:14 +1100 Subject: [PATCH 004/145] update --- .../src/main/java/driver/PTAComparator.java | 2 +- .../src/main/java/driver/PTAFactory.java | 45 +- .../src/main/java/qilin/core/PTA.java | 7 +- .../main/java/qilin/core/VirtualCalls.java | 60 +-- .../qilin/core/builder/CallGraphBuilder.java | 12 +- .../java/qilin/core/callgraph/CallGraph.java | 413 ++++++++++++++++++ .../main/java/qilin/core/callgraph/Edge.java | 287 ++++++++++++ .../main/java/qilin/core/callgraph/Kind.java | 273 ++++++++++++ .../core/context/TypeContextElement.java | 6 +- .../java/qilin/core/pag/VirtualCallSite.java | 2 +- .../main/java/qilin/core/solver/Solver.java | 2 + .../src/main/java/qilin/pta/StagedPTA.java | 5 + .../java/qilin/pta/toolkits/common/OAG.java | 6 +- .../java/qilin/pta/toolkits/eagle/Eagle.java | 12 +- .../qilin/pta/toolkits/selectx/Selectx.java | 10 +- .../pta/toolkits/turner/AbstractMVFG.java | 6 +- .../toolkits/turner/MethodLevelCallGraph.java | 2 +- .../pta/toolkits/turner/ModularMVFG.java | 4 +- .../java/qilin/pta/toolkits/turner/OCG.java | 5 +- .../qilin/pta/toolkits/turner/Turner.java | 16 +- .../main/java/qilin/pta/tools/BasePTA.java | 7 +- .../main/java/qilin/pta/tools/BeanPTA.java | 6 +- .../java/qilin/pta/tools/CallSiteSensPTA.java | 4 +- .../java/qilin/pta/tools/DataDrivenPTA.java | 4 +- .../java/qilin/pta/tools/DebloatedPTA.java | 3 +- .../main/java/qilin/pta/tools/EaglePTA.java | 5 +- .../qilin/pta/tools/HybridObjectSensPTA.java | 4 +- .../qilin/pta/tools/HybridTypeSensPTA.java | 4 +- .../main/java/qilin/pta/tools/MahjongPTA.java | 4 +- .../java/qilin/pta/tools/ObjectSensPTA.java | 4 +- .../pta/tools/PartialCallSiteSensPTA.java | 4 +- .../qilin/pta/tools/PartialObjSensPTA.java | 4 +- .../main/java/qilin/pta/tools/SelectxPTA.java | 5 +- .../src/main/java/qilin/pta/tools/Spark.java | 4 +- .../java/qilin/pta/tools/TunnelingPTA.java | 4 +- .../main/java/qilin/pta/tools/TurnerPTA.java | 5 +- .../java/qilin/pta/tools/TypeSensPTA.java | 4 +- .../main/java/qilin/pta/tools/ZipperPTA.java | 6 +- .../main/java/qilin/stat/BenchmarkStat.java | 8 +- .../main/java/qilin/stat/CallGraphStat.java | 4 +- .../src/main/java/qilin/stat/Exporter.java | 8 +- .../main/java/qilin/stat/PointsToStat.java | 7 +- .../java/qilin/stat/SimplifiedEvaluator.java | 4 +- .../main/java/qilin/stat/TypeClientStat.java | 10 +- .../src/main/java/qilin/stat/YummyStat.java | 6 +- .../src/main/java/qilin/util/PTAUtils.java | 43 +- 46 files changed, 1200 insertions(+), 146 deletions(-) create mode 100644 sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java create mode 100644 sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java create mode 100644 sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java diff --git a/sootup.qilin/src/main/java/driver/PTAComparator.java b/sootup.qilin/src/main/java/driver/PTAComparator.java index 91a29ccb0ab..dc9d9ba735e 100644 --- a/sootup.qilin/src/main/java/driver/PTAComparator.java +++ b/sootup.qilin/src/main/java/driver/PTAComparator.java @@ -49,7 +49,7 @@ public static void runCompare(String[] args, String ptaPtn1, String ptaPtn2) { String[] ptaArg1 = Util.concat(args, new String[]{"-pta=" + ptaPtn1}); comparator.record(Main.run(ptaArg1)); PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPtn2); - PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + PTA pta = PTAFactory.createPTA(null, PTAConfig.v().getPtaConfig().ptaPattern); pta.pureRun(); comparator.compare(pta); comparator.out.close(); diff --git a/sootup.qilin/src/main/java/driver/PTAFactory.java b/sootup.qilin/src/main/java/driver/PTAFactory.java index 6b873478e5f..7670b3ef9fd 100644 --- a/sootup.qilin/src/main/java/driver/PTAFactory.java +++ b/sootup.qilin/src/main/java/driver/PTAFactory.java @@ -22,24 +22,25 @@ import qilin.parm.ctxcons.*; import qilin.pta.PTAConfig; import qilin.pta.tools.*; +import sootup.core.views.View; public class PTAFactory { - public static PTA createPTA(PTAPattern ptaPattern) { + public static PTA createPTA(View view, PTAPattern ptaPattern) { switch (ptaPattern.getContextKind()) { case HYBOBJ: { switch (ptaPattern.getApproach()) { case DATADRIVEN -> { // data-driven hybrid-2obj, Sehun Jeong oopsla'17 CtxConstructor ctxCons = new HybObjCtxConstructor(); - return new DataDrivenPTA(ctxCons); + return new DataDrivenPTA(view, ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new HybObjCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } default -> { // static method using callsite as context, Yannis pldi'13 - return new HybridObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new HybridObjectSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } } } @@ -48,7 +49,7 @@ public static PTA createPTA(PTAPattern ptaPattern) { case EAGLE -> { // k-obj pointer analysis with Eagle pre-analysis, Jingbo OOPSLA'19 assert ptaPattern.getContextDepth() == ptaPattern.getHeapContextDepth() + 1; - BasePTA eagle = new EaglePTA(ptaPattern.getContextDepth()); + BasePTA eagle = new EaglePTA(view, ptaPattern.getContextDepth()); if (PTAConfig.v().getPtaConfig().ctxDebloating) { return new DebloatedPTA(eagle); } else { @@ -57,14 +58,14 @@ public static PTA createPTA(PTAPattern ptaPattern) { } case BEAN -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - return new BeanPTA(ctxCons); + return new BeanPTA(view, ctxCons); } case TURNER -> { - return new TurnerPTA(ptaPattern.getContextDepth()); + return new TurnerPTA(view, ptaPattern.getContextDepth()); } case ZIPPER -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - BasePTA zipperPTA = new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + BasePTA zipperPTA = new ZipperPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); if (PTAConfig.v().getPtaConfig().ctxDebloating) { return new DebloatedPTA(zipperPTA); } else { @@ -73,7 +74,7 @@ public static PTA createPTA(PTAPattern ptaPattern) { } case MAHJONG -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - BasePTA mahjongPTA = new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + BasePTA mahjongPTA = new MahjongPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); if (PTAConfig.v().getPtaConfig().ctxDebloating) { return new DebloatedPTA(mahjongPTA); } else { @@ -82,14 +83,14 @@ public static PTA createPTA(PTAPattern ptaPattern) { } case DATADRIVEN -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - return new DataDrivenPTA(ctxCons); + return new DataDrivenPTA(view, ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } default -> { - BasePTA kobj = new ObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + BasePTA kobj = new ObjectSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); if (PTAConfig.v().getPtaConfig().ctxDebloating) { return new DebloatedPTA(kobj); @@ -104,15 +105,15 @@ public static PTA createPTA(PTAPattern ptaPattern) { switch (ptaPattern.getApproach()) { case DATADRIVEN -> { CtxConstructor ctxCons = new TypeCtxConstructor(); - return new DataDrivenPTA(ctxCons); + return new DataDrivenPTA(view, ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new TypeCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } default -> { // normal type-sensitive pointer analysis, Yannis popl'11 - return new TypeSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TypeSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } } } @@ -120,32 +121,32 @@ public static PTA createPTA(PTAPattern ptaPattern) { switch (ptaPattern.getApproach()) { case ZIPPER -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + return new ZipperPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); } case MAHJONG -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + return new MahjongPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); } case DATADRIVEN -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new DataDrivenPTA(ctxCons); + return new DataDrivenPTA(view, ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } case SELECTX -> { - return new SelectxPTA(ptaPattern.getContextDepth()); + return new SelectxPTA(view, ptaPattern.getContextDepth()); } default -> { // CallSite Sensitive - return new CallSiteSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new CallSiteSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } } } case INSENS: default: - return new Spark(); + return new Spark(view); } } } diff --git a/sootup.qilin/src/main/java/qilin/core/PTA.java b/sootup.qilin/src/main/java/qilin/core/PTA.java index fddbc420817..4e6006a3bc0 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTA.java +++ b/sootup.qilin/src/main/java/qilin/core/PTA.java @@ -20,6 +20,7 @@ import qilin.core.builder.CallGraphBuilder; import qilin.core.builder.ExceptionHandler; +import qilin.core.callgraph.CallGraph; import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.*; @@ -28,10 +29,10 @@ import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.HeapAbstractor; import qilin.parm.select.CtxSelector; -import soot.jimple.toolkits.callgraph.CallGraph; import sootup.core.jimple.basic.Local; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.java.core.JavaIdentifierFactory; import java.util.Collection; import java.util.HashSet; @@ -49,8 +50,8 @@ public PTA() { this.pag = createPAG(); this.cgb = createCallGraphBuilder(); this.eh = new ExceptionHandler(this); - AllocNode rootBase = pag.makeAllocNode("ROOT", RefType.v("java.lang.Object"), null); - this.rootNode = new ContextAllocNode(rootBase, CtxConstructor.emptyContext); + AllocNode rootBase = pag.makeAllocNode("ROOT", JavaIdentifierFactory.getInstance().getType("java.lang.Object"), null); + this.rootNode = new ContextAllocNode(pag.getView(), rootBase, CtxConstructor.emptyContext); } protected abstract PAG createPAG(); diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index fbdcf210e46..f62dfe2d6b4 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -19,10 +19,17 @@ package qilin.core; import qilin.util.DataFactory; -import soot.*; -import soot.jimple.SpecialInvokeExpr; -import soot.util.*; -import soot.util.queue.ChunkedQueue; +import qilin.util.queue.ChunkedQueue; +import sootup.core.IdentifierFactory; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSubSignature; +import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; +import sootup.core.types.NullType; +import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; import java.util.HashSet; import java.util.LinkedList; @@ -36,7 +43,7 @@ */ public class VirtualCalls { private static volatile VirtualCalls instance = null; - private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); + private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); protected Map> baseToSubTypes = DataFactory.createMap(); private VirtualCalls() { @@ -57,16 +64,16 @@ public static void reset() { instance = null; } - public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container) { + public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container) { return resolveSpecial(iie, subSig, container, false); } - public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container, boolean appOnly) { + public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container, boolean appOnly) { SootMethod target = iie.getMethod(); /* cf. JVM spec, invokespecial instruction */ - if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClass().getType(), - target.getDeclaringClass().getType()) - && container.getDeclaringClass().getType() != target.getDeclaringClass().getType() + if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClassType(), + target.getDeclaringClassType()) + && container.getDeclaringClassType() != target.getDeclaringClassType() && !target.getName().equals("") && subSig != Scene.v().getSubSigNumberer().findOrAdd("void ()")) { @@ -76,12 +83,12 @@ public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, S } } - public SootMethod resolveNonSpecial(RefType t, NumberedString subSig) { + public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig) { return resolveNonSpecial(t, subSig, false); } - public SootMethod resolveNonSpecial(RefType t, NumberedString subSig, boolean appOnly) { - Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); + public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, boolean appOnly) { + Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); SootMethod ret = vtbl.get(subSig); if (ret != null) { return ret; @@ -109,26 +116,27 @@ public SootMethod resolveNonSpecial(RefType t, NumberedString subSig, boolean ap return ret; } - public void resolve(Type t, Type declaredType, NumberedString subSig, SootMethod container, + public void resolve(Type t, Type declaredType, MethodSubSignature subSig, SootMethod container, ChunkedQueue targets) { resolve(t, declaredType, null, subSig, container, targets); } - public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, ChunkedQueue targets) { resolve(t, declaredType, sigType, subSig, container, targets, false); } - public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, ChunkedQueue targets, boolean appOnly) { + IdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); if (declaredType instanceof ArrayType) { - declaredType = RefType.v("java.lang.Object"); + declaredType = identifierFactory.getType("java.lang.Object"); } if (sigType instanceof ArrayType) { - sigType = RefType.v("java.lang.Object"); + sigType = identifierFactory.getType("java.lang.Object"); } if (t instanceof ArrayType) { - t = RefType.v("java.lang.Object"); + t = identifierFactory.getType("java.lang.Object"); } if (declaredType != null && !Scene.v().getFastHierarchy().canStoreType(t, declaredType)) { @@ -137,13 +145,13 @@ public void resolve(Type t, Type declaredType, Type sigType, NumberedString subS if (sigType != null && !Scene.v().getFastHierarchy().canStoreType(t, sigType)) { return; } - if (t instanceof RefType) { - SootMethod target = resolveNonSpecial((RefType) t, subSig, appOnly); + if (t instanceof ClassType) { + SootMethod target = resolveNonSpecial((ClassType) t, subSig, appOnly); if (target != null) { targets.add(target); } - } else if (t instanceof AnySubType) { - RefType base = ((AnySubType) t).getBase(); + // } else if (t instanceof AnySubType) { + // RefType base = ((AnySubType) t).getBase(); /* * Whenever any sub type of a specific type is considered as receiver for a method to call and the base type is an @@ -156,15 +164,15 @@ public void resolve(Type t, Type declaredType, Type sigType, NumberedString subS * * Since Java has no multiple inheritance call by signature resolution is only activated if the base is an interface. */ - resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); + // resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); } else if (t instanceof NullType) { } else { throw new RuntimeException("oops " + t); } } - protected void resolveAnySubType(Type declaredType, Type sigType, NumberedString subSig, SootMethod container, - ChunkedQueue targets, boolean appOnly, RefType base) { + protected void resolveAnySubType(Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, + ChunkedQueue targets, boolean appOnly, ClassType base) { { Set subTypes = baseToSubTypes.get(base); if (subTypes != null && !subTypes.isEmpty()) { diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 35053c41b60..0f26820ce99 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -21,6 +21,9 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; +import qilin.core.callgraph.Kind; import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.P2SetVisitor; @@ -30,8 +33,6 @@ import qilin.util.queue.ChunkedQueue; import qilin.util.queue.QueueReader; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; @@ -57,12 +58,13 @@ public class CallGraphBuilder { protected final Set calledges; protected final PTA pta; protected final PAG pag; + protected CallGraph callGraph; protected CallGraph cicg; public CallGraphBuilder(PTA pta) { this.pta = pta; this.pag = pta.getPag(); - PTAScene.v().setCallGraph(new CallGraph()); + this.callGraph = new CallGraph(); receiverToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); methodToInvokeStmt = DataFactory.createMap(); reachMethods = DataFactory.createSet(); @@ -91,7 +93,7 @@ public CallGraph getCallGraph() { if (cicg == null) { constructCallGraph(); } - return PTAScene.v().getCallGraph(); + return callGraph; } public CallGraph getCICallGraph() { @@ -108,7 +110,7 @@ private void constructCallGraph() { PTAScene.v().getCallGraph().addEdge(e); SootMethod src = e.src(); SootMethod tgt = e.tgt(); - Unit unit = e.srcUnit(); + Stmt unit = e.srcUnit(); Map> submap = map.computeIfAbsent(unit, k -> DataFactory.createMap()); Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); if (set.add(tgt)) { diff --git a/sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java b/sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java new file mode 100644 index 00000000000..f1c25f937cb --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java @@ -0,0 +1,413 @@ +package qilin.core.callgraph; + +import qilin.core.pag.ContextMethod; +import qilin.util.queue.ChunkedQueue; +import qilin.util.queue.QueueReader; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; + +import java.util.Collection; +import java.util.HashSet; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +/** + * Represents the edges in a call graph. This class is meant to act as only a container of edges; code for various call graph + * builders should be kept out of it, as well as most code for accessing the edges. + * + * @author Ondrej Lhotak + */ +public class CallGraph implements Iterable { + protected Set edges = new LinkedHashSet<>(); + protected ChunkedQueue stream = new ChunkedQueue<>(); + protected QueueReader reader = stream.reader(); + protected Map srcMethodToEdge = new LinkedHashMap<>(); + protected Map srcUnitToEdge = new LinkedHashMap<>(); + protected Map tgtToEdge = new LinkedHashMap<>(); + protected Edge dummy = new Edge(null, null, null, Kind.INVALID); + + /** + * Used to add an edge to the call graph. Returns true iff the edge was not already present. + */ + public boolean addEdge(Edge e) { + if (!edges.add(e)) { + return false; + } + + stream.add(e); + + Edge position = srcUnitToEdge.get(e.srcUnit()); + if (position == null) { + srcUnitToEdge.put(e.srcUnit(), e); + position = dummy; + } + e.insertAfterByUnit(position); + + position = srcMethodToEdge.get(e.getSrc()); + if (position == null) { + srcMethodToEdge.put(e.getSrc(), e); + position = dummy; + } + e.insertAfterBySrc(position); + + position = tgtToEdge.get(e.getTgt()); + if (position == null) { + tgtToEdge.put(e.getTgt(), e); + position = dummy; + } + e.insertAfterByTgt(position); + return true; + } + + /** + * Removes all outgoing edges that start at the given unit + * + * @param u + * The unit from which to remove all outgoing edges + * @return True if at least one edge has been removed, otherwise false + */ + public boolean removeAllEdgesOutOf(Stmt u) { + boolean hasRemoved = false; + Set edgesToRemove = new HashSet<>(); + for (QueueReader edgeRdr = listener(); edgeRdr.hasNext();) { + Edge e = edgeRdr.next(); + if (e.srcUnit() == u) { + e.remove(); + removeEdge(e, false); + edgesToRemove.add(e); + hasRemoved = true; + } + } + if (hasRemoved) { + reader.remove(edgesToRemove); + } + return hasRemoved; + } + + /** + * Swaps an invocation statement. All edges that previously went from the given statement to some callee now go from the + * new statement to the same callee. This method is intended to be used when a Jimple statement is replaced, but the + * replacement does not semantically affect the edges. + * + * @param out + * The old statement + * @param in + * The new statement + * @return True if at least one edge was affected by this operation + */ + public boolean swapEdgesOutOf(Stmt out, Stmt in) { + boolean hasSwapped = false; + for (Iterator edgeRdr = edgesOutOf(out); edgeRdr.hasNext();) { + Edge e = edgeRdr.next(); + ContextMethod src = e.getSrc(); + ContextMethod tgt = e.getTgt(); + removeEdge(e); + e.remove(); + addEdge(new Edge(src, in, tgt)); + hasSwapped = true; + } + return hasSwapped; + } + + /** + * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. + */ + public boolean removeEdge(Edge e) { + return removeEdge(e, true); + } + + /** + * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. + * + * @param e + * the edge + * @param removeInEdgeList + * when true (recommended), it is ensured that the edge reader is informed about the removal + * @return whether the removal was successful. + */ + public boolean removeEdge(Edge e, boolean removeInEdgeList) { + if (!edges.remove(e)) { + return false; + } + e.remove(); + + if (srcUnitToEdge.get(e.srcUnit()) == e) { + if (e.nextByUnit().srcUnit() == e.srcUnit()) { + srcUnitToEdge.put(e.srcUnit(), e.nextByUnit()); + } else { + srcUnitToEdge.remove(e.srcUnit()); + } + } + + if (srcMethodToEdge.get(e.getSrc()) == e) { + if (e.nextBySrc().getSrc() == e.getSrc()) { + srcMethodToEdge.put(e.getSrc(), e.nextBySrc()); + } else { + srcMethodToEdge.remove(e.getSrc()); + } + } + + if (tgtToEdge.get(e.getTgt()) == e) { + if (e.nextByTgt().getTgt() == e.getTgt()) { + tgtToEdge.put(e.getTgt(), e.nextByTgt()); + } else { + tgtToEdge.remove(e.getTgt()); + } + } + // This is an linear operation, so we want to avoid it if possible. + if (removeInEdgeList) { + reader.remove(e); + } + return true; + } + + /** + * Removes the edges from the call graph. Returns true iff one edge was originally present in the call graph. + * + * @param edges + * the edges + * @return whether the removal was successful. + */ + public boolean removeEdges(Collection edges) { + if (!this.edges.removeAll(edges)) { + return false; + } + for (Edge e : edges) { + removeEdge(e, false); + } + reader.remove(edges); + return true; + } + + /** + * Does this method have no incoming edge? + * + * @param method + * @return + */ + public boolean isEntryMethod(SootMethod method) { + return !tgtToEdge.containsKey(method); + } + + /** + * Find the specific call edge that is going out from the callsite u and the call target is callee. Without advanced data + * structure, we can only sequentially search for the match. Fortunately, the number of outgoing edges for a unit is not + * too large. + * + * @param u + * @param callee + * @return + */ + public Edge findEdge(Stmt u, SootMethod callee) { + Edge e = srcUnitToEdge.get(u); + if (e != null) { + while (e.srcUnit() == u && e.kind() != Kind.INVALID) { + if (e.tgt() == callee) { + return e; + } + e = e.nextByUnit(); + } + } + return null; + } + + /** + * Returns an iterator over all methods that are the sources of at least one edge. + */ + public Iterator sourceMethods() { + return srcMethodToEdge.keySet().iterator(); + } + + /** + * Returns an iterator over all edges that have u as their source unit. + */ + public Iterator edgesOutOf(Stmt u) { + return new TargetsOfUnitIterator(u); + } + + class TargetsOfUnitIterator implements Iterator { + private final Stmt u; + private Edge position; + + TargetsOfUnitIterator(Stmt u) { + this.u = u; + if (u == null) { + throw new RuntimeException(); + } + this.position = srcUnitToEdge.get(u); + if (position == null) { + position = dummy; + } + } + + @Override + public boolean hasNext() { + if (position.srcUnit() != u) { + return false; + } + return position.kind() != Kind.INVALID; + } + + @Override + public Edge next() { + Edge ret = position; + position = position.nextByUnit(); + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns an iterator over all edges that have m as their source method. + */ + public Iterator edgesOutOf(ContextMethod m) { + return new TargetsOfMethodIterator(m); + } + + class TargetsOfMethodIterator implements Iterator { + private final ContextMethod m; + private Edge position; + + TargetsOfMethodIterator(ContextMethod m) { + this.m = m; + if (m == null) { + throw new RuntimeException(); + } + this.position = srcMethodToEdge.get(m); + if (position == null) { + position = dummy; + } + } + + @Override + public boolean hasNext() { + if (position.getSrc() != m) { + return false; + } + return position.kind() != Kind.INVALID; + } + + @Override + public Edge next() { + Edge ret = position; + position = position.nextBySrc(); + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns an iterator over all edges that have m as their target method. + */ + public Iterator edgesInto(ContextMethod m) { + return new CallersOfMethodIterator(m); + } + + class CallersOfMethodIterator implements Iterator { + private final ContextMethod m; + private Edge position; + + CallersOfMethodIterator(ContextMethod m) { + this.m = m; + if (m == null) { + throw new RuntimeException(); + } + this.position = tgtToEdge.get(m); + if (position == null) { + position = dummy; + } + } + + @Override + public boolean hasNext() { + if (position.getTgt() != m) { + return false; + } + return position.kind() != Kind.INVALID; + } + + @Override + public Edge next() { + Edge ret = position; + position = position.nextByTgt(); + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns a QueueReader object containing all edges added so far, and which will be informed of any new edges that are + * later added to the graph. + */ + public QueueReader listener() { + return reader.clone(); + } + + /** + * Returns a QueueReader object which will contain ONLY NEW edges which will be added to the graph. + */ + public QueueReader newListener() { + return stream.reader(); + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + for (QueueReader reader = listener(); reader.hasNext();) { + Edge e = reader.next(); + out.append(e.toString()).append('\n'); + } + return out.toString(); + } + + /** + * Returns the number of edges in the call graph. + */ + public int size() { + return edges.size(); + } + + @Override + public Iterator iterator() { + return edges.iterator(); + } +} + diff --git a/sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java b/sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java new file mode 100644 index 00000000000..6746e88c298 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java @@ -0,0 +1,287 @@ +package qilin.core.callgraph; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import qilin.core.context.Context; +import qilin.core.pag.ContextMethod; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; + +/** + * Represents a single edge in a call graph. + * + * @author Ondrej Lhotak + */ +public final class Edge { + + /** + * The method in which the call occurs; may be null for calls not occurring in a specific method (eg. implicit calls by the + * VM) + */ + private ContextMethod src; + + /** + * The target method of the call edge. + */ + private ContextMethod tgt; + + /** + * The unit at which the call occurs; may be null for calls not occurring at a specific statement (eg. calls in native + * code) + */ + private Stmt srcUnit; + + /** + * The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as isExplicit() should be + * added. + */ + private final Kind kind; + + private boolean invalid = false; + + public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt, Kind kind) { + this.src = src; + this.srcUnit = srcUnit; + this.tgt = tgt; + this.kind = kind; + } + + public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt) { + this.kind = ieToKind(srcUnit.getInvokeExpr()); + this.src = src; + this.srcUnit = srcUnit; + this.tgt = tgt; + } + + public SootMethod src() { + return (src == null) ? null : src.method(); + } + + public Context srcCtxt() { + return (src == null) ? null : src.context(); + } + + public ContextMethod getSrc() { + return src; + } + + public Stmt srcUnit() { + return srcUnit; + } + + public Stmt srcStmt() { + return srcUnit; + } + + public SootMethod tgt() { + return (tgt == null) ? null : tgt.method(); + } + + public Context tgtCtxt() { + return (tgt == null) ? null : tgt.context(); + } + + public ContextMethod getTgt() { + return tgt; + } + + public Kind kind() { + return kind; + } + + public static Kind ieToKind(AbstractInvokeExpr ie) { + if (ie instanceof JVirtualInvokeExpr) { + return Kind.VIRTUAL; + } else if (ie instanceof JSpecialInvokeExpr) { + return Kind.SPECIAL; + } else if (ie instanceof JInterfaceInvokeExpr) { + return Kind.INTERFACE; + } else if (ie instanceof JStaticInvokeExpr) { + return Kind.STATIC; + } else { + throw new RuntimeException(); + } + } + + /** + * Returns true if the call is due to an explicit invoke statement. + */ + public boolean isExplicit() { + return Kind.isExplicit(this.kind); + } + + /** + * Returns true if the call is due to an explicit instance invoke statement. + */ + public boolean isInstance() { + return Kind.isInstance(this.kind); + } + + public boolean isVirtual() { + return Kind.isVirtual(this.kind); + } + + public boolean isSpecial() { + return Kind.isSpecial(this.kind); + } + + /** + * Returns true if the call is to static initializer. + */ + public boolean isClinit() { + return Kind.isClinit(this.kind); + } + + /** + * Returns true if the call is due to an explicit static invoke statement. + */ + public boolean isStatic() { + return Kind.isStatic(this.kind); + } + + public boolean isThreadRunCall() { + return Kind.isThread(this.kind); + } + + public boolean passesParameters() { + return Kind.passesParameters(this.kind); + } + + @Override + public int hashCode() { + if (invalid) { + return 0; + } + int ret = (tgt.hashCode() + 20) + (kind == null ? 0 : kind.getNumber()); + if (src != null) { + ret = ret * 32 + src.hashCode(); + } + if (srcUnit != null) { + ret = ret * 32 + srcUnit.hashCode(); + } + return ret; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Edge)) { + return false; + } + Edge o = (Edge) other; + return (o.src == this.src) && (o.srcUnit == srcUnit) && (o.tgt == tgt) && (o.kind == kind); + } + + @Override + public String toString() { + return String.valueOf(this.kind) + " edge: " + srcUnit + " in " + src + " ==> " + tgt; + } + + private Edge nextByUnit = this; + private Edge prevByUnit = this; + private Edge nextBySrc = this; + private Edge prevBySrc = this; + private Edge nextByTgt = this; + private Edge prevByTgt = this; + + void insertAfterByUnit(Edge other) { + nextByUnit = other.nextByUnit; + nextByUnit.prevByUnit = this; + other.nextByUnit = this; + prevByUnit = other; + } + + void insertAfterBySrc(Edge other) { + nextBySrc = other.nextBySrc; + nextBySrc.prevBySrc = this; + other.nextBySrc = this; + prevBySrc = other; + } + + void insertAfterByTgt(Edge other) { + nextByTgt = other.nextByTgt; + nextByTgt.prevByTgt = this; + other.nextByTgt = this; + prevByTgt = other; + } + + void insertBeforeByUnit(Edge other) { + prevByUnit = other.prevByUnit; + prevByUnit.nextByUnit = this; + other.prevByUnit = this; + nextByUnit = other; + } + + void insertBeforeBySrc(Edge other) { + prevBySrc = other.prevBySrc; + prevBySrc.nextBySrc = this; + other.prevBySrc = this; + nextBySrc = other; + } + + void insertBeforeByTgt(Edge other) { + prevByTgt = other.prevByTgt; + prevByTgt.nextByTgt = this; + other.prevByTgt = this; + nextByTgt = other; + } + + void remove() { + invalid = true; + nextByUnit.prevByUnit = prevByUnit; + prevByUnit.nextByUnit = nextByUnit; + nextBySrc.prevBySrc = prevBySrc; + prevBySrc.nextBySrc = nextBySrc; + nextByTgt.prevByTgt = prevByTgt; + prevByTgt.nextByTgt = nextByTgt; + } + + Edge nextByUnit() { + return nextByUnit; + } + + Edge nextBySrc() { + return nextBySrc; + } + + Edge nextByTgt() { + return nextByTgt; + } + + Edge prevByUnit() { + return prevByUnit; + } + + Edge prevBySrc() { + return prevBySrc; + } + + Edge prevByTgt() { + return prevByTgt; + } +} + diff --git a/sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java b/sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java new file mode 100644 index 00000000000..f737e7ce5f5 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java @@ -0,0 +1,273 @@ +package qilin.core.callgraph; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import qilin.core.util.Numberable; + +/** + * Enumeration type representing the kind of a call graph edge. + * + * @author Ondrej Lhotak + */ +public final class Kind implements Numberable { + + public static final Kind INVALID = new Kind("INVALID"); + /** + * Due to explicit invokestatic instruction. + */ + public static final Kind STATIC = new Kind("STATIC"); + /** + * Due to explicit invokevirtual instruction. + */ + public static final Kind VIRTUAL = new Kind("VIRTUAL"); + /** + * Due to explicit invokeinterface instruction. + */ + public static final Kind INTERFACE = new Kind("INTERFACE"); + /** + * Due to explicit invokespecial instruction. + */ + public static final Kind SPECIAL = new Kind("SPECIAL"); + /** + * Implicit call to static initializer. + */ + public static final Kind CLINIT = new Kind("CLINIT"); + /** + * Fake edges from our generic callback model. + */ + public static final Kind GENERIC_FAKE = new Kind("GENERIC_FAKE"); + /** + * Implicit call to Thread.run() due to Thread.start() call. + */ + public static final Kind THREAD = new Kind("THREAD"); + /** + * Implicit call to java.lang.Runnable.run() due to Executor.execute() call. + */ + public static final Kind EXECUTOR = new Kind("EXECUTOR"); + /** + * Implicit call to AsyncTask.doInBackground() due to AsyncTask.execute() call. + */ + public static final Kind ASYNCTASK = new Kind("ASYNCTASK"); + /** + * Implicit call to java.lang.ref.Finalizer.register from new bytecode. + */ + public static final Kind FINALIZE = new Kind("FINALIZE"); + /** + * Implicit call to Handler.handleMessage(android.os.Message) due to Handler.sendxxxxMessagexxxx() call. + */ + public static final Kind HANDLER = new Kind("HANDLER"); + /** + * Implicit call to finalize() from java.lang.ref.Finalizer.invokeFinalizeMethod(). + */ + public static final Kind INVOKE_FINALIZE = new Kind("INVOKE_FINALIZE"); + /** + * Implicit call to run() through AccessController.doPrivileged(). + */ + public static final Kind PRIVILEGED = new Kind("PRIVILEGED"); + /** + * Implicit call to constructor from java.lang.Class.newInstance(). + */ + public static final Kind NEWINSTANCE = new Kind("NEWINSTANCE"); + /** + * Due to call to Method.invoke(..). + */ + public static final Kind REFL_INVOKE = new Kind("REFL_METHOD_INVOKE"); + /** + * Due to call to Constructor.newInstance(..). + */ + public static final Kind REFL_CONSTR_NEWINSTANCE = new Kind("REFL_CONSTRUCTOR_NEWINSTANCE"); + /** + * Due to call to Class.newInstance(..) when reflection log is enabled. + */ + public static final Kind REFL_CLASS_NEWINSTANCE = new Kind("REFL_CLASS_NEWINSTANCE"); + + private final String name; + private int num; + + private Kind(String name) { + this.name = name; + } + + public String name() { + return name; + } + + @Override + public int getNumber() { + return num; + } + + @Override + public void setNumber(int num) { + this.num = num; + } + + @Override + public String toString() { + return name(); + } + + public boolean passesParameters() { + return passesParameters(this); + } + + public boolean isFake() { + return isFake(this); + } + + /** + * Returns true if the call is due to an explicit invoke statement. + */ + public boolean isExplicit() { + return isExplicit(this); + } + + /** + * Returns true if the call is due to an explicit instance invoke statement. + */ + public boolean isInstance() { + return isInstance(this); + } + + /** + * Returns true if the call is due to an explicit virtual invoke statement. + */ + public boolean isVirtual() { + return isVirtual(this); + } + + public boolean isSpecial() { + return isSpecial(this); + } + + /** + * Returns true if the call is to static initializer. + */ + public boolean isClinit() { + return isClinit(this); + } + + /** + * Returns true if the call is due to an explicit static invoke statement. + */ + public boolean isStatic() { + return isStatic(this); + } + + public boolean isThread() { + return isThread(this); + } + + public boolean isExecutor() { + return isExecutor(this); + } + + public boolean isAsyncTask() { + return isAsyncTask(this); + } + + public boolean isPrivileged() { + return isPrivileged(this); + } + + public boolean isReflection() { + return isReflection(this); + } + + public boolean isReflInvoke() { + return isReflInvoke(this); + } + + public static boolean passesParameters(Kind k) { + return isExplicit(k) || k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == FINALIZE || k == PRIVILEGED + || k == NEWINSTANCE || k == INVOKE_FINALIZE || k == REFL_INVOKE || k == REFL_CONSTR_NEWINSTANCE + || k == REFL_CLASS_NEWINSTANCE; + } + + public static boolean isFake(Kind k) { + return k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == PRIVILEGED || k == HANDLER || k == GENERIC_FAKE; + } + + /** + * Returns true if the call is due to an explicit invoke statement. + */ + public static boolean isExplicit(Kind k) { + return isInstance(k) || isStatic(k); + } + + /** + * Returns true if the call is due to an explicit instance invoke statement. + */ + public static boolean isInstance(Kind k) { + return k == VIRTUAL || k == INTERFACE || k == SPECIAL; + } + + /** + * Returns true if the call is due to an explicit virtual invoke statement. + */ + public static boolean isVirtual(Kind k) { + return k == VIRTUAL; + } + + public static boolean isSpecial(Kind k) { + return k == SPECIAL; + } + + /** + * Returns true if the call is to static initializer. + */ + public static boolean isClinit(Kind k) { + return k == CLINIT; + } + + /** + * Returns true if the call is due to an explicit static invoke statement. + */ + public static boolean isStatic(Kind k) { + return k == STATIC; + } + + public static boolean isThread(Kind k) { + return k == THREAD; + } + + public static boolean isExecutor(Kind k) { + return k == EXECUTOR; + } + + public static boolean isAsyncTask(Kind k) { + return k == ASYNCTASK; + } + + public static boolean isPrivileged(Kind k) { + return k == PRIVILEGED; + } + + public static boolean isReflection(Kind k) { + return k == REFL_CLASS_NEWINSTANCE || k == REFL_CONSTR_NEWINSTANCE || k == REFL_INVOKE; + } + + public static boolean isReflInvoke(Kind k) { + return k == REFL_INVOKE; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java index 5df60c5810a..54ef5b09020 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java +++ b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java @@ -24,7 +24,7 @@ import sootup.core.IdentifierFactory; import sootup.core.model.SootMethod; import sootup.core.types.Type; -import sootup.core.views.View; +import sootup.java.core.JavaIdentifierFactory; /** * Type based context element in the points to analysis. @@ -37,9 +37,9 @@ private TypeContextElement(Type type) { this.type = type; } - public static TypeContextElement getTypeContextElement(View view, AllocNode a) { + public static TypeContextElement getTypeContextElement(AllocNode a) { SootMethod declaringMethod = a.getMethod(); - IdentifierFactory identifierFactory = view.getIdentifierFactory(); + IdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); Type declType = identifierFactory.getType("java.lang.Object"); if (declaringMethod != null) { declType = declaringMethod.getDeclaringClassType(); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java index 42cf808a364..47af935eb7b 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java @@ -18,7 +18,7 @@ package qilin.core.pag; -import soot.Kind; +import qilin.core.callgraph.Kind; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.signatures.MethodSubSignature; diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index cb5acf43a4a..ad1c3b5b67f 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -24,6 +24,8 @@ import qilin.core.builder.CallGraphBuilder; import qilin.core.builder.ExceptionHandler; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.Edge; +import qilin.core.callgraph.Kind; import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.DoublePointsToSet; diff --git a/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java b/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java index cc9a56ccff9..44cd999cef5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java @@ -1,6 +1,7 @@ package qilin.pta; import qilin.pta.tools.BasePTA; +import sootup.core.views.View; /* * Many recent pointer analyses are two-staged analyses with a preanalysis and a main analysis. @@ -9,6 +10,10 @@ public abstract class StagedPTA extends BasePTA { protected BasePTA prePTA; + public StagedPTA(View view) { + super(view); + } + public BasePTA getPrePTA() { return this.prePTA; } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java index 400611c66c9..6b68ae99e28 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java @@ -109,9 +109,9 @@ public boolean reaches(AllocNode source, AllocNode dest) { protected void buildOAG() { Map> pts = PTAUtils.calcStaticThisPTS(this.pta); for (SootMethod method : this.pta.getNakedReachableMethods()) { - if (method.isPhantom()) { - continue; - } +// if (method.isPhantom()) { +// continue; +// } MethodPAG srcmpag = pta.getPag().getMethodPAG(method); MethodNodeFactory srcnf = srcmpag.nodeFactory(); LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index 68e9e0c552d..c1c973becc3 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -21,14 +21,14 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Util; import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; @@ -264,9 +264,9 @@ public void buildGraph(PTA prePTA) { CallGraph callGraph = prePTA.getCallGraph(); for (SootMethod method : prePTA.getNakedReachableMethods()) { - if (method.isPhantom()) { - continue; - } +// if (method.isPhantom()) { +// continue; +// } MethodPAG srcmpag = prePAG.getMethodPAG(method); MethodNodeFactory srcnf = srcmpag.nodeFactory(); LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); @@ -346,7 +346,7 @@ else if (to instanceof FieldRefNode fr) { // static call receiver = thisRef; } - for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); for (int i = 0; i < numArgs; i++) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index 0f087bf12f4..1b62abe8cf7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -25,9 +25,9 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.util.queue.QueueReader; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; @@ -229,9 +229,9 @@ int getCallSiteNumber(CallSite callsite) { private void buildGraph() { for (SootMethod method : prePTA.getNakedReachableMethods()) { - if (method.isPhantom()) { - continue; - } +// if (method.isPhantom()) { +// continue; +// } MethodPAG srcmpag = prePAG.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -292,7 +292,7 @@ private void buildGraph() { if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } - for (Iterator it = prePTA.getCallGraph().edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = prePTA.getCallGraph().edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 6eb873061d0..90c01e9d0b1 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -21,12 +21,12 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.util.Pair; import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; @@ -179,7 +179,7 @@ else if (to instanceof FieldRefNode fr) { } Set targets = new HashSet<>(); - for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); targets.add(tgtmtd); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java index e91354a5dd9..9c48031caa6 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java @@ -18,9 +18,9 @@ package qilin.pta.toolkits.turner; +import qilin.core.callgraph.CallGraph; import qilin.util.graph.DirectedGraph; import qilin.util.graph.DirectedGraphImpl; -import soot.jimple.toolkits.callgraph.CallGraph; import sootup.core.model.SootMethod; import java.util.Collection; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java index 18ed2b167f8..5a75da5531b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -47,7 +47,7 @@ public ModularMVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode protected boolean statisfyAddingLoadCondition(Set targets) { for (SootMethod tgtmtd : targets) { // the target method is in the same scc with current method. - if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { + if (/* tgtmtd.isPhantom() || */ sccNode.getContent().contains(tgtmtd)) { return true; } if (!(tgtmtd.getReturnType() instanceof ReferenceType)) { @@ -69,7 +69,7 @@ protected boolean statisfyAddingLoadCondition(Set targets) { protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { for (SootMethod tgtmtd : targets) { // the target method is in the same scc with current method. - if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { + if (/* tgtmtd.isPhantom() || */ sccNode.getContent().contains(tgtmtd)) { return true; } MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java index 642ea277058..8f7f4e3388a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -26,6 +26,7 @@ import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.PrimitiveType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; @@ -57,7 +58,7 @@ protected void buildGraph() { SparkField f = contextField.getField(); if (f.getType() instanceof ArrayType at) { - if (at.getBaseType() instanceof PrimType) { + if (at.getBaseType() instanceof PrimitiveType) { return; } } @@ -249,7 +250,7 @@ boolean isFactoryObject(AllocNode heap) { return false; } if (retType instanceof ArrayType at) { - if (at.getBaseType() instanceof PrimType) { + if (at.getBaseType() instanceof PrimitiveType) { return false; } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java index 3f45885e976..5528e73f1b9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java @@ -167,25 +167,25 @@ private void statObjInOCG(Map ret) { } private Collection computeCtxLevelForVariables(SootMethod method) { - if (method.isPhantom()) { - return Collections.emptySet(); - } else { +// if (method.isPhantom()) { +// return Collections.emptySet(); +// } else { AbstractMVFG mvfg = MethodVFG.findOrCreateMethodVFG(prePTA, method, ocg); mvfg.computeNodesInPrecisionLossPatterns(); mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); return mvfg.getCSNodes(); - } +// } } private Collection computeCtxLevelForVariables(SootMethod method, MergedNode sccNode) { - if (method.isPhantom()) { - return Collections.emptySet(); - } else { +// if (method.isPhantom()) { +// return Collections.emptySet(); +// } else { AbstractMVFG mvfg = ModularMVFG.findOrCreateMethodVFG(prePTA, method, ocg, sccNode); mvfg.computeNodesInPrecisionLossPatterns(); mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); return mvfg.getCSNodes(); - } +// } } private void mergeNodeAndEdgeCount(int nodeCnt, int edgeCnt) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java index 7b7b3fa5499..6761cb10c11 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java @@ -10,11 +10,14 @@ import qilin.stat.PTAEvaluator; import qilin.stat.SimplifiedEvaluator; import qilin.util.PTAUtils; +import sootup.core.views.View; public abstract class BasePTA extends CorePTA { protected IEvaluator evaluator; + protected View view; - public BasePTA() { + public BasePTA(View view) { + this.view = view; // this.evaluator = new PTAEvaluator(this); this.evaluator = new SimplifiedEvaluator(this); } @@ -25,7 +28,7 @@ public IEvaluator evaluator() { @Override protected PAG createPAG() { - return new PAG(this); + return new PAG(view, this); } @Override diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java index d825cae2ac8..50c36e7206f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java @@ -29,6 +29,7 @@ import qilin.pta.StagedPTA; import qilin.pta.toolkits.bean.Bean; import qilin.util.Stopwatch; +import sootup.core.views.View; import java.util.HashMap; import java.util.Map; @@ -41,7 +42,8 @@ public class BeanPTA extends StagedPTA { // [current heap, [allocator heap, [heap ctx, new ctx]]] only for B-2obj; Map>> beanNexCtxMap = new HashMap<>(); - public BeanPTA(CtxConstructor ctxCons) { + public BeanPTA(View view, CtxConstructor ctxCons) { + super(view); this.ctxCons = ctxCons; CtxSelector us = new BeanSelector(pag, beanNexCtxMap); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { @@ -54,7 +56,7 @@ public BeanPTA(CtxConstructor ctxCons) { } else { this.heapAbst = new AllocSiteAbstractor(); } - prePTA = new Spark(); + prePTA = new Spark(view); System.out.println("bean ..."); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java index 1bdf094bb70..eadcbabdd4f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java @@ -26,6 +26,7 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; +import sootup.core.views.View; /* * refer to "Two approaches to interprocedural data flow analysis" (PFA 1981) @@ -33,7 +34,8 @@ public class CallSiteSensPTA extends BasePTA { - public CallSiteSensPTA(int k, int hk) { + public CallSiteSensPTA(View view, int k, int hk) { + super(view); this.ctxCons = new CallsiteCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java index b43824e9783..6d59f4bf66f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java @@ -26,6 +26,7 @@ import qilin.parm.select.PipelineSelector; import qilin.pta.PTAConfig; import qilin.pta.toolkits.dd.DataDrivenSelector; +import sootup.core.views.View; /* * Support Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017): * https://doi.org/10.1145/3133924 @@ -38,7 +39,8 @@ public class DataDrivenPTA extends BasePTA { - public DataDrivenPTA(CtxConstructor ctxCons) { + public DataDrivenPTA(View view, CtxConstructor ctxCons) { + super(view); this.ctxCons = ctxCons; CtxSelector us = new DataDrivenSelector(ctxCons.getClass()); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java index 734f56c6a54..d46cf16af0f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java @@ -49,13 +49,14 @@ public class DebloatedPTA extends StagedPTA { * Thus the base PTA should be k-OBJ, Zipper-OBJ or Eagle-OBJ. * */ public DebloatedPTA(BasePTA basePTA) { + super(basePTA.view); this.basePTA = basePTA; CtxSelector debloatingSelector = new DebloatingSelector(ctxDepHeaps); basePTA.setContextSelector(new PipelineSelector(basePTA.ctxSelector(), debloatingSelector)); if (basePTA instanceof StagedPTA stagedPTA) { this.prePTA = stagedPTA.getPrePTA(); } else { - this.prePTA = new Spark(); + this.prePTA = new Spark(basePTA.view); } System.out.println("debloating ...."); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java index 69006afea65..ae95212cd6a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java @@ -28,6 +28,7 @@ import sootup.core.jimple.common.expr.Expr; import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.views.View; import java.io.FileNotFoundException; import java.io.PrintWriter; @@ -39,8 +40,8 @@ * (TOSEM'21) * */ public class EaglePTA extends PartialObjSensPTA { - public EaglePTA(int ctxLen) { - super(ctxLen); + public EaglePTA(View view, int ctxLen) { + super(view, ctxLen); System.out.println("Eagle ...."); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java index 1ef7cef9008..e43cb5dc653 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java @@ -26,13 +26,15 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; +import sootup.core.views.View; /** * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) */ public class HybridObjectSensPTA extends BasePTA { - public HybridObjectSensPTA(int k, int hk) { + public HybridObjectSensPTA(View view, int k, int hk) { + super(view); this.ctxCons = new HybObjCtxConstructor(); CtxSelector us = new UniformSelector(k + 1, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java index 34db6856bde..56b1017aff1 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java @@ -26,6 +26,7 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; +import sootup.core.views.View; /** * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) @@ -33,7 +34,8 @@ public class HybridTypeSensPTA extends BasePTA { - public HybridTypeSensPTA(int k, int hk) { + public HybridTypeSensPTA(View view, int k, int hk) { + super(view); this.ctxCons = new HybTypeCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java index 965a33d9813..ee98e173655 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java @@ -27,6 +27,7 @@ import qilin.pta.PTAConfig; import qilin.pta.StagedPTA; import qilin.pta.toolkits.mahjong.Mahjong; +import sootup.core.views.View; import java.util.HashMap; import java.util.HashSet; @@ -41,7 +42,8 @@ public class MahjongPTA extends StagedPTA { public Set mergedHeap = new HashSet<>(); public Set csHeap = new HashSet<>(); - public MahjongPTA(int k, int hk, CtxConstructor ctxCons) { + public MahjongPTA(View view, int k, int hk, CtxConstructor ctxCons) { + super(view); this.ctxCons = ctxCons; CtxSelector us = new UniformSelector(k, hk); CtxSelector ds = new DebloatingSelector(csHeap); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java index aaa9010bd48..57a46da1e62 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java @@ -26,12 +26,14 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; +import sootup.core.views.View; /* * refer to "Parameterized object sensitivity for points-to analysis for Java" (TSE'05) * */ public class ObjectSensPTA extends BasePTA { - public ObjectSensPTA(int k, int hk) { + public ObjectSensPTA(View view, int k, int hk) { + super(view); this.ctxCons = new ObjCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index 8724ac093af..fb60b89c20d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -38,6 +38,7 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; +import sootup.core.views.View; import java.util.HashSet; import java.util.Map; @@ -53,7 +54,8 @@ public abstract class PartialCallSiteSensPTA extends StagedPTA { Set PCSM = new HashSet<>(); Set CSM = new HashSet<>(); - public PartialCallSiteSensPTA(int ctxLen) { + public PartialCallSiteSensPTA(View view, int ctxLen) { + super(view); this.ctxCons = new CallsiteCtxConstructor(); CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index f3923df26eb..57d9fafbbb7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -39,6 +39,7 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; +import sootup.core.views.View; import java.util.HashSet; import java.util.Map; @@ -53,7 +54,8 @@ public abstract class PartialObjSensPTA extends StagedPTA { Set PCSM = new HashSet<>(); Set CSM = new HashSet<>(); - public PartialObjSensPTA(int ctxLen) { + public PartialObjSensPTA(View view, int ctxLen) { + super(view); this.ctxCons = new ObjCtxConstructor(); CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java index 3640b614914..8b0dc824178 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java @@ -19,13 +19,14 @@ package qilin.pta.tools; import qilin.pta.toolkits.selectx.Selectx; +import sootup.core.views.View; import java.util.Map; public class SelectxPTA extends PartialCallSiteSensPTA { - public SelectxPTA(int ctxLen) { - super(ctxLen); + public SelectxPTA(View view, int ctxLen) { + super(view, ctxLen); System.out.println("selectx ... "); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java index da0a21fb2fb..2ae32a37ff2 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java @@ -23,12 +23,14 @@ import qilin.parm.heapabst.HeuristicAbstractor; import qilin.parm.select.InsenSelector; import qilin.pta.PTAConfig; +import sootup.core.views.View; /* * refer to "Scaling Java Points-To Analysis using SPARK" (CC'03) * */ public class Spark extends BasePTA { - public Spark() { + public Spark(View view) { + super(view); this.ctxCons = new InsensCtxConstructor(); this.ctxSel = new InsenSelector(); if (PTAConfig.v().getPtaConfig().mergeHeap) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java index dc02e2a5f15..c4d0f88c5ec 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java @@ -27,6 +27,7 @@ import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; import qilin.pta.toolkits.dd.TunnelingConstructor; +import sootup.core.views.View; /* * This class support context tunneling from the paper "Precise and Scalable Points-to Analysis via Data-Driven @@ -34,7 +35,8 @@ * not show the claimed effectiveness. Maybe we should train the benchmarks to get new formulas? * */ public class TunnelingPTA extends BasePTA { - public TunnelingPTA(CtxConstructor ctxCons, int k, int hk) { + public TunnelingPTA(View view, CtxConstructor ctxCons, int k, int hk) { + super(view); this.ctxCons = new TunnelingConstructor(ctxCons); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java index cb159f3397c..bf34a6f1343 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java @@ -19,6 +19,7 @@ package qilin.pta.tools; import qilin.pta.toolkits.turner.Turner; +import sootup.core.views.View; import java.util.Map; @@ -28,8 +29,8 @@ public class TurnerPTA extends PartialObjSensPTA { private final int k; - public TurnerPTA(int k) { - super(k); + public TurnerPTA(View view, int k) { + super(view, k); this.k = k; System.out.println("Turner ..."); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java index 022996b4743..62c659e8391 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java @@ -26,13 +26,15 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; +import sootup.core.views.View; /* * refer to "Pick Your Contexts Well: Understanding Object-Sensitivity" (PLDI'11) * */ public class TypeSensPTA extends BasePTA { - public TypeSensPTA(int k, int hk) { + public TypeSensPTA(View view, int k, int hk) { + super(view); this.ctxCons = new TypeCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index b0b72ec6235..55a9e6194ec 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -40,6 +40,7 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; +import sootup.core.views.View; import java.util.HashSet; import java.util.Set; @@ -55,7 +56,8 @@ public class ZipperPTA extends StagedPTA { * Zipper support object-sensitivity, callsite-sensitivity by using corresponding * context-constructor. * */ - public ZipperPTA(int k, int hk, CtxConstructor ctxCons) { + public ZipperPTA(View view, int k, int hk, CtxConstructor ctxCons) { + super(view); this.ctxCons = ctxCons; CtxSelector us = new PartialMethodLvSelector(k, hk, PCMs); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { @@ -68,7 +70,7 @@ public ZipperPTA(int k, int hk, CtxConstructor ctxCons) { } else { this.heapAbst = new AllocSiteAbstractor(); } - this.prePTA = new Spark(); + this.prePTA = new Spark(view); } @Override diff --git a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java index eb7ca062137..614af1d2320 100644 --- a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java @@ -22,6 +22,8 @@ import qilin.core.PTA; import qilin.core.PTAScene; import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import java.util.Set; import java.util.stream.Collectors; @@ -42,8 +44,12 @@ public BenchmarkStat(PTA pta) { init(); } + private SootClass getDeclaringClass(SootMethod method) { + ClassType classType = method.getDeclaringClassType(); + return (SootClass) pta.getPag().getView().getClass(classType).get(); + } private void init() { - reachableClasses = pta.getNakedReachableMethods().stream().map(SootMethod::getDeclaringClass) + reachableClasses = pta.getNakedReachableMethods().stream().map(this::getDeclaringClass) .collect(Collectors.toSet()); reachableAppClasses = reachableClasses.stream().filter(SootClass::isApplicationClass) .collect(Collectors.toSet()); diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index 810b04b3be8..55db477ea68 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -22,11 +22,11 @@ import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.FakeMainFactory; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; import qilin.core.pag.ContextMethod; import qilin.core.pag.ContextVarNode; import qilin.core.pag.LocalVarNode; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.model.SootMethod; import java.util.HashSet; diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index c5857b21878..4f9c7256568 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -20,13 +20,13 @@ import qilin.CoreConfig; import qilin.core.PTA; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; import qilin.core.pag.AllocNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.Parm; import qilin.core.sets.PointsToSet; import qilin.util.Util; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JCastExpr; import sootup.core.jimple.common.stmt.JAssignStmt; @@ -202,8 +202,8 @@ public void dumpInsensCallGraph(CallGraph ciCallGraph) { mfile.createNewFile(); BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); for (Edge edge : ciCallGraph) { - String srcSig = Util.stripQuotes(edge.src().getSignature()); - String dstSig = Util.stripQuotes(edge.tgt().getSignature()); + String srcSig = Util.stripQuotes(edge.src().getSignature().toString()); + String dstSig = Util.stripQuotes(edge.tgt().getSignature().toString()); String str = edge.srcStmt() + " in method " + srcSig + "\t" + dstSig + "\n"; writer.write(str); } diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java index 84413d55fc3..d75c4a0d023 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -26,8 +26,10 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import sootup.core.jimple.basic.Local; +import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; @@ -144,7 +146,10 @@ private void init() { if (!handledNatives.contains(lvn.getMethod().toString())) { mLocalVarNodesNoNative.add(lvn); } - boolean app = lvn.getMethod().getDeclaringClass().isApplicationClass(); + SootMethod method = lvn.getMethod(); + ClassType classType = method.getDeclaringClassType(); + SootClass sootClass = (SootClass) pag.getView().getClass(classType).get(); + boolean app = sootClass.isApplicationClass(); totalLocalPointersCi++; if (app) { appLocalPointersCi++; diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index 29df4b4d6ca..e5b9fc7d0e8 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -3,12 +3,12 @@ import qilin.core.PTA; import qilin.core.builder.FakeMainFactory; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.expr.AbstractInvokeExpr; diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index e0ae7993f9e..f72201d83b9 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -21,11 +21,11 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.FakeMainFactory; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; import qilin.core.pag.AllocNode; import qilin.core.pag.ContextMethod; import qilin.util.PTAUtils; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.expr.AbstractInvokeExpr; @@ -33,7 +33,9 @@ import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; @@ -73,7 +75,9 @@ private void init() { } for (SootMethod sm : reachableMethods) { - boolean app = sm.getDeclaringClass().isApplicationClass(); + ClassType declClassType = sm.getDeclaringClassType(); + SootClass declClass = (SootClass) pta.getPag().getView().getClass(declClassType).get(); + boolean app = declClass.isApplicationClass(); // All the statements in the method for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java index a6e3beed0b1..ba0eae9ee40 100644 --- a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -21,10 +21,10 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; import qilin.core.pag.ContextMethod; import qilin.core.sets.PointsToSet; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -69,7 +69,7 @@ private void init() { Set instanceReachables = new HashSet<>(); for (final ContextMethod momc : pta.getReachableMethods()) { SootMethod method = momc.method(); - if (!method.isPhantom() && !method.isStatic()) { + if (/*!method.isPhantom() && */!method.isStatic()) { instanceReachables.add(method); } } diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 3b7ec14b7ad..80ffa34e6c7 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -25,6 +25,10 @@ import qilin.core.PTAScene; import qilin.core.VirtualCalls; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.CallGraph; +import qilin.core.callgraph.Edge; +import qilin.core.callgraph.Kind; +import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.*; @@ -33,9 +37,12 @@ import qilin.util.queue.ChunkedQueue; import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; +import sootup.core.IdentifierFactory; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.stmt.JAssignStmt; @@ -43,10 +50,13 @@ import sootup.core.model.Body; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.NullType; +import sootup.core.types.PrimitiveType; import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; import java.io.*; import java.net.URL; @@ -58,7 +68,7 @@ public final class PTAUtils { private static final Logger logger = LoggerFactory.getLogger(PTAUtils.class); static final String output_dir = CoreConfig.v().getOutConfig().outDir; static Map nodes = new TreeMap<>(); - private static final ClassType clRunnable = RefType.v("java.lang.Runnable"); + private static final ClassType clRunnable = (ClassType) JavaIdentifierFactory.getInstance().getType("java.lang.Runnable"); public static Map> calcStaticThisPTS(PTA pta) { Map> pts = new HashMap<>(); @@ -536,7 +546,8 @@ private static void drawInvPAGMap(DotGraph canvas, Map")) { + if (finalizeMethod != null && finalizeMethod.getSignature().toString().equals("")) { return false; } return finalizeMethod != null; @@ -622,14 +634,14 @@ private static void initEmptyHeapContextTypes() { public static boolean isOfPrimitiveBaseType(AllocNode heap) { if (heap.getType() instanceof ArrayType arrayType) { - return arrayType.getBaseType() instanceof PrimType; + return arrayType.getBaseType() instanceof PrimitiveType; } return false; } public static boolean isPrimitiveArrayType(Type type) { if (type instanceof ArrayType arrayType) { - return arrayType.getArrayElementType() instanceof PrimType; + return arrayType.getArrayElementType() instanceof PrimitiveType; } return false; } @@ -642,7 +654,7 @@ public static boolean isPrimitiveArrayType(Type type) { public static boolean enforceEmptyContext(AllocNode probe) { // primitive array objects should be context-insenstive. if (probe.getType() instanceof ArrayType arrayType) { - if (arrayType.getArrayElementType() instanceof PrimType) { + if (arrayType.getArrayElementType() instanceof PrimitiveType) { return true; } } @@ -756,10 +768,10 @@ public static String findMainFromMetaInfo(String appPath) { public static SootClass getSootClass(Type type) { SootClass allocated = null; - if (type instanceof RefType) { - allocated = ((RefType) type).getSootClass(); - } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof RefType) { - allocated = ((RefType) ((ArrayType) type).getArrayElementType()).getSootClass(); + if (type instanceof ClassType classType) { + allocated = classType.getSootClass(); + } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof ClassType classType) { + allocated = classType.getSootClass(); } return allocated; } @@ -785,10 +797,10 @@ public static Body getMethodBody(SootMethod m) { public static boolean isEmptyArray(AllocNode heap) { Object var = heap.getNewExpr(); - if (var instanceof NewArrayExpr nae) { + if (var instanceof JNewArrayExpr nae) { Value sizeVal = nae.getSize(); if (sizeVal instanceof IntConstant size) { - return size.value == 0; + return size.getValue() == 0; } } return false; @@ -846,7 +858,8 @@ public static Set clinitsOf(SootClass cl) { } } for (SootClass sc : visit) { - final SootMethod initStart = sc.getMethod(Scene.v().getSubSigNumberer().findOrAdd("void ()")); + MethodSubSignature msubsig = JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); + final SootMethod initStart = (SootMethod) sc.getMethod(msubsig).get(); if (initStart != null) { ret.add(initStart); } From b8969179875a8c44fdde229e5d4ad36fd2773f8d Mon Sep 17 00:00:00 2001 From: Dongjie He Date: Wed, 28 Dec 2022 21:57:04 +1100 Subject: [PATCH 005/145] update sootup.qilin --- sootup.qilin/pom.xml | 6 + .../java/qilin/core/ArtificialMethod.java | 49 +++++--- .../qilin/core/builder/CallGraphBuilder.java | 8 +- .../qilin/core/builder/FakeMainFactory.java | 65 ++++++---- .../qilin/core/builder/MethodNodeFactory.java | 114 ++++++++++-------- .../main/java/qilin/core/solver/Solver.java | 10 +- .../qilin/pta/toolkits/common/ToolUtil.java | 9 +- .../pta/toolkits/conch/AbstractConch.java | 8 +- .../qilin/pta/toolkits/conch/AbstractPAG.java | 5 +- .../java/qilin/pta/toolkits/conch/Conch.java | 17 ++- .../toolkits/conch/DepOnParamAnalysis.java | 6 +- .../pta/toolkits/conch/LeakAnalysis.java | 8 +- .../analysis/PotentialContextElement.java | 3 +- .../pta/toolkits/zipper/analysis/Zipper.java | 2 +- .../main/java/qilin/stat/CallGraphStat.java | 13 +- .../src/main/java/qilin/util/PTAUtils.java | 6 + 16 files changed, 199 insertions(+), 130 deletions(-) diff --git a/sootup.qilin/pom.xml b/sootup.qilin/pom.xml index 632ca28c9e7..b1d8eb584f0 100644 --- a/sootup.qilin/pom.xml +++ b/sootup.qilin/pom.xml @@ -51,6 +51,12 @@ oshi-core 6.4.0 + + + de.upb.cs.swt + heros + 1.2.3 + diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index d17af3804f2..dec51cd938e 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -31,18 +31,23 @@ import sootup.core.jimple.common.ref.IdentityRef; import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JParameterRef; +import sootup.core.jimple.common.ref.JStaticFieldRef; import sootup.core.model.Body; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.signatures.FieldSignature; import sootup.core.signatures.MethodSignature; import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; +import sootup.core.views.View; +import sootup.java.core.JavaIdentifierFactory; import java.util.Arrays; import java.util.List; public abstract class ArtificialMethod { - + protected View view; protected IdentifierFactory identifierFactory; protected SootMethod method; protected Body body; @@ -51,7 +56,7 @@ public abstract class ArtificialMethod { protected int paraStart; protected int localStart; - protected Value getThis() { + protected Local getThis() { if (thisLocal == null) { ClassType type = method.getDeclaringClassType(); thisLocal = getLocal(type, 0); @@ -60,8 +65,8 @@ protected Value getThis() { return thisLocal; } - protected Value getPara(int index) { - Value paraLocal = paraLocals[index]; + protected Local getPara(int index) { + Local paraLocal = paraLocals[index]; if (paraLocal == null) { Type type = method.getParameterType(index); return getPara(index, type); @@ -69,7 +74,7 @@ protected Value getPara(int index) { return paraLocal; } - protected Value getPara(int index, Type type) { + protected Local getPara(int index, Type type) { Local paraLocal = paraLocals[index]; if (paraLocal == null) { IdentityRef paraRef = new JParameterRef(type, index); @@ -84,21 +89,21 @@ private void addIdentity(Local lValue, IdentityRef rValue) { body.getUnits().add(Jimple.newIdentityStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); } - protected Value getNew(ClassType type) { + protected Local getNew(ClassType type) { Value newExpr = new JNewExpr(type); - Value local = getNextLocal(type); + Local local = getNextLocal(type); addAssign(local, newExpr); return local; } - protected Value getNewArray(ReferenceType type) { + protected Local getNewArray(ReferenceType type) { Value newExpr = new JNewArrayExpr(type, IntConstant.getInstance(1), identifierFactory); - Value local = getNextLocal(identifierFactory.getArrayType(type, 1)); + Local local = getNextLocal(identifierFactory.getArrayType(type, 1)); addAssign(local, newExpr); return local; } - protected Value getNextLocal(Type type) { + protected Local getNextLocal(Type type) { return getLocal(type, localStart++); } @@ -112,11 +117,13 @@ protected void addReturn(Immediate ret) { body.getUnits().add(Jimple.newReturnStmt(ret, StmtPositionInfo.createNoStmtPositionInfo())); } - protected Value getStaticFieldRef(String className, String name) { - return Jimple.newStaticFieldRef(RefType.v(className).getSootClass().getFieldByName(name).makeRef()); + protected JStaticFieldRef getStaticFieldRef(String className, String name, String fieldType) { + ClassType classType = (ClassType) JavaIdentifierFactory.getInstance().getType(className); + FieldSignature fieldSignature = JavaIdentifierFactory.getInstance().getFieldSignature(name, classType, fieldType); + return Jimple.newStaticFieldRef(fieldSignature); } - protected Value getArrayRef(Value base) { + protected JArrayRef getArrayRef(Value base) { return new JArrayRef((Local) base, IntConstant.getInstance(0), ); } @@ -125,8 +132,10 @@ protected Value getArrayRef(Value base) { */ protected void addInvoke(Value receiver, String sig, Immediate... args) { MethodSignature msig = identifierFactory.parseMethodSignature(sig); + ClassType classType = msig.getDeclClassType(); + SootClass sootClass = (SootClass) view.getClass(classType).get(); List argsL = Arrays.asList(args); - AbstractInvokeExpr invoke = msig.getDeclaringClass().isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) + AbstractInvokeExpr invoke = sootClass.isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) : Jimple.newVirtualInvokeExpr((Local) receiver, msig, argsL); body.getUnits().add(Jimple.newInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo())); } @@ -136,12 +145,14 @@ protected void addInvoke(Value receiver, String sig, Immediate... args) { * * @return rx */ - protected Value getInvoke(Value receiver, String sig, Immediate... args) { + protected Local getInvoke(Value receiver, String sig, Immediate... args) { MethodSignature msig = identifierFactory.parseMethodSignature(sig); List argsL = Arrays.asList(args); - Value invoke = methodRef.getDeclaringClass().isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) + ClassType classType = msig.getDeclClassType(); + SootClass sootClass = (SootClass) view.getClass(classType).get(); + Value invoke = sootClass.isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) : Jimple.newVirtualInvokeExpr((Local) receiver, msig, argsL); - Value rx = getNextLocal(msig.getType()); + Local rx = getNextLocal(msig.getType()); addAssign(rx, invoke); return rx; } @@ -160,10 +171,10 @@ protected void addInvoke(String sig, Immediate... args) { * * @return rx */ - protected Value getInvoke(String sig, Immediate... args) { + protected Local getInvoke(String sig, Immediate... args) { MethodSignature msig = identifierFactory.parseMethodSignature(sig); List argsL = Arrays.asList(args); - Value rx = getNextLocal(msig.getType()); + Local rx = getNextLocal(msig.getType()); addAssign(rx, Jimple.newStaticInvokeExpr(msig, argsL)); return rx; } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 0f26820ce99..425293a204e 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -65,7 +65,7 @@ public CallGraphBuilder(PTA pta) { this.pta = pta; this.pag = pta.getPag(); this.callGraph = new CallGraph(); - receiverToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); + receiverToSites = DataFactory.createMap(1000); methodToInvokeStmt = DataFactory.createMap(); reachMethods = DataFactory.createSet(); calledges = DataFactory.createSet(); @@ -107,14 +107,14 @@ private void constructCallGraph() { cicg = new CallGraph(); Map>> map = DataFactory.createMap(); calledges.forEach(e -> { - PTAScene.v().getCallGraph().addEdge(e); + callGraph.addEdge(e); SootMethod src = e.src(); SootMethod tgt = e.tgt(); Stmt unit = e.srcUnit(); Map> submap = map.computeIfAbsent(unit, k -> DataFactory.createMap()); Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); if (set.add(tgt)) { - cicg.addEdge(new Edge(src, e.srcUnit(), tgt, e.kind())); + cicg.addEdge(new Edge(new ContextMethod(src, pta.emptyContext()), e.srcUnit(), new ContextMethod(tgt, pta.emptyContext()), e.kind())); } }); } @@ -236,7 +236,7 @@ private void processCallAssign(Edge e) { } // add normal return edge if (s instanceof JAssignStmt jassign) { - Value dest = (jassign.getLeftOp(); + Value dest = jassign.getLeftOp(); if (dest.getType() instanceof ReferenceType) { Node destNode = srcnf.getNode(dest); diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index 5c5cc4fe45c..cb9aeead35f 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -21,9 +21,15 @@ import qilin.CoreConfig; import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; +import sootup.core.IdentifierFactory; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.ref.JStaticFieldRef; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.JavaSootMethod; import java.util.ArrayList; import java.util.Collections; @@ -86,27 +92,36 @@ public SootMethod getFakeMain() { return this.method; } - public Value getFieldCurrentThread() { - return getStaticFieldRef("FakeMain", "currentThread"); + public JStaticFieldRef getFieldCurrentThread() { + return getStaticFieldRef("FakeMain", "currentThread", "java.lang.Thread"); } - public Value getFieldGlobalThrow() { - return getStaticFieldRef("FakeMain", "globalThrow"); + public JStaticFieldRef getFieldGlobalThrow() { + return getStaticFieldRef("FakeMain", "globalThrow", "java.lang.Exception"); + } + + private boolean isStaticInitializer (SootMethod method) { + if (method instanceof JavaSootMethod jm) { + return jm.isStaticInitializer(); + } + return false; } private void makeFakeMain() { implicitCallEdges = 0; + IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); for (SootMethod entry : getEntryPoints()) { if (entry.isStatic()) { - if (entry.getSubSignature().equals("void main(java.lang.String[])")) { - Value mockStr = getNew(RefType.v("java.lang.String")); - Value strArray = getNewArray(RefType.v("java.lang.String")); + if (entry.isMain()) { + ClassType classType = (ClassType) idFactory.getType("java.lang.String"); + Value mockStr = getNew(classType); + Local strArray = getNewArray(classType); addAssign(getArrayRef(strArray), mockStr); - addInvoke(entry.getSignature(), strArray); + addInvoke(entry.getSignature().toString(), strArray); implicitCallEdges++; - } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !entry.isStaticInitializer()) { + } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !isStaticInitializer(entry)) { // in the on fly mode, we won't add a call directly for methods. - addInvoke(entry.getSignature()); + addInvoke(entry.getSignature().toString()); implicitCallEdges++; } } @@ -114,42 +129,42 @@ private void makeFakeMain() { if (CoreConfig.v().getPtaConfig().singleentry) { return; } - Value sv = getNextLocal(RefType.v("java.lang.String")); - Value mainThread = getNew(RefType.v("java.lang.Thread")); - Value mainThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); - Value systemThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + Local sv = getNextLocal(idFactory.getType("java.lang.String")); + Local mainThread = getNew((ClassType) idFactory.getType("java.lang.Thread")); + Local mainThreadGroup = getNew((ClassType) idFactory.getType("java.lang.ThreadGroup")); + Local systemThreadGroup = getNew((ClassType) idFactory.getType("java.lang.ThreadGroup")); Value gCurrentThread = getFieldCurrentThread(); addAssign(gCurrentThread, mainThread); // Store - Value vRunnable = getNextLocal(RefType.v("java.lang.Runnable")); + Local vRunnable = getNextLocal(idFactory.getType("java.lang.Runnable")); - Value lThreadGroup = getNextLocal(RefType.v("java.lang.ThreadGroup")); + Local lThreadGroup = getNextLocal(idFactory.getType("java.lang.ThreadGroup")); addInvoke(mainThread, "(java.lang.ThreadGroup,java.lang.String)>", mainThreadGroup, sv); - Value tmpThread = getNew(RefType.v("java.lang.Thread")); + Value tmpThread = getNew((ClassType) idFactory.getType("java.lang.Thread")); addInvoke(tmpThread, "(java.lang.ThreadGroup,java.lang.Runnable)>", lThreadGroup, vRunnable); addInvoke(tmpThread, ""); addInvoke(systemThreadGroup, "()>"); addInvoke(mainThreadGroup, "(java.lang.ThreadGroup,java.lang.String)>", systemThreadGroup, sv); - Value lThread = getNextLocal(RefType.v("java.lang.Thread")); - Value lThrowable = getNextLocal(RefType.v("java.lang.Throwable")); - Value tmpThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + Local lThread = getNextLocal(idFactory.getType("java.lang.Thread")); + Local lThrowable = getNextLocal(idFactory.getType("java.lang.Throwable")); + Value tmpThreadGroup = getNew((ClassType) idFactory.getType("java.lang.ThreadGroup")); addInvoke(tmpThreadGroup, "", lThread, lThrowable); // TODO. // ClassLoader - Value defaultClassLoader = getNew(RefType.v("sun.misc.Launcher$AppClassLoader")); + Value defaultClassLoader = getNew((ClassType) idFactory.getType("sun.misc.Launcher$AppClassLoader")); addInvoke(defaultClassLoader, "()>"); - Value vClass = getNextLocal(RefType.v("java.lang.Class")); - Value vDomain = getNextLocal(RefType.v("java.security.ProtectionDomain")); + Local vClass = getNextLocal(idFactory.getType("java.lang.Class")); + Local vDomain = getNextLocal(idFactory.getType("java.security.ProtectionDomain")); addInvoke(defaultClassLoader, "", sv); addInvoke(defaultClassLoader, "", vClass, vDomain); addInvoke(defaultClassLoader, "", vClass); // PrivilegedActionException - Value privilegedActionException = getNew(RefType.v("java.security.PrivilegedActionException")); - Value gLthrow = getNextLocal(RefType.v("java.lang.Exception")); + Value privilegedActionException = getNew((ClassType) idFactory.getType("java.security.PrivilegedActionException")); + Local gLthrow = getNextLocal(idFactory.getType("java.lang.Exception")); addInvoke(privilegedActionException, "(java.lang.Exception)>", gLthrow); } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index 20d86d917ea..ebf78f80733 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -148,59 +148,9 @@ private void resolveClinit(JStaticFieldRef staticFieldRef) { PTAUtils.clinitsOf(sootClass).forEach(mpag::addTriggeredClinit); } - /** - * Adds the edges required for this statement to the graph. - */ - private void handleIntraStmt(Stmt s) { - s.apply(new AbstractStmtSwitch<>() { - public void caseAssignStmt(JAssignStmt as) { - Value l = as.getLeftOp(); - Value r = as.getRightOp(); - if (l instanceof JStaticFieldRef sfr) { - resolveClinit(sfr); - } else if (r instanceof JStaticFieldRef sfr) { - resolveClinit(sfr); - } - - if (!(l.getType() instanceof ReferenceType)) - return; - // check for improper casts, with mal-formed code we might get - // l = (refliketype)int_type, if so just return - if (r instanceof JCastExpr && (!(((JCastExpr) r).getOp().getType() instanceof ReferenceType))) { - return; - } - - if (!(r.getType() instanceof ReferenceType)) - throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + as - + " in method " + method.getSignature()); - Node dest = getNode(l); - Node src = getNode(r); - mpag.addInternalEdge(src, dest); - } - public void caseReturnStmt(JReturnStmt rs) { - if (!(rs.getOp().getType() instanceof ReferenceType)) - return; - Node retNode = getNode(rs.getOp()); - mpag.addInternalEdge(retNode, caseRet()); - } - public void caseIdentityStmt(JIdentityStmt is) { - if (!(is.getLeftOp().getType() instanceof ReferenceType)) { - return; - } - Node dest = getNode(is.getLeftOp()); - Node src = getNode(is.getRightOp()); - mpag.addInternalEdge(src, dest); - } - - public void caseThrowStmt(JThrowStmt ts) { - if (!CoreConfig.v().getPtaConfig().preciseExceptions) { - mpag.addInternalEdge(getNode(ts.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); - } - } - }); - } + /* cases for handle values */ private VarNode caseLocal(Local l) { return pag.makeLocalVarNode(l, l.getType(), method); @@ -343,4 +293,66 @@ final public VarNode caseClassConstant(ClassConstant cc) { } + /* cases for handle intra-statements */ + /** + * Adds the edges required for this statement to the graph. + */ + public void caseAssignStmt(JAssignStmt as) { + Value l = as.getLeftOp(); + Value r = as.getRightOp(); + if (l instanceof JStaticFieldRef sfr) { + resolveClinit(sfr); + } else if (r instanceof JStaticFieldRef sfr) { + resolveClinit(sfr); + } + + if (!(l.getType() instanceof ReferenceType)) + return; + // check for improper casts, with mal-formed code we might get + // l = (refliketype)int_type, if so just return + if (r instanceof JCastExpr && (!(((JCastExpr) r).getOp().getType() instanceof ReferenceType))) { + return; + } + + if (!(r.getType() instanceof ReferenceType)) + throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + as + + " in method " + method.getSignature()); + Node dest = getNode(l); + Node src = getNode(r); + mpag.addInternalEdge(src, dest); + } + + public void caseReturnStmt(JReturnStmt rs) { + if (!(rs.getOp().getType() instanceof ReferenceType)) + return; + Node retNode = getNode(rs.getOp()); + mpag.addInternalEdge(retNode, caseRet()); + } + + public void caseIdentityStmt(JIdentityStmt is) { + if (!(is.getLeftOp().getType() instanceof ReferenceType)) { + return; + } + Node dest = getNode(is.getLeftOp()); + Node src = getNode(is.getRightOp()); + mpag.addInternalEdge(src, dest); + } + + public void caseThrowStmt(JThrowStmt ts) { + if (!CoreConfig.v().getPtaConfig().preciseExceptions) { + mpag.addInternalEdge(getNode(ts.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); + } + } + + private void handleIntraStmt(Stmt s) { + if (s instanceof JAssignStmt as) { + caseAssignStmt(as); + } else if (s instanceof JReturnStmt rs) { + caseReturnStmt(rs); + } else if (s instanceof JIdentityStmt is) { + caseIdentityStmt(is); + } else if (s instanceof JThrowStmt ts) { + caseThrowStmt(ts); + } + } } diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index ad1c3b5b67f..ccbbfc60370 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -42,6 +42,7 @@ import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; import sootup.core.signatures.MethodSubSignature; import java.util.*; @@ -109,9 +110,9 @@ public void processStmts(Iterator newRMs) { while (newRMs.hasNext()) { ContextMethod momc = newRMs.next(); SootMethod method = momc.method(); - if (method.isPhantom()) { - continue; - } +// if (method.isPhantom()) { +// continue; +// } MethodPAG mpag = pag.getMethodPAG(method); addToPAG(mpag, momc.context()); // !FIXME in a context-sensitive pointer analysis, clinits in a method maybe added multiple times. @@ -144,7 +145,8 @@ private void recordCallStmts(ContextMethod m, Collection units) { // !TODO dynamicInvoke is provided in JDK after Java 7. // currently, PTA does not handle dynamicInvokeExpr. } else if (ie instanceof JStaticInvokeExpr sie) { - SootMethod tgt = ie.getMethod(); + MethodSignature msig = sie.getMethodSignature(); + SootMethod tgt = (SootMethod) pag.getView().getMethod(msig).get(); VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); recNode = (VarNode) pta.parameterize(recNode, m.context()); cgb.addStaticEdge(m, s, tgt, Edge.ieToKind(ie)); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index 7d74ac3f064..7b6cb2845b7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -22,9 +22,11 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.PAG; import qilin.core.pag.VarNode; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; +import sootup.core.views.View; import java.util.Collections; import java.util.HashSet; @@ -66,12 +68,13 @@ public static int pointsToSetSizeOf(final PTA pta, VarNode var) { * @param pOuter potential outer class * @return whether pInner is an inner class of pOuter */ - public static boolean isInnerType(final ClassType pInner, ClassType pOuter) { + public static boolean isInnerType(final View view, final ClassType pInner, ClassType pOuter) { final String pInnerStr = pInner.toString(); while (!pInnerStr.startsWith(pOuter.toString() + "$")) { - SootClass sc = pOuter.getSootClass(); + SootClass sc = (SootClass) view.getClass(pOuter).get(); if (sc.hasSuperclass()) { - pOuter = sc.getSuperclass().getType(); + SootClass superClass = (SootClass) sc.getSuperclass().get(); + pOuter = superClass.getType(); } else { return false; } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java index 0da0a2d208a..ae73f392602 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java @@ -26,6 +26,7 @@ import qilin.util.Pair; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.PrimitiveType; import java.util.*; @@ -54,7 +55,8 @@ private void init() { * The following line computes the receiver objects for the this_ptr of static methods. * */ Map> pts = PTAUtils.calcStaticThisPTS(pta); - pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(method -> { + pta.getNakedReachableMethods().stream()//.filter(m -> !m.isPhantom()) + .forEach(method -> { collectStoresIn(method); collectLoadsIn(method); buildInvokedOnFor(method, pts); @@ -164,14 +166,14 @@ private void collectStoresIn(SootMethod method) { private boolean primitiveField(SparkField f) { String s = "java.lang.String"; - if (f.getType() instanceof PrimType) { + if (f.getType() instanceof PrimitiveType) { return true; } else if (f.getType() instanceof ArrayType at) { /* * here, we let primitive array as primitive type as that in Turner. * this wont hurt precision of clients. * */ - return at.getBaseType() instanceof PrimType; + return at.getBaseType() instanceof PrimitiveType; } else return f.getType().toString().equals(s); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java index 76e44cdf230..00e70359fd7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -23,6 +23,7 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.CallGraph; import qilin.core.pag.*; import qilin.util.queue.QueueReader; import sootup.core.jimple.common.stmt.Stmt; @@ -67,7 +68,7 @@ protected AbstractPAG(PTA prePTA) { protected void build() { prePTA.getNakedReachableMethods() - .parallelStream().filter(m -> !m.isPhantom()) + .parallelStream()// .filter(m -> !m.isPhantom()) .forEach(this::buildFG); } @@ -217,6 +218,6 @@ private void runExecutorAndAwaitCompletion() { } protected AllocNode getSymbolicHeapOf(SootMethod method, Stmt invokeStmt) { - return symbolicHeaps.computeIfAbsent(method, k -> new ConcurrentHashMap<>()).computeIfAbsent(invokeStmt, k -> new AllocNode(invokeStmt, null, method)); + return symbolicHeaps.computeIfAbsent(method, k -> new ConcurrentHashMap<>()).computeIfAbsent(invokeStmt, k -> new AllocNode(prePAG.getView(), invokeStmt, null, method)); } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index 0a792a483cf..fc25f0d3830 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -31,6 +31,7 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; +import sootup.java.core.JavaSootMethod; import java.util.*; import java.util.stream.Collectors; @@ -76,8 +77,8 @@ private SootMethod findInvokedConstructorOf(AllocNode heap) { VarNode baseNode = (VarNode) nodeFactory.getNode(base); PointsToSet v1pts = pta.reachingObjects(baseNode); MethodSignature targetSig = iie.getMethodSignature(); - SootMethod target = null; - if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && targetSig.isConstructor()) { + JavaSootMethod target = (JavaSootMethod) pag.getView().getMethod(targetSig).get(); + if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && target.isConstructor()) { return target; } } @@ -96,7 +97,8 @@ private SootMethod findInvokedConstructorOf(SootMethod outerInit) { if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); - SootMethod target = iie.getMethod(); + MethodSignature methodSignature = iie.getMethodSignature(); + JavaSootMethod target = (JavaSootMethod) pag.getView().getMethod(methodSignature).get(); if (PTAUtils.mustAlias(pta, thisNode, baseNode) && target.isConstructor()) { return target; } @@ -128,7 +130,9 @@ private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMeth if (!(stmt.getInvokeExpr() instanceof JSpecialInvokeExpr)) { continue; } - SootMethod target = stmt.getInvokeExpr().getMethod(); + AbstractInvokeExpr invokeExpr = stmt.getInvokeExpr(); + MethodSignature methodSignature = invokeExpr.getMethodSignature(); + SootMethod target = (SootMethod) pag.getView().getMethod(methodSignature).get(); if (target != null && target.equals(curr)) { for (Node n : params) { if (n instanceof VarNode paramNode) { @@ -205,7 +209,8 @@ private Trilean checkResult(Set res) { private Trilean isCommingFromParams(LocalVarNode from, SootMethod method, AllocNode heap) { Set ret = this.pfg.fetchReachableParamsOf(from); - if (method.isConstructor()) { + JavaSootMethod method1 = (JavaSootMethod) method; + if (method1.isConstructor()) { return handleTransitiveConstructors(method, heap, ret); } else { return checkResult(ret); @@ -295,7 +300,7 @@ public void runClassifier() { || PTAUtils.isOfPrimitiveBaseType(heap)) { ciHeaps.add(heap); } else { - SootMethod mthd = heap.getMethod(); + JavaSootMethod mthd = (JavaSootMethod) heap.getMethod(); if (mthd.isStaticInitializer()) { ciHeaps.add(heap); } else { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index c140c2c5a2b..056ade6d4ad 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -20,9 +20,9 @@ import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; +import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -112,13 +112,13 @@ public void run() { containingMethod = heap.getMethod(); } - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); MethodNodeFactory srcnf = srcmpag.nodeFactory(); - Stmt invokeStmt = (Stmt) edge.srcUnit(); + Stmt invokeStmt = edge.srcUnit(); if (invokeStmt instanceof JAssignStmt assignStmt) { VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java index 3d1b300cea0..3ffd9e3f501 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -19,9 +19,9 @@ package qilin.pta.toolkits.conch; import qilin.core.PTA; +import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -128,7 +128,7 @@ public void run() { AllocNode sourceHeap = (AllocNode) sourceNode; result.add(sourceHeap); SootMethod containingMethod = sourceHeap.getMethod(); - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); @@ -148,7 +148,7 @@ public void run() { } else if (initState == DFA.State.F) { LocalVarNode pj = (LocalVarNode) sourceNode; SootMethod containingMethod = pj.getMethod(); - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); @@ -176,7 +176,7 @@ public void run() { // ret = pi.f* LocalVarNode retOrThrow = (LocalVarNode) sourceNode; SootMethod containingMethod = retOrThrow.getMethod(); - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); VarNode pi = (VarNode) pe.getTgtNode(); // add r --> ai summary edge inverse_inter_load. while (it.hasNext()) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java index ebc86bc094d..c8936ade446 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java @@ -3,6 +3,7 @@ import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.AllocNode; +import qilin.core.pag.ContextMethod; import qilin.core.pag.VarNode; import qilin.core.sets.PointsToSet; import qilin.pta.toolkits.common.OAG; @@ -160,7 +161,7 @@ private Set invokedMethodsOf(final AllocNode obj) { while (!queue.isEmpty()) { final SootMethod method = queue.poll(); methods.add(method); - pta.getCallGraph().edgesOutOf(method).forEachRemaining(edge -> { + pta.getCallGraph().edgesOutOf(new ContextMethod(method, pta.emptyContext())).forEachRemaining(edge -> { SootMethod callee = edge.getTgt().method(); if (callee.isStatic() && !methods.contains(callee)) { queue.offer(callee); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java index 067dfff3acd..34cd145c0a5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java @@ -185,7 +185,7 @@ private void analyze(ClassType type, FlowAnalysis fa) { // are also considered as the OUT methods of current type pce.PCEMethodsOf(type).stream() .filter(m -> !m.isPrivate() && !m.isStatic()) - .filter(m -> ToolUtil.isInnerType( + .filter(m -> ToolUtil.isInnerType(pta.getPag().getView(), m.getDeclaringClassType(), type)) .forEach(outms::add); pce.PCEMethodsOf(type).stream() diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index 55db477ea68..bc3bfaa3e1d 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -27,7 +27,10 @@ import qilin.core.pag.ContextMethod; import qilin.core.pag.ContextVarNode; import qilin.core.pag.LocalVarNode; +import qilin.util.PTAUtils; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import java.util.HashSet; import java.util.Iterator; @@ -71,7 +74,8 @@ private void init() { CSCallEdges = csCallGraph.size(); for (final ContextMethod momc : pta.getCgb().getReachableMethods()) { final SootMethod m = momc.method(); - boolean toApp = m.getDeclaringClass().isApplicationClass(); + SootClass declClass = PTAUtils.getDeclaringClass(pta.getPag().getView(), m); + boolean toApp = declClass.isApplicationClass(); reachableParameterizedMethods.add(momc); reachableMethods.add(m); // if (m.toString().equals("")) { @@ -86,7 +90,8 @@ private void init() { for (Iterator iterator = csCallGraph.edgesInto(momc); iterator.hasNext(); ) { Edge e = iterator.next(); final SootMethod srcm = e.getSrc().method(); - boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); + SootClass sc = PTAUtils.getDeclaringClass(pta.getPag().getView(), srcm); + boolean fromApp = sc.isApplicationClass(); if (fromApp && toApp) { CSApp2app++; } else if (fromApp) { @@ -112,7 +117,7 @@ private void init() { CallGraph ciCallGraph = pta.getCallGraph(); CICallEdges = ciCallGraph.size(); for (SootMethod sm : reachableMethods) { - boolean toApp = sm.getDeclaringClass().isApplicationClass(); + boolean toApp = PTAUtils.getDeclaringClass(pta.getPag().getView(), sm).isApplicationClass(); if (sm.isStatic()) { reachableStatic++; if (toApp) { @@ -125,7 +130,7 @@ private void init() { // if (sm.toString().equals("")) { // System.out.println("from:" + srcm); // } - boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); + boolean fromApp = PTAUtils.getDeclaringClass(pta.getPag().getView(), srcm).isApplicationClass(); if (fromApp && toApp) { CIApp2app++; } else if (fromApp) { diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 80ffa34e6c7..a9195460323 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -56,6 +56,7 @@ import sootup.core.types.NullType; import sootup.core.types.PrimitiveType; import sootup.core.types.Type; +import sootup.core.views.View; import sootup.java.core.JavaIdentifierFactory; import java.io.*; @@ -70,6 +71,11 @@ public final class PTAUtils { static Map nodes = new TreeMap<>(); private static final ClassType clRunnable = (ClassType) JavaIdentifierFactory.getInstance().getType("java.lang.Runnable"); + public static SootClass getDeclaringClass(View view, SootMethod method) { + ClassType classType = method.getDeclaringClassType(); + return (SootClass) view.getClass(classType).get(); + } + public static Map> calcStaticThisPTS(PTA pta) { Map> pts = new HashMap<>(); Set workList = new HashSet<>(); From 3edcd44c59e5faf014dfe96e0390b15f56a9b0e9 Mon Sep 17 00:00:00 2001 From: Dongjie He Date: Wed, 28 Dec 2022 22:40:25 +1100 Subject: [PATCH 006/145] update --- .../toolkits/dd/CtxTunnelingFeaturesTrueTable.java | 11 ++++++++--- .../qilin/pta/toolkits/dd/TunnelingConstructor.java | 7 +++++-- .../src/main/java/qilin/pta/tools/TunnelingPTA.java | 2 +- .../src/main/java/qilin/stat/CallGraphStat.java | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index d5bdb0b2e14..5722ae0acfb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -34,16 +34,20 @@ import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.views.View; /* * features and formulas used in "Precise and Scalable Points-to Analysis via Data-Driven * Context Tunneling" (OOPSLA 2018). * */ public class CtxTunnelingFeaturesTrueTable { + private final View view; private final boolean[] f = new boolean[24]; - public CtxTunnelingFeaturesTrueTable(SootMethod sm) { + public CtxTunnelingFeaturesTrueTable(SootMethod sm, View view) { + this.view = view; String sig = sm.getSignature().toString(); // the 10 atomic signature features. this.f[1] = sig.contains("java"); @@ -98,11 +102,12 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm) { this.f[20] = heapAllocCnt == 1; this.f[21] = sig.contains("Object"); this.f[22] = heapAllocCnt >= 1; // note, the original implementation is >=1 not > 1 which is conflict with the paper. - this.f[23] = sm.getDeclaringClass().getMethods().size() > 20; // their artifact uses 20 as the threshold. + SootClass sc = PTAUtils.getDeclaringClass(view, sm); + this.f[23] = sc.getMethods().size() > 20; // their artifact uses 20 as the threshold. } public boolean containedInNestedClass(SootMethod sm) { - SootClass sc = sm.getDeclaringClass(); + SootClass sc = PTAUtils.getDeclaringClass(view, sm); return sc.toString().contains("$"); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java index e133fb3dcb4..9f479273f13 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java @@ -24,19 +24,22 @@ import qilin.core.pag.ContextMethod; import qilin.parm.ctxcons.*; import sootup.core.model.SootMethod; +import sootup.core.views.View; import java.util.HashMap; import java.util.Map; public class TunnelingConstructor implements CtxConstructor { + private final View view; private final CtxConstructor ctxCons; private final Map m2ftt = new HashMap<>(); private CtxTunnelingFeaturesTrueTable findOrCreateTunnelingFeaturesTrueTable(SootMethod sm) { - return m2ftt.computeIfAbsent(sm, k -> new CtxTunnelingFeaturesTrueTable(sm)); + return m2ftt.computeIfAbsent(sm, k -> new CtxTunnelingFeaturesTrueTable(sm, view)); } - public TunnelingConstructor(CtxConstructor ctxCons) { + public TunnelingConstructor(View view, CtxConstructor ctxCons) { + this.view = view; this.ctxCons = ctxCons; } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java index c4d0f88c5ec..52cd6c232f7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java @@ -37,7 +37,7 @@ public class TunnelingPTA extends BasePTA { public TunnelingPTA(View view, CtxConstructor ctxCons, int k, int hk) { super(view); - this.ctxCons = new TunnelingConstructor(ctxCons); + this.ctxCons = new TunnelingConstructor(view, ctxCons); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index bc3bfaa3e1d..609baad11a6 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -124,7 +124,7 @@ private void init() { reachableAppStatic++; } } - for (Iterator iterator = ciCallGraph.edgesInto(sm); iterator.hasNext(); ) { + for (Iterator iterator = ciCallGraph.edgesInto(new ContextMethod(sm, pta.emptyContext())); iterator.hasNext(); ) { Edge e = iterator.next(); final SootMethod srcm = e.getSrc().method(); // if (sm.toString().equals("")) { From 97b37560941303032c83767ce73c5eb8c69c55d8 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Fri, 15 Sep 2023 18:31:06 +0800 Subject: [PATCH 007/145] qilin:16f2bcd --- sootup.qilin/.DS_Store | Bin 6148 -> 6148 bytes sootup.qilin/src/.DS_Store | Bin 6148 -> 6148 bytes sootup.qilin/src/main/.DS_Store | Bin 6148 -> 8196 bytes sootup.qilin/src/main/java/.DS_Store | Bin 6148 -> 6148 bytes sootup.qilin/src/main/java/driver/Main.java | 230 ++++++++- .../src/main/java/driver/PTAComparator.java | 4 +- .../src/main/java/driver/PTAFactory.java | 53 +- .../src/main/java/driver/PTAOption.java | 13 +- sootup.qilin/src/main/java/qilin/.DS_Store | Bin 6148 -> 6148 bytes .../src/main/java/qilin/CoreConfig.java | 4 +- .../java/qilin/core/ArtificialMethod.java | 135 +++-- .../src/main/java/qilin/core/CorePTA.java | 7 +- .../src/main/java/qilin/core/PTA.java | 19 +- .../src/main/java/qilin/core/PTAScene.java | 7 +- .../java/qilin/core/PointsToAnalysis.java | 6 +- .../main/java/qilin/core/VirtualCalls.java | 60 +-- .../qilin/core/builder/CallGraphBuilder.java | 91 ++-- .../qilin/core/builder/ExceptionHandler.java | 20 +- .../qilin/core/builder/FakeMainFactory.java | 70 +-- .../qilin/core/builder/MethodNodeFactory.java | 252 ++++------ .../java/qilin/core/callgraph/CallGraph.java | 413 ---------------- .../main/java/qilin/core/callgraph/Edge.java | 287 ----------- .../main/java/qilin/core/callgraph/Kind.java | 273 ----------- .../main/java/qilin/core/context/Context.java | 4 - .../qilin/core/context/ContextElements.java | 2 + .../core/context/TypeContextElement.java | 16 +- .../JavaIoFileSystemGetFileSystemNative.java | 12 +- .../natives/JavaIoFileSystemListNative.java | 17 +- .../natives/JavaLangObjectCloneNative.java | 8 +- ...efFinalizerInvokeFinalizeMethodNative.java | 5 +- .../core/natives/JavaLangReflectArrayGet.java | 16 +- .../core/natives/JavaLangReflectArraySet.java | 11 +- .../JavaLangSystemArraycopyNative.java | 15 +- .../natives/JavaLangSystemSetErr0Native.java | 4 +- .../natives/JavaLangSystemSetIn0Native.java | 4 +- .../natives/JavaLangSystemSetOut0Native.java | 4 +- .../natives/JavaLangThreadCurrentThread.java | 11 +- .../natives/JavaLangThreadStart0Native.java | 4 +- ...ityAccessControllerDoPrivilegedNative.java | 8 +- ...ontrollerDoPrivileged_ExceptionNative.java | 8 +- .../java/qilin/core/natives/NativeMethod.java | 6 +- .../core/natives/NativeMethodDriver.java | 4 +- .../main/java/qilin/core/pag/AllocNode.java | 19 +- .../java/qilin/core/pag/ArrayElement.java | 7 +- .../main/java/qilin/core/pag/CallSite.java | 8 +- .../qilin/core/pag/ClassConstantNode.java | 8 +- .../java/qilin/core/pag/ConstantNode.java | 9 +- .../java/qilin/core/pag/ContextAllocNode.java | 7 +- .../java/qilin/core/pag/ContextField.java | 17 +- .../java/qilin/core/pag/ContextMethod.java | 7 +- .../java/qilin/core/pag/ContextVarNode.java | 7 +- .../qilin/core/pag/ExceptionThrowSite.java | 13 +- .../src/main/java/qilin/core/pag/Field.java | 9 +- .../java/qilin/core/pag/FieldRefNode.java | 9 +- .../java/qilin/core/pag/FieldValNode.java | 6 +- .../java/qilin/core/pag/GlobalVarNode.java | 16 +- .../java/qilin/core/pag/LocalVarNode.java | 16 +- .../java/qilin/core/pag/MergedNewExpr.java | 28 +- .../main/java/qilin/core/pag/MethodPAG.java | 64 +-- .../src/main/java/qilin/core/pag/Node.java | 9 +- .../src/main/java/qilin/core/pag/PAG.java | 114 ++--- .../src/main/java/qilin/core/pag/Parm.java | 8 +- .../main/java/qilin/core/pag/SparkField.java | 8 - .../qilin/core/pag/StringConstantNode.java | 10 +- .../src/main/java/qilin/core/pag/ValNode.java | 9 +- .../src/main/java/qilin/core/pag/VarNode.java | 15 +- .../java/qilin/core/pag/VirtualCallSite.java | 25 +- .../core/reflection/NopReflectionModel.java | 22 +- .../core/reflection/ReflectionModel.java | 44 +- .../qilin/core/reflection/TamiflexModel.java | 239 ++++----- .../qilin/core/sets/HybridPointsToSet.java | 4 +- .../java/qilin/core/sets/PointsToSet.java | 4 +- .../core/sets/UnmodifiablePointsToSet.java | 32 +- .../main/java/qilin/core/solver/Solver.java | 86 ++-- .../java/qilin/core/util/ArrayNumberer.java | 155 ------ .../java/qilin/core/util/BitSetIterator.java | 92 ---- .../main/java/qilin/core/util/BitVector.java | 463 ------------------ .../qilin/core/util/IterableNumberer.java | 14 - .../main/java/qilin/core/util/Numberable.java | 6 - .../main/java/qilin/core/util/Numberer.java | 53 -- .../parm/ctxcons/CallsiteCtxConstructor.java | 8 +- .../qilin/parm/ctxcons/CtxConstructor.java | 8 +- .../parm/ctxcons/HybTypeCtxConstructor.java | 8 +- .../parm/ctxcons/InsensCtxConstructor.java | 8 +- .../qilin/parm/ctxcons/ObjCtxConstructor.java | 8 +- .../parm/ctxcons/TypeCtxConstructor.java | 8 +- .../parm/heapabst/HeuristicAbstractor.java | 13 +- .../parm/heapabst/MahjongAbstractor.java | 4 +- .../java/qilin/parm/select/BeanSelector.java | 4 +- .../java/qilin/parm/select/CtxSelector.java | 4 +- .../qilin/parm/select/DebloatingSelector.java | 4 +- .../parm/select/FullMethodLvSelector.java | 4 +- .../qilin/parm/select/HeuristicSelector.java | 4 +- .../java/qilin/parm/select/InsenSelector.java | 4 +- .../parm/select/PartialMethodLvSelector.java | 4 +- .../qilin/parm/select/PartialVarSelector.java | 4 +- .../qilin/parm/select/PipelineSelector.java | 4 +- .../qilin/parm/select/UniformSelector.java | 4 +- .../java/qilin/parm/select/VarLvSelector.java | 4 +- .../src/main/java/qilin/pta/PTAConfig.java | 12 + .../src/main/java/qilin/pta/StagedPTA.java | 36 -- .../pta/toolkits/common/DebloatedOAG.java | 29 ++ .../toolkits/common/FieldPointstoGraph.java | 2 +- .../java/qilin/pta/toolkits/common/OAG.java | 30 +- .../qilin/pta/toolkits/common/ToolUtil.java | 21 +- .../pta/toolkits/conch/AbstractConch.java | 14 +- .../qilin/pta/toolkits/conch/AbstractPAG.java | 18 +- .../java/qilin/pta/toolkits/conch/Conch.java | 52 +- .../toolkits/conch/DepOnParamAnalysis.java | 14 +- .../pta/toolkits/conch/LeakAnalysis.java | 12 +- .../java/qilin/pta/toolkits/conch/SMPAG.java | 2 +- .../dd/CtxTunnelingFeaturesTrueTable.java | 55 +-- .../pta/toolkits/dd/DataDrivenSelector.java | 4 +- .../pta/toolkits/dd/FeaturesTrueTable.java | 56 +-- .../pta/toolkits/dd/TunnelingConstructor.java | 15 +- .../debloaterx/CollectionHeuristic.java | 205 ++++++++ .../toolkits/debloaterx/ContainerFinder.java | 119 +++++ .../pta/toolkits/debloaterx/DebloaterX.java | 169 +++++++ .../qilin/pta/toolkits/debloaterx/Edge.java | 18 + .../pta/toolkits/debloaterx/EdgeKind.java | 19 + .../debloaterx/HeapContainerQuery.java | 77 +++ .../debloaterx/InterFlowAnalysis.java | 222 +++++++++ .../debloaterx/IntraFlowAnalysis.java | 298 +++++++++++ .../qilin/pta/toolkits/debloaterx/State.java | 5 + .../qilin/pta/toolkits/debloaterx/XPAG.java | 267 ++++++++++ .../pta/toolkits/debloaterx/XUtility.java | 314 ++++++++++++ .../java/qilin/pta/toolkits/eagle/Eagle.java | 51 +- .../pta/toolkits/mahjong/HeapAbstraction.java | 2 +- .../pta/toolkits/mahjong/automata/DFA.java | 2 +- .../automata/DFAEquivalenceChecker.java | 4 +- .../toolkits/mahjong/automata/DFAFactory.java | 4 +- .../toolkits/mahjong/automata/DFAState.java | 4 +- .../pta/toolkits/mahjong/automata/NFA.java | 4 +- .../qilin/pta/toolkits/selectx/Selectx.java | 45 +- .../pta/toolkits/turner/AbstractMVFG.java | 46 +- .../toolkits/turner/MethodLevelCallGraph.java | 4 +- .../qilin/pta/toolkits/turner/MethodVFG.java | 2 +- .../pta/toolkits/turner/ModularMVFG.java | 12 +- .../java/qilin/pta/toolkits/turner/OCG.java | 13 +- .../qilin/pta/toolkits/turner/Turner.java | 20 +- .../java/qilin/pta/toolkits/zipper/Main.java | 2 +- .../analysis/PotentialContextElement.java | 7 +- .../pta/toolkits/zipper/analysis/Zipper.java | 24 +- .../pta/toolkits/zipper/cases/CaseA.java | 19 + .../pta/toolkits/zipper/cases/CaseB.java | 25 + .../pta/toolkits/zipper/cases/CaseC.java | 35 ++ .../pta/toolkits/zipper/cases/CaseD.java | 21 + .../zipper/flowgraph/FlowAnalysis.java | 23 +- .../zipper/flowgraph/ObjectFlowGraph.java | 12 +- .../main/java/qilin/pta/tools/BasePTA.java | 25 +- .../main/java/qilin/pta/tools/BeanPTA.java | 7 +- .../java/qilin/pta/tools/CallSiteSensPTA.java | 4 +- .../java/qilin/pta/tools/DataDrivenPTA.java | 4 +- .../java/qilin/pta/tools/DebloatedPTA.java | 80 ++- .../main/java/qilin/pta/tools/EaglePTA.java | 17 +- .../qilin/pta/tools/HybridObjectSensPTA.java | 4 +- .../qilin/pta/tools/HybridTypeSensPTA.java | 4 +- .../main/java/qilin/pta/tools/MahjongPTA.java | 5 +- .../java/qilin/pta/tools/ObjectSensPTA.java | 4 +- .../pta/tools/PartialCallSiteSensPTA.java | 42 +- .../qilin/pta/tools/PartialObjSensPTA.java | 45 +- .../main/java/qilin/pta/tools/SelectxPTA.java | 5 +- .../src/main/java/qilin/pta/tools/Spark.java | 4 +- .../main/java/qilin/pta/tools/StagedPTA.java | 49 ++ .../java/qilin/pta/tools/TunnelingPTA.java | 6 +- .../main/java/qilin/pta/tools/TurnerPTA.java | 5 +- .../java/qilin/pta/tools/TypeSensPTA.java | 4 +- .../main/java/qilin/pta/tools/ZipperPTA.java | 44 +- .../src/main/java/qilin/stat/AliasStat.java | 177 +++++++ .../main/java/qilin/stat/BenchmarkStat.java | 11 +- .../main/java/qilin/stat/CallGraphStat.java | 29 +- .../src/main/java/qilin/stat/Exporter.java | 45 +- .../src/main/java/qilin/stat/IEvaluator.java | 18 + .../main/java/qilin/stat/PTAEvaluator.java | 9 +- .../main/java/qilin/stat/PointsToStat.java | 16 +- .../java/qilin/stat/SimplifiedEvaluator.java | 61 ++- .../main/java/qilin/stat/TypeClientStat.java | 47 +- .../src/main/java/qilin/stat/YummyStat.java | 18 +- .../src/main/java/qilin/util/DataFactory.java | 25 +- .../src/main/java/qilin/util/PTAUtils.java | 157 +++--- .../src/main/java/qilin/util/Util.java | 6 +- .../java/qilin/util/graph/Reachability.java | 7 +- .../java/qilin/util/graph/SCCMergedGraph.java | 6 +- .../graph/StronglyConnectedComponents.java | 6 +- .../qilin/util/graph/TopologicalSorter.java | 6 +- .../java/qilin/util/queue/ChunkedQueue.java | 98 ---- .../java/qilin/util/queue/QueueReader.java | 194 -------- sootup.qilin/src/main/java/soot/Context.java | 30 ++ .../main/java/soot/MethodOrMethodContext.java | 37 ++ .../src/main/java/soot/util/Numberable.java | 36 ++ .../main/java/soot/util/NumberedString.java | 88 ++++ .../main/java/soot/util/StringNumberer.java | 54 ++ .../test/java/qilin/test/FlowSensTests.java | 55 +++ .../java/qilin/test/context/CFATests.java | 45 ++ .../qilin/test/context/CollectionsTests.java | 74 +++ .../java/qilin/test/context/HybTests.java | 39 ++ .../java/qilin/test/context/OBJTests.java | 70 +++ .../java/qilin/test/context/TypeTests.java | 34 ++ .../test/java/qilin/test/core/ArrayTests.java | 49 ++ .../java/qilin/test/core/AssignTests.java | 89 ++++ .../test/java/qilin/test/core/CallTests.java | 40 ++ .../java/qilin/test/core/ClinitTests.java | 44 ++ .../java/qilin/test/core/ExceptionTests.java | 39 ++ .../test/java/qilin/test/core/FieldTests.java | 44 ++ .../java/qilin/test/core/GlobalTests.java | 39 ++ .../java/qilin/test/core/NativeTests.java | 91 ++++ .../java/qilin/test/core/ReflogTests.java | 88 ++++ .../java/qilin/test/util/AliasAssertion.java | 118 +++++ .../qilin/test/util/AssertionsParser.java | 68 +++ .../test/java/qilin/test/util/IAssertion.java | 23 + .../test/java/qilin/test/util/JunitTests.java | 110 +++++ 211 files changed, 5185 insertions(+), 3853 deletions(-) delete mode 100644 sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/context/Context.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/pag/SparkField.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/util/BitVector.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/util/Numberable.java delete mode 100644 sootup.qilin/src/main/java/qilin/core/util/Numberer.java delete mode 100644 sootup.qilin/src/main/java/qilin/pta/StagedPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java create mode 100644 sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java create mode 100644 sootup.qilin/src/main/java/qilin/stat/AliasStat.java delete mode 100644 sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java delete mode 100644 sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java create mode 100644 sootup.qilin/src/main/java/soot/Context.java create mode 100644 sootup.qilin/src/main/java/soot/MethodOrMethodContext.java create mode 100644 sootup.qilin/src/main/java/soot/util/Numberable.java create mode 100644 sootup.qilin/src/main/java/soot/util/NumberedString.java create mode 100644 sootup.qilin/src/main/java/soot/util/StringNumberer.java create mode 100644 sootup.qilin/src/test/java/qilin/test/FlowSensTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/context/CFATests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/context/HybTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/context/OBJTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/context/TypeTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/AssignTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/CallTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/FieldTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/NativeTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java create mode 100644 sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java create mode 100644 sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java create mode 100644 sootup.qilin/src/test/java/qilin/test/util/IAssertion.java create mode 100644 sootup.qilin/src/test/java/qilin/test/util/JunitTests.java diff --git a/sootup.qilin/.DS_Store b/sootup.qilin/.DS_Store index 845106103b9852232a6cf03b52fbc3414521b8bc..c87f3589a1a18943a30c12e170cbb0d69e9e0476 100644 GIT binary patch delta 124 zcmZoMXfc@J&&akhU^gQp+hiW5Ovde#%a{t)#H*`~&2AvvYFu@;fKuA^iXV delta 87 zcmZoMXfc@J&&aYdU^gQp%VZv=OvW9P%a{t)C912<%#Cyuj13KIbrh;CjSO@YOpMKH rYdJYYmG!NI;EQ}c5 diff --git a/sootup.qilin/src/.DS_Store b/sootup.qilin/src/.DS_Store index c9420b0e9741716ca50e4983e426769cb8cc943d..d27cdc8362eee179de0411042805a8ca8e6b5aae 100644 GIT binary patch delta 290 zcmZoMXfc=|#>B!ku~2NHo+2ar#(>?7ixZfc7}+QDFxfM1pX|d_7%g61ZEUWiU}SDq ztD{hDX>O^bU~XnwTg%BIs;qAv6rY`wo0s3o00xYV5SoD(O2eowAcKV=mm!fMlOZpq zI5{UNKR<_IG7Gb_C<{XgLn=ctLrGG3aY0f}eiBeA*ycDY+6=X#EVw8yCqFM8Xa(cu kK;{#So7p+|Ie;MmB)qu~2NHo+2a5#(>?7j4YFRSnL^hOfFz8RF|l(HZwQUQ7|?%tkqGd zwlp%(Q7|z!tF7ha5LMQ<4vNpt$<52}n#|57&)7X#g4KDm7>6Ls#D?{o**W+*fF^Gi ZK_85meLM~JLp1^|*?9oGN= diff --git a/sootup.qilin/src/main/.DS_Store b/sootup.qilin/src/main/.DS_Store index 242a4d504888332fae1a774fc94a5830141029bf..ee3c7b448f0296c4b6b93350c8053674b2eb3590 100644 GIT binary patch literal 8196 zcmeHMO>h)N6z*>llAeLU1PEl1#l>JG5JDgXh$w7+knp2HHY6bgmff9!j7(IRA*9ii{j7w^`;_)nkteYd$!$jvKhhEKgqbSAeji|gpj160%1y0m?BIu5M~Y#<}{xO*G~v3%o&0=({sW%Bg{|`CLV|f z%NY_vMs0*Zguu-R__=!}dxE7|k)?0Q-#clp}{4X*&%XGcg)(em- zDrZzx^J+emA4rZm<4G^=72K|Le!oBJcN{BI>ZdaUrZJvU=XX1{mo{x99~hXrK}$vk zOi^5fe#|5hq<8u2F^~(O}Zq~}s_xZDBrR5g8g_9L^B`1F@IVmeMwSmDQC8f?S zk|%vR&va~ez{tBKQ|cU-Jl>vl?A>|8pC8ORR$>W3CZ*;I|x@N{Q`t9_XA*++})PjZeHQFL= zacM@Zo3`U>10O16%qI(`cYI2nJ*P&|;!9<&em0`hXFclZ{)_ZrM$_W=bH3l#cjpai zg<8>?R**ru-zCq)Bb1iavaGuOM`_E2snWKN%c{QDN@ol!RBh}a)y~19fHzb=yqU|j zXdcQsV`Jo|E7V$7H|OfPgZ{gBrCqNtXV~Sh>e|NnusfR08-3%%xst_B&Vwx@y>GHr zH$5jW0EugTobU4=)~W0CoSKF83m)I2X|ykJOarhQtc7D*><#iB>U^ z>2}jt3*BYCY=jvs$Bwg?*(7_9onoJ}Z`gVEJ-f($Vwc!u_6z%sU15Kq0+pyjHB@L= zgnJOf3bbJz+R=#}*oj?u3`vaO01o014A^jxLmtQQ44%bvcmc2AExe6)@Gd^aDV)Y9 zID@nJ7T@7KF5nV=#${Z=pZE)ZOI)gzmPw7$1JZJ-Nm?sykP_n4rBVb9i*c!y{L|su zUHyoDryCVQ4q6QTWqDGf{Vchr9)9GDWK#jjhLz^o3~JSO{y$-O=qk-ruxzGFL-)} zeaX(Ub8L!u`YSQ?cXkyVvr&&FXvA_fp&6^N9vjhtO?U`fu?@WePx~=|LF~gYvc%HE z7==kJ^-w?&PX}Cmp1ArdUc>8n18-sy@8bh}h>rr+eu}Sd;NgxE1BJxb*YdEK%-fb@ zA0b_dx7RO^M$-sXh;F@~|8Kqh@Bh;VQ7=LuLg0Ug04jTuJzeD1?T$=8*N#&?MAa|; wx(Oiz6KaBVoMe!WlPv$kkos|2>f0njIUyuzsQl+Y1Vs0LbpHp;yStlz04@AIH~;_u delta 141 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{MGjUEV6q~50$jH1gU^gQp^JE@@Eh1*-Mmh?{ zhK98|3e}cI2098R#%7bR2-s}CC8o=`vEdZ+Vs;J=L1v(KAQ0dN60RVVHWq$op3E=f Y2(pTSk%55)L^DC`0*h^q=b6I{08PLcUjP6A diff --git a/sootup.qilin/src/main/java/.DS_Store b/sootup.qilin/src/main/java/.DS_Store index e20303f6bbada722eb0cd54b6e433900049eb567..52b7655e678acbaa1c43548818d2ad2b85b25057 100644 GIT binary patch delta 299 zcmZoMXfc@J&&ahgU^g=(*JK_RIW|Ti1_p+MlMPsAh!~m~=qQ*PTGZ+&RGS-t*v5vF z@33UBF*bnJc(G0sF*GpMQ7|$$1F5kzx71NEH!}sQF|KE2C}hZF$N}QKl;Y%^r2PCG zpe6<+;j-YOyqx^Jbf73B5VJ58GvotdiDyoJa#Buy5>QM4DAf(5_5OnakcFf!sl2!V zs&0EyK~83IiGjg2MkZz!RyKBy$+fHrYU0(^#^yQ-#s;Ry&a18EMbQFvY4Qq82sx6HSbQDaC n%_iSr$zWqx4_4#FIt`Z^exQj^o!7i?@$W8BQn@s}R}RqGn| diff --git a/sootup.qilin/src/main/java/driver/Main.java b/sootup.qilin/src/main/java/driver/Main.java index 4dd9198ed27..73f0282fd25 100644 --- a/sootup.qilin/src/main/java/driver/Main.java +++ b/sootup.qilin/src/main/java/driver/Main.java @@ -1,23 +1,147 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + package driver; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sootup.core.inputlocation.ClassLoadingOptions; -import sootup.core.model.SourceType; -import sootup.java.bytecode.inputlocation.BytecodeClassLoadingOptions; -import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; -import sootup.java.core.JavaProject; -import sootup.java.core.language.JavaLanguage; -import sootup.java.core.views.JavaView; - -import java.io.File; -import java.util.Collection; -import java.util.Collections; +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.pta.PTAConfig; +import qilin.util.MemoryWatcher; +import qilin.util.PTAUtils; +import qilin.util.Stopwatch; +import soot.PackManager; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.options.Options; + +import java.io.*; +import java.util.*; import java.util.stream.Collectors; public class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); + + public static PTA run(String[] args) { + PTA pta; + new PTAOption().parseCommandLine(args); + setupSoot(); + if (PTAConfig.v().getOutConfig().dumpJimple) { + String jimplePath = PTAConfig.v().getAppConfig().APP_PATH.replace(".jar", ""); + PTAUtils.dumpJimple(jimplePath); + System.out.println("Jimple files have been dumped to: " + jimplePath); + } + logger.info("Constructing the callgraph..."); + PackManager.v().getPack("cg").apply(); + CallGraph cg = PTAScene.v().getCallGraph(); + System.out.println("#CALLGRAPH:" + cg.size()); + pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + pta.run(); + return pta; + } + + public static void mainRun(String[] args) { + Stopwatch ptaTimer = Stopwatch.newAndStart("Main PTA (including pre-analysis)"); + long pid = ProcessHandle.current().pid(); + MemoryWatcher memoryWatcher = new MemoryWatcher(pid, "Main PTA"); + memoryWatcher.start(); + run(args); + ptaTimer.stop(); + System.out.println(ptaTimer); + memoryWatcher.stop(); + System.out.println(memoryWatcher); + } + + public static void setupSoot() { + setSootOptions(PTAConfig.v()); + setSootClassPath(PTAConfig.v()); + PTAScene.v().addBasicClasses(); + PTAScene.v().loadNecessaryClasses(); + } + + /** + * Set command line options for soot. + */ + private static void setSootOptions(PTAConfig config) { + List dirs = new ArrayList<>(); + PTAConfig.ApplicationConfiguration appConfig = config.getAppConfig(); + dirs.add(appConfig.APP_PATH); + Options.v().set_process_dir(dirs); + + if (appConfig.MAIN_CLASS == null) { + appConfig.MAIN_CLASS = PTAUtils.findMainFromMetaInfo(appConfig.APP_PATH); + } + + if (appConfig.MAIN_CLASS != null) { + Options.v().set_main_class(appConfig.MAIN_CLASS); + } + + if (appConfig.INCLUDE_ALL) { + Options.v().set_include_all(true); + } + + if (appConfig.INCLUDE != null) { + Options.v().set_include(appConfig.INCLUDE); + } + + if (appConfig.EXCLUDE != null) { + Options.v().set_no_bodies_for_excluded(true); + Options.v().set_exclude(appConfig.EXCLUDE); + } + + // configure callgraph construction algorithm + configureCallgraphAlg(config.callgraphAlg); + + Options.v().setPhaseOption("jb", "use-original-names:true"); + Options.v().setPhaseOption("jb", "model-lambdametafactory:false"); + Options.v().set_output_format(Options.output_format_jimple); + + if (appConfig.REFLECTION_LOG != null) { + Options.v().setPhaseOption("cg", "reflection-log:" + appConfig.REFLECTION_LOG); + } + + Options.v().set_keep_line_number(true); + Options.v().set_full_resolver(true); + + // Options.v().set_src_prec(Options.src_prec_class); + Options.v().set_src_prec(Options.src_prec_only_class); + Options.v().set_allow_phantom_refs(true); + + } + + /** + * Set the soot class path to point to the default class path appended with the + * app path (the classes dir or the application jar) and jar files in the + * library dir of the application. + */ + private static void setSootClassPath(PTAConfig config) { + List cps = new ArrayList<>(); + PTAConfig.ApplicationConfiguration appConfig = config.getAppConfig(); + // note that the order is important! + cps.add(appConfig.APP_PATH); + cps.addAll(getLibJars(appConfig.LIB_PATH)); + cps.addAll(getJreJars(appConfig.JRE)); + final String classpath = String.join(File.pathSeparator, cps); + logger.info("Setting Soot ClassPath: {}", classpath); + System.setProperty("soot.class.path", classpath); + } + private static Collection getJreJars(String JRE) { if (JRE == null) { return Collections.emptySet(); @@ -54,20 +178,80 @@ private static Collection getLibJars(String LIB_PATH) { return null; } - public static void main(String[] args) { - String appPath = "/Users/dongjie/Documents/Work/QilinOfficial/artifact/benchmarks/dacapo2006/luindex.jar"; - String libPath = "/Users/dongjie/Documents/Work/QilinOfficial/artifact/benchmarks/dacapo2006/luindex-deps.jar"; - String jrePath = "/Users/dongjie/Documents/Work/QilinOfficial/artifact/benchmarks/JREs/jre1.6.0_45"; - JavaProject.JavaProjectBuilder builder = new JavaProject.JavaProjectBuilder(new JavaLanguage(6)); - builder.addInputLocation(new JavaClassPathAnalysisInputLocation(appPath, SourceType.Application)); - for (String libJar : getLibJars(libPath)) { - builder.addInputLocation(new JavaClassPathAnalysisInputLocation(libJar, SourceType.Library)); + // callgraph relevant APIs + // refer to https://github.com/secure-software-engineering/FlowDroid/blob/develop/soot-infoflow-android/src/soot/jimple/infoflow/android/SetupApplication.java + private static void configureCallgraphAlg(PTAConfig.CallgraphAlgorithm cgAlg) { + switch (cgAlg) { + case CHA -> { + Options.v().setPhaseOption("cg.cha", "on"); + break; + } + case VTA -> { + Options.v().setPhaseOption("cg.spark", "on"); + Options.v().setPhaseOption("cg.spark", "vta:true"); + break; + } + case RTA -> { + Options.v().setPhaseOption("cg.spark", "on"); + Options.v().setPhaseOption("cg.spark", "rta:true"); + Options.v().setPhaseOption("cg.spark", "on-fly-cg:false"); + break; + } + case GEOM -> { + Options.v().setPhaseOption("cg.spark", "on"); + Options.v().setPhaseOption("cg.spark", "geom-pta:true"); + // Those are default options, not sure whether removing them works. + Options.v().setPhaseOption("cg.spark", "geom-encoding:Geom"); + Options.v().setPhaseOption("cg.spark", "geom-worklist:PQ"); + break; + } + case SPARK -> { + Options.v().setPhaseOption("cg.spark", "on"); + break; + } + case QILIN -> { + } + default -> { + break; + } + } + } + + public static CallGraph runCallgraphAlg(String[] args) { + CallGraph cg; + new PTAOption().parseCommandLine(args); + setupSoot(); + if (PTAConfig.v().getOutConfig().dumpJimple) { + String jimplePath = PTAConfig.v().getAppConfig().APP_PATH.replace(".jar", ""); + PTAUtils.dumpJimple(jimplePath); + System.out.println("Jimple files have been dumped to: " + jimplePath); } - for (String jreJar : getJreJars(jrePath)) { - builder.addInputLocation(new JavaClassPathAnalysisInputLocation(jreJar, SourceType.Library)); + logger.info("Constructing the callgraph using " + PTAConfig.v().callgraphAlg + "..."); + if (PTAConfig.v().callgraphAlg == PTAConfig.CallgraphAlgorithm.QILIN) { + PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + pta.run(); + } else { + PackManager.v().getPack("cg").apply(); } - JavaProject project = builder.build(); - JavaView view = project.createOnDemandView(ail -> BytecodeClassLoadingOptions.Default); + cg = PTAScene.v().getCallGraph(); + System.out.println("#CALLGRAPH:" + cg.size()); + return cg; + } + public static void mainCG(String[] args) { + Stopwatch cgTimer = Stopwatch.newAndStart("Main CG"); + long pid = ProcessHandle.current().pid(); + MemoryWatcher memoryWatcher = new MemoryWatcher(pid, "Main CG"); + memoryWatcher.start(); + runCallgraphAlg(args); + cgTimer.stop(); + System.out.println(cgTimer); + memoryWatcher.stop(); + System.out.println(memoryWatcher); + } + + public static void main(String[] args) { + mainRun(args); + // mainCG(args); } } diff --git a/sootup.qilin/src/main/java/driver/PTAComparator.java b/sootup.qilin/src/main/java/driver/PTAComparator.java index dc9d9ba735e..9598ccd0775 100644 --- a/sootup.qilin/src/main/java/driver/PTAComparator.java +++ b/sootup.qilin/src/main/java/driver/PTAComparator.java @@ -25,7 +25,7 @@ import qilin.core.sets.PointsToSet; import qilin.pta.PTAConfig; import qilin.util.Util; -import sootup.core.jimple.basic.Local; +import soot.Local; import java.io.PrintStream; import java.util.*; @@ -49,7 +49,7 @@ public static void runCompare(String[] args, String ptaPtn1, String ptaPtn2) { String[] ptaArg1 = Util.concat(args, new String[]{"-pta=" + ptaPtn1}); comparator.record(Main.run(ptaArg1)); PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPtn2); - PTA pta = PTAFactory.createPTA(null, PTAConfig.v().getPtaConfig().ptaPattern); + PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); pta.pureRun(); comparator.compare(pta); comparator.out.close(); diff --git a/sootup.qilin/src/main/java/driver/PTAFactory.java b/sootup.qilin/src/main/java/driver/PTAFactory.java index 7670b3ef9fd..41fe63373b4 100644 --- a/sootup.qilin/src/main/java/driver/PTAFactory.java +++ b/sootup.qilin/src/main/java/driver/PTAFactory.java @@ -22,25 +22,24 @@ import qilin.parm.ctxcons.*; import qilin.pta.PTAConfig; import qilin.pta.tools.*; -import sootup.core.views.View; public class PTAFactory { - public static PTA createPTA(View view, PTAPattern ptaPattern) { + public static PTA createPTA(PTAPattern ptaPattern) { switch (ptaPattern.getContextKind()) { case HYBOBJ: { switch (ptaPattern.getApproach()) { case DATADRIVEN -> { // data-driven hybrid-2obj, Sehun Jeong oopsla'17 CtxConstructor ctxCons = new HybObjCtxConstructor(); - return new DataDrivenPTA(view, ctxCons); + return new DataDrivenPTA(ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new HybObjCtxConstructor(); - return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } default -> { // static method using callsite as context, Yannis pldi'13 - return new HybridObjectSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new HybridObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } } } @@ -49,51 +48,51 @@ public static PTA createPTA(View view, PTAPattern ptaPattern) { case EAGLE -> { // k-obj pointer analysis with Eagle pre-analysis, Jingbo OOPSLA'19 assert ptaPattern.getContextDepth() == ptaPattern.getHeapContextDepth() + 1; - BasePTA eagle = new EaglePTA(view, ptaPattern.getContextDepth()); + BasePTA eagle = new EaglePTA(ptaPattern.getContextDepth()); if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(eagle); + return new DebloatedPTA(eagle, PTAConfig.v().getPtaConfig().debloatApproach); } else { return eagle; } } case BEAN -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - return new BeanPTA(view, ctxCons); + return new BeanPTA(ctxCons); } case TURNER -> { - return new TurnerPTA(view, ptaPattern.getContextDepth()); + return new TurnerPTA(ptaPattern.getContextDepth()); } case ZIPPER -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - BasePTA zipperPTA = new ZipperPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + BasePTA zipperPTA = new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(zipperPTA); + return new DebloatedPTA(zipperPTA, PTAConfig.v().getPtaConfig().debloatApproach); } else { return zipperPTA; } } case MAHJONG -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - BasePTA mahjongPTA = new MahjongPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + BasePTA mahjongPTA = new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(mahjongPTA); + return new DebloatedPTA(mahjongPTA, PTAConfig.v().getPtaConfig().debloatApproach); } else { return mahjongPTA; } } case DATADRIVEN -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - return new DataDrivenPTA(view, ctxCons); + return new DataDrivenPTA(ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new ObjCtxConstructor(); - return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } default -> { - BasePTA kobj = new ObjectSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + BasePTA kobj = new ObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(kobj); + return new DebloatedPTA(kobj, PTAConfig.v().getPtaConfig().debloatApproach); } else { // normal object-sensitive pointer analysis, Milanova TOSEM'05 return kobj; @@ -105,15 +104,15 @@ public static PTA createPTA(View view, PTAPattern ptaPattern) { switch (ptaPattern.getApproach()) { case DATADRIVEN -> { CtxConstructor ctxCons = new TypeCtxConstructor(); - return new DataDrivenPTA(view, ctxCons); + return new DataDrivenPTA(ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new TypeCtxConstructor(); - return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } default -> { // normal type-sensitive pointer analysis, Yannis popl'11 - return new TypeSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TypeSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } } } @@ -121,32 +120,32 @@ public static PTA createPTA(View view, PTAPattern ptaPattern) { switch (ptaPattern.getApproach()) { case ZIPPER -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new ZipperPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + return new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); } case MAHJONG -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new MahjongPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + return new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); } case DATADRIVEN -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new DataDrivenPTA(view, ctxCons); + return new DataDrivenPTA(ctxCons); } case TUNNELING -> { CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new TunnelingPTA(view, ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } case SELECTX -> { - return new SelectxPTA(view, ptaPattern.getContextDepth()); + return new SelectxPTA(ptaPattern.getContextDepth()); } default -> { // CallSite Sensitive - return new CallSiteSensPTA(view, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + return new CallSiteSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); } } } case INSENS: default: - return new Spark(view); + return new Spark(); } } } diff --git a/sootup.qilin/src/main/java/driver/PTAOption.java b/sootup.qilin/src/main/java/driver/PTAOption.java index 9aa19148d32..f61035c8398 100644 --- a/sootup.qilin/src/main/java/driver/PTAOption.java +++ b/sootup.qilin/src/main/java/driver/PTAOption.java @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import qilin.pta.PTAConfig; import qilin.pta.toolkits.turner.Turner; +import qilin.pta.tools.DebloatedPTA; import java.util.*; @@ -82,8 +83,12 @@ public PTAOption() { // a specific PTA's configuration addOption("tc", "turnerconfig", "[DEFAULT, PHASE_ONE, PHASE_TWO]", "Run Turner in the given setting (default value: DEFAULT)"); addOption("cd", "ctxdebloat", "Enable context debloating optimization (default value: false)"); + addOption("cda", "debloatapproach", "[CONCH, DEBLOATERX]", "Specify debloating approach (default value: CONCH)"); addOption("tmd", "modular", "Enable Turner to run modularly (default value: false)"); + // callgraph algorithm configurations + addOption("cga", "callgraphalg", "[CHA, VTA, RTA, SPARK, GEOM, QILIN]", "Specify callgraph construction algorithm (default value: QILIN)"); + // others addOption("h", "help", "print this message"); addOption("pre", "preonly", "Run only pre-analysis (default value: false)"); @@ -137,6 +142,9 @@ protected void parseCommandLineOptions(CommandLine cmd) { } if (cmd.hasOption("ctxdebloat")) { PTAConfig.v().getPtaConfig().ctxDebloating = true; + if (cmd.hasOption("debloatapproach")) { + PTAConfig.v().getPtaConfig().debloatApproach = DebloatedPTA.DebloatApproach.valueOf(cmd.getOptionValue("debloatapproach")); + } } if (cmd.hasOption("preciseexceptions")) { PTAConfig.v().getPtaConfig().preciseExceptions = true; @@ -169,7 +177,10 @@ protected void parseCommandLineOptions(CommandLine cmd) { if (cmd.hasOption("turnerconfig")) { PTAConfig.v().turnerConfig = PTAConfig.TurnerConfig.valueOf(cmd.getOptionValue("turnerconfig")); } - + // callgraph + if (cmd.hasOption("callgraphalg")) { + PTAConfig.v().callgraphAlg = PTAConfig.CallgraphAlgorithm.valueOf(cmd.getOptionValue("callgraphalg")); + } // output if (cmd.hasOption("dumpjimple")) { PTAConfig.v().getOutConfig().dumpJimple = true; diff --git a/sootup.qilin/src/main/java/qilin/.DS_Store b/sootup.qilin/src/main/java/qilin/.DS_Store index 0f17e6702794b7aa7588abb4fee87fce56b11723..5fe65c9d9a0f140abc250dd9df934f2b7ebf485c 100644 GIT binary patch delta 197 zcmZoMXfc@J&&a(oU^g=(_hcRxY1WAh3=H~{byzIe82*EqSuD!pxggemFaWX`7?>Ff z7)lrtCrhx%PoB%dKKT?&gNUJ-fsTTyp+&8ZLbbUOh;3{*IgZteGo?5=Cn-NahjDTr zs{tG1ZID@$kFYASF?oWSZ&>9Sw@>C_D^wG&t~NH;Q7|$$0~umzZmFYSZf06r%gG_C etZy9@pPiGNm)|)#52&GQ^AR>f#?9;;fB6A0NHrw@ delta 176 zcmZoMXfc@J&&ahgU^g=(*JK_RX;w!D1_r&!IxH4!jNM>n7K^g_PY~-r7ywxe49pA# z3?&SSo;mr+NjdpRKoJ2TUO#yY%QO))b0ZxEV?)DQ9ffL3BLf`;6JxWH@93ugXjm7jc-r4*Mo argsL = Arrays.asList(args); - AbstractInvokeExpr invoke = sootClass.isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) - : Jimple.newVirtualInvokeExpr((Local) receiver, msig, argsL); - body.getUnits().add(Jimple.newInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo())); + protected void addInvoke(Value receiver, String sig, Value... args) { + SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + List argsL = Arrays.asList(args); + Value invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) + : new JVirtualInvokeExpr(receiver, methodRef, argsL); + body.getUnits().add(new JInvokeStmt(invoke)); } /** @@ -145,14 +122,12 @@ protected void addInvoke(Value receiver, String sig, Immediate... args) { * * @return rx */ - protected Local getInvoke(Value receiver, String sig, Immediate... args) { - MethodSignature msig = identifierFactory.parseMethodSignature(sig); - List argsL = Arrays.asList(args); - ClassType classType = msig.getDeclClassType(); - SootClass sootClass = (SootClass) view.getClass(classType).get(); - Value invoke = sootClass.isInterface() ? Jimple.newInterfaceInvokeExpr((Local) receiver, msig, argsL) - : Jimple.newVirtualInvokeExpr((Local) receiver, msig, argsL); - Local rx = getNextLocal(msig.getType()); + protected Value getInvoke(Value receiver, String sig, Value... args) { + SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + List argsL = Arrays.asList(args); + Value invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) + : new JVirtualInvokeExpr(receiver, methodRef, argsL); + Value rx = getNextLocal(methodRef.getReturnType()); addAssign(rx, invoke); return rx; } @@ -160,10 +135,10 @@ protected Local getInvoke(Value receiver, String sig, Immediate... args) { /** * add a static invocation sig(args) */ - protected void addInvoke(String sig, Immediate... args) { - MethodSignature msig = identifierFactory.parseMethodSignature(sig); - List argsL = Arrays.asList(args); - body.getUnits().add(Jimple.newInvokeStmt(Jimple.newStaticInvokeExpr(msig, argsL), StmtPositionInfo.createNoStmtPositionInfo())); + protected void addInvoke(String sig, Value... args) { + SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + List argsL = Arrays.asList(args); + body.getUnits().add(new JInvokeStmt(new JStaticInvokeExpr(methodRef, argsL))); } /** @@ -171,15 +146,15 @@ protected void addInvoke(String sig, Immediate... args) { * * @return rx */ - protected Local getInvoke(String sig, Immediate... args) { - MethodSignature msig = identifierFactory.parseMethodSignature(sig); - List argsL = Arrays.asList(args); - Local rx = getNextLocal(msig.getType()); - addAssign(rx, Jimple.newStaticInvokeExpr(msig, argsL)); + protected Value getInvoke(String sig, Value... args) { + SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + List argsL = Arrays.asList(args); + Value rx = getNextLocal(methodRef.getReturnType()); + addAssign(rx, new JStaticInvokeExpr(methodRef, argsL)); return rx; } protected void addAssign(Value lValue, Value rValue) { - body.getUnits().add(Jimple.newAssignStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); + body.getUnits().add(new JAssignStmt(lValue, rValue)); } } diff --git a/sootup.qilin/src/main/java/qilin/core/CorePTA.java b/sootup.qilin/src/main/java/qilin/core/CorePTA.java index a04ea55ec54..fc2abd458ff 100644 --- a/sootup.qilin/src/main/java/qilin/core/CorePTA.java +++ b/sootup.qilin/src/main/java/qilin/core/CorePTA.java @@ -18,13 +18,12 @@ package qilin.core; -import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.solver.Propagator; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.HeapAbstractor; import qilin.parm.select.CtxSelector; -import sootup.core.model.SootMethod; +import soot.*; /* * This represents a parameterized PTA which could be concreted to many pointer analyses. @@ -56,7 +55,7 @@ public HeapAbstractor heapAbstractor() { public abstract Propagator getPropagator(); @Override - public Context createCalleeCtx(ContextMethod caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { return ctxCons.constructCtx(caller, (ContextAllocNode) receiverNode, callSite, target); } @@ -111,7 +110,7 @@ protected ContextAllocNode parameterize(AllocNode node, Context context) { * Finds or creates the ContextMethod for method and context. */ @Override - public ContextMethod parameterize(SootMethod method, Context context) { + public MethodOrMethodContext parameterize(SootMethod method, Context context) { Context ctx = ctxSel.select(method, context); return pag.makeContextMethod(ctx, method); } diff --git a/sootup.qilin/src/main/java/qilin/core/PTA.java b/sootup.qilin/src/main/java/qilin/core/PTA.java index 4e6006a3bc0..564e3a45cef 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTA.java +++ b/sootup.qilin/src/main/java/qilin/core/PTA.java @@ -20,8 +20,6 @@ import qilin.core.builder.CallGraphBuilder; import qilin.core.builder.ExceptionHandler; -import qilin.core.callgraph.CallGraph; -import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.*; import qilin.core.sets.PointsToSet; @@ -29,10 +27,9 @@ import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.HeapAbstractor; import qilin.parm.select.CtxSelector; -import sootup.core.jimple.basic.Local; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; -import sootup.java.core.JavaIdentifierFactory; +import soot.*; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.CallGraph; import java.util.Collection; import java.util.HashSet; @@ -50,8 +47,8 @@ public PTA() { this.pag = createPAG(); this.cgb = createCallGraphBuilder(); this.eh = new ExceptionHandler(this); - AllocNode rootBase = pag.makeAllocNode("ROOT", JavaIdentifierFactory.getInstance().getType("java.lang.Object"), null); - this.rootNode = new ContextAllocNode(pag.getView(), rootBase, CtxConstructor.emptyContext); + AllocNode rootBase = pag.makeAllocNode("ROOT", RefType.v("java.lang.Object"), null); + this.rootNode = new ContextAllocNode(rootBase, CtxConstructor.emptyContext); } protected abstract PAG createPAG(); @@ -85,7 +82,7 @@ public CallGraph getCallGraph() { return callGraph; } - public Collection getReachableMethods() { + public Collection getReachableMethods() { return cgb.getReachableMethods(); } @@ -103,13 +100,13 @@ public Collection getNakedReachableMethods() { public abstract Node parameterize(Node n, Context context); - public abstract ContextMethod parameterize(SootMethod method, Context context); + public abstract MethodOrMethodContext parameterize(SootMethod method, Context context); public abstract AllocNode getRootNode(); public abstract Context emptyContext(); - public abstract Context createCalleeCtx(ContextMethod caller, AllocNode receiverNode, CallSite callSite, SootMethod target); + public abstract Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target); public abstract HeapAbstractor heapAbstractor(); diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java index bf53d72cb54..2becfa9b1e7 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTAScene.java +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -20,16 +20,11 @@ import qilin.core.builder.FakeMainFactory; import qilin.util.DataFactory; +import soot.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.util.Chain; import soot.util.IterableNumberer; import soot.util.StringNumberer; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootClass; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java b/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java index 6cc6c893024..e9584cb4474 100644 --- a/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java @@ -18,11 +18,11 @@ package qilin.core; -import qilin.core.context.Context; import qilin.core.pag.Node; import qilin.core.sets.PointsToSet; -import sootup.core.jimple.basic.Local; -import sootup.core.model.SootField; +import soot.Context; +import soot.Local; +import soot.SootField; /** * A generic interface to any type of pointer analysis. diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index f62dfe2d6b4..fbdcf210e46 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -19,17 +19,10 @@ package qilin.core; import qilin.util.DataFactory; -import qilin.util.queue.ChunkedQueue; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.signatures.MethodSubSignature; -import sootup.core.types.ArrayType; -import sootup.core.types.ClassType; -import sootup.core.types.NullType; -import sootup.core.types.Type; -import sootup.java.core.JavaIdentifierFactory; +import soot.*; +import soot.jimple.SpecialInvokeExpr; +import soot.util.*; +import soot.util.queue.ChunkedQueue; import java.util.HashSet; import java.util.LinkedList; @@ -43,7 +36,7 @@ */ public class VirtualCalls { private static volatile VirtualCalls instance = null; - private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); + private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); protected Map> baseToSubTypes = DataFactory.createMap(); private VirtualCalls() { @@ -64,16 +57,16 @@ public static void reset() { instance = null; } - public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container) { + public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container) { return resolveSpecial(iie, subSig, container, false); } - public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container, boolean appOnly) { + public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container, boolean appOnly) { SootMethod target = iie.getMethod(); /* cf. JVM spec, invokespecial instruction */ - if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClassType(), - target.getDeclaringClassType()) - && container.getDeclaringClassType() != target.getDeclaringClassType() + if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClass().getType(), + target.getDeclaringClass().getType()) + && container.getDeclaringClass().getType() != target.getDeclaringClass().getType() && !target.getName().equals("") && subSig != Scene.v().getSubSigNumberer().findOrAdd("void ()")) { @@ -83,12 +76,12 @@ public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subS } } - public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig) { + public SootMethod resolveNonSpecial(RefType t, NumberedString subSig) { return resolveNonSpecial(t, subSig, false); } - public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, boolean appOnly) { - Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); + public SootMethod resolveNonSpecial(RefType t, NumberedString subSig, boolean appOnly) { + Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); SootMethod ret = vtbl.get(subSig); if (ret != null) { return ret; @@ -116,27 +109,26 @@ public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, bool return ret; } - public void resolve(Type t, Type declaredType, MethodSubSignature subSig, SootMethod container, + public void resolve(Type t, Type declaredType, NumberedString subSig, SootMethod container, ChunkedQueue targets) { resolve(t, declaredType, null, subSig, container, targets); } - public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, + public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, ChunkedQueue targets) { resolve(t, declaredType, sigType, subSig, container, targets, false); } - public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, + public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, ChunkedQueue targets, boolean appOnly) { - IdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); if (declaredType instanceof ArrayType) { - declaredType = identifierFactory.getType("java.lang.Object"); + declaredType = RefType.v("java.lang.Object"); } if (sigType instanceof ArrayType) { - sigType = identifierFactory.getType("java.lang.Object"); + sigType = RefType.v("java.lang.Object"); } if (t instanceof ArrayType) { - t = identifierFactory.getType("java.lang.Object"); + t = RefType.v("java.lang.Object"); } if (declaredType != null && !Scene.v().getFastHierarchy().canStoreType(t, declaredType)) { @@ -145,13 +137,13 @@ public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature if (sigType != null && !Scene.v().getFastHierarchy().canStoreType(t, sigType)) { return; } - if (t instanceof ClassType) { - SootMethod target = resolveNonSpecial((ClassType) t, subSig, appOnly); + if (t instanceof RefType) { + SootMethod target = resolveNonSpecial((RefType) t, subSig, appOnly); if (target != null) { targets.add(target); } - // } else if (t instanceof AnySubType) { - // RefType base = ((AnySubType) t).getBase(); + } else if (t instanceof AnySubType) { + RefType base = ((AnySubType) t).getBase(); /* * Whenever any sub type of a specific type is considered as receiver for a method to call and the base type is an @@ -164,15 +156,15 @@ public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature * * Since Java has no multiple inheritance call by signature resolution is only activated if the base is an interface. */ - // resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); + resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); } else if (t instanceof NullType) { } else { throw new RuntimeException("oops " + t); } } - protected void resolveAnySubType(Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, - ChunkedQueue targets, boolean appOnly, ClassType base) { + protected void resolveAnySubType(Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + ChunkedQueue targets, boolean appOnly, RefType base) { { Set subTypes = baseToSubTypes.get(base); if (subTypes != null && !subTypes.isEmpty()) { diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 425293a204e..b866ac1b761 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -21,61 +21,48 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; -import qilin.core.callgraph.Kind; -import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.P2SetVisitor; import qilin.core.sets.PointsToSetInternal; import qilin.util.DataFactory; import qilin.util.PTAUtils; - -import qilin.util.queue.ChunkedQueue; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.StmtPositionInfo; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JInvokeStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import soot.*; +import soot.jimple.*; +import soot.jimple.internal.JInvokeStmt; +import soot.jimple.internal.JStaticInvokeExpr; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.queue.ChunkedQueue; +import soot.util.queue.QueueReader; import java.util.*; public class CallGraphBuilder { protected final Map> receiverToSites; protected final Map> methodToInvokeStmt; - protected final Set reachMethods; - private ChunkedQueue rmQueue; + protected final Set reachMethods; + private ChunkedQueue rmQueue; protected final Set calledges; protected final PTA pta; protected final PAG pag; - protected CallGraph callGraph; protected CallGraph cicg; public CallGraphBuilder(PTA pta) { this.pta = pta; this.pag = pta.getPag(); - this.callGraph = new CallGraph(); - receiverToSites = DataFactory.createMap(1000); + PTAScene.v().setCallGraph(new CallGraph()); + receiverToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); methodToInvokeStmt = DataFactory.createMap(); reachMethods = DataFactory.createSet(); calledges = DataFactory.createSet(); } - public void setRMQueue(ChunkedQueue rmQueue) { + public void setRMQueue(ChunkedQueue rmQueue) { this.rmQueue = rmQueue; } - public Collection getReachableMethods() { + public Collection getReachableMethods() { return reachMethods; } @@ -93,7 +80,7 @@ public CallGraph getCallGraph() { if (cicg == null) { constructCallGraph(); } - return callGraph; + return PTAScene.v().getCallGraph(); } public CallGraph getCICallGraph() { @@ -105,21 +92,21 @@ public CallGraph getCICallGraph() { private void constructCallGraph() { cicg = new CallGraph(); - Map>> map = DataFactory.createMap(); + Map>> map = DataFactory.createMap(); calledges.forEach(e -> { - callGraph.addEdge(e); + PTAScene.v().getCallGraph().addEdge(e); SootMethod src = e.src(); SootMethod tgt = e.tgt(); - Stmt unit = e.srcUnit(); + Unit unit = e.srcUnit(); Map> submap = map.computeIfAbsent(unit, k -> DataFactory.createMap()); Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); if (set.add(tgt)) { - cicg.addEdge(new Edge(new ContextMethod(src, pta.emptyContext()), e.srcUnit(), new ContextMethod(tgt, pta.emptyContext()), e.kind())); + cicg.addEdge(new Edge(src, e.srcUnit(), tgt, e.kind())); } }); } - public List getEntryPoints() { + public List getEntryPoints() { Node thisRef = pag.getMethodPAG(PTAScene.v().getFakeMainMethod()).nodeFactory().caseThis(); thisRef = pta.parameterize(thisRef, pta.emptyContext()); pag.addEdge(pta.getRootNode(), thisRef); @@ -127,14 +114,14 @@ public List getEntryPoints() { } public void initReachableMethods() { - for (ContextMethod momc : getEntryPoints()) { + for (MethodOrMethodContext momc : getEntryPoints()) { if (reachMethods.add(momc)) { rmQueue.add(momc); } } } - public VarNode getReceiverVarNode(Local receiver, ContextMethod m) { + public VarNode getReceiverVarNode(Local receiver, MethodOrMethodContext m) { LocalVarNode base = pag.makeLocalVarNode(receiver, receiver.getType(), m.method()); return (VarNode) pta.parameterize(base, m.context()); } @@ -144,8 +131,8 @@ protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { final QueueReader targets = PTAUtils.dispatch(type, site); while (targets.hasNext()) { SootMethod target = targets.next(); - if (site.iie() instanceof JSpecialInvokeExpr) { - Type calleeDeclType = target.getDeclaringClassType(); + if (site.iie() instanceof SpecialInvokeExpr) { + Type calleeDeclType = target.getDeclaringClass().getType(); if (!Scene.v().getFastHierarchy().canStoreType(type, calleeDeclType)) { continue; } @@ -154,34 +141,34 @@ protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { } } - private void addVirtualEdge(ContextMethod caller, Stmt callStmt, SootMethod callee, Kind kind, AllocNode receiverNode) { + private void addVirtualEdge(MethodOrMethodContext caller, Unit callStmt, SootMethod callee, Kind kind, AllocNode receiverNode) { Context tgtContext = pta.createCalleeCtx(caller, receiverNode, new CallSite(callStmt), callee); - ContextMethod cstarget = pta.parameterize(callee, tgtContext); + MethodOrMethodContext cstarget = pta.parameterize(callee, tgtContext); handleCallEdge(new Edge(caller, callStmt, cstarget, kind)); Node thisRef = pag.getMethodPAG(callee).nodeFactory().caseThis(); thisRef = pta.parameterize(thisRef, cstarget.context()); pag.addEdge(receiverNode, thisRef); } - public void injectCallEdge(Object heapOrType, ContextMethod callee, Kind kind) { + public void injectCallEdge(Object heapOrType, MethodOrMethodContext callee, Kind kind) { Map stmtMap = methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap()); if (!stmtMap.containsKey(heapOrType)) { - AbstractInvokeExpr ie = new JStaticInvokeExpr(callee.method().getSignature(), Collections.emptyList()); - JInvokeStmt stmt = new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo()); + InvokeExpr ie = new JStaticInvokeExpr(callee.method().makeRef(), Collections.emptyList()); + JInvokeStmt stmt = new JInvokeStmt(ie); stmtMap.put(heapOrType, stmt); handleCallEdge(new Edge(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext()), stmtMap.get(heapOrType), callee, kind)); } } - public void addStaticEdge(ContextMethod caller, Stmt callStmt, SootMethod calleem, Kind kind) { + public void addStaticEdge(MethodOrMethodContext caller, Unit callStmt, SootMethod calleem, Kind kind) { Context typeContext = pta.createCalleeCtx(caller, null, new CallSite(callStmt), calleem); - ContextMethod callee = pta.parameterize(calleem, typeContext); + MethodOrMethodContext callee = pta.parameterize(calleem, typeContext); handleCallEdge(new Edge(caller, callStmt, callee, kind)); } protected void handleCallEdge(Edge edge) { if (calledges.add(edge)) { - ContextMethod callee = edge.getTgt(); + MethodOrMethodContext callee = edge.getTgt(); if (reachMethods.add(callee)) { rmQueue.add(callee); } @@ -216,16 +203,16 @@ private void processCallAssign(Edge e) { MethodNodeFactory srcnf = srcmpag.nodeFactory(); MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); SootMethod tgtmtd = tgtmpag.getMethod(); - AbstractInvokeExpr ie = s.getInvokeExpr(); + InvokeExpr ie = s.getInvokeExpr(); // add arg --> param edges. int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { continue; } Type tgtType = tgtmtd.getParameterType(i); - if (!(tgtType instanceof ReferenceType)) { + if (!(tgtType instanceof RefLikeType)) { continue; } Node argNode = srcnf.getNode(arg); @@ -235,13 +222,13 @@ private void processCallAssign(Edge e) { pag.addEdge(argNode, parm); } // add normal return edge - if (s instanceof JAssignStmt jassign) { - Value dest = jassign.getLeftOp(); + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { + if (dest.getType() instanceof RefLikeType) { Node destNode = srcnf.getNode(dest); destNode = pta.parameterize(destNode, srcContext); - if (tgtmtd.getReturnType() instanceof ReferenceType) { + if (tgtmtd.getReturnType() instanceof RefLikeType) { Node retNode = tgtnf.caseRet(); retNode = pta.parameterize(retNode, tgtContext); pag.addEdge(retNode, destNode); diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index 5f793be172b..9bd3d76ec94 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -20,21 +20,17 @@ import qilin.core.PTA; import qilin.core.PTAScene; -import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.P2SetVisitor; import qilin.core.sets.PointsToSetInternal; import qilin.util.DataFactory; -import sootup.core.jimple.basic.Trap; -import sootup.core.jimple.common.stmt.JIdentityStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; +import soot.*; +import soot.jimple.IdentityStmt; import java.util.*; public class ExceptionHandler { - protected final Map> throwNodeToSites = DataFactory.createMap(1000); + protected final Map> throwNodeToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); protected PTA pta; protected PAG pag; @@ -65,7 +61,7 @@ public void visit(Node n) { * */ public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { Type type = throwObj.getType(); - ContextMethod momc = site.container(); + MethodOrMethodContext momc = site.container(); SootMethod sm = momc.method(); Context context = momc.context(); MethodPAG mpag = pag.getMethodPAG(sm); @@ -73,10 +69,10 @@ public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { VarNode throwNode = site.getThrowNode(); List trapList = mpag.stmt2wrapperedTraps.getOrDefault(site.getUnit(), Collections.emptyList()); for (Trap trap : trapList) { - if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, trap.getExceptionType())) { - Stmt handler = trap.getHandlerStmt(); - assert handler instanceof JIdentityStmt; - JIdentityStmt handlerStmt = (JIdentityStmt) handler; + if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, trap.getException().getType())) { + Unit handler = trap.getHandlerUnit(); + assert handler instanceof IdentityStmt; + IdentityStmt handlerStmt = (IdentityStmt) handler; Node caughtParam = nodeFactory.getNode(handlerStmt.getRightOp()); Node dst = pta.parameterize(caughtParam, context); pag.addEdge(throwObj, dst); diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index cb9aeead35f..669201cf005 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -21,15 +21,8 @@ import qilin.CoreConfig; import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.ref.JStaticFieldRef; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.java.core.JavaIdentifierFactory; -import sootup.java.core.JavaSootMethod; +import soot.*; +import soot.jimple.JimpleBody; import java.util.ArrayList; import java.util.Collections; @@ -92,36 +85,27 @@ public SootMethod getFakeMain() { return this.method; } - public JStaticFieldRef getFieldCurrentThread() { - return getStaticFieldRef("FakeMain", "currentThread", "java.lang.Thread"); + public Value getFieldCurrentThread() { + return getStaticFieldRef("FakeMain", "currentThread"); } - public JStaticFieldRef getFieldGlobalThrow() { - return getStaticFieldRef("FakeMain", "globalThrow", "java.lang.Exception"); - } - - private boolean isStaticInitializer (SootMethod method) { - if (method instanceof JavaSootMethod jm) { - return jm.isStaticInitializer(); - } - return false; + public Value getFieldGlobalThrow() { + return getStaticFieldRef("FakeMain", "globalThrow"); } private void makeFakeMain() { implicitCallEdges = 0; - IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); for (SootMethod entry : getEntryPoints()) { if (entry.isStatic()) { - if (entry.isMain()) { - ClassType classType = (ClassType) idFactory.getType("java.lang.String"); - Value mockStr = getNew(classType); - Local strArray = getNewArray(classType); + if (entry.getSubSignature().equals("void main(java.lang.String[])")) { + Value mockStr = getNew(RefType.v("java.lang.String")); + Value strArray = getNewArray(RefType.v("java.lang.String")); addAssign(getArrayRef(strArray), mockStr); - addInvoke(entry.getSignature().toString(), strArray); + addInvoke(entry.getSignature(), strArray); implicitCallEdges++; - } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !isStaticInitializer(entry)) { + } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !entry.isStaticInitializer()) { // in the on fly mode, we won't add a call directly for methods. - addInvoke(entry.getSignature().toString()); + addInvoke(entry.getSignature()); implicitCallEdges++; } } @@ -129,42 +113,42 @@ private void makeFakeMain() { if (CoreConfig.v().getPtaConfig().singleentry) { return; } - Local sv = getNextLocal(idFactory.getType("java.lang.String")); - Local mainThread = getNew((ClassType) idFactory.getType("java.lang.Thread")); - Local mainThreadGroup = getNew((ClassType) idFactory.getType("java.lang.ThreadGroup")); - Local systemThreadGroup = getNew((ClassType) idFactory.getType("java.lang.ThreadGroup")); + Value sv = getNextLocal(RefType.v("java.lang.String")); + Value mainThread = getNew(RefType.v("java.lang.Thread")); + Value mainThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + Value systemThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); Value gCurrentThread = getFieldCurrentThread(); addAssign(gCurrentThread, mainThread); // Store - Local vRunnable = getNextLocal(idFactory.getType("java.lang.Runnable")); + Value vRunnable = getNextLocal(RefType.v("java.lang.Runnable")); - Local lThreadGroup = getNextLocal(idFactory.getType("java.lang.ThreadGroup")); + Value lThreadGroup = getNextLocal(RefType.v("java.lang.ThreadGroup")); addInvoke(mainThread, "(java.lang.ThreadGroup,java.lang.String)>", mainThreadGroup, sv); - Value tmpThread = getNew((ClassType) idFactory.getType("java.lang.Thread")); + Value tmpThread = getNew(RefType.v("java.lang.Thread")); addInvoke(tmpThread, "(java.lang.ThreadGroup,java.lang.Runnable)>", lThreadGroup, vRunnable); addInvoke(tmpThread, ""); addInvoke(systemThreadGroup, "()>"); addInvoke(mainThreadGroup, "(java.lang.ThreadGroup,java.lang.String)>", systemThreadGroup, sv); - Local lThread = getNextLocal(idFactory.getType("java.lang.Thread")); - Local lThrowable = getNextLocal(idFactory.getType("java.lang.Throwable")); - Value tmpThreadGroup = getNew((ClassType) idFactory.getType("java.lang.ThreadGroup")); + Value lThread = getNextLocal(RefType.v("java.lang.Thread")); + Value lThrowable = getNextLocal(RefType.v("java.lang.Throwable")); + Value tmpThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); addInvoke(tmpThreadGroup, "", lThread, lThrowable); // TODO. // ClassLoader - Value defaultClassLoader = getNew((ClassType) idFactory.getType("sun.misc.Launcher$AppClassLoader")); + Value defaultClassLoader = getNew(RefType.v("sun.misc.Launcher$AppClassLoader")); addInvoke(defaultClassLoader, "()>"); - Local vClass = getNextLocal(idFactory.getType("java.lang.Class")); - Local vDomain = getNextLocal(idFactory.getType("java.security.ProtectionDomain")); + Value vClass = getNextLocal(RefType.v("java.lang.Class")); + Value vDomain = getNextLocal(RefType.v("java.security.ProtectionDomain")); addInvoke(defaultClassLoader, "", sv); addInvoke(defaultClassLoader, "", vClass, vDomain); addInvoke(defaultClassLoader, "", vClass); // PrivilegedActionException - Value privilegedActionException = getNew((ClassType) idFactory.getType("java.security.PrivilegedActionException")); - Local gLthrow = getNextLocal(idFactory.getType("java.lang.Exception")); + Value privilegedActionException = getNew(RefType.v("java.security.PrivilegedActionException")); + Value gLthrow = getNextLocal(RefType.v("java.lang.Exception")); addInvoke(privilegedActionException, "(java.lang.Exception)>", gLthrow); } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index ebf78f80733..edecc349dbc 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -24,38 +24,9 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Pair; -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.ClassConstant; -import sootup.core.jimple.common.constant.IntConstant; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.constant.StringConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JCastExpr; -import sootup.core.jimple.common.expr.JNewArrayExpr; -import sootup.core.jimple.common.expr.JNewExpr; -import sootup.core.jimple.common.expr.JNewMultiArrayExpr; -import sootup.core.jimple.common.ref.JArrayRef; -import sootup.core.jimple.common.ref.JCaughtExceptionRef; -import sootup.core.jimple.common.ref.JInstanceFieldRef; -import sootup.core.jimple.common.ref.JParameterRef; -import sootup.core.jimple.common.ref.JStaticFieldRef; -import sootup.core.jimple.common.ref.JThisRef; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JIdentityStmt; -import sootup.core.jimple.common.stmt.JReturnStmt; -import sootup.core.jimple.common.stmt.JThrowStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootClass; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; -import sootup.core.types.ArrayType; -import sootup.core.types.ClassType; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; -import sootup.java.core.JavaIdentifierFactory; +import soot.*; +import soot.jimple.*; +import soot.jimple.internal.JNewArrayExpr; /** * @author Ondrej Lhotak @@ -74,31 +45,31 @@ public MethodNodeFactory(PAG pag, MethodPAG mpag) { public Node getNode(Value v) { if (v instanceof Local l) { return caseLocal(l); - } else if (v instanceof JCastExpr castExpr) { + } else if (v instanceof CastExpr castExpr) { return caseCastExpr(castExpr); - } else if (v instanceof JNewExpr ne) { + } else if (v instanceof NewExpr ne) { return caseNewExpr(ne); - } else if (v instanceof JStaticFieldRef sfr) { + } else if (v instanceof StaticFieldRef sfr) { return caseStaticFieldRef(sfr); - } else if (v instanceof JNewArrayExpr nae) { + } else if (v instanceof NewArrayExpr nae) { return caseNewArrayExpr(nae); - } else if (v instanceof JArrayRef ar) { + } else if (v instanceof ArrayRef ar) { return caseArrayRef(ar); } else if (v instanceof ClassConstant cc) { return caseClassConstant(cc); } else if (v instanceof StringConstant sc) { return caseStringConstant(sc); - } else if (v instanceof JCaughtExceptionRef cef) { + } else if (v instanceof CaughtExceptionRef cef) { return caseCaughtExceptionRef(cef); - } else if (v instanceof JParameterRef pr) { + } else if (v instanceof ParameterRef pr) { return caseParameterRef(pr); } else if (v instanceof NullConstant nc) { return caseNullConstant(nc); - } else if (v instanceof JInstanceFieldRef ifr) { + } else if (v instanceof InstanceFieldRef ifr) { return caseInstanceFieldRef(ifr); - } else if (v instanceof JThisRef) { + } else if (v instanceof ThisRef) { return caseThis(); - } else if (v instanceof JNewMultiArrayExpr nmae) { + } else if (v instanceof NewMultiArrayExpr nmae) { return caseNewMultiArrayExpr(nmae); } System.out.println(v + ";;" + v.getClass()); @@ -122,82 +93,130 @@ final public void handleStmt(Stmt s) { * the invoke method throws an Exception. */ protected void handleInvokeStmt(Stmt s) { - AbstractInvokeExpr ie = s.getInvokeExpr(); + InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { continue; } getNode(arg); } - if (s instanceof JAssignStmt assignStmt) { - Value l = assignStmt.getLeftOp(); - if ((l.getType() instanceof ReferenceType)) { + if (s instanceof AssignStmt) { + Value l = ((AssignStmt) s).getLeftOp(); + if ((l.getType() instanceof RefLikeType)) { getNode(l); } } - if (ie instanceof AbstractInstanceInvokeExpr iie) { - getNode(iie.getBase()); + if (ie instanceof InstanceInvokeExpr) { + getNode(((InstanceInvokeExpr) ie).getBase()); } } - private void resolveClinit(JStaticFieldRef staticFieldRef) { - ClassType declClassType = staticFieldRef.getFieldSignature().getDeclClassType(); - SootClass sootClass = (SootClass) pag.getView().getClass(declClassType).get(); - PTAUtils.clinitsOf(sootClass).forEach(mpag::addTriggeredClinit); + private void resolveClinit(StaticFieldRef staticFieldRef) { + PTAUtils.clinitsOf(staticFieldRef.getField().getDeclaringClass()).forEach(mpag::addTriggeredClinit); } + /** + * Adds the edges required for this statement to the graph. + */ + private void handleIntraStmt(Stmt s) { + s.apply(new AbstractStmtSwitch<>() { + public void caseAssignStmt(AssignStmt as) { + Value l = as.getLeftOp(); + Value r = as.getRightOp(); + if (l instanceof StaticFieldRef) { + resolveClinit((StaticFieldRef) l); + } else if (r instanceof StaticFieldRef) { + resolveClinit((StaticFieldRef) r); + } + + if (!(l.getType() instanceof RefLikeType)) + return; + // check for improper casts, with mal-formed code we might get + // l = (refliketype)int_type, if so just return + if (r instanceof CastExpr && (!(((CastExpr) r).getOp().getType() instanceof RefLikeType))) { + return; + } + + if (!(r.getType() instanceof RefLikeType)) + throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + as + + " in method " + method.getSignature()); + Node dest = getNode(l); + Node src = getNode(r); + mpag.addInternalEdge(src, dest); + } + + public void caseReturnStmt(ReturnStmt rs) { + if (!(rs.getOp().getType() instanceof RefLikeType)) + return; + Node retNode = getNode(rs.getOp()); + mpag.addInternalEdge(retNode, caseRet()); + } + public void caseIdentityStmt(IdentityStmt is) { + if (!(is.getLeftOp().getType() instanceof RefLikeType)) { + return; + } + Node dest = getNode(is.getLeftOp()); + Node src = getNode(is.getRightOp()); + mpag.addInternalEdge(src, dest); + } - /* cases for handle values */ + public void caseThrowStmt(ThrowStmt ts) { + if (!CoreConfig.v().getPtaConfig().preciseExceptions) { + mpag.addInternalEdge(getNode(ts.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); + } + } + }); + } private VarNode caseLocal(Local l) { return pag.makeLocalVarNode(l, l.getType(), method); } - private AllocNode caseNewArrayExpr(JNewArrayExpr nae) { + private AllocNode caseNewArrayExpr(NewArrayExpr nae) { return pag.makeAllocNode(nae, nae.getType(), method); } - private AllocNode caseNewExpr(JNewExpr ne) { + private AllocNode caseNewExpr(NewExpr ne) { SootClass cl = PTAScene.v().loadClassAndSupport(ne.getType().toString()); PTAUtils.clinitsOf(cl).forEach(mpag::addTriggeredClinit); return pag.makeAllocNode(ne, ne.getType(), method); } - private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { - SootField sf = (SootField) pag.getView().getField(ifr.getFieldSignature()).get(); -// if (sf == null) { -// sf = new SootField(ifr.getFieldSignature(), ifr.getType(), Modifier.PUBLIC); -// sf.setNumber(Scene.v().getFieldNumberer().size()); -// Scene.v().getFieldNumberer().add(sf); -// System.out.println("Warnning:" + ifr + " is resolved to be a null field in Scene."); -// } + private FieldRefNode caseInstanceFieldRef(InstanceFieldRef ifr) { + SootField sf = ifr.getField(); + if (sf == null) { + sf = new SootField(ifr.getFieldRef().name(), ifr.getType(), Modifier.PUBLIC); + sf.setNumber(Scene.v().getFieldNumberer().size()); + Scene.v().getFieldNumberer().add(sf); + System.out.println("Warnning:" + ifr + " is resolved to be a null field in Scene."); + } return pag.makeFieldRefNode(pag.makeLocalVarNode(ifr.getBase(), ifr.getBase().getType(), method), new Field(sf)); } - private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { + private VarNode caseNewMultiArrayExpr(NewMultiArrayExpr nmae) { ArrayType type = (ArrayType) nmae.getType(); int pos = 0; - AllocNode prevAn = pag.makeAllocNode(new JNewArrayExpr(type, nmae.getSize(pos), JavaIdentifierFactory.getInstance()), type, method); + AllocNode prevAn = pag.makeAllocNode(new JNewArrayExpr(type, nmae.getSize(pos)), type, method); VarNode prevVn = pag.makeLocalVarNode(prevAn.getNewExpr(), prevAn.getType(), method); mpag.addInternalEdge(prevAn, prevVn); // new VarNode ret = prevVn; while (true) { - Type t = type.getArrayElementType(); + Type t = type.getElementType(); if (!(t instanceof ArrayType)) { break; } type = (ArrayType) t; ++pos; - Immediate sizeVal; + Value sizeVal; if (pos < nmae.getSizeCount()) { sizeVal = nmae.getSize(pos); } else { - sizeVal = IntConstant.getInstance(1); + sizeVal = IntConstant.v(1); } - AllocNode an = pag.makeAllocNode(new JNewArrayExpr(type, sizeVal, JavaIdentifierFactory.getInstance()), type, method); + AllocNode an = pag.makeAllocNode(new JNewArrayExpr(type, sizeVal), type, method); VarNode vn = pag.makeLocalVarNode(an.getNewExpr(), an.getType(), method); mpag.addInternalEdge(an, vn); // new mpag.addInternalEdge(vn, pag.makeFieldRefNode(prevVn, ArrayElement.v())); // store @@ -206,15 +225,15 @@ private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { return ret; } - private VarNode caseCastExpr(JCastExpr ce) { + private VarNode caseCastExpr(CastExpr ce) { Node opNode = getNode(ce.getOp()); - VarNode castNode = pag.makeLocalVarNode(ce, ce.getType(), method); + VarNode castNode = pag.makeLocalVarNode(ce, ce.getCastType(), method); mpag.addInternalEdge(opNode, castNode); return castNode; } public VarNode caseThis() { - Type type = method.isStatic() ? JavaIdentifierFactory.getInstance().getType("java.lang.Object") : method.getDeclaringClassType(); + Type type = method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClass().getType(); VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THIS_NODE), type, method); ret.setInterProcTarget(); return ret; @@ -233,7 +252,7 @@ public VarNode caseRet() { } public VarNode caseMethodThrow() { - VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), JavaIdentifierFactory.getInstance().getType("java.lang.Throwable"), method); + VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), RefType.v("java.lang.Throwable"), method); ret.setInterProcSource(); return ret; } @@ -242,7 +261,7 @@ final public FieldRefNode caseArray(VarNode base) { return pag.makeFieldRefNode(base, ArrayElement.v()); } - private Node caseCaughtExceptionRef(JCaughtExceptionRef cer) { + private Node caseCaughtExceptionRef(CaughtExceptionRef cer) { if (CoreConfig.v().getPtaConfig().preciseExceptions) { // we model caughtException expression as an local assignment. return pag.makeLocalVarNode(cer, cer.getType(), method); @@ -251,16 +270,16 @@ private Node caseCaughtExceptionRef(JCaughtExceptionRef cer) { } } - private FieldRefNode caseArrayRef(JArrayRef ar) { + private FieldRefNode caseArrayRef(ArrayRef ar) { return caseArray(caseLocal((Local) ar.getBase())); } - private VarNode caseParameterRef(JParameterRef pr) { + private VarNode caseParameterRef(ParameterRef pr) { return caseParm(pr.getIndex()); } - private VarNode caseStaticFieldRef(JStaticFieldRef sfr) { - return pag.makeGlobalVarNode(sfr.getFieldSignature(), sfr.getType()); + private VarNode caseStaticFieldRef(StaticFieldRef sfr) { + return pag.makeGlobalVarNode(sfr.getField(), sfr.getField().getType()); } private Node caseNullConstant(NullConstant nr) { @@ -268,91 +287,26 @@ private Node caseNullConstant(NullConstant nr) { } private VarNode caseStringConstant(StringConstant sc) { - Type type = JavaIdentifierFactory.getInstance().getType("java.lang.String"); AllocNode stringConstantNode = pag.makeStringConstantNode(sc); - VarNode stringConstantVar = pag.makeGlobalVarNode(sc, type); + VarNode stringConstantVar = pag.makeGlobalVarNode(sc, RefType.v("java.lang.String")); mpag.addInternalEdge(stringConstantNode, stringConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), type, method); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), RefType.v("java.lang.String"), method); mpag.addInternalEdge(stringConstantVar, vn); return vn; } public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { - Type type = JavaIdentifierFactory.getInstance().getType("java.lang.Throwable"); - return pag.makeLocalVarNode(invoke, type, method); + return pag.makeLocalVarNode(invoke, RefType.v("java.lang.Throwable"), method); } final public VarNode caseClassConstant(ClassConstant cc) { - Type type = JavaIdentifierFactory.getInstance().getType("java.lang.Class"); AllocNode classConstant = pag.makeClassConstantNode(cc); - VarNode classConstantVar = pag.makeGlobalVarNode(cc, type); + VarNode classConstantVar = pag.makeGlobalVarNode(cc, RefType.v("java.lang.Class")); mpag.addInternalEdge(classConstant, classConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), type, method); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), RefType.v("java.lang.Class"), method); mpag.addInternalEdge(classConstantVar, vn); return vn; } - /* cases for handle intra-statements */ - /** - * Adds the edges required for this statement to the graph. - */ - public void caseAssignStmt(JAssignStmt as) { - Value l = as.getLeftOp(); - Value r = as.getRightOp(); - if (l instanceof JStaticFieldRef sfr) { - resolveClinit(sfr); - } else if (r instanceof JStaticFieldRef sfr) { - resolveClinit(sfr); - } - - if (!(l.getType() instanceof ReferenceType)) - return; - // check for improper casts, with mal-formed code we might get - // l = (refliketype)int_type, if so just return - if (r instanceof JCastExpr && (!(((JCastExpr) r).getOp().getType() instanceof ReferenceType))) { - return; - } - - if (!(r.getType() instanceof ReferenceType)) - throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + as - + " in method " + method.getSignature()); - Node dest = getNode(l); - Node src = getNode(r); - mpag.addInternalEdge(src, dest); - } - - public void caseReturnStmt(JReturnStmt rs) { - if (!(rs.getOp().getType() instanceof ReferenceType)) - return; - Node retNode = getNode(rs.getOp()); - mpag.addInternalEdge(retNode, caseRet()); - } - - public void caseIdentityStmt(JIdentityStmt is) { - if (!(is.getLeftOp().getType() instanceof ReferenceType)) { - return; - } - Node dest = getNode(is.getLeftOp()); - Node src = getNode(is.getRightOp()); - mpag.addInternalEdge(src, dest); - } - - public void caseThrowStmt(JThrowStmt ts) { - if (!CoreConfig.v().getPtaConfig().preciseExceptions) { - mpag.addInternalEdge(getNode(ts.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); - } - } - - private void handleIntraStmt(Stmt s) { - if (s instanceof JAssignStmt as) { - caseAssignStmt(as); - } else if (s instanceof JReturnStmt rs) { - caseReturnStmt(rs); - } else if (s instanceof JIdentityStmt is) { - caseIdentityStmt(is); - } else if (s instanceof JThrowStmt ts) { - caseThrowStmt(ts); - } - } } diff --git a/sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java b/sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java deleted file mode 100644 index f1c25f937cb..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/callgraph/CallGraph.java +++ /dev/null @@ -1,413 +0,0 @@ -package qilin.core.callgraph; - -import qilin.core.pag.ContextMethod; -import qilin.util.queue.ChunkedQueue; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; - -import java.util.Collection; -import java.util.HashSet; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2003 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -/** - * Represents the edges in a call graph. This class is meant to act as only a container of edges; code for various call graph - * builders should be kept out of it, as well as most code for accessing the edges. - * - * @author Ondrej Lhotak - */ -public class CallGraph implements Iterable { - protected Set edges = new LinkedHashSet<>(); - protected ChunkedQueue stream = new ChunkedQueue<>(); - protected QueueReader reader = stream.reader(); - protected Map srcMethodToEdge = new LinkedHashMap<>(); - protected Map srcUnitToEdge = new LinkedHashMap<>(); - protected Map tgtToEdge = new LinkedHashMap<>(); - protected Edge dummy = new Edge(null, null, null, Kind.INVALID); - - /** - * Used to add an edge to the call graph. Returns true iff the edge was not already present. - */ - public boolean addEdge(Edge e) { - if (!edges.add(e)) { - return false; - } - - stream.add(e); - - Edge position = srcUnitToEdge.get(e.srcUnit()); - if (position == null) { - srcUnitToEdge.put(e.srcUnit(), e); - position = dummy; - } - e.insertAfterByUnit(position); - - position = srcMethodToEdge.get(e.getSrc()); - if (position == null) { - srcMethodToEdge.put(e.getSrc(), e); - position = dummy; - } - e.insertAfterBySrc(position); - - position = tgtToEdge.get(e.getTgt()); - if (position == null) { - tgtToEdge.put(e.getTgt(), e); - position = dummy; - } - e.insertAfterByTgt(position); - return true; - } - - /** - * Removes all outgoing edges that start at the given unit - * - * @param u - * The unit from which to remove all outgoing edges - * @return True if at least one edge has been removed, otherwise false - */ - public boolean removeAllEdgesOutOf(Stmt u) { - boolean hasRemoved = false; - Set edgesToRemove = new HashSet<>(); - for (QueueReader edgeRdr = listener(); edgeRdr.hasNext();) { - Edge e = edgeRdr.next(); - if (e.srcUnit() == u) { - e.remove(); - removeEdge(e, false); - edgesToRemove.add(e); - hasRemoved = true; - } - } - if (hasRemoved) { - reader.remove(edgesToRemove); - } - return hasRemoved; - } - - /** - * Swaps an invocation statement. All edges that previously went from the given statement to some callee now go from the - * new statement to the same callee. This method is intended to be used when a Jimple statement is replaced, but the - * replacement does not semantically affect the edges. - * - * @param out - * The old statement - * @param in - * The new statement - * @return True if at least one edge was affected by this operation - */ - public boolean swapEdgesOutOf(Stmt out, Stmt in) { - boolean hasSwapped = false; - for (Iterator edgeRdr = edgesOutOf(out); edgeRdr.hasNext();) { - Edge e = edgeRdr.next(); - ContextMethod src = e.getSrc(); - ContextMethod tgt = e.getTgt(); - removeEdge(e); - e.remove(); - addEdge(new Edge(src, in, tgt)); - hasSwapped = true; - } - return hasSwapped; - } - - /** - * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. - */ - public boolean removeEdge(Edge e) { - return removeEdge(e, true); - } - - /** - * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. - * - * @param e - * the edge - * @param removeInEdgeList - * when true (recommended), it is ensured that the edge reader is informed about the removal - * @return whether the removal was successful. - */ - public boolean removeEdge(Edge e, boolean removeInEdgeList) { - if (!edges.remove(e)) { - return false; - } - e.remove(); - - if (srcUnitToEdge.get(e.srcUnit()) == e) { - if (e.nextByUnit().srcUnit() == e.srcUnit()) { - srcUnitToEdge.put(e.srcUnit(), e.nextByUnit()); - } else { - srcUnitToEdge.remove(e.srcUnit()); - } - } - - if (srcMethodToEdge.get(e.getSrc()) == e) { - if (e.nextBySrc().getSrc() == e.getSrc()) { - srcMethodToEdge.put(e.getSrc(), e.nextBySrc()); - } else { - srcMethodToEdge.remove(e.getSrc()); - } - } - - if (tgtToEdge.get(e.getTgt()) == e) { - if (e.nextByTgt().getTgt() == e.getTgt()) { - tgtToEdge.put(e.getTgt(), e.nextByTgt()); - } else { - tgtToEdge.remove(e.getTgt()); - } - } - // This is an linear operation, so we want to avoid it if possible. - if (removeInEdgeList) { - reader.remove(e); - } - return true; - } - - /** - * Removes the edges from the call graph. Returns true iff one edge was originally present in the call graph. - * - * @param edges - * the edges - * @return whether the removal was successful. - */ - public boolean removeEdges(Collection edges) { - if (!this.edges.removeAll(edges)) { - return false; - } - for (Edge e : edges) { - removeEdge(e, false); - } - reader.remove(edges); - return true; - } - - /** - * Does this method have no incoming edge? - * - * @param method - * @return - */ - public boolean isEntryMethod(SootMethod method) { - return !tgtToEdge.containsKey(method); - } - - /** - * Find the specific call edge that is going out from the callsite u and the call target is callee. Without advanced data - * structure, we can only sequentially search for the match. Fortunately, the number of outgoing edges for a unit is not - * too large. - * - * @param u - * @param callee - * @return - */ - public Edge findEdge(Stmt u, SootMethod callee) { - Edge e = srcUnitToEdge.get(u); - if (e != null) { - while (e.srcUnit() == u && e.kind() != Kind.INVALID) { - if (e.tgt() == callee) { - return e; - } - e = e.nextByUnit(); - } - } - return null; - } - - /** - * Returns an iterator over all methods that are the sources of at least one edge. - */ - public Iterator sourceMethods() { - return srcMethodToEdge.keySet().iterator(); - } - - /** - * Returns an iterator over all edges that have u as their source unit. - */ - public Iterator edgesOutOf(Stmt u) { - return new TargetsOfUnitIterator(u); - } - - class TargetsOfUnitIterator implements Iterator { - private final Stmt u; - private Edge position; - - TargetsOfUnitIterator(Stmt u) { - this.u = u; - if (u == null) { - throw new RuntimeException(); - } - this.position = srcUnitToEdge.get(u); - if (position == null) { - position = dummy; - } - } - - @Override - public boolean hasNext() { - if (position.srcUnit() != u) { - return false; - } - return position.kind() != Kind.INVALID; - } - - @Override - public Edge next() { - Edge ret = position; - position = position.nextByUnit(); - return ret; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - /** - * Returns an iterator over all edges that have m as their source method. - */ - public Iterator edgesOutOf(ContextMethod m) { - return new TargetsOfMethodIterator(m); - } - - class TargetsOfMethodIterator implements Iterator { - private final ContextMethod m; - private Edge position; - - TargetsOfMethodIterator(ContextMethod m) { - this.m = m; - if (m == null) { - throw new RuntimeException(); - } - this.position = srcMethodToEdge.get(m); - if (position == null) { - position = dummy; - } - } - - @Override - public boolean hasNext() { - if (position.getSrc() != m) { - return false; - } - return position.kind() != Kind.INVALID; - } - - @Override - public Edge next() { - Edge ret = position; - position = position.nextBySrc(); - return ret; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - /** - * Returns an iterator over all edges that have m as their target method. - */ - public Iterator edgesInto(ContextMethod m) { - return new CallersOfMethodIterator(m); - } - - class CallersOfMethodIterator implements Iterator { - private final ContextMethod m; - private Edge position; - - CallersOfMethodIterator(ContextMethod m) { - this.m = m; - if (m == null) { - throw new RuntimeException(); - } - this.position = tgtToEdge.get(m); - if (position == null) { - position = dummy; - } - } - - @Override - public boolean hasNext() { - if (position.getTgt() != m) { - return false; - } - return position.kind() != Kind.INVALID; - } - - @Override - public Edge next() { - Edge ret = position; - position = position.nextByTgt(); - return ret; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - /** - * Returns a QueueReader object containing all edges added so far, and which will be informed of any new edges that are - * later added to the graph. - */ - public QueueReader listener() { - return reader.clone(); - } - - /** - * Returns a QueueReader object which will contain ONLY NEW edges which will be added to the graph. - */ - public QueueReader newListener() { - return stream.reader(); - } - - @Override - public String toString() { - StringBuilder out = new StringBuilder(); - for (QueueReader reader = listener(); reader.hasNext();) { - Edge e = reader.next(); - out.append(e.toString()).append('\n'); - } - return out.toString(); - } - - /** - * Returns the number of edges in the call graph. - */ - public int size() { - return edges.size(); - } - - @Override - public Iterator iterator() { - return edges.iterator(); - } -} - diff --git a/sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java b/sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java deleted file mode 100644 index 6746e88c298..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/callgraph/Edge.java +++ /dev/null @@ -1,287 +0,0 @@ -package qilin.core.callgraph; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2003 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import qilin.core.context.Context; -import qilin.core.pag.ContextMethod; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; -import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.expr.JVirtualInvokeExpr; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; - -/** - * Represents a single edge in a call graph. - * - * @author Ondrej Lhotak - */ -public final class Edge { - - /** - * The method in which the call occurs; may be null for calls not occurring in a specific method (eg. implicit calls by the - * VM) - */ - private ContextMethod src; - - /** - * The target method of the call edge. - */ - private ContextMethod tgt; - - /** - * The unit at which the call occurs; may be null for calls not occurring at a specific statement (eg. calls in native - * code) - */ - private Stmt srcUnit; - - /** - * The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as isExplicit() should be - * added. - */ - private final Kind kind; - - private boolean invalid = false; - - public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt, Kind kind) { - this.src = src; - this.srcUnit = srcUnit; - this.tgt = tgt; - this.kind = kind; - } - - public Edge(ContextMethod src, Stmt srcUnit, ContextMethod tgt) { - this.kind = ieToKind(srcUnit.getInvokeExpr()); - this.src = src; - this.srcUnit = srcUnit; - this.tgt = tgt; - } - - public SootMethod src() { - return (src == null) ? null : src.method(); - } - - public Context srcCtxt() { - return (src == null) ? null : src.context(); - } - - public ContextMethod getSrc() { - return src; - } - - public Stmt srcUnit() { - return srcUnit; - } - - public Stmt srcStmt() { - return srcUnit; - } - - public SootMethod tgt() { - return (tgt == null) ? null : tgt.method(); - } - - public Context tgtCtxt() { - return (tgt == null) ? null : tgt.context(); - } - - public ContextMethod getTgt() { - return tgt; - } - - public Kind kind() { - return kind; - } - - public static Kind ieToKind(AbstractInvokeExpr ie) { - if (ie instanceof JVirtualInvokeExpr) { - return Kind.VIRTUAL; - } else if (ie instanceof JSpecialInvokeExpr) { - return Kind.SPECIAL; - } else if (ie instanceof JInterfaceInvokeExpr) { - return Kind.INTERFACE; - } else if (ie instanceof JStaticInvokeExpr) { - return Kind.STATIC; - } else { - throw new RuntimeException(); - } - } - - /** - * Returns true if the call is due to an explicit invoke statement. - */ - public boolean isExplicit() { - return Kind.isExplicit(this.kind); - } - - /** - * Returns true if the call is due to an explicit instance invoke statement. - */ - public boolean isInstance() { - return Kind.isInstance(this.kind); - } - - public boolean isVirtual() { - return Kind.isVirtual(this.kind); - } - - public boolean isSpecial() { - return Kind.isSpecial(this.kind); - } - - /** - * Returns true if the call is to static initializer. - */ - public boolean isClinit() { - return Kind.isClinit(this.kind); - } - - /** - * Returns true if the call is due to an explicit static invoke statement. - */ - public boolean isStatic() { - return Kind.isStatic(this.kind); - } - - public boolean isThreadRunCall() { - return Kind.isThread(this.kind); - } - - public boolean passesParameters() { - return Kind.passesParameters(this.kind); - } - - @Override - public int hashCode() { - if (invalid) { - return 0; - } - int ret = (tgt.hashCode() + 20) + (kind == null ? 0 : kind.getNumber()); - if (src != null) { - ret = ret * 32 + src.hashCode(); - } - if (srcUnit != null) { - ret = ret * 32 + srcUnit.hashCode(); - } - return ret; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof Edge)) { - return false; - } - Edge o = (Edge) other; - return (o.src == this.src) && (o.srcUnit == srcUnit) && (o.tgt == tgt) && (o.kind == kind); - } - - @Override - public String toString() { - return String.valueOf(this.kind) + " edge: " + srcUnit + " in " + src + " ==> " + tgt; - } - - private Edge nextByUnit = this; - private Edge prevByUnit = this; - private Edge nextBySrc = this; - private Edge prevBySrc = this; - private Edge nextByTgt = this; - private Edge prevByTgt = this; - - void insertAfterByUnit(Edge other) { - nextByUnit = other.nextByUnit; - nextByUnit.prevByUnit = this; - other.nextByUnit = this; - prevByUnit = other; - } - - void insertAfterBySrc(Edge other) { - nextBySrc = other.nextBySrc; - nextBySrc.prevBySrc = this; - other.nextBySrc = this; - prevBySrc = other; - } - - void insertAfterByTgt(Edge other) { - nextByTgt = other.nextByTgt; - nextByTgt.prevByTgt = this; - other.nextByTgt = this; - prevByTgt = other; - } - - void insertBeforeByUnit(Edge other) { - prevByUnit = other.prevByUnit; - prevByUnit.nextByUnit = this; - other.prevByUnit = this; - nextByUnit = other; - } - - void insertBeforeBySrc(Edge other) { - prevBySrc = other.prevBySrc; - prevBySrc.nextBySrc = this; - other.prevBySrc = this; - nextBySrc = other; - } - - void insertBeforeByTgt(Edge other) { - prevByTgt = other.prevByTgt; - prevByTgt.nextByTgt = this; - other.prevByTgt = this; - nextByTgt = other; - } - - void remove() { - invalid = true; - nextByUnit.prevByUnit = prevByUnit; - prevByUnit.nextByUnit = nextByUnit; - nextBySrc.prevBySrc = prevBySrc; - prevBySrc.nextBySrc = nextBySrc; - nextByTgt.prevByTgt = prevByTgt; - prevByTgt.nextByTgt = nextByTgt; - } - - Edge nextByUnit() { - return nextByUnit; - } - - Edge nextBySrc() { - return nextBySrc; - } - - Edge nextByTgt() { - return nextByTgt; - } - - Edge prevByUnit() { - return prevByUnit; - } - - Edge prevBySrc() { - return prevBySrc; - } - - Edge prevByTgt() { - return prevByTgt; - } -} - diff --git a/sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java b/sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java deleted file mode 100644 index f737e7ce5f5..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/callgraph/Kind.java +++ /dev/null @@ -1,273 +0,0 @@ -package qilin.core.callgraph; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2003 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import qilin.core.util.Numberable; - -/** - * Enumeration type representing the kind of a call graph edge. - * - * @author Ondrej Lhotak - */ -public final class Kind implements Numberable { - - public static final Kind INVALID = new Kind("INVALID"); - /** - * Due to explicit invokestatic instruction. - */ - public static final Kind STATIC = new Kind("STATIC"); - /** - * Due to explicit invokevirtual instruction. - */ - public static final Kind VIRTUAL = new Kind("VIRTUAL"); - /** - * Due to explicit invokeinterface instruction. - */ - public static final Kind INTERFACE = new Kind("INTERFACE"); - /** - * Due to explicit invokespecial instruction. - */ - public static final Kind SPECIAL = new Kind("SPECIAL"); - /** - * Implicit call to static initializer. - */ - public static final Kind CLINIT = new Kind("CLINIT"); - /** - * Fake edges from our generic callback model. - */ - public static final Kind GENERIC_FAKE = new Kind("GENERIC_FAKE"); - /** - * Implicit call to Thread.run() due to Thread.start() call. - */ - public static final Kind THREAD = new Kind("THREAD"); - /** - * Implicit call to java.lang.Runnable.run() due to Executor.execute() call. - */ - public static final Kind EXECUTOR = new Kind("EXECUTOR"); - /** - * Implicit call to AsyncTask.doInBackground() due to AsyncTask.execute() call. - */ - public static final Kind ASYNCTASK = new Kind("ASYNCTASK"); - /** - * Implicit call to java.lang.ref.Finalizer.register from new bytecode. - */ - public static final Kind FINALIZE = new Kind("FINALIZE"); - /** - * Implicit call to Handler.handleMessage(android.os.Message) due to Handler.sendxxxxMessagexxxx() call. - */ - public static final Kind HANDLER = new Kind("HANDLER"); - /** - * Implicit call to finalize() from java.lang.ref.Finalizer.invokeFinalizeMethod(). - */ - public static final Kind INVOKE_FINALIZE = new Kind("INVOKE_FINALIZE"); - /** - * Implicit call to run() through AccessController.doPrivileged(). - */ - public static final Kind PRIVILEGED = new Kind("PRIVILEGED"); - /** - * Implicit call to constructor from java.lang.Class.newInstance(). - */ - public static final Kind NEWINSTANCE = new Kind("NEWINSTANCE"); - /** - * Due to call to Method.invoke(..). - */ - public static final Kind REFL_INVOKE = new Kind("REFL_METHOD_INVOKE"); - /** - * Due to call to Constructor.newInstance(..). - */ - public static final Kind REFL_CONSTR_NEWINSTANCE = new Kind("REFL_CONSTRUCTOR_NEWINSTANCE"); - /** - * Due to call to Class.newInstance(..) when reflection log is enabled. - */ - public static final Kind REFL_CLASS_NEWINSTANCE = new Kind("REFL_CLASS_NEWINSTANCE"); - - private final String name; - private int num; - - private Kind(String name) { - this.name = name; - } - - public String name() { - return name; - } - - @Override - public int getNumber() { - return num; - } - - @Override - public void setNumber(int num) { - this.num = num; - } - - @Override - public String toString() { - return name(); - } - - public boolean passesParameters() { - return passesParameters(this); - } - - public boolean isFake() { - return isFake(this); - } - - /** - * Returns true if the call is due to an explicit invoke statement. - */ - public boolean isExplicit() { - return isExplicit(this); - } - - /** - * Returns true if the call is due to an explicit instance invoke statement. - */ - public boolean isInstance() { - return isInstance(this); - } - - /** - * Returns true if the call is due to an explicit virtual invoke statement. - */ - public boolean isVirtual() { - return isVirtual(this); - } - - public boolean isSpecial() { - return isSpecial(this); - } - - /** - * Returns true if the call is to static initializer. - */ - public boolean isClinit() { - return isClinit(this); - } - - /** - * Returns true if the call is due to an explicit static invoke statement. - */ - public boolean isStatic() { - return isStatic(this); - } - - public boolean isThread() { - return isThread(this); - } - - public boolean isExecutor() { - return isExecutor(this); - } - - public boolean isAsyncTask() { - return isAsyncTask(this); - } - - public boolean isPrivileged() { - return isPrivileged(this); - } - - public boolean isReflection() { - return isReflection(this); - } - - public boolean isReflInvoke() { - return isReflInvoke(this); - } - - public static boolean passesParameters(Kind k) { - return isExplicit(k) || k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == FINALIZE || k == PRIVILEGED - || k == NEWINSTANCE || k == INVOKE_FINALIZE || k == REFL_INVOKE || k == REFL_CONSTR_NEWINSTANCE - || k == REFL_CLASS_NEWINSTANCE; - } - - public static boolean isFake(Kind k) { - return k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == PRIVILEGED || k == HANDLER || k == GENERIC_FAKE; - } - - /** - * Returns true if the call is due to an explicit invoke statement. - */ - public static boolean isExplicit(Kind k) { - return isInstance(k) || isStatic(k); - } - - /** - * Returns true if the call is due to an explicit instance invoke statement. - */ - public static boolean isInstance(Kind k) { - return k == VIRTUAL || k == INTERFACE || k == SPECIAL; - } - - /** - * Returns true if the call is due to an explicit virtual invoke statement. - */ - public static boolean isVirtual(Kind k) { - return k == VIRTUAL; - } - - public static boolean isSpecial(Kind k) { - return k == SPECIAL; - } - - /** - * Returns true if the call is to static initializer. - */ - public static boolean isClinit(Kind k) { - return k == CLINIT; - } - - /** - * Returns true if the call is due to an explicit static invoke statement. - */ - public static boolean isStatic(Kind k) { - return k == STATIC; - } - - public static boolean isThread(Kind k) { - return k == THREAD; - } - - public static boolean isExecutor(Kind k) { - return k == EXECUTOR; - } - - public static boolean isAsyncTask(Kind k) { - return k == ASYNCTASK; - } - - public static boolean isPrivileged(Kind k) { - return k == PRIVILEGED; - } - - public static boolean isReflection(Kind k) { - return k == REFL_CLASS_NEWINSTANCE || k == REFL_CONSTR_NEWINSTANCE || k == REFL_INVOKE; - } - - public static boolean isReflInvoke(Kind k) { - return k == REFL_INVOKE; - } -} diff --git a/sootup.qilin/src/main/java/qilin/core/context/Context.java b/sootup.qilin/src/main/java/qilin/core/context/Context.java deleted file mode 100644 index 94b8b6829f2..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/context/Context.java +++ /dev/null @@ -1,4 +0,0 @@ -package qilin.core.context; - -public interface Context { -} diff --git a/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java b/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java index 0ad3f869158..2e186994d55 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java +++ b/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java @@ -18,6 +18,8 @@ package qilin.core.context; +import soot.Context; + import java.util.Arrays; public class ContextElements implements Context { diff --git a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java index 54ef5b09020..135d00bae0f 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java +++ b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java @@ -21,10 +21,9 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.ClassConstantNode; import qilin.core.pag.StringConstantNode; -import sootup.core.IdentifierFactory; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; -import sootup.java.core.JavaIdentifierFactory; +import soot.RefType; +import soot.SootMethod; +import soot.Type; /** * Type based context element in the points to analysis. @@ -39,14 +38,13 @@ private TypeContextElement(Type type) { public static TypeContextElement getTypeContextElement(AllocNode a) { SootMethod declaringMethod = a.getMethod(); - IdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); - Type declType = identifierFactory.getType("java.lang.Object"); + Type declType = RefType.v("java.lang.Object"); if (declaringMethod != null) { - declType = declaringMethod.getDeclaringClassType(); + declType = declaringMethod.getDeclaringClass().getType(); } else if (a instanceof ClassConstantNode) { - declType = identifierFactory.getType("java.lang.System"); + declType = RefType.v("java.lang.System"); } else if (a instanceof StringConstantNode) { - declType = identifierFactory.getType("java.lang.String"); + declType = RefType.v("java.lang.String"); } return new TypeContextElement(declType); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index a50741b3774..72a3c1ec335 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -18,11 +18,9 @@ package qilin.core.natives; -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.java.core.JavaIdentifierFactory; +import soot.RefType; +import soot.SootMethod; +import soot.Value; public class JavaIoFileSystemGetFileSystemNative extends NativeMethod { public JavaIoFileSystemGetFileSystemNative(SootMethod method) { @@ -37,8 +35,8 @@ public JavaIoFileSystemGetFileSystemNative(SootMethod method) { * only exists in old version of JDK(e.g., JDK6). */ public void simulate() { - Value newLocal0 = getNew((ClassType) JavaIdentifierFactory.getInstance().getType("java.io.UnixFileSystem")); + Value newLocal0 = getNew(RefType.v("java.io.UnixFileSystem")); addInvoke(newLocal0, "()>"); - addReturn((Immediate) newLocal0); + addReturn(newLocal0); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java index 67bb0898334..9aa887897a7 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -18,13 +18,9 @@ package qilin.core.natives; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.core.types.ReferenceType; -import sootup.java.core.JavaIdentifierFactory; +import soot.RefType; +import soot.SootMethod; +import soot.Value; public class JavaIoFileSystemListNative extends NativeMethod { public JavaIoFileSystemListNative(SootMethod method) { @@ -37,11 +33,10 @@ public JavaIoFileSystemListNative(SootMethod method) { * only exists in old JDK(e.g., JDK6). */ public void simulate() { - IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); - Value arrLocal = getNewArray((ReferenceType) idFactory.getType("java.lang.String")); - Value elem = getNew((ClassType) idFactory.getType("java.lang.String")); + Value arrLocal = getNewArray(RefType.v("java.lang.String")); + Value elem = getNew(RefType.v("java.lang.String")); // addInvoke(elem, "()>"); addAssign(getArrayRef(arrLocal), elem); - addReturn((Immediate) arrLocal); + addReturn(arrLocal); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java index f2a586570ce..2015305c614 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java @@ -18,10 +18,8 @@ package qilin.core.natives; - -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaLangObjectCloneNative extends NativeMethod { @@ -35,7 +33,7 @@ public JavaLangObjectCloneNative(SootMethod method) { */ public void simulate() { Value r0 = getThis(); - addReturn((Immediate) r0); + addReturn(r0); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java index 8321a0a9938..88c109910de 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java @@ -18,9 +18,8 @@ package qilin.core.natives; - -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaLangRefFinalizerInvokeFinalizeMethodNative extends NativeMethod { public JavaLangRefFinalizerInvokeFinalizeMethodNative(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index d6880c29369..829f8bab37a 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -18,11 +18,10 @@ package qilin.core.natives; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; -import sootup.java.core.JavaIdentifierFactory; +import soot.ArrayType; +import soot.RefType; +import soot.SootMethod; +import soot.Value; /* * @@ -35,11 +34,10 @@ public class JavaLangReflectArrayGet extends NativeMethod { @Override void simulate() { - IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); - Value arrayBase = getPara(0, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); + Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); Value arrayRef = getArrayRef(arrayBase); - Value ret = getNextLocal(idFactory.getType("java.lang.Object")); + Value ret = getNextLocal(RefType.v("java.lang.Object")); addAssign(ret, arrayRef); - addReturn((Immediate) ret); + addReturn(ret); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java index 070723a4fa9..c608b635fc8 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -18,10 +18,10 @@ package qilin.core.natives; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; -import sootup.java.core.JavaIdentifierFactory; +import soot.ArrayType; +import soot.RefType; +import soot.SootMethod; +import soot.Value; /* * handle @@ -34,8 +34,7 @@ public class JavaLangReflectArraySet extends NativeMethod { @Override void simulate() { - IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); - Value arrayBase = getPara(0, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); + Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); Value rightValue = getPara(2); Value arrayRef = getArrayRef(arrayBase); addAssign(arrayRef, rightValue); // a[] = b; diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java index c100d8c8415..f03dcfc9c81 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -18,10 +18,10 @@ package qilin.core.natives; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; -import sootup.java.core.JavaIdentifierFactory; +import soot.ArrayType; +import soot.RefType; +import soot.SootMethod; +import soot.Value; /* * This file will be temporarily discarded. Yes, it is correct but need one more level of context. @@ -39,12 +39,11 @@ public JavaLangSystemArraycopyNative(SootMethod method) { public void simulate() { // Value srcArr = getPara(0); // Value dstArr = getPara(2); - IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); - Value srcArr = getPara(0, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); - Value dstArr = getPara(2, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); + Value srcArr = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + Value dstArr = getPara(2, ArrayType.v(RefType.v("java.lang.Object"), 1)); Value src = getArrayRef(srcArr); Value dst = getArrayRef(dstArr); - Value temp = getNextLocal(idFactory.getType("java.lang.Object")); + Value temp = getNextLocal(RefType.v("java.lang.Object")); addAssign(temp, src); addAssign(dst, temp); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java index 632ebf1cbfc..84d5f0786e5 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaLangSystemSetErr0Native extends NativeMethod { public JavaLangSystemSetErr0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java index d427bca5444..e6d36202de4 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaLangSystemSetIn0Native extends NativeMethod { public JavaLangSystemSetIn0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java index ff8ac0a358f..203a5f0ce0f 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaLangSystemSetOut0Native extends NativeMethod { public JavaLangSystemSetOut0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java index d17c374712b..c8eda289ed1 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -19,10 +19,9 @@ package qilin.core.natives; import qilin.core.PTAScene; -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; -import sootup.java.core.JavaIdentifierFactory; +import soot.RefType; +import soot.SootMethod; +import soot.Value; public class JavaLangThreadCurrentThread extends NativeMethod { JavaLangThreadCurrentThread(SootMethod method) { @@ -31,9 +30,9 @@ public class JavaLangThreadCurrentThread extends NativeMethod { @Override void simulate() { - Value lv = getNextLocal(JavaIdentifierFactory.getInstance().getType("java.lang.Thread")); + Value lv = getNextLocal(RefType.v("java.lang.Thread")); Value rv = PTAScene.v().getFieldCurrentThread(); addAssign(lv, rv); - addReturn((Immediate) lv); + addReturn(lv); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java index be330b7d483..c1dd4da9507 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java @@ -19,8 +19,8 @@ package qilin.core.natives; import qilin.core.PTAScene; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaLangThreadStart0Native extends NativeMethod { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java index f4c5c0d845d..3ff7f9d4c31 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java @@ -17,10 +17,8 @@ */ package qilin.core.natives; - -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaSecurityAccessControllerDoPrivilegedNative extends NativeMethod { public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { @@ -36,6 +34,6 @@ public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { public void simulate() { Value r0 = getPara(0); Value r1 = getInvoke(r0, ""); - addReturn((Immediate) r1); + addReturn(r1); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java index 12a3fff3684..dee72f7f120 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java @@ -18,10 +18,8 @@ package qilin.core.natives; - -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Value; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public class JavaSecurityAccessControllerDoPrivileged_ExceptionNative extends NativeMethod { public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod method) { @@ -37,6 +35,6 @@ public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod metho public void simulate() { Value r0 = getPara(0); Value r1 = getInvoke(r0, ""); - addReturn((Immediate) r1); + addReturn(r1); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java index b94cbcb1b02..d54d470b0a5 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java @@ -20,8 +20,8 @@ import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; -import sootup.core.jimple.basic.Local; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; public abstract class NativeMethod extends ArtificialMethod { @@ -29,7 +29,7 @@ public abstract class NativeMethod extends ArtificialMethod { this.method = method; this.body = PTAUtils.getMethodBody(method); int paraCount = method.getParameterCount(); - paraLocals = new Local[paraCount]; + paraLocals = new Value[paraCount]; this.paraStart = method.isStatic() ? 0 : 1; this.localStart = this.paraStart + paraCount; } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java index 5be8c9372b5..aaa70916b69 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java @@ -19,14 +19,14 @@ package qilin.core.natives; import qilin.core.PTAScene; -import sootup.core.model.SootMethod; +import soot.SootMethod; public class NativeMethodDriver { public void buildNative(SootMethod method) { if (!PTAScene.v().nativeBuilt.add(method)) { return; } - String sig = method.getSignature().toString(); + String sig = method.getSignature(); switch (sig) { case "": case "": diff --git a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java index 7e0d7d48f8d..264a17f0153 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java @@ -20,12 +20,10 @@ import qilin.CoreConfig; import qilin.core.context.ContextElement; -import qilin.core.util.Numberable; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.RefType; +import soot.SootMethod; +import soot.Type; +import soot.util.Numberable; /** * Represents an allocation site node in the pointer assignment graph. @@ -36,12 +34,11 @@ public class AllocNode extends Node implements ContextElement, Numberable { protected Object newExpr; private final SootMethod method; - public AllocNode(View view, Object newExpr, Type t, SootMethod m) { - super(view, t); + public AllocNode(Object newExpr, Type t, SootMethod m) { + super(t); this.method = m; - if (t instanceof ClassType rt) { - SootClass sc = (SootClass) view.getClass(rt).get(); - if (sc.isAbstract()) { + if (t instanceof RefType rt) { + if (rt.getSootClass().isAbstract()) { boolean usesReflectionLog = CoreConfig.v().getAppConfig().REFLECTION_LOG != null; if (!usesReflectionLog) { throw new RuntimeException("Attempt to create allocnode with abstract type " + t); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java index 6af84842c5c..8498bb13ccb 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java @@ -18,8 +18,9 @@ package qilin.core.pag; -import sootup.core.types.Type; -import sootup.java.core.JavaIdentifierFactory; +import soot.RefType; +import soot.Type; +import soot.jimple.spark.pag.SparkField; /** * Represents an array element. @@ -50,6 +51,6 @@ public final void setNumber(int number) { } public Type getType() { - return JavaIdentifierFactory.getInstance().getType("java.lang.Object"); + return RefType.v("java.lang.Object"); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java index 8e31efd4d52..3bd957c380c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java @@ -19,20 +19,20 @@ package qilin.core.pag; import qilin.core.context.ContextElement; -import sootup.core.jimple.common.stmt.Stmt; +import soot.Unit; /** * callsite based context element in the points to analysis. */ public class CallSite implements ContextElement { - private final Stmt unit; + private final Unit unit; - public CallSite(Stmt unit) { + public CallSite(Unit unit) { this.unit = unit; } - public Stmt getUnit() { + public Unit getUnit() { return unit; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java index b568fcce8c7..aabb2bddb8e 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java @@ -18,8 +18,8 @@ package qilin.core.pag; -import sootup.core.jimple.common.constant.ClassConstant; -import sootup.core.views.View; +import soot.RefType; +import soot.jimple.ClassConstant; /** * Represents an allocation site node the represents a known java.lang.Class object. @@ -27,8 +27,8 @@ * @author Ondrej Lhotak */ public class ClassConstantNode extends ConstantNode { - public ClassConstantNode(View view, ClassConstant cc) { - super(view, cc, view.getIdentifierFactory().getType("java.lang.Class"), null); + public ClassConstantNode(ClassConstant cc) { + super(cc, RefType.v("java.lang.Class"), null); } public String toString() { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java index 2a00eee045d..7901ba1844f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java @@ -18,12 +18,11 @@ package qilin.core.pag; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.SootMethod; +import soot.Type; public abstract class ConstantNode extends AllocNode { - protected ConstantNode(View view, Object newExpr, Type t, SootMethod m) { - super(view, newExpr, t, m); + protected ConstantNode(Object newExpr, Type t, SootMethod m) { + super(newExpr, t, m); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java index 97487f5068e..484f26aa521 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java @@ -18,15 +18,14 @@ package qilin.core.pag; -import qilin.core.context.Context; -import sootup.core.views.View; +import soot.Context; public class ContextAllocNode extends AllocNode { private final Context context; private final AllocNode base; - public ContextAllocNode(View view, AllocNode base, Context context) { - super(view, base.getNewExpr(), base.getType(), base.getMethod()); + public ContextAllocNode(AllocNode base, Context context) { + super(base.getNewExpr(), base.getType(), base.getMethod()); this.context = context; this.base = base; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java index 869df5d4ebd..b640bc1dd46 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java @@ -19,26 +19,27 @@ package qilin.core.pag; import qilin.CoreConfig; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; -import sootup.core.types.ArrayType; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.ArrayType; +import soot.Context; +import soot.RefType; +import soot.Type; +import soot.jimple.spark.pag.SparkField; public class ContextField extends ValNode { protected Context context; protected SparkField field; - public ContextField(View view, Context context, SparkField field) { - super(view, refineFieldType(view, context, field)); + public ContextField(Context context, SparkField field) { + super(refineFieldType(context, field)); this.context = context; this.field = field; } - private static Type refineFieldType(View view, Context context, SparkField field) { + private static Type refineFieldType(Context context, SparkField field) { if (!CoreConfig.v().getPtaConfig().preciseArrayElement) { - return view.getIdentifierFactory().getType("java.lang.Object"); + return RefType.v("java.lang.Object"); } if (field instanceof ArrayElement) { ContextElement[] contextElements = ((ContextElements) context).getElements(); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java index ee7a59adcf1..240e159af19 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java @@ -18,10 +18,11 @@ package qilin.core.pag; -import qilin.core.context.Context; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; -public final class ContextMethod { +public final class ContextMethod implements MethodOrMethodContext { private final SootMethod method; private final Context context; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java index 75f597d7c21..70430c9e4d3 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java @@ -18,15 +18,14 @@ package qilin.core.pag; -import qilin.core.context.Context; -import sootup.core.views.View; +import soot.Context; public class ContextVarNode extends VarNode { private final Context context; private final VarNode base; - public ContextVarNode(View view, VarNode base, Context context) { - super(view, base.getVariable(), base.getType()); + public ContextVarNode(VarNode base, Context context) { + super(base.getVariable(), base.getType()); this.context = context; this.base = base; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java index 68a8618bdab..e9d8fbc5350 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java @@ -18,22 +18,23 @@ package qilin.core.pag; -import sootup.core.jimple.common.stmt.Stmt; +import soot.MethodOrMethodContext; +import soot.Unit; import java.util.Objects; public class ExceptionThrowSite { - private final Stmt unit; + private final Unit unit; private final VarNode throwNode; - private final ContextMethod container; + private final MethodOrMethodContext container; - public ExceptionThrowSite(VarNode throwNode, Stmt unit, ContextMethod container) { + public ExceptionThrowSite(VarNode throwNode, Unit unit, MethodOrMethodContext container) { this.unit = unit; this.container = container; this.throwNode = throwNode; } - public ContextMethod container() { + public MethodOrMethodContext container() { return container; } @@ -41,7 +42,7 @@ public VarNode getThrowNode() { return throwNode; } - public Stmt getUnit() { + public Unit getUnit() { return unit; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Field.java b/sootup.qilin/src/main/java/qilin/core/pag/Field.java index 4244773bea1..891f956c82d 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Field.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Field.java @@ -18,9 +18,9 @@ package qilin.core.pag; - -import sootup.core.model.SootField; -import sootup.core.types.Type; +import soot.SootField; +import soot.Type; +import soot.jimple.spark.pag.SparkField; import java.util.Objects; @@ -36,8 +36,7 @@ public Field(SootField sf) { @Override public int getNumber() { - throw new UnsupportedOperationException(); - // return field.getNumber(); + return field.getNumber(); } @Override diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java index cd7650eb92d..44ad12b8d1f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java @@ -18,9 +18,8 @@ package qilin.core.pag; - -import qilin.core.util.Numberable; -import sootup.core.views.View; +import soot.jimple.spark.pag.SparkField; +import soot.util.Numberable; /** * Represents a field reference node in the pointer assignment graph. @@ -31,8 +30,8 @@ public class FieldRefNode extends Node implements Numberable { protected VarNode base; protected SparkField field; - public FieldRefNode(View view, VarNode base, SparkField field) { - super(view, field.getType()); + public FieldRefNode(VarNode base, SparkField field) { + super(field.getType()); this.base = base; this.field = field; base.addField(this, field); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java index 768cec9a516..9cf03ecac92 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java @@ -18,15 +18,15 @@ package qilin.core.pag; -import sootup.core.views.View; +import soot.jimple.spark.pag.SparkField; public class FieldValNode extends ValNode { // note, field could only be ArrayElement or Field type. // Parm should be a local variable in some methods. private final SparkField field; - public FieldValNode(View view, SparkField field) { - super(view, field.getType()); + public FieldValNode(SparkField field) { + super(field.getType()); this.field = field; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java index 6524251dbc5..21303c257c5 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java @@ -18,11 +18,9 @@ package qilin.core.pag; - -import sootup.core.model.SootClass; -import sootup.core.model.SootField; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.SootClass; +import soot.SootField; +import soot.Type; /** * Represents a simple variable node in the pointer assignment graph that is not associated with any particular @@ -31,8 +29,8 @@ * @author Ondrej Lhotak */ public class GlobalVarNode extends VarNode { - public GlobalVarNode(View view, Object variable, Type t) { - super(view, variable, t); + public GlobalVarNode(Object variable, Type t) { + super(variable, t); } @Override @@ -45,8 +43,8 @@ public String toString() { } public SootClass getDeclaringClass() { - if (variable instanceof SootField sootField) { - return (SootClass) view.getClass(sootField.getDeclaringClassType()).get(); + if (variable instanceof SootField) { + return ((SootField) variable).getDeclaringClass(); } return null; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java index 64692d104fa..39796873515 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java @@ -18,9 +18,8 @@ package qilin.core.pag; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.SootMethod; +import soot.Type; /** * @author Ondrej Lhotak @@ -28,8 +27,8 @@ public class LocalVarNode extends VarNode { protected SootMethod method; - public LocalVarNode(View view, Object variable, Type t, SootMethod m) { - super(view, variable, t); + public LocalVarNode(Object variable, Type t, SootMethod m) { + super(variable, t); this.method = m; } @@ -51,6 +50,13 @@ public boolean isThis() { return false; } + public boolean isReturn() { + if (variable instanceof Parm parm) { + return parm.isReturn(); + } + return false; + } + @Override public VarNode base() { return this; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java index 7dd9fc02601..e8229b92e8c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java @@ -1,19 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + package qilin.core.pag; import qilin.util.DataFactory; -import sootup.core.types.ReferenceType; +import soot.RefLikeType; import java.util.Map; public class MergedNewExpr { - private final ReferenceType type; - private static final Map map = DataFactory.createMap(); + private final RefLikeType type; + private static final Map map = DataFactory.createMap(); - private MergedNewExpr(ReferenceType type) { + private MergedNewExpr(RefLikeType type) { this.type = type; } - public static MergedNewExpr v(ReferenceType type) { + public static MergedNewExpr v(RefLikeType type) { return map.computeIfAbsent(type, k -> new MergedNewExpr(type)); } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index 242382ed081..bd41e95d512 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -22,21 +22,14 @@ import qilin.util.DataFactory; import qilin.core.builder.MethodNodeFactory; import qilin.util.PTAUtils; - -import qilin.util.queue.ChunkedQueue; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.Jimple; -import sootup.core.jimple.basic.Trap; -import sootup.core.jimple.common.ref.JStaticFieldRef; -import sootup.core.jimple.common.stmt.JThrowStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.Body; -import sootup.core.model.SootClass; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.core.views.View; -import sootup.java.core.JavaIdentifierFactory; +import soot.*; +import soot.jimple.Jimple; +import soot.jimple.StaticFieldRef; +import soot.jimple.Stmt; +import soot.jimple.ThrowStmt; +import soot.util.Chain; +import soot.util.queue.ChunkedQueue; +import soot.util.queue.QueueReader; import java.util.*; @@ -49,7 +42,7 @@ public class MethodPAG { private final ChunkedQueue internalEdges = new ChunkedQueue<>(); private final QueueReader internalReader = internalEdges.reader(); private final Set clinits = DataFactory.createSet(); - private final Collection invokeStmts = DataFactory.createSet(); + private final Collection invokeStmts = DataFactory.createSet(); public Body body; /** * Since now the exception analysis is handled on-the-fly, we should record the @@ -57,7 +50,6 @@ public class MethodPAG { */ private final Map> exceptionEdges = DataFactory.createMap(); protected MethodNodeFactory nodeFactory; - protected PAG pag; SootMethod method; /* * List[i-1] is wrappered in List[i]. @@ -69,7 +61,6 @@ public class MethodPAG { public final Map>> node2wrapperedTraps = DataFactory.createMap(); public MethodPAG(PAG pag, SootMethod m, Body body) { - this.pag = pag; this.method = m; this.nodeFactory = new MethodNodeFactory(pag, this); this.body = body; @@ -84,11 +75,11 @@ public MethodNodeFactory nodeFactory() { return nodeFactory; } - public Collection getInvokeStmts() { + public Collection getInvokeStmts() { return invokeStmts; } - public boolean addCallStmt(Stmt unit) { + public boolean addCallStmt(Unit unit) { return this.invokeStmts.add(unit); } @@ -104,14 +95,11 @@ protected void build() { protected void buildNormal() { if (method.isStatic()) { - View view = pag.getView(); - ClassType declClassType = method.getDeclaringClassType(); - SootClass declClass = (SootClass) view.getClass(declClassType).get(); - PTAUtils.clinitsOf(declClass).forEach(this::addTriggeredClinit); + PTAUtils.clinitsOf(method.getDeclaringClass()).forEach(this::addTriggeredClinit); } - for (Stmt unit : body.getStmts()) { + for (Unit unit : body.getUnits()) { try { - nodeFactory.handleStmt(unit); + nodeFactory.handleStmt((Stmt) unit); } catch (Exception e) { System.out.println("Warning:" + e); } @@ -123,24 +111,24 @@ protected void buildException() { if (!CoreConfig.v().getPtaConfig().preciseExceptions) { return; } - List traps = body.getTraps(); - List units = body.getStmts(); - Set inTraps = DataFactory.createSet(); + Chain traps = body.getTraps(); + PatchingChain units = body.getUnits(); + Set inTraps = DataFactory.createSet(); /* * The traps is already visited in order. , ; implies is a previous Trap of . * */ traps.forEach(trap -> { - units.iterator().forEachRemaining(unit -> { - if (unit == trap.getEndStmt()) { + units.iterator(trap.getBeginUnit(), trap.getEndUnit()).forEachRemaining(unit -> { + if (unit == trap.getEndUnit()) { return; } inTraps.add(unit); - Stmt stmt = unit; + Stmt stmt = (Stmt) unit; Node src = null; if (stmt.containsInvokeExpr()) { // note, method.getExceptions() does not return implicit exceptions. src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); - } else if (stmt instanceof JThrowStmt ts) { + } else if (stmt instanceof ThrowStmt ts) { src = nodeFactory.getNode(ts.getOp()); } if (src != null) { @@ -149,7 +137,7 @@ protected void buildException() { }); }); - for (Stmt unit : body.getStmts()) { + for (Unit unit : body.getUnits()) { if (inTraps.contains(unit)) { continue; } @@ -157,7 +145,7 @@ protected void buildException() { Node src = null; if (stmt.containsInvokeExpr()) { src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); - } else if (stmt instanceof JThrowStmt ts) { + } else if (stmt instanceof ThrowStmt ts) { src = nodeFactory.getNode(ts.getOp()); } if (src != null) { @@ -177,11 +165,7 @@ private void addStmtTrap(Node src, Stmt stmt, Trap trap) { protected void addMiscEdges() { if (method.getSignature().equals("(java.lang.Object,java.lang.ref.ReferenceQueue)>")) { // Implements the special status of java.lang.ref.Reference just as in Doop (library/reference.logic). - ClassType type = (ClassType) JavaIdentifierFactory.getInstance().getType("java.lang.ref.Reference"); - View view = pag.getView(); - SootClass sootClass = (SootClass) view.getClass(type).get(); - SootField sootField = (SootField) sootClass.getField("pending").get(); - JStaticFieldRef sfr = Jimple.newStaticFieldRef(sootField.getSignature()); + StaticFieldRef sfr = Jimple.v().newStaticFieldRef(RefType.v("java.lang.ref.Reference").getSootClass().getFieldByName("pending").makeRef()); addInternalEdge(nodeFactory.caseThis(), nodeFactory.getNode(sfr)); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Node.java b/sootup.qilin/src/main/java/qilin/core/pag/Node.java index 09877c8e3aa..1707b0f76ad 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Node.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Node.java @@ -19,10 +19,9 @@ package qilin.core.pag; import qilin.core.sets.DoublePointsToSet; -import qilin.core.util.Numberable; import qilin.util.PTAUtils; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.Type; +import soot.util.Numberable; /** * Represents every node in the pointer assignment graph. @@ -30,7 +29,6 @@ * @author Ondrej Lhotak */ public class Node implements Numberable { - protected View view; protected Type type; protected DoublePointsToSet p2set; private int number = 0; @@ -38,11 +36,10 @@ public class Node implements Numberable { /** * Creates a new node of pointer assignment graph pag, with type type. */ - protected Node(View view, Type type) { + protected Node(Type type) { if (PTAUtils.isUnresolved(type)) { throw new RuntimeException("Unresolved type " + type); } - this.view = view; this.type = type; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 44dc038a21a..c74bc62a75d 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -22,35 +22,22 @@ import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.PointsToAnalysis; -import qilin.core.context.Context; import qilin.core.natives.NativeMethodDriver; import qilin.core.reflection.NopReflectionModel; import qilin.core.reflection.ReflectionModel; import qilin.core.reflection.TamiflexModel; -import qilin.core.util.ArrayNumberer; import qilin.parm.heapabst.HeapAbstractor; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import qilin.util.queue.ChunkedQueue; -import qilin.util.queue.QueueReader; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.Jimple; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.StmtPositionInfo; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.ClassConstant; -import sootup.core.jimple.common.constant.IntConstant; -import sootup.core.jimple.common.constant.StringConstant; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.ref.JArrayRef; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.Body; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; -import sootup.core.views.View; -import sootup.java.core.language.JavaJimple; +import soot.*; +import soot.jimple.*; +import soot.jimple.internal.JArrayRef; +import soot.jimple.internal.JAssignStmt; +import soot.jimple.internal.JimpleLocal; +import soot.jimple.spark.pag.SparkField; +import soot.util.ArrayNumberer; +import soot.util.queue.ChunkedQueue; +import soot.util.queue.QueueReader; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -68,7 +55,7 @@ public class PAG { // ========================= context-sensitive nodes ================================= protected final Map> contextVarNodeMap; protected final Map> contextAllocNodeMap; - protected final Map> contextMethodMap; + protected final Map> contextMethodMap; protected final Map> addedContexts; protected final Map> contextFieldMap; @@ -96,11 +83,9 @@ public class PAG { protected final Map> store; protected final Map> storeInv; - protected final View view; protected final PTA pta; - public PAG(View view, PTA pta) { - this.view = view; + public PAG(PTA pta) { this.pta = pta; this.simple = DataFactory.createMap(); this.simpleInv = DataFactory.createMap(); @@ -124,10 +109,6 @@ public PAG(View view, PTA pta) { this.locals = DataFactory.createSet(100000); } - public View getView() { - return this.view; - } - public void setEdgeQueue(ChunkedQueue edgeQueue) { this.edgeQueue = edgeQueue; } @@ -313,7 +294,7 @@ public AllocNode findAllocNode(Object obj) { public AllocNode makeAllocNode(Object newExpr, Type type, SootMethod m) { AllocNode ret = valToAllocNode.get(newExpr); if (ret == null) { - valToAllocNode.put(newExpr, ret = new AllocNode(view, newExpr, type, m)); + valToAllocNode.put(newExpr, ret = new AllocNode(newExpr, type, m)); allocNodeNumberer.add(ret); } else if (!(ret.getType().equals(type))) { throw new RuntimeException("NewExpr " + newExpr + " of type " + type + " previously had type " + ret.getType()); @@ -324,11 +305,11 @@ public AllocNode makeAllocNode(Object newExpr, Type type, SootMethod m) { public AllocNode makeStringConstantNode(StringConstant sc) { StringConstant stringConstant = sc; if (!CoreConfig.v().getPtaConfig().stringConstants) { - stringConstant = JavaJimple.getInstance().newStringConstant(PointsToAnalysis.STRING_NODE); + stringConstant = StringConstant.v(PointsToAnalysis.STRING_NODE); } AllocNode ret = valToAllocNode.get(stringConstant); if (ret == null) { - valToAllocNode.put(stringConstant, ret = new StringConstantNode(view, stringConstant)); + valToAllocNode.put(stringConstant, ret = new StringConstantNode(stringConstant)); allocNodeNumberer.add(ret); } return ret; @@ -337,7 +318,7 @@ public AllocNode makeStringConstantNode(StringConstant sc) { public AllocNode makeClassConstantNode(ClassConstant cc) { AllocNode ret = valToAllocNode.get(cc); if (ret == null) { - valToAllocNode.put(cc, ret = new ClassConstantNode(view, cc)); + valToAllocNode.put(cc, ret = new ClassConstantNode(cc)); allocNodeNumberer.add(ret); } return ret; @@ -349,7 +330,7 @@ public AllocNode makeClassConstantNode(ClassConstant cc) { public GlobalVarNode makeGlobalVarNode(Object value, Type type) { GlobalVarNode ret = (GlobalVarNode) valToValNode.get(value); if (ret == null) { - ret = (GlobalVarNode) valToValNode.computeIfAbsent(value, k -> new GlobalVarNode(view, value, type)); + ret = (GlobalVarNode) valToValNode.computeIfAbsent(value, k -> new GlobalVarNode(value, type)); valNodeNumberer.add(ret); if (value instanceof SootField) { globals.add((SootField) value); @@ -366,12 +347,12 @@ public GlobalVarNode makeGlobalVarNode(Object value, Type type) { public LocalVarNode makeLocalVarNode(Object value, Type type, SootMethod method) { LocalVarNode ret = (LocalVarNode) valToValNode.get(value); if (ret == null) { - valToValNode.put(value, ret = new LocalVarNode(view, value, type, method)); + valToValNode.put(value, ret = new LocalVarNode(value, type, method)); valNodeNumberer.add(ret); if (value instanceof Local local) { -// if (local.getNumber() == 0) { -// PTAScene.v().getLocalNumberer().add(local); -// } + if (local.getNumber() == 0) { + PTAScene.v().getLocalNumberer().add(local); + } locals.add(local); } } else if (!(ret.getType().equals(type))) { @@ -387,7 +368,7 @@ public LocalVarNode makeLocalVarNode(Object value, Type type, SootMethod method) public FieldValNode makeFieldValNode(SparkField field) { FieldValNode ret = (FieldValNode) valToValNode.get(field); if (ret == null) { - valToValNode.put(field, ret = new FieldValNode(view, field)); + valToValNode.put(field, ret = new FieldValNode(field)); valNodeNumberer.add(ret); } return ret; @@ -400,7 +381,7 @@ public FieldValNode makeFieldValNode(SparkField field) { public FieldRefNode makeFieldRefNode(VarNode base, SparkField field) { FieldRefNode ret = base.dot(field); if (ret == null) { - ret = new FieldRefNode(view, base, field); + ret = new FieldRefNode(base, field); fieldRefNodeNumberer.add(ret); } return ret; @@ -413,7 +394,7 @@ public ContextVarNode makeContextVarNode(VarNode base, Context context) { Map contextMap = contextVarNodeMap.computeIfAbsent(base, k1 -> DataFactory.createMap()); ContextVarNode ret = contextMap.get(context); if (ret == null) { - contextMap.put(context, ret = new ContextVarNode(view, base, context)); + contextMap.put(context, ret = new ContextVarNode(base, context)); valNodeNumberer.add(ret); } return ret; @@ -426,7 +407,7 @@ public ContextAllocNode makeContextAllocNode(AllocNode allocNode, Context contex Map contextMap = contextAllocNodeMap.computeIfAbsent(allocNode, k1 -> DataFactory.createMap()); ContextAllocNode ret = contextMap.get(context); if (ret == null) { - contextMap.put(context, ret = new ContextAllocNode(view, allocNode, context)); + contextMap.put(context, ret = new ContextAllocNode(allocNode, context)); allocNodeNumberer.add(ret); } return ret; @@ -435,8 +416,8 @@ public ContextAllocNode makeContextAllocNode(AllocNode allocNode, Context contex /** * Finds or creates the ContextMethod for method and context. */ - public ContextMethod makeContextMethod(Context context, SootMethod method) { - Map contextMap = contextMethodMap.computeIfAbsent(method, k1 -> DataFactory.createMap()); + public MethodOrMethodContext makeContextMethod(Context context, SootMethod method) { + Map contextMap = contextMethodMap.computeIfAbsent(method, k1 -> DataFactory.createMap()); return contextMap.computeIfAbsent(context, k -> new ContextMethod(method, context)); } @@ -464,7 +445,7 @@ public Map> getContextAllocNodeMap() { return contextAllocNodeMap; } - public Map> getContextMethodMap() { + public Map> getContextMethodMap() { return contextMethodMap; } @@ -477,7 +458,7 @@ public ContextField makeContextField(Context context, FieldValNode fieldValNode) Map field2odotf = contextFieldMap.computeIfAbsent(context, k -> DataFactory.createMap()); ContextField ret = field2odotf.get(field); if (ret == null) { - field2odotf.put(field, ret = new ContextField(view, context, field)); + field2odotf.put(field, ret = new ContextField(context, field)); valNodeNumberer.add(ret); } return ret; @@ -523,7 +504,7 @@ public ContextVarNode findContextVarNode(Local baseValue, Context context) { protected ReflectionModel createReflectionModel() { ReflectionModel model; if (CoreConfig.v().getAppConfig().REFLECTION_LOG != null && CoreConfig.v().getAppConfig().REFLECTION_LOG.length() > 0) { - model = new TamiflexModel(view); + model = new TamiflexModel(); } else { model = new NopReflectionModel(); } @@ -561,24 +542,25 @@ public MethodPAG getMethodPAG(SootMethod m) { } private void handleArrayCopy(SootMethod method) { - Map> newUnits = DataFactory.createMap(); - IdentifierFactory identifierFactory = view.getIdentifierFactory(); + Map> newUnits = DataFactory.createMap(); Body body = PTAUtils.getMethodBody(method); - for (Stmt s : body.getStmts()) { + for (Unit unit : body.getUnits()) { + Stmt s = (Stmt) unit; if (s.containsInvokeExpr()) { - AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); - if (invokeExpr instanceof JStaticInvokeExpr sie) { - String sig = sie.getMethodSignature().toString(); + InvokeExpr invokeExpr = s.getInvokeExpr(); + if (invokeExpr instanceof StaticInvokeExpr sie) { + SootMethod sm = sie.getMethod(); + String sig = sm.getSignature(); if (sig.equals("")) { Value srcArr = sie.getArg(0); if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { continue; } - Type objType = identifierFactory.getType("java.lang.Object"); + Type objType = RefType.v("java.lang.Object"); if (srcArr.getType() == objType) { - Local localSrc = Jimple.newLocal("intermediate/" + body.getLocalCount(), identifierFactory.getArrayType(objType, 1)); + Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); body.getLocals().add(localSrc); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(Jimple.newAssignStmt(localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr)); srcArr = localSrc; } Value dstArr = sie.getArg(2); @@ -586,28 +568,28 @@ private void handleArrayCopy(SootMethod method) { continue; } if (dstArr.getType() == objType) { - Local localDst = Jimple.newLocal("intermediate/" + body.getLocalCount(), identifierFactory.getArrayType(objType, 1)); + Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); body.getLocals().add(localDst); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(Jimple.newAssignStmt(localDst, dstArr, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr)); dstArr = localDst; } - Value src = new JArrayRef((Local) srcArr, IntConstant.getInstance(0), identifierFactory); - Value dst = new JArrayRef((Local) dstArr, IntConstant.getInstance(0), identifierFactory); - Local local = Jimple.newLocal("nativeArrayCopy" + body.getLocalCount(), identifierFactory.getType("java.lang.Object")); + Value src = new JArrayRef(srcArr, IntConstant.v(0)); + Value dst = new JArrayRef(dstArr, IntConstant.v(0)); + Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), RefType.v("java.lang.Object")); body.getLocals().add(local); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(Jimple.newAssignStmt(local, src, StmtPositionInfo.createNoStmtPositionInfo())); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(Jimple.newAssignStmt(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(unit, k -> DataFactory.createSet()).add(new JAssignStmt(local, src)); + newUnits.computeIfAbsent(unit, k -> DataFactory.createSet()).add(new JAssignStmt(dst, local)); } } } } - for (Stmt unit : newUnits.keySet()) { + for (Unit unit : newUnits.keySet()) { body.getUnits().insertAfter(newUnits.get(unit), unit); } } public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { - return makeLocalVarNode(invoke, view.getIdentifierFactory().getType("java.lang.Throwable"), method); + return makeLocalVarNode(invoke, RefType.v("java.lang.Throwable"), method); } public HeapAbstractor heapAbstractor() { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java index 12b8c6aae9a..f35918a85c8 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java @@ -19,9 +19,9 @@ package qilin.core.pag; import qilin.core.PointsToAnalysis; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; -import sootup.java.core.JavaIdentifierFactory; +import soot.RefType; +import soot.SootMethod; +import soot.Type; import java.util.Objects; @@ -69,7 +69,7 @@ public Type getType() { if (index == PointsToAnalysis.RETURN_NODE) { return method.getReturnType(); } else if (index == PointsToAnalysis.THIS_NODE) { - return method.isStatic() ? JavaIdentifierFactory.getInstance().getType("java.lang.Object") : method.getDeclaringClassType(); + return method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClass().getType(); } return method.getParameterType(index); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java deleted file mode 100644 index ce3593a9f66..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java +++ /dev/null @@ -1,8 +0,0 @@ -package qilin.core.pag; - -import qilin.core.util.Numberable; -import sootup.core.types.Type; - -public interface SparkField extends Numberable { - public Type getType(); -} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java index cdf1ee456e1..1c5a574d99f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java @@ -18,8 +18,8 @@ package qilin.core.pag; -import sootup.core.jimple.common.constant.StringConstant; -import sootup.core.views.View; +import soot.RefType; +import soot.jimple.StringConstant; /** * Represents an allocation site node the represents a constant string. @@ -27,8 +27,8 @@ * @author Ondrej Lhotak */ public class StringConstantNode extends ConstantNode { - public StringConstantNode(View view, StringConstant sc) { - super(view, sc, view.getIdentifierFactory().getType("java.lang.String"), null); + public StringConstantNode(StringConstant sc) { + super(sc, RefType.v("java.lang.String"), null); } public String toString() { @@ -36,6 +36,6 @@ public String toString() { } public String getString() { - return ((StringConstant) newExpr).getValue(); + return ((StringConstant) newExpr).value; } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java index ef63d8aae18..ea1690b5b23 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java @@ -19,17 +19,16 @@ package qilin.core.pag; import qilin.core.sets.DoublePointsToSet; -import qilin.core.util.Numberable; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.Type; +import soot.util.Numberable; /** * Represents a simple of pointer node in the pointer assignment graph. */ public class ValNode extends Node implements Comparable, Numberable { - protected ValNode(View view, Type t) { - super(view, t); + protected ValNode(Type t) { + super(t); } public int compareTo(Object o) { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java index 446a8f6e935..86e37d8cf4f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java @@ -18,11 +18,12 @@ package qilin.core.pag; -import qilin.core.context.Context; import qilin.util.DataFactory; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.AnySubType; +import soot.Context; +import soot.RefLikeType; +import soot.Type; +import soot.jimple.spark.pag.SparkField; import java.util.Collection; import java.util.Collections; @@ -40,9 +41,9 @@ public abstract class VarNode extends ValNode { protected boolean interProcTarget = false; protected boolean interProcSource = false; - protected VarNode(View view, Object variable, Type t) { - super(view, t); - if (!(t instanceof ReferenceType)) { + protected VarNode(Object variable, Type t) { + super(t); + if (!(t instanceof RefLikeType) || t instanceof AnySubType) { throw new RuntimeException("Attempt to create VarNode of type " + t); } this.variable = variable; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java index 47af935eb7b..b7c7aad4237 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java @@ -18,10 +18,11 @@ package qilin.core.pag; -import qilin.core.callgraph.Kind; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.signatures.MethodSubSignature; +import soot.Kind; +import soot.MethodOrMethodContext; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.Stmt; +import soot.util.NumberedString; import java.util.Objects; @@ -32,13 +33,13 @@ */ public class VirtualCallSite extends CallSite { private final VarNode recNode; - private final ContextMethod container; - private final AbstractInstanceInvokeExpr iie; - private final MethodSubSignature subSig; + private final MethodOrMethodContext container; + private final InstanceInvokeExpr iie; + private final NumberedString subSig; private final Kind kind; - public VirtualCallSite(VarNode recNode, Stmt stmt, ContextMethod container, AbstractInstanceInvokeExpr iie, - MethodSubSignature subSig, Kind kind) { + public VirtualCallSite(VarNode recNode, Stmt stmt, MethodOrMethodContext container, InstanceInvokeExpr iie, + NumberedString subSig, Kind kind) { super(stmt); this.recNode = recNode; this.container = container; @@ -51,15 +52,15 @@ public VarNode recNode() { return recNode; } - public ContextMethod container() { + public MethodOrMethodContext container() { return container; } - public AbstractInstanceInvokeExpr iie() { + public InstanceInvokeExpr iie() { return iie; } - public MethodSubSignature subSig() { + public NumberedString subSig() { return subSig; } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java index a144beb3e32..d2a03d6cc1f 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java @@ -18,8 +18,8 @@ package qilin.core.reflection; - -import sootup.core.jimple.common.stmt.Stmt; +import soot.Unit; +import soot.jimple.Stmt; import java.util.Collection; import java.util.Collections; @@ -31,47 +31,47 @@ public class NopReflectionModel extends ReflectionModel { @Override - Collection transformClassForName(Stmt s) { + Collection transformClassForName(Stmt s) { return Collections.emptySet(); } @Override - Collection transformClassNewInstance(Stmt s) { + Collection transformClassNewInstance(Stmt s) { return Collections.emptySet(); } @Override - Collection transformContructorNewInstance(Stmt s) { + Collection transformContructorNewInstance(Stmt s) { return Collections.emptySet(); } @Override - Collection transformMethodInvoke(Stmt s) { + Collection transformMethodInvoke(Stmt s) { return Collections.emptySet(); } @Override - Collection transformFieldSet(Stmt s) { + Collection transformFieldSet(Stmt s) { return Collections.emptySet(); } @Override - Collection transformFieldGet(Stmt s) { + Collection transformFieldGet(Stmt s) { return Collections.emptySet(); } @Override - Collection transformArrayNewInstance(Stmt s) { + Collection transformArrayNewInstance(Stmt s) { return Collections.emptySet(); } @Override - Collection transformArrayGet(Stmt s) { + Collection transformArrayGet(Stmt s) { return Collections.emptySet(); } @Override - Collection transformArraySet(Stmt s) { + Collection transformArraySet(Stmt s) { return Collections.emptySet(); } } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index 61cf207ab96..1c46a6fe5a8 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -21,13 +21,14 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Unit; +import soot.UnitPatchingChain; +import soot.jimple.InvokeExpr; +import soot.jimple.Stmt; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.Map; public abstract class ReflectionModel { @@ -50,9 +51,9 @@ public abstract class ReflectionModel { protected final String sigReifiedMethodArray = ""; protected final String sigReifiedDeclaredMethodArray = ""; - private Collection transform(Stmt s) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - return switch (ie.getMethodSignature().toString()) { + private Collection transform(Stmt s) { + InvokeExpr ie = s.getInvokeExpr(); + return switch (ie.getMethodRef().getSignature()) { case sigForName, sigForName2 -> transformClassForName(s); case sigClassNewInstance -> transformClassNewInstance(s); case sigConstructorNewInstance -> transformContructorNewInstance(s); @@ -73,33 +74,34 @@ public void buildReflection(SootMethod m) { if (!PTAScene.v().reflectionBuilt.add(m)) { return; } - Map> newUnits = DataFactory.createMap(); - List units = PTAUtils.getMethodBody(m).getStmts(); - for (final Stmt s : units) { + Map> newUnits = DataFactory.createMap(); + UnitPatchingChain units = PTAUtils.getMethodBody(m).getUnits(); + for (final Unit u : units) { + final Stmt s = (Stmt) u; if (s.containsInvokeExpr()) { - newUnits.put(s, transform(s)); + newUnits.put(u, transform(s)); } } - for (Stmt unit : newUnits.keySet()) { + for (Unit unit : newUnits.keySet()) { units.insertAfter(newUnits.get(unit), unit); } } - abstract Collection transformClassForName(Stmt s); + abstract Collection transformClassForName(Stmt s); - abstract Collection transformClassNewInstance(Stmt s); + abstract Collection transformClassNewInstance(Stmt s); - abstract Collection transformContructorNewInstance(Stmt s); + abstract Collection transformContructorNewInstance(Stmt s); - abstract Collection transformMethodInvoke(Stmt s); + abstract Collection transformMethodInvoke(Stmt s); - abstract Collection transformFieldSet(Stmt s); + abstract Collection transformFieldSet(Stmt s); - abstract Collection transformFieldGet(Stmt s); + abstract Collection transformFieldGet(Stmt s); - abstract Collection transformArrayNewInstance(Stmt s); + abstract Collection transformArrayNewInstance(Stmt s); - abstract Collection transformArrayGet(Stmt s); + abstract Collection transformArrayGet(Stmt s); - abstract Collection transformArraySet(Stmt s); + abstract Collection transformArraySet(Stmt s); } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index 7287939707b..b120591f0d6 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -22,34 +22,10 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.Jimple; -import sootup.core.jimple.basic.Immediate; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.StmtPositionInfo; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.ClassConstant; -import sootup.core.jimple.common.constant.IntConstant; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JNewArrayExpr; -import sootup.core.jimple.common.expr.JNewExpr; -import sootup.core.jimple.common.ref.JArrayRef; -import sootup.core.jimple.common.ref.JFieldRef; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.Body; -import sootup.core.model.Position; -import sootup.core.model.SootClass; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; -import sootup.core.signatures.FieldSignature; -import sootup.core.signatures.MethodSubSignature; -import sootup.core.types.ArrayType; -import sootup.core.types.ReferenceType; -import sootup.core.views.View; -import sootup.java.core.JavaIdentifierFactory; -import sootup.java.core.language.JavaJimple; +import soot.*; +import soot.jimple.*; +import soot.jimple.internal.*; +import soot.tagkit.LineNumberTag; import java.io.BufferedReader; import java.io.FileInputStream; @@ -62,28 +38,27 @@ */ public class TamiflexModel extends ReflectionModel { - protected View view; protected Map>> reflectionMap; - public TamiflexModel(View view) { - this.view = view; + public TamiflexModel() { reflectionMap = DataFactory.createMap(); - parseTamiflexLog(CoreConfig.v().getAppConfig().REFLECTION_LOG, false); + parseTamiflexLog(CoreConfig.v().getAppConfig().REFLECTION_LOG, true); } @Override - Collection transformClassForName(Stmt s) { + Collection transformClassForName(Stmt s) { // // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> classForNames = reflectionMap.getOrDefault(ReflectionKind.ClassForName, Collections.emptyMap()); if (classForNames.containsKey(s)) { Collection fornames = classForNames.get(s); for (String clazz : fornames) { - ClassConstant cc = JavaJimple.getInstance().newClassConstant(clazz); - if (s instanceof JAssignStmt jassign) { - Value lvalue = jassign.getLeftOp(); - ret.add(new JAssignStmt(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); + Type refType = RefType.v(clazz); + ClassConstant cc = ClassConstant.fromType(refType); + if (s instanceof AssignStmt) { + Value lvalue = ((AssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt(lvalue, cc)); } } } @@ -91,25 +66,23 @@ Collection transformClassForName(Stmt s) { } @Override - protected Collection transformClassNewInstance(Stmt s) { + protected Collection transformClassNewInstance(Stmt s) { // - if (!(s instanceof JAssignStmt)) { + if (!(s instanceof AssignStmt)) { return Collections.emptySet(); } - Value lvalue = ((JAssignStmt) s).getLeftOp(); - Collection ret = DataFactory.createSet(); + Value lvalue = ((AssignStmt) s).getLeftOp(); + Collection ret = DataFactory.createSet(); Map> classNewInstances = reflectionMap.getOrDefault(ReflectionKind.ClassNewInstance, Collections.emptyMap()); if (classNewInstances.containsKey(s)) { Collection classNames = classNewInstances.get(s); for (String clsName : classNames) { SootClass cls = PTAScene.v().getSootClass(clsName); - MethodSubSignature msubsig = view.getIdentifierFactory().parseMethodSubSignature("void ()"); - Optional constrOpt = cls.getMethod(msubsig); - if (constrOpt.isPresent()) { - JNewExpr newExpr = Jimple.newNewExpr(cls.getType()); - ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); - SootMethod constructor = constrOpt.get(); - ret.add(Jimple.newInvokeStmt(Jimple.newSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), Collections.emptyList()), StmtPositionInfo.createNoStmtPositionInfo())); + if (cls.declaresMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()"))) { + JNewExpr newExpr = new JNewExpr(cls.getType()); + ret.add(new JAssignStmt(lvalue, newExpr)); + SootMethod constructor = cls.getMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()")); + ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.makeRef(), Collections.emptyList()))); } } } @@ -117,74 +90,74 @@ protected Collection transformClassNewInstance(Stmt s) { } @Override - protected Collection transformContructorNewInstance(Stmt s) { + protected Collection transformContructorNewInstance(Stmt s) { // - if (!(s instanceof JAssignStmt)) { + if (!(s instanceof AssignStmt)) { return Collections.emptySet(); } - Value lvalue = ((JAssignStmt) s).getLeftOp(); - Collection ret = DataFactory.createSet(); + Value lvalue = ((AssignStmt) s).getLeftOp(); + Collection ret = DataFactory.createSet(); Map> constructorNewInstances = reflectionMap.getOrDefault(ReflectionKind.ConstructorNewInstance, Collections.emptyMap()); if (constructorNewInstances.containsKey(s)) { Collection constructorSignatures = constructorNewInstances.get(s); - AbstractInvokeExpr iie = s.getInvokeExpr(); + InvokeExpr iie = s.getInvokeExpr(); Value args = iie.getArg(0); - JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0), JavaIdentifierFactory.getInstance()); - Local arg = Jimple.newLocal("intermediate/" + arrayRef, JavaIdentifierFactory.getInstance().getType("java.lang.Object")); - ret.add(Jimple.newAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + ArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); + Value arg = new JimpleLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + ret.add(new JAssignStmt(arg, arrayRef)); for (String constructorSignature : constructorSignatures) { SootMethod constructor = PTAScene.v().getMethod(constructorSignature); - JNewExpr newExpr = new JNewExpr(constructor.getDeclaringClassType()); - ret.add(Jimple.newAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + SootClass cls = constructor.getDeclaringClass(); + JNewExpr newExpr = new JNewExpr(cls.getType()); + ret.add(new JAssignStmt(lvalue, newExpr)); int argCount = constructor.getParameterCount(); - List mArgs = new ArrayList<>(argCount); + List mArgs = new ArrayList<>(argCount); for (int i = 0; i < argCount; i++) { mArgs.add(arg); } - ret.add(Jimple.newInvokeStmt(Jimple.newSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), mArgs), StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.makeRef(), mArgs))); } } return ret; } @Override - protected Collection transformMethodInvoke(Stmt s) { + protected Collection transformMethodInvoke(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> methodInvokes = reflectionMap.getOrDefault(ReflectionKind.MethodInvoke, Collections.emptyMap()); if (methodInvokes.containsKey(s)) { Collection methodSignatures = methodInvokes.get(s); - AbstractInvokeExpr iie = s.getInvokeExpr(); + InvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); Value args = iie.getArg(1); - Local arg = null; + Value arg = null; if (args.getType() instanceof ArrayType) { - IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); - JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0), idFactory); - arg = Jimple.newLocal("intermediate/" + arrayRef, idFactory.getType("java.lang.Object")); - ret.add(Jimple.newAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + ArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); + arg = new JimpleLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + ret.add(new JAssignStmt(arg, arrayRef)); } for (String methodSignature : methodSignatures) { SootMethod method = PTAScene.v().getMethod(methodSignature); int argCount = method.getParameterCount(); - List mArgs = new ArrayList<>(argCount); + List mArgs = new ArrayList<>(argCount); for (int i = 0; i < argCount; i++) { mArgs.add(arg); } - AbstractInvokeExpr ie; + InvokeExpr ie; if (method.isStatic()) { assert base instanceof NullConstant; - ie = Jimple.newStaticInvokeExpr(method.getSignature(), mArgs); + ie = new JStaticInvokeExpr(method.makeRef(), mArgs); } else { assert !(base instanceof NullConstant); - ie = Jimple.newVirtualInvokeExpr((Local) base, method.getSignature(), mArgs); + ie = new JVirtualInvokeExpr(base, method.makeRef(), mArgs); } - if (s instanceof JAssignStmt jassign) { - Value lvalue = jassign.getLeftOp(); - ret.add(Jimple.newAssignStmt(lvalue, ie, StmtPositionInfo.createNoStmtPositionInfo())); + if (s instanceof AssignStmt) { + Value lvalue = ((AssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt(lvalue, ie)); } else { - ret.add(Jimple.newInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JInvokeStmt(ie)); } } } @@ -192,27 +165,26 @@ protected Collection transformMethodInvoke(Stmt s) { } @Override - protected Collection transformFieldSet(Stmt s) { + protected Collection transformFieldSet(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> fieldSets = reflectionMap.getOrDefault(ReflectionKind.FieldSet, Collections.emptyMap()); if (fieldSets.containsKey(s)) { Collection fieldSignatures = fieldSets.get(s); - AbstractInvokeExpr iie = s.getInvokeExpr(); + InvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); Value rValue = iie.getArg(1); for (String fieldSignature : fieldSignatures) { - FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); - SootField field = (SootField) view.getField(fieldSig).get(); - JFieldRef fieldRef; + SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + FieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; - fieldRef = Jimple.newStaticFieldRef(fieldSig); + fieldRef = Jimple.v().newStaticFieldRef(field.makeRef()); } else { assert !(base instanceof NullConstant); - fieldRef = Jimple.newInstanceFieldRef((Local) base, fieldSig); + fieldRef = new JInstanceFieldRef(base, field.makeRef()); } - Stmt stmt = Jimple.newAssignStmt(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + Stmt stmt = new JAssignStmt(fieldRef, rValue); ret.add(stmt); } } @@ -220,28 +192,27 @@ protected Collection transformFieldSet(Stmt s) { } @Override - protected Collection transformFieldGet(Stmt s) { + protected Collection transformFieldGet(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> fieldGets = reflectionMap.getOrDefault(ReflectionKind.FieldGet, Collections.emptyMap()); - if (fieldGets.containsKey(s) && s instanceof JAssignStmt) { + if (fieldGets.containsKey(s) && s instanceof AssignStmt) { Collection fieldSignatures = fieldGets.get(s); - Value lvalue = ((JAssignStmt) s).getLeftOp(); - AbstractInvokeExpr iie = s.getInvokeExpr(); + Value lvalue = ((AssignStmt) s).getLeftOp(); + InvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); for (String fieldSignature : fieldSignatures) { - FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); - SootField field = (SootField) view.getField(fieldSig).get(); - JFieldRef fieldRef; + SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + FieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; - fieldRef = Jimple.newStaticFieldRef(fieldSig); + fieldRef = Jimple.v().newStaticFieldRef(field.makeRef()); } else { assert !(base instanceof NullConstant); - fieldRef = Jimple.newInstanceFieldRef((Local) base, fieldSig); + fieldRef = new JInstanceFieldRef(base, field.makeRef()); } - if (fieldRef.getType() instanceof ReferenceType) { - Stmt stmt = Jimple.newAssignStmt(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); + if (fieldRef.getType() instanceof RefLikeType) { + Stmt stmt = new JAssignStmt(lvalue, fieldRef); ret.add(stmt); } } @@ -250,54 +221,53 @@ protected Collection transformFieldGet(Stmt s) { } @Override - protected Collection transformArrayNewInstance(Stmt s) { + protected Collection transformArrayNewInstance(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> mappedToArrayTypes = reflectionMap.getOrDefault(ReflectionKind.ArrayNewInstance, Collections.emptyMap()); Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); for (String arrayType : arrayTypes) { ArrayType at = (ArrayType) PTAScene.v().getTypeUnsafe(arrayType, true); - JNewArrayExpr newExpr = new JNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1), view.getIdentifierFactory()); - if (s instanceof JAssignStmt) { - Value lvalue = ((JAssignStmt) s).getLeftOp(); - ret.add(Jimple.newAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + JNewArrayExpr newExpr = new JNewArrayExpr(at.getElementType(), IntConstant.v(1)); + if (s instanceof AssignStmt) { + Value lvalue = ((AssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt(lvalue, newExpr)); } } return ret; } @Override - Collection transformArrayGet(Stmt s) { - Collection ret = DataFactory.createSet(); - AbstractInvokeExpr iie = s.getInvokeExpr(); + Collection transformArrayGet(Stmt s) { + Collection ret = DataFactory.createSet(); + InvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); - IdentifierFactory idFactory = view.getIdentifierFactory(); - if (s instanceof JAssignStmt) { - Value lvalue = ((JAssignStmt) s).getLeftOp(); + if (s instanceof AssignStmt) { + Value lvalue = ((AssignStmt) s).getLeftOp(); Value arrayRef = null; if (base.getType() instanceof ArrayType) { - arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0), idFactory); - } else if (base.getType() == idFactory.getType("java.lang.Object")) { - Local local = Jimple.newLocal("intermediate/" + base, idFactory.getArrayType(idFactory.getType("java.lang.Object"), 1)); - ret.add(Jimple.newAssignStmt(local, base, StmtPositionInfo.createNoStmtPositionInfo())); - arrayRef = new JArrayRef(local, IntConstant.getInstance(0), idFactory); + arrayRef = new JArrayRef(base, IntConstant.v(0)); + } else if (base.getType() == RefType.v("java.lang.Object")) { + Local local = new JimpleLocal("intermediate/" + base, ArrayType.v(RefType.v("java.lang.Object"), 1)); + ret.add(new JAssignStmt(local, base)); + arrayRef = new JArrayRef(local, IntConstant.v(0)); } if (arrayRef != null) { - ret.add(Jimple.newAssignStmt(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JAssignStmt(lvalue, arrayRef)); } } return ret; } @Override - Collection transformArraySet(Stmt s) { - Collection ret = DataFactory.createSet(); - AbstractInvokeExpr iie = s.getInvokeExpr(); + Collection transformArraySet(Stmt s) { + Collection ret = DataFactory.createSet(); + InvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); if (base.getType() instanceof ArrayType) { Value from = iie.getArg(2); - Value arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0), view.getIdentifierFactory()); - ret.add(Jimple.newAssignStmt(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); + Value arrayRef = new JArrayRef(base, IntConstant.v(0)); + ret.add(new JAssignStmt(arrayRef, from)); } return ret; } @@ -386,10 +356,9 @@ private Collection inferSourceMethod(String inClzDotMthd) { } SootClass sootClass = PTAScene.v().getSootClass(inClassStr); Set ret = DataFactory.createSet(); - for (Object m: sootClass.getMethods()) { - SootMethod sm = (SootMethod) m; - if (sm.isConcrete() && sm.getName().equals(inMethodStr)) { - ret.add(sm); + for (SootMethod m : sootClass.getMethods()) { + if (m.isConcrete() && m.getName().equals(inMethodStr)) { + ret.add(m); } } return ret; @@ -401,18 +370,20 @@ private Collection inferSourceStmt(String inClzDotMthd, ReflectionKind kin Collection sourceMethods = inferSourceMethod(inClzDotMthd); for (SootMethod sm : sourceMethods) { Body body = PTAUtils.getMethodBody(sm); - for (Stmt stmt : body.getStmts()) { - if (stmt.containsInvokeExpr()) { - String methodSig = stmt.getInvokeExpr().getMethodSignature().toString(); - if (matchReflectionKind(kind, methodSig)) { - potential.add(stmt); - } - } + for (Unit u : body.getUnits()) { + if (u instanceof Stmt stmt) { + if (stmt.containsInvokeExpr()) { + String methodSig = stmt.getInvokeExpr().getMethodRef().getSignature(); + if (matchReflectionKind(kind, methodSig)) { + potential.add(stmt); + } + } + } } } for (Stmt stmt : potential) { - Position pos = stmt.getPositionInfo().getStmtPosition(); - if (lineNumber < 0 || pos != null && pos.getLastLine() >= lineNumber && pos.getFirstLine() <= lineNumber) { + LineNumberTag tag = (LineNumberTag) stmt.getTag("LineNumberTag"); + if (lineNumber < 0 || tag != null && tag.getLineNumber() == lineNumber) { ret.add(stmt); } } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java index cac5754cb90..d38f8c7de83 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java @@ -18,8 +18,8 @@ package qilin.core.sets; -import qilin.core.util.BitSetIterator; -import qilin.core.util.BitVector; +import soot.util.BitSetIterator; +import soot.util.BitVector; import java.util.Arrays; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java index e70092569d4..e608a16a634 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java @@ -19,8 +19,8 @@ package qilin.core.sets; import qilin.core.pag.AllocNode; -import sootup.core.jimple.common.constant.ClassConstant; -import sootup.core.types.Type; +import soot.Type; +import soot.jimple.ClassConstant; import java.util.Collection; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java index a1aa81fbc89..c820fbd7fe1 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java @@ -1,3 +1,21 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + package qilin.core.sets; import qilin.core.PTA; @@ -5,11 +23,9 @@ import qilin.core.pag.ClassConstantNode; import qilin.core.pag.Node; import qilin.core.pag.StringConstantNode; -import sootup.core.jimple.common.constant.ClassConstant; -import sootup.core.model.SootClass; -import sootup.core.types.ClassType; -import sootup.core.types.Type; -import sootup.core.views.View; +import soot.RefType; +import soot.Type; +import soot.jimple.ClassConstant; import java.util.*; @@ -46,10 +62,8 @@ public Set possibleTypes() { pts.forall(new P2SetVisitor(pta) { public void visit(Node n) { Type t = n.getType(); - if (t instanceof ClassType rt) { - View view = pta.getPag().getView(); - SootClass sootClass = (SootClass) view.getClass(rt).get(); - if (sootClass.isAbstract()) { + if (t instanceof RefType rt) { + if (rt.getSootClass().isAbstract()) { return; } } diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index ccbbfc60370..075938491ef 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -24,26 +24,20 @@ import qilin.core.builder.CallGraphBuilder; import qilin.core.builder.ExceptionHandler; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.Edge; -import qilin.core.callgraph.Kind; -import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.DoublePointsToSet; +import qilin.core.sets.HybridPointsToSet; import qilin.core.sets.P2SetVisitor; import qilin.core.sets.PointsToSetInternal; import qilin.util.PTAUtils; -import qilin.util.queue.ChunkedQueue; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JDynamicInvokeExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.stmt.JThrowStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.signatures.MethodSignature; -import sootup.core.signatures.MethodSubSignature; +import soot.*; +import soot.jimple.*; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.Edge; +import soot.options.Options; +import soot.util.NumberedString; +import soot.util.queue.ChunkedQueue; +import soot.util.queue.QueueReader; import java.util.*; @@ -57,7 +51,7 @@ public class Solver extends Propagator { private final ChunkedQueue virtualCallSiteQueue = new ChunkedQueue<>(); private final ChunkedQueue edgeQueue = new ChunkedQueue<>(); - private final ChunkedQueue rmQueue = new ChunkedQueue<>(); + private final ChunkedQueue rmQueue = new ChunkedQueue<>(); public Solver(PTA pta) { this.cgb = pta.getCgb(); @@ -70,7 +64,7 @@ public Solver(PTA pta) { @Override public void propagate() { - final QueueReader newRMs = rmQueue.reader(); + final QueueReader newRMs = rmQueue.reader(); final QueueReader newPAGEdges = edgeQueue.reader(); final QueueReader newThrows = throwSiteQueue.reader(); final QueueReader newCalls = virtualCallSiteQueue.reader(); @@ -106,13 +100,13 @@ public void propagate() { } } - public void processStmts(Iterator newRMs) { + public void processStmts(Iterator newRMs) { while (newRMs.hasNext()) { - ContextMethod momc = newRMs.next(); + MethodOrMethodContext momc = newRMs.next(); SootMethod method = momc.method(); -// if (method.isPhantom()) { -// continue; -// } + if (method.isPhantom()) { + continue; + } MethodPAG mpag = pag.getMethodPAG(method); addToPAG(mpag, momc.context()); // !FIXME in a context-sensitive pointer analysis, clinits in a method maybe added multiple times. @@ -121,7 +115,7 @@ public void processStmts(Iterator newRMs) { Iterator it = mpag.triggeredClinits(); while (it.hasNext()) { SootMethod sm = it.next(); - cgb.injectCallEdge(sm.getDeclaringClassType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); + cgb.injectCallEdge(sm.getDeclaringClass().getType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); } } recordCallStmts(momc, mpag.getInvokeStmts()); @@ -129,36 +123,40 @@ public void processStmts(Iterator newRMs) { } } - private void recordCallStmts(ContextMethod m, Collection units) { - for (final Stmt s : units) { + private void recordCallStmts(MethodOrMethodContext m, Collection units) { + for (final Unit u : units) { + final Stmt s = (Stmt) u; if (s.containsInvokeExpr()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof AbstractInstanceInvokeExpr iie) { - Local receiver = iie.getBase(); + InvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof InstanceInvokeExpr iie) { + Local receiver = (Local) iie.getBase(); VarNode recNode = cgb.getReceiverVarNode(receiver, m); - MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); + NumberedString subSig = iie.getMethodRef().getSubSignature(); VirtualCallSite virtualCallSite = new VirtualCallSite(recNode, s, m, iie, subSig, Edge.ieToKind(iie)); if (cgb.recordVirtualCallSite(recNode, virtualCallSite)) { virtualCallSiteQueue.add(virtualCallSite); } - } else if (ie instanceof JDynamicInvokeExpr) { - // !TODO dynamicInvoke is provided in JDK after Java 7. - // currently, PTA does not handle dynamicInvokeExpr. - } else if (ie instanceof JStaticInvokeExpr sie) { - MethodSignature msig = sie.getMethodSignature(); - SootMethod tgt = (SootMethod) pag.getView().getMethod(msig).get(); - VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); - recNode = (VarNode) pta.parameterize(recNode, m.context()); - cgb.addStaticEdge(m, s, tgt, Edge.ieToKind(ie)); } else { - throw new InternalError("Unresolved target " + ie.getMethodSignature() - + ". Resolution error should have occured earlier."); + SootMethod tgt = ie.getMethod(); + if (tgt != null) { // static invoke or dynamic invoke + VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); + recNode = (VarNode) pta.parameterize(recNode, m.context()); + if (ie instanceof DynamicInvokeExpr) { + // !TODO dynamicInvoke is provided in JDK after Java 7. + // currently, PTA does not handle dynamicInvokeExpr. + } else { + cgb.addStaticEdge(m, s, tgt, Edge.ieToKind(ie)); + } + } else if (!Options.v().ignore_resolution_errors()) { + throw new InternalError("Unresolved target " + ie.getMethod() + + ". Resolution error should have occured earlier."); + } } } } } - private void recordThrowStmts(ContextMethod m, Collection stmts) { + private void recordThrowStmts(MethodOrMethodContext m, Collection stmts) { for (final Stmt stmt : stmts) { SootMethod sm = m.method(); MethodPAG mpag = pag.getMethodPAG(sm); @@ -167,8 +165,8 @@ private void recordThrowStmts(ContextMethod m, Collection stmts) { if (stmt.containsInvokeExpr()) { src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, sm); } else { - assert stmt instanceof JThrowStmt; - JThrowStmt ts = (JThrowStmt) stmt; + assert stmt instanceof ThrowStmt; + ThrowStmt ts = (ThrowStmt) stmt; src = nodeFactory.getNode(ts.getOp()); } VarNode throwNode = (VarNode) pta.parameterize(src, m.context()); @@ -256,7 +254,7 @@ public void visit(Node n) { }); } - private void activateConstraints(QueueReader newCalls, QueueReader newRMs, QueueReader newThrows, QueueReader addedEdges) { + private void activateConstraints(QueueReader newCalls, QueueReader newRMs, QueueReader newThrows, QueueReader addedEdges) { while (newCalls.hasNext()) { while (newCalls.hasNext()) { final VirtualCallSite site = newCalls.next(); diff --git a/sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java b/sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java deleted file mode 100644 index d261c903c2f..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/util/ArrayNumberer.java +++ /dev/null @@ -1,155 +0,0 @@ -package qilin.core.util; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2002 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import java.util.Arrays; -import java.util.BitSet; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * A class that numbers objects, so they can be placed in bitsets. - * - * @author Ondrej Lhotak - * @author xiao, generalize it. - */ -public class ArrayNumberer implements IterableNumberer { - - protected E[] numberToObj; - protected int lastNumber; - protected BitSet freeNumbers; - - @SuppressWarnings("unchecked") - public ArrayNumberer() { - this.numberToObj = (E[]) new Numberable[1024]; - this.lastNumber = 0; - } - - public ArrayNumberer(E[] elements) { - this.numberToObj = elements; - this.lastNumber = elements.length; - } - - private void resize(int n) { - numberToObj = Arrays.copyOf(numberToObj, n); - } - - @Override - public synchronized void add(E o) { - if (o.getNumber() != 0) { - return; - } - - // In case we removed entries from the numberer, we want to re-use the free space - int chosenNumber = -1; - if (freeNumbers != null) { - int ns = freeNumbers.nextSetBit(0); - if (ns != -1) { - chosenNumber = ns; - freeNumbers.clear(ns); - } - } - if (chosenNumber == -1) { - chosenNumber = ++lastNumber; - } - if (chosenNumber >= numberToObj.length) { - resize(numberToObj.length * 2); - } - numberToObj[chosenNumber] = o; - o.setNumber(chosenNumber); - } - - @Override - public long get(E o) { - if (o == null) { - return 0; - } - int ret = o.getNumber(); - if (ret == 0) { - throw new RuntimeException("unnumbered: " + o); - } - return ret; - } - - @Override - public E get(long number) { - if (number == 0) { - return null; - } - E ret = numberToObj[(int) number]; - if (ret == null) { - return null; - } - return ret; - } - - @Override - public int size() { - return lastNumber; - } - - @Override - public Iterator iterator() { - return new Iterator() { - int cur = 1; - - @Override - public final boolean hasNext() { - return cur <= lastNumber && cur < numberToObj.length && numberToObj[cur] != null; - } - - @Override - public final E next() { - if (hasNext()) { - return numberToObj[cur++]; - } - throw new NoSuchElementException(); - } - - @Override - public final void remove() { - ArrayNumberer.this.remove(numberToObj[cur - 1]); - } - }; - } - - @Override - public boolean remove(E o) { - if (o == null) { - return false; - } - - int num = o.getNumber(); - if (num == 0) { - return false; - } - if (freeNumbers == null) { - freeNumbers = new BitSet(2 * num); - } - numberToObj[num] = null; - o.setNumber(0); - freeNumbers.set(num); - return true; - } -} - diff --git a/sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java b/sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java deleted file mode 100644 index db1f0dae3ff..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/util/BitSetIterator.java +++ /dev/null @@ -1,92 +0,0 @@ -package qilin.core.util; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2001 Felix Kwok - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import java.util.NoSuchElementException; - -/** - * A fast enumerator for sparse bit sets. When the enumerator is created, it takes a snapshot of the underlying BitVector, - * and iterates through the set bits. Note that this class almost implements the Iterator interface, but it doesn't because - * the return type of next is int rather than Object. - */ -public class BitSetIterator { - - long[] bits; // Bits inherited from the underlying BitVector - int index; // The 64-bit block currently being examined - long save = 0; // A copy of the 64-bit block (for fast access) - - /* - * Computes log_2(x) modulo 67. This uses the fact that 2 is a primitive root modulo 67 - */ - final static int[] lookup = { -1, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, -1, 13, 10, 17, 62, 60, 28, - 42, 30, 20, 51, 25, 44, 55, 47, 5, 32, -1, 38, 14, 22, 11, 58, 18, 53, -1, 9, 61, 27, 29, 50, 43, 46, 31, 37, 21, 57, - 52, 8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33 }; - - /** Creates a new BitSetIterator */ - BitSetIterator(long[] bits) { - // this.bits = new long[bits.length]; - // System.arraycopy(bits,0,this.bits,0,bits.length); - this.bits = bits; - index = 0; - - /* Zip through empty blocks */ - while (index < bits.length && bits[index] == 0L) { - index++; - } - if (index < bits.length) { - save = bits[index]; - } - } - - /** Returns true if there are more set bits in the BitVector; false otherwise. */ - public boolean hasNext() { - return index < bits.length; - } - - /** - * Returns the index of the next set bit. Note that the return type is int, and not Object. - */ - public int next() { - if (index >= bits.length) { - throw new NoSuchElementException(); - } - - long k = (save & (save - 1)); // Clears the last non-zero bit. save is guaranteed non-zero. - long diff = save ^ k; // Finds out which bit it is. diff has exactly one bit set. - save = k; - - // Computes the position of the set bit. - int result = (diff < 0) ? 64 * index + 63 : 64 * index + lookup[(int) (diff % 67)]; - - if (save == 0) { - index++; - while (index < bits.length && bits[index] == 0L) { - index++; - } - if (index < bits.length) { - save = bits[index]; - } - } - return result; - } -} diff --git a/sootup.qilin/src/main/java/qilin/core/util/BitVector.java b/sootup.qilin/src/main/java/qilin/core/util/BitVector.java deleted file mode 100644 index 5765d4723eb..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/util/BitVector.java +++ /dev/null @@ -1,463 +0,0 @@ -package qilin.core.util; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2003 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -/** - * This is the Soot internal implementation of java.util.BitSet with Felix and Jerome's clever efficient iterator. It was - * re-implemented from scratch by Ondrej Lhotak to avoid licence issues. It was named BitVector rather than BitSet to avoid a - * name clash with the one in the standard Java library. - * - * @author Ondrej Lhotak - */ -public class BitVector { - - private long[] bits; - - public BitVector() { - this(64); - } - - /** Copy constructor */ - // Added by Adam Richard. More efficient than clone(), and easier to extend - public BitVector(BitVector other) { - final long[] otherBits = other.bits; - bits = new long[otherBits.length]; - System.arraycopy(otherBits, 0, bits, 0, otherBits.length); - } - - public BitVector(int numBits) { - int lastIndex = indexOf(numBits - 1); - bits = new long[lastIndex + 1]; - } - - private int indexOf(int bit) { - return bit >> 6; - } - - private long mask(int bit) { - return 1L << (bit & 63); - } - - public void and(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int numToAnd = otherBits.length; - if (bits.length < numToAnd) { - numToAnd = bits.length; - } - int i; - for (i = 0; i < numToAnd; i++) { - bits[i] = bits[i] & otherBits[i]; - } - for (; i < bits.length; i++) { - bits[i] = 0L; - } - } - - public void andNot(BitVector other) { - final long[] otherBits = other.bits; - int numToAnd = otherBits.length; - if (bits.length < numToAnd) { - numToAnd = bits.length; - } - for (int i = 0; i < numToAnd; i++) { - bits[i] = bits[i] & ~otherBits[i]; - } - } - - public void clear(int bit) { - if (indexOf(bit) < bits.length) { - bits[indexOf(bit)] &= ~mask(bit); - } - } - - @Override - public Object clone() { - try { - BitVector ret = (BitVector) super.clone(); - System.arraycopy(bits, 0, ret.bits, 0, ret.bits.length); - return ret; - } catch (CloneNotSupportedException e) { - // cannot occur - throw new RuntimeException(e); - } - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof BitVector)) { - return false; - } - final long[] otherBits = ((BitVector) o).bits; - long[] longer = otherBits; - int min = bits.length; - if (otherBits.length < min) { - min = otherBits.length; - longer = bits; - } - int i; - for (i = 0; i < min; i++) { - if (bits[i] != otherBits[i]) { - return false; - } - } - for (; i < longer.length; i++) { - if (longer[i] != 0L) { - return false; - } - } - return true; - } - - public boolean get(int bit) { - if (indexOf(bit) >= bits.length) { - return false; - } - return (bits[indexOf(bit)] & mask(bit)) != 0L; - } - - @Override - public int hashCode() { - long ret = 0; - for (long element : bits) { - ret ^= element; - } - return (int) ((ret >> 32) ^ ret); - } - - /** Returns index of highest-numbered one bit. */ - public int length() { - int i; - for (i = bits.length - 1; i >= 0; i--) { - if (bits[i] != 0L) { - break; - } - } - if (i < 0) { - return 0; - } - long j = bits[i]; - i++; - i <<= 6; - for (long k = 1L << 63; (k & j) == 0L; k >>= 1, i--) { - } - return i; - } - - public void copyFrom(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int j; - for (j = otherBits.length - 1; j >= 0; j--) { - if (otherBits[j] != 0L) { - break; - } - } - expand(j << 6); - int i = j + 1; - for (; j >= 0; j--) { - bits[j] = otherBits[j]; - } - for (; i < bits.length; i++) { - bits[i] = 0L; - } - } - - public void or(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int j; - for (j = otherBits.length - 1; j >= 0; j--) { - if (otherBits[j] != 0L) { - break; - } - } - expand(j << 6); - for (; j >= 0; j--) { - bits[j] |= otherBits[j]; - } - } - - /** - * Count the number of ones in the bitvector. - * - * @author Adam Richard This is Brian Kernighan's algorithm from: http://graphics.stanford.edu/~seander/bithacks.html and - * is efficient for sparse bit sets. - */ - public int cardinality() { - int c = 0; - for (long v : bits) { - while (v != 0) { - v &= v - 1; - ++c; - } - } - return c; - } - - /** - * Returns true if the both the current and the specified bitvectors have at least one bit set in common. - * - * @author Quentin Sabah Inspired by the BitVector.and method. - */ - public boolean intersects(BitVector other) { - final long[] otherBits = other.bits; - int numToCheck = otherBits.length; - if (bits.length < numToCheck) { - numToCheck = bits.length; - } - int i; - for (i = 0; i < numToCheck; i++) { - if ((bits[i] & otherBits[i]) != 0) { - return true; - } - } - return false; - } - - private void expand(int bit) { - int n = indexOf(bit) + 1; - if (n <= bits.length) { - return; - } - if (bits.length * 2 > n) { - n = bits.length * 2; - } - long[] newBits = new long[n]; - System.arraycopy(bits, 0, newBits, 0, bits.length); - bits = newBits; - } - - public void xor(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int j; - for (j = otherBits.length - 1; j >= 0; j--) { - if (otherBits[j] != 0L) { - break; - } - } - expand(j << 6); - for (; j >= 0; j--) { - bits[j] ^= otherBits[j]; - } - } - - public boolean set(int bit) { - expand(bit); - boolean ret = !get(bit); - bits[indexOf(bit)] |= mask(bit); - return ret; - } - - /** Returns number of bits in the underlying array. */ - public int size() { - return bits.length << 6; - } - - @Override - public String toString() { - StringBuilder ret = new StringBuilder(); - ret.append('{'); - boolean start = true; - for (BitSetIterator it = new BitSetIterator(bits); it.hasNext();) { - int bit = it.next(); - if (start) { - start = false; - } else { - ret.append(", "); - } - ret.append(bit); - } - ret.append('}'); - return ret.toString(); - } - - /** - * Computes this = this OR ((orset AND andset ) AND (NOT andnotset)) Returns true iff this is modified. - */ - public boolean orAndAndNot(BitVector orset, BitVector andset, BitVector andnotset) { - final long[] a, b, c, d; - final int al, bl, cl, dl; - { - a = this.bits; - al = a.length; - } - if (orset == null) { - b = null; - bl = 0; - } else { - b = orset.bits; - bl = b.length; - } - if (andset == null) { - c = null; - cl = 0; - } else { - c = andset.bits; - cl = c.length; - } - if (andnotset == null) { - d = null; - dl = 0; - } else { - d = andnotset.bits; - dl = d.length; - } - - final long[] e; - if (al < bl) { - e = new long[bl]; - System.arraycopy(a, 0, e, 0, al); - this.bits = e; - } else { - e = a; - } - - boolean ret = false; - if (c == null) { - if (dl <= bl) { - int i = 0; - for (; i < dl; i++) { - long l = b[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - for (; i < bl; i++) { - long l = b[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } else { - for (int i = 0; i < bl; i++) { - long l = b[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } - } else if (bl <= cl && bl <= dl) { - // bl is the shortest - for (int i = 0; i < bl; i++) { - long l = b[i] & c[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } else if (cl <= bl && cl <= dl) { - // cl is the shortest - for (int i = 0; i < cl; i++) { - long l = b[i] & c[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } else { - // dl is the shortest - int i = 0; - for (; i < dl; i++) { - long l = b[i] & c[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - for (int shorter = (bl < cl) ? bl : cl; i < shorter; i++) { - long l = b[i] & c[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } - - return ret; - } - - public static BitVector and(BitVector set1, BitVector set2) { - int min = set1.size(); - { - int max = set2.size(); - if (min > max) { - min = max; - } - // max is not necessarily correct at this point, so let it go - // out of scope - } - - BitVector ret = new BitVector(min); - long[] retbits = ret.bits; - long[] bits1 = set1.bits; - long[] bits2 = set2.bits; - min >>= 6; - for (int i = 0; i < min; i++) { - retbits[i] = bits1[i] & bits2[i]; - } - return ret; - } - - public static BitVector or(BitVector set1, BitVector set2) { - int min = set1.size(); - int max = set2.size(); - if (min > max) { - min = max; - max = set1.size(); - } - - BitVector ret = new BitVector(max); - long[] retbits = ret.bits; - long[] bits1 = set1.bits; - long[] bits2 = set2.bits; - min >>= 6; - max >>= 6; - for (int i = 0; i < min; i++) { - retbits[i] = bits1[i] | bits2[i]; - } - if (bits1.length == min) { - System.arraycopy(bits2, min, retbits, min, max - min); - } else { - System.arraycopy(bits1, min, retbits, min, max - min); - } - return ret; - } - - public BitSetIterator iterator() { - return new BitSetIterator(bits); - } -} - diff --git a/sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java b/sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java deleted file mode 100644 index 24efd6e012c..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/util/IterableNumberer.java +++ /dev/null @@ -1,14 +0,0 @@ -package qilin.core.util; - -import java.util.Iterator; - -/** - * A numberer which also supports an iterator on newly-added objects. - * - * @author xiao, generalize the interface - */ -public interface IterableNumberer extends Numberer, Iterable { - /** Returns an iterator over all objects added to the numberer. */ - @Override - Iterator iterator(); -} diff --git a/sootup.qilin/src/main/java/qilin/core/util/Numberable.java b/sootup.qilin/src/main/java/qilin/core/util/Numberable.java deleted file mode 100644 index cacf87f6b4e..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/util/Numberable.java +++ /dev/null @@ -1,6 +0,0 @@ -package qilin.core.util; - -public interface Numberable { - void setNumber(int number); - int getNumber(); -} diff --git a/sootup.qilin/src/main/java/qilin/core/util/Numberer.java b/sootup.qilin/src/main/java/qilin/core/util/Numberer.java deleted file mode 100644 index b6882917415..00000000000 --- a/sootup.qilin/src/main/java/qilin/core/util/Numberer.java +++ /dev/null @@ -1,53 +0,0 @@ -package qilin.core.util; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2004 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -/** - * A numberer converts objects to unique non-negative integers, and vice-versa. - * - * @author xiao, generalize the interface - */ -public interface Numberer { - /** Tells the numberer that a new object needs to be assigned a number. */ - public void add(E o); - - /** - * Removes the number for a given object. - * - * @param o - * the element - * @return true if the removal was successful, false when not - */ - public boolean remove(E o); - - /** - * Should return the number that was assigned to object o that was previously passed as an argument to add(). - */ - public long get(E o); - - /** Should return the object that was assigned the number number. */ - public E get(long number); - - /** Should return the number of objects that have been assigned numbers. */ - public int size(); -} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java index 34d7297f2f7..5309b88908b 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java @@ -18,18 +18,18 @@ package qilin.parm.ctxcons; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import qilin.core.pag.ContextMethod; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; public class CallsiteCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); assert callerContext instanceof ContextElements; ContextElements ctxElems = (ContextElements) callerContext; diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java index 00afc962d49..c7cb8e5a990 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java @@ -18,16 +18,16 @@ package qilin.parm.ctxcons; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import qilin.core.pag.ContextMethod; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; public interface CtxConstructor { - Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target); + Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target); Context emptyContext = new ContextElements(new ContextElement[0], 0); } \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java index de3d83279b9..2e7cc3dbd5b 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java @@ -18,20 +18,20 @@ package qilin.parm.ctxcons; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.context.TypeContextElement; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import qilin.core.pag.ContextMethod; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; // implementation of selective hybrid context...(Yannis pldi'13) public class HybTypeCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); if (receiverNode == null) { // static invoke assert callerContext instanceof ContextElements; diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java index c38bb569cc2..cdd393d9b10 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java @@ -18,16 +18,16 @@ package qilin.parm.ctxcons; -import qilin.core.context.Context; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import qilin.core.pag.ContextMethod; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; public class InsensCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { return emptyContext; } } diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java index e60e680242a..8b7131df7bb 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java @@ -18,19 +18,19 @@ package qilin.parm.ctxcons; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import qilin.core.pag.ContextMethod; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; // implementation of obj context...(Ana Tosem'05) public class ObjCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); if (receiverNode == null) { // static invoke return callerContext; diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java index fd9a4212770..6cf034383e4 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java @@ -18,21 +18,21 @@ package qilin.parm.ctxcons; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.context.TypeContextElement; import qilin.core.pag.AllocNode; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import qilin.core.pag.ContextMethod; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; // implementation of type context...(Yannis popl'11) public class TypeCtxConstructor implements CtxConstructor { @Override - public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { Context callerContext = caller.context(); if (receiverNode == null) { // static invoke return callerContext; diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java index 58c781bb4e9..ed388baa161 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -23,11 +23,7 @@ import qilin.core.pag.PAG; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import sootup.core.IdentifierFactory; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; -import sootup.java.core.JavaIdentifierFactory; +import soot.*; import java.util.Set; @@ -37,9 +33,8 @@ public class HeuristicAbstractor implements HeapAbstractor { public HeuristicAbstractor(PAG pag) { this.pag = pag; - IdentifierFactory idFactory = JavaIdentifierFactory.getInstance(); - mergedTypes.add(idFactory.getType("java.lang.StringBuffer")); - mergedTypes.add(idFactory.getType("java.lang.StringBuilder")); + mergedTypes.add(RefType.v("java.lang.StringBuffer")); + mergedTypes.add(RefType.v("java.lang.StringBuilder")); } @Override @@ -47,7 +42,7 @@ public AllocNode abstractHeap(AllocNode heap) { Type type = heap.getType(); SootMethod m = heap.getMethod(); if (mergedTypes.contains(type) || (PTAUtils.isThrowable(type) && mergedTypes.add(type))) { - return pag.makeAllocNode(MergedNewExpr.v((ReferenceType) type), type, null); + return pag.makeAllocNode(MergedNewExpr.v((RefLikeType) type), type, null); } else { return heap; } diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java index e822f6c5030..1f3ffe1689d 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java @@ -21,8 +21,8 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; import qilin.util.PTAUtils; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; +import soot.SootMethod; +import soot.Type; import java.util.Map; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java index cab87611402..ec804562d98 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java @@ -18,14 +18,14 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.PAG; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java index 766925d6a99..c549881c9d4 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java @@ -18,14 +18,14 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; public abstract class CtxSelector { public abstract Context select(SootMethod m, Context context); diff --git a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java index 767fe94534a..83476653680 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java index db8658c1087..0244781aaa9 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java index ea17428fbd1..ec0479c0238 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java @@ -18,13 +18,13 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; import qilin.util.PTAUtils; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; public class HeuristicSelector extends CtxSelector { diff --git a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java index ee3e6a3b454..ead5ce4c20e 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; public class InsenSelector extends CtxSelector { @Override diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java index 6091252820c..e81c93d89b3 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java index 7abf7e0ea8b..d5f7a5af813 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java @@ -18,12 +18,12 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java index 632c92c2285..4528c0a8523 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; /* * A pipeline context selector which selects context by firstly using ctxSelA and then ctxSelB. diff --git a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java index ae5d14fdac6..c3ee0b8fc05 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; public class UniformSelector extends CtxSelector { private final int k; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java index c02537bd9f8..d8f0b02bcf2 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java @@ -18,11 +18,11 @@ package qilin.parm.select; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java b/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java index 7b6e40aa43b..87995973128 100644 --- a/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java +++ b/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java @@ -20,6 +20,7 @@ import driver.PTAPattern; import qilin.CoreConfig; +import qilin.pta.tools.DebloatedPTA; public class PTAConfig extends CoreConfig { private static PTAConfig config = null; @@ -49,6 +50,7 @@ public static class PointerAnalysisConfiguration extends CorePTAConfiguration { * If this option is turned on, we will apply context debloating techniques. */ public boolean ctxDebloating = false; + public DebloatedPTA.DebloatApproach debloatApproach = DebloatedPTA.DebloatApproach.CONCH; } @@ -71,4 +73,14 @@ private PTAConfig() { public PointerAnalysisConfiguration getPtaConfig() { return (PointerAnalysisConfiguration) this.ptaConfig; } + + /* + * Configures the callgraph options + * */ + public enum CallgraphAlgorithm { + /*CHA, VTA, RTA, GEOM, and SPARK are all provided by Soot */ + CHA, VTA, RTA, GEOM, SPARK, QILIN + } + + public CallgraphAlgorithm callgraphAlg = CallgraphAlgorithm.QILIN; } diff --git a/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java b/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java deleted file mode 100644 index 44cd999cef5..00000000000 --- a/sootup.qilin/src/main/java/qilin/pta/StagedPTA.java +++ /dev/null @@ -1,36 +0,0 @@ -package qilin.pta; - -import qilin.pta.tools.BasePTA; -import sootup.core.views.View; - -/* - * Many recent pointer analyses are two-staged analyses with a preanalysis and a main analysis. - * This class gives a structure for such kinds of analyses. - * */ -public abstract class StagedPTA extends BasePTA { - protected BasePTA prePTA; - - public StagedPTA(View view) { - super(view); - } - - public BasePTA getPrePTA() { - return this.prePTA; - } - - protected abstract void preAnalysis(); - - protected void mainAnalysis() { - if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { - System.out.println("selective pta starts!"); - super.run(); - } - } - - @Override - public void run() { - preAnalysis(); - prePTA.getPag().resetPointsToSet(); - mainAnalysis(); - } -} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java new file mode 100644 index 00000000000..37a96a38ed8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java @@ -0,0 +1,29 @@ +package qilin.pta.toolkits.common; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; + +import java.util.HashSet; +import java.util.Set; + +public class DebloatedOAG extends OAG { + private final Set ctxDepHeaps; + + public DebloatedOAG(PTA prePta, Set ctxDepHeaps) { + super(prePta); + this.ctxDepHeaps = ctxDepHeaps; + } + + @Override + /** + * Add a directed object allocation edge to the OAG. + */ + protected void addEdge(AllocNode src, AllocNode tgt) { + nodes.add(src); + nodes.add(tgt); + if (this.ctxDepHeaps.contains(tgt)) { + this.predecessors.computeIfAbsent(tgt, k -> new HashSet<>()).add(src); + this.successors.computeIfAbsent(src, k -> new HashSet<>()).add(tgt); + } + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java index 37e6d39b0a5..2dc40e83df9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java @@ -21,8 +21,8 @@ import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; -import qilin.core.pag.SparkField; import qilin.core.sets.PointsToSet; +import soot.jimple.spark.pag.SparkField; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java index 6b68ae99e28..e1018e6a66c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java @@ -23,12 +23,11 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.MethodPAG; -import qilin.core.pag.Node; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.graph.DirectedGraph; -import qilin.util.queue.QueueReader; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.util.queue.QueueReader; import java.util.*; @@ -39,9 +38,9 @@ public class OAG implements DirectedGraph { protected final PTA pta; protected final Map> successors; protected final Map> predecessors; - private final Set nodes = new HashSet<>(); - private Collection rootNodes; - private Collection tailNodes; + protected final Set nodes = new HashSet<>(); + protected Collection rootNodes; + protected Collection tailNodes; public OAG(PTA prePta) { this.pta = prePta; @@ -109,13 +108,13 @@ public boolean reaches(AllocNode source, AllocNode dest) { protected void buildOAG() { Map> pts = PTAUtils.calcStaticThisPTS(this.pta); for (SootMethod method : this.pta.getNakedReachableMethods()) { -// if (method.isPhantom()) { -// continue; -// } + if (method.isPhantom()) { + continue; + } MethodPAG srcmpag = pta.getPag().getMethodPAG(method); MethodNodeFactory srcnf = srcmpag.nodeFactory(); LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - QueueReader reader = srcmpag.getInternalReader().clone(); + QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { qilin.core.pag.Node from = reader.next(), to = reader.next(); if (from instanceof AllocNode tgt) { @@ -149,4 +148,15 @@ protected void addEdge(AllocNode src, AllocNode tgt) { this.successors.computeIfAbsent(src, k -> new HashSet<>()).add(tgt); } + public int nodeSize() { + return this.nodes.size(); + } + + public int edgeSize() { + int ret = 0; + for (AllocNode obj : predecessors.keySet()) { + ret += predecessors.get(obj).size(); + } + return ret; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index 7b6cb2845b7..e542c95bfe6 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -19,14 +19,14 @@ package qilin.pta.toolkits.common; import qilin.core.PTA; +import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.PAG; import qilin.core.pag.VarNode; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.core.types.ReferenceType; -import sootup.core.views.View; +import soot.RefLikeType; +import soot.RefType; +import soot.SootClass; +import soot.SootMethod; import java.util.Collections; import java.util.HashSet; @@ -42,7 +42,7 @@ public static Set getParameters(PAG pag, SootMethod m) { MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); Set ret = new HashSet<>(); for (int i = 0; i < m.getParameterCount(); ++i) { - if (m.getParameterType(i) instanceof ReferenceType) { + if (m.getParameterType(i) instanceof RefLikeType) { qilin.core.pag.VarNode param = mthdNF.caseParm(i); ret.add(param); } @@ -52,7 +52,7 @@ public static Set getParameters(PAG pag, SootMethod m) { public static Set getRetVars(PAG pag, SootMethod m) { MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); - if (m.getReturnType() instanceof ReferenceType) { + if (m.getReturnType() instanceof RefLikeType) { VarNode ret = mthdNF.caseRet(); return Collections.singleton(ret); } @@ -68,13 +68,12 @@ public static int pointsToSetSizeOf(final PTA pta, VarNode var) { * @param pOuter potential outer class * @return whether pInner is an inner class of pOuter */ - public static boolean isInnerType(final View view, final ClassType pInner, ClassType pOuter) { + public static boolean isInnerType(final RefType pInner, RefType pOuter) { final String pInnerStr = pInner.toString(); while (!pInnerStr.startsWith(pOuter.toString() + "$")) { - SootClass sc = (SootClass) view.getClass(pOuter).get(); + SootClass sc = pOuter.getSootClass(); if (sc.hasSuperclass()) { - SootClass superClass = (SootClass) sc.getSuperclass().get(); - pOuter = superClass.getType(); + pOuter = sc.getSuperclass().getType(); } else { return false; } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java index ae73f392602..5af968d47c5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java @@ -24,9 +24,10 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import sootup.core.model.SootMethod; -import sootup.core.types.ArrayType; -import sootup.core.types.PrimitiveType; +import soot.ArrayType; +import soot.PrimType; +import soot.SootMethod; +import soot.jimple.spark.pag.SparkField; import java.util.*; @@ -55,8 +56,7 @@ private void init() { * The following line computes the receiver objects for the this_ptr of static methods. * */ Map> pts = PTAUtils.calcStaticThisPTS(pta); - pta.getNakedReachableMethods().stream()//.filter(m -> !m.isPhantom()) - .forEach(method -> { + pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(method -> { collectStoresIn(method); collectLoadsIn(method); buildInvokedOnFor(method, pts); @@ -166,14 +166,14 @@ private void collectStoresIn(SootMethod method) { private boolean primitiveField(SparkField f) { String s = "java.lang.String"; - if (f.getType() instanceof PrimitiveType) { + if (f.getType() instanceof PrimType) { return true; } else if (f.getType() instanceof ArrayType at) { /* * here, we let primitive array as primitive type as that in Turner. * this wont hurt precision of clients. * */ - return at.getBaseType() instanceof PrimitiveType; + return at.baseType instanceof PrimType; } else return f.getType().toString().equals(s); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java index 00e70359fd7..514c5841096 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -23,12 +23,12 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.CallGraph; import qilin.core.pag.*; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; +import soot.RefLikeType; +import soot.SootMethod; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.util.queue.QueueReader; import java.util.Collection; import java.util.Collections; @@ -68,7 +68,7 @@ protected AbstractPAG(PTA prePTA) { protected void build() { prePTA.getNakedReachableMethods() - .parallelStream()// .filter(m -> !m.isPhantom()) + .parallelStream().filter(m -> !m.isPhantom()) .forEach(this::buildFG); } @@ -101,12 +101,12 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { + if (method.getParameterType(i) instanceof RefLikeType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); addParamEdge(param); } } - if (method.getReturnType() instanceof ReferenceType) { + if (method.getReturnType() instanceof RefLikeType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); addReturnEdge(mret); } @@ -218,6 +218,6 @@ private void runExecutorAndAwaitCompletion() { } protected AllocNode getSymbolicHeapOf(SootMethod method, Stmt invokeStmt) { - return symbolicHeaps.computeIfAbsent(method, k -> new ConcurrentHashMap<>()).computeIfAbsent(invokeStmt, k -> new AllocNode(prePAG.getView(), invokeStmt, null, method)); + return symbolicHeaps.computeIfAbsent(method, k -> new ConcurrentHashMap<>()).computeIfAbsent(invokeStmt, k -> new AllocNode(invokeStmt, null, method)); } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index fc25f0d3830..deaad929bfe 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -24,14 +24,14 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.jimple.common.stmt.JInvokeStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.signatures.MethodSignature; -import sootup.java.core.JavaSootMethod; +import soot.SootMethod; +import soot.Unit; +import soot.Value; +import soot.jimple.InvokeExpr; +import soot.jimple.InvokeStmt; +import soot.jimple.SpecialInvokeExpr; +import soot.jimple.Stmt; +import soot.jimple.spark.pag.SparkField; import java.util.*; import java.util.stream.Collectors; @@ -69,15 +69,14 @@ private SootMethod findInvokedConstructorOf(AllocNode heap) { SootMethod containingMethod = heap.getMethod(); MethodPAG cmpag = pag.getMethodPAG(containingMethod); MethodNodeFactory nodeFactory = cmpag.nodeFactory(); - for (Stmt stmt : cmpag.getInvokeStmts()) { - if (stmt instanceof JInvokeStmt invokeStmt) { - AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof JSpecialInvokeExpr iie) { + for (Unit unit : cmpag.getInvokeStmts()) { + if (unit instanceof InvokeStmt invokeStmt) { + InvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof SpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); PointsToSet v1pts = pta.reachingObjects(baseNode); - MethodSignature targetSig = iie.getMethodSignature(); - JavaSootMethod target = (JavaSootMethod) pag.getView().getMethod(targetSig).get(); + SootMethod target = iie.getMethod(); if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && target.isConstructor()) { return target; } @@ -91,14 +90,13 @@ private SootMethod findInvokedConstructorOf(SootMethod outerInit) { MethodPAG cmpag = pag.getMethodPAG(outerInit); MethodNodeFactory nodeFactory = cmpag.nodeFactory(); VarNode thisNode = nodeFactory.caseThis(); - for (Stmt stmt : cmpag.getInvokeStmts()) { - if (stmt instanceof JInvokeStmt invokeStmt) { - AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof JSpecialInvokeExpr iie) { + for (Unit unit : cmpag.getInvokeStmts()) { + if (unit instanceof InvokeStmt invokeStmt) { + InvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof SpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); - MethodSignature methodSignature = iie.getMethodSignature(); - JavaSootMethod target = (JavaSootMethod) pag.getView().getMethod(methodSignature).get(); + SootMethod target = iie.getMethod(); if (PTAUtils.mustAlias(pta, thisNode, baseNode) && target.isConstructor()) { return target; } @@ -126,13 +124,12 @@ private ArrayList recoverConstructorChain(SootMethod sm, AllocNode h private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMethod curr, SootMethod caller) { MethodPAG cmpag = pag.getMethodPAG(caller); Set ret = new HashSet<>(); - for (Stmt stmt : cmpag.getInvokeStmts()) { - if (!(stmt.getInvokeExpr() instanceof JSpecialInvokeExpr)) { + for (Unit unit : cmpag.getInvokeStmts()) { + Stmt stmt = (Stmt) unit; + if (!(stmt.getInvokeExpr() instanceof SpecialInvokeExpr)) { continue; } - AbstractInvokeExpr invokeExpr = stmt.getInvokeExpr(); - MethodSignature methodSignature = invokeExpr.getMethodSignature(); - SootMethod target = (SootMethod) pag.getView().getMethod(methodSignature).get(); + SootMethod target = stmt.getInvokeExpr().getMethod(); if (target != null && target.equals(curr)) { for (Node n : params) { if (n instanceof VarNode paramNode) { @@ -209,8 +206,7 @@ private Trilean checkResult(Set res) { private Trilean isCommingFromParams(LocalVarNode from, SootMethod method, AllocNode heap) { Set ret = this.pfg.fetchReachableParamsOf(from); - JavaSootMethod method1 = (JavaSootMethod) method; - if (method1.isConstructor()) { + if (method.isConstructor()) { return handleTransitiveConstructors(method, heap, ret); } else { return checkResult(ret); @@ -300,7 +296,7 @@ public void runClassifier() { || PTAUtils.isOfPrimitiveBaseType(heap)) { ciHeaps.add(heap); } else { - JavaSootMethod mthd = (JavaSootMethod) heap.getMethod(); + SootMethod mthd = heap.getMethod(); if (mthd.isStaticInitializer()) { ciHeaps.add(heap); } else { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index 056ade6d4ad..b99aaefd3f5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -20,12 +20,12 @@ import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.util.PTAUtils; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.jimple.AssignStmt; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.Edge; import java.util.Collections; import java.util.Iterator; @@ -112,14 +112,14 @@ public void run() { containingMethod = heap.getMethod(); } - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + Iterator it = callGraph.edgesInto(containingMethod); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); MethodNodeFactory srcnf = srcmpag.nodeFactory(); - Stmt invokeStmt = edge.srcUnit(); - if (invokeStmt instanceof JAssignStmt assignStmt) { + Stmt invokeStmt = (Stmt) edge.srcUnit(); + if (invokeStmt instanceof AssignStmt assignStmt) { VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); if (sourceParam instanceof LocalVarNode pj) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java index 3ffd9e3f501..dcee2a57e59 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -19,11 +19,11 @@ package qilin.pta.toolkits.conch; import qilin.core.PTA; -import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.util.PTAUtils; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.Edge; import java.util.Collections; import java.util.Iterator; @@ -128,7 +128,7 @@ public void run() { AllocNode sourceHeap = (AllocNode) sourceNode; result.add(sourceHeap); SootMethod containingMethod = sourceHeap.getMethod(); - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + Iterator it = callGraph.edgesInto(containingMethod); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); @@ -148,7 +148,7 @@ public void run() { } else if (initState == DFA.State.F) { LocalVarNode pj = (LocalVarNode) sourceNode; SootMethod containingMethod = pj.getMethod(); - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + Iterator it = callGraph.edgesInto(containingMethod); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); @@ -176,7 +176,7 @@ public void run() { // ret = pi.f* LocalVarNode retOrThrow = (LocalVarNode) sourceNode; SootMethod containingMethod = retOrThrow.getMethod(); - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + Iterator it = callGraph.edgesInto(containingMethod); VarNode pi = (VarNode) pe.getTgtNode(); // add r --> ai summary edge inverse_inter_load. while (it.hasNext()) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java index 8a3452e712f..67719f67d54 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java @@ -21,8 +21,8 @@ import qilin.core.pag.*; import qilin.util.Pair; import qilin.util.graph.DirectedGraphImpl; -import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; +import soot.util.queue.QueueReader; import java.util.HashSet; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index 5722ae0acfb..585feb7432a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -19,36 +19,18 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; -import sootup.core.jimple.common.expr.JNewArrayExpr; -import sootup.core.jimple.common.expr.JNewExpr; -import sootup.core.jimple.common.expr.JNewMultiArrayExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.expr.JVirtualInvokeExpr; -import sootup.core.jimple.common.ref.JArrayRef; -import sootup.core.jimple.common.ref.JInstanceFieldRef; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JInvokeStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.Body; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.views.View; +import soot.*; +import soot.jimple.*; /* * features and formulas used in "Precise and Scalable Points-to Analysis via Data-Driven * Context Tunneling" (OOPSLA 2018). * */ public class CtxTunnelingFeaturesTrueTable { - private final View view; private final boolean[] f = new boolean[24]; - public CtxTunnelingFeaturesTrueTable(SootMethod sm, View view) { - this.view = view; - String sig = sm.getSignature().toString(); + public CtxTunnelingFeaturesTrueTable(SootMethod sm) { + String sig = sm.getSignature(); // the 10 atomic signature features. this.f[1] = sig.contains("java"); this.f[2] = sig.contains("lang"); @@ -67,32 +49,32 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm, View view) { Body body = PTAUtils.getMethodBody(sm); this.f[15] = body.getLocalCount() > 0; int heapAllocCnt = 0; - for (Stmt stmt : body.getStmts()) { - if (stmt instanceof JAssignStmt assignStmt) { + for (Unit unit : body.getUnits()) { + if (unit instanceof AssignStmt assignStmt) { Value left = assignStmt.getLeftOp(); if (left instanceof Local) { Value right = assignStmt.getRightOp(); if (right instanceof Local) { this.f[14] = true; - } else if (right instanceof JNewExpr || right instanceof JNewArrayExpr || right instanceof JNewMultiArrayExpr) { + } else if (right instanceof NewExpr || right instanceof NewArrayExpr || right instanceof NewMultiArrayExpr) { heapAllocCnt++; - } else if (right instanceof AbstractInvokeExpr) { - if (right instanceof JStaticInvokeExpr) { + } else if (right instanceof InvokeExpr) { + if (right instanceof StaticInvokeExpr) { this.f[17] = true; - } else if (right instanceof JVirtualInvokeExpr || right instanceof JInterfaceInvokeExpr) { + } else if (right instanceof VirtualInvokeExpr || right instanceof InterfaceInvokeExpr) { this.f[18] = true; } - } else if (right instanceof JArrayRef) { + } else if (right instanceof ArrayRef) { this.f[13] = true; } - } else if (left instanceof JInstanceFieldRef) { + } else if (left instanceof InstanceFieldRef) { this.f[16] = true; } - } else if (stmt instanceof JInvokeStmt invokeStmt) { - AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof JStaticInvokeExpr) { + } else if (unit instanceof InvokeStmt invokeStmt) { + InvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof StaticInvokeExpr) { this.f[17] = true; - } else if (expr instanceof JVirtualInvokeExpr || expr instanceof JInterfaceInvokeExpr) { + } else if (expr instanceof VirtualInvokeExpr || expr instanceof InterfaceInvokeExpr) { this.f[18] = true; } } @@ -102,12 +84,11 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm, View view) { this.f[20] = heapAllocCnt == 1; this.f[21] = sig.contains("Object"); this.f[22] = heapAllocCnt >= 1; // note, the original implementation is >=1 not > 1 which is conflict with the paper. - SootClass sc = PTAUtils.getDeclaringClass(view, sm); - this.f[23] = sc.getMethods().size() > 20; // their artifact uses 20 as the threshold. + this.f[23] = sm.getDeclaringClass().getMethods().size() > 20; // their artifact uses 20 as the threshold. } public boolean containedInNestedClass(SootMethod sm) { - SootClass sc = PTAUtils.getDeclaringClass(view, sm); + SootClass sc = sm.getDeclaringClass(); return sc.toString().contains("$"); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java index 7b63afb0391..bad5177c403 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java @@ -18,7 +18,6 @@ package qilin.pta.toolkits.dd; -import qilin.core.context.Context; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; @@ -27,7 +26,8 @@ import qilin.parm.ctxcons.ObjCtxConstructor; import qilin.parm.ctxcons.TypeCtxConstructor; import qilin.parm.select.CtxSelector; -import sootup.core.model.SootMethod; +import soot.Context; +import soot.SootMethod; import java.util.HashMap; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java index f5308c67ded..da07066824d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -19,23 +19,10 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JGotoStmt; -import sootup.core.jimple.common.stmt.JIdentityStmt; -import sootup.core.jimple.common.stmt.JIfStmt; -import sootup.core.jimple.common.stmt.JInvokeStmt; -import sootup.core.jimple.common.stmt.JNopStmt; -import sootup.core.jimple.common.stmt.JReturnStmt; -import sootup.core.jimple.common.stmt.JReturnVoidStmt; -import sootup.core.jimple.common.stmt.JThrowStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.jimple.javabytecode.stmt.JBreakpointStmt; -import sootup.core.jimple.javabytecode.stmt.JEnterMonitorStmt; -import sootup.core.jimple.javabytecode.stmt.JExitMonitorStmt; -import sootup.core.jimple.javabytecode.stmt.JRetStmt; -import sootup.core.jimple.javabytecode.stmt.JSwitchStmt; -import sootup.core.model.Body; -import sootup.core.model.SootMethod; +import soot.Body; +import soot.SootMethod; +import soot.Unit; +import soot.jimple.*; /* * features and formulas used in "Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017)" @@ -44,7 +31,7 @@ public class FeaturesTrueTable { private final boolean[] features = new boolean[26]; public FeaturesTrueTable(SootMethod sm) { - String sig = sm.getSignature().toString(); + String sig = sm.getSignature(); this.features[1] = sig.contains("java"); this.features[2] = sig.contains("lang"); this.features[3] = sig.contains("sun"); @@ -56,36 +43,37 @@ public FeaturesTrueTable(SootMethod sm) { this.features[9] = sig.contains("String"); this.features[10] = sig.contains("init"); Body body = PTAUtils.getMethodBody(sm); - for (Stmt stmt : body.getStmts()) { - if (stmt instanceof JAssignStmt) { + for (Unit unit : body.getUnits()) { + if (unit instanceof AssignStmt) { this.features[11] = true; - } else if (stmt instanceof JIdentityStmt) { + } else if (unit instanceof IdentityStmt) { this.features[12] = true; - } else if (stmt instanceof JInvokeStmt) { + } else if (unit instanceof InvokeStmt) { this.features[13] = true; - } else if (stmt instanceof JReturnStmt) { + } else if (unit instanceof ReturnStmt) { this.features[14] = true; - } else if (stmt instanceof JThrowStmt) { + } else if (unit instanceof ThrowStmt) { this.features[15] = true; - } else if (stmt instanceof JBreakpointStmt) { + } else if (unit instanceof BreakpointStmt) { this.features[16] = true; - } else if (stmt instanceof JEnterMonitorStmt) { + } else if (unit instanceof EnterMonitorStmt) { this.features[17] = true; - } else if (stmt instanceof JExitMonitorStmt) { + } else if (unit instanceof ExitMonitorStmt) { this.features[18] = true; - } else if (stmt instanceof JGotoStmt) { + } else if (unit instanceof GotoStmt) { this.features[19] = true; - } else if (stmt instanceof JIfStmt) { + } else if (unit instanceof IfStmt) { this.features[20] = true; - } else if (stmt instanceof JSwitchStmt) { + } else if (unit instanceof LookupSwitchStmt) { this.features[21] = true; - this.features[25] = true; - } else if (stmt instanceof JNopStmt) { + } else if (unit instanceof NopStmt) { this.features[22] = true; - } else if (stmt instanceof JRetStmt) { + } else if (unit instanceof RetStmt) { this.features[23] = true; - } else if (stmt instanceof JReturnVoidStmt) { + } else if (unit instanceof ReturnVoidStmt) { this.features[24] = true; + } else if (unit instanceof TableSwitchStmt) { + this.features[25] = true; } } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java index 9f479273f13..4b0eac23b04 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java @@ -18,33 +18,30 @@ package qilin.pta.toolkits.dd; -import qilin.core.context.Context; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; -import qilin.core.pag.ContextMethod; import qilin.parm.ctxcons.*; -import sootup.core.model.SootMethod; -import sootup.core.views.View; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.SootMethod; import java.util.HashMap; import java.util.Map; public class TunnelingConstructor implements CtxConstructor { - private final View view; private final CtxConstructor ctxCons; private final Map m2ftt = new HashMap<>(); private CtxTunnelingFeaturesTrueTable findOrCreateTunnelingFeaturesTrueTable(SootMethod sm) { - return m2ftt.computeIfAbsent(sm, k -> new CtxTunnelingFeaturesTrueTable(sm, view)); + return m2ftt.computeIfAbsent(sm, k -> new CtxTunnelingFeaturesTrueTable(sm)); } - public TunnelingConstructor(View view, CtxConstructor ctxCons) { - this.view = view; + public TunnelingConstructor(CtxConstructor ctxCons) { this.ctxCons = ctxCons; } @Override - public Context constructCtx(ContextMethod caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { CtxTunnelingFeaturesTrueTable ctftt1 = findOrCreateTunnelingFeaturesTrueTable(caller.method()); CtxTunnelingFeaturesTrueTable ctftt2 = findOrCreateTunnelingFeaturesTrueTable(target); if (ctxCons instanceof CallsiteCtxConstructor) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java new file mode 100644 index 00000000000..b0512b8d6c2 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java @@ -0,0 +1,205 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.core.pag.FieldRefNode; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.MethodPAG; +import qilin.core.pag.Node; +import qilin.core.pag.PAG; +import soot.ArrayType; +import soot.RefType; +import soot.SootClass; +import soot.SootMethod; +import soot.Type; +import soot.jimple.spark.pag.SparkField; +import soot.util.queue.QueueReader; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/* + * This is a much simpler scheme for finding context-dependent objects. + * This file does not belong to any part of DebloaterX. + * (1) a container type is a class which has a `java.lang.Object` field or a container type field, + * or it implements `java.util.Collection` or is nested in a class implementing `java.util.Collection`. + * (2) an object is context-dependent if it is of a container type. + * */ +public class CollectionHeuristic { + protected final PTA pta; + protected final PAG pag; + + protected final Map> t2Fields = new ConcurrentHashMap<>(); + + protected final Set containerType = ConcurrentHashMap.newKeySet(); + + protected final Set ctxDepHeaps = ConcurrentHashMap.newKeySet(); + + public Set getCtxDepHeaps() { + return ctxDepHeaps; + } + + public CollectionHeuristic(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + + } + + private void buildHeapFieldsMappingIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + Set stores = new HashSet<>(); + Set loads = new HashSet<>(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof FieldRefNode frn) { + stores.add(frn); + } + } else if (from instanceof FieldRefNode frn) { + loads.add(frn); + } + } + // handle STORE + for (FieldRefNode frn : stores) { + LocalVarNode storeBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + } + } + // handle LOAD + for (FieldRefNode frn : loads) { + LocalVarNode loadBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + } + } + } + + private void buildHeapFieldsMapping() { + pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(this::buildHeapFieldsMappingIn); + } + + private boolean isImplementingCollection(SootClass sc) { + Set allInterfaces = new HashSet<>(sc.getInterfaces()); + while (sc.hasSuperclass()) { + sc = sc.getSuperclass(); + allInterfaces.addAll(sc.getInterfaces()); + } + // interface may also have super class + Set worklist = new HashSet<>(); + for (SootClass tmp : allInterfaces) { + while (tmp.hasSuperclass() && tmp.getSuperclass().isInterface()) { + worklist.add(tmp.getSuperclass()); + tmp = tmp.getSuperclass(); + } + } + allInterfaces.addAll(worklist); + boolean flag = false; + for (SootClass interf : allInterfaces) { + if (interf.getType() == RefType.v("java.util.Collection") + // || interf.getType() == RefType.v("java.util.Map") + ) { + flag = true; + } + } + return flag; + } + + private boolean isNestedInClassImplementCollection(SootClass sc) { + if (!sc.isInnerClass()) { + return false; + } + SootClass outer = sc.getOuterClass(); + if (isImplementingCollection(outer)) { + return true; + } + return isNestedInClassImplementCollection(outer); + } + + private void computeContainerTypes() { + for (Type type : t2Fields.keySet()) { + if (type instanceof RefType refType) { + SootClass sc = refType.getSootClass(); + if (isImplementingCollection(sc) || isNestedInClassImplementCollection(sc)) { + containerType.add(type); + } else { + for (SparkField sf : t2Fields.get(type)) { + if (sf.getType() == RefType.v("java.lang.Object")) { + containerType.add(type); + break; + } + } + } + } else if (type instanceof ArrayType at) { + if (at.baseType == RefType.v("java.lang.Object")) { + containerType.add(at); + } + } else { + System.out.println(type); + } + } + // build a mapping from any field type to their containing type. + Map> ft2t = new HashMap<>(); + for (Type type : t2Fields.keySet()) { + if (type instanceof RefType) { + for (SparkField sf : t2Fields.get(type)) { + Type sft = sf.getType(); + if (sft instanceof ArrayType at) { + sft = at.baseType; + } + ft2t.computeIfAbsent(sft, k -> new HashSet<>()).add(type); + } + } else if (type instanceof ArrayType at) { + ft2t.computeIfAbsent(at.baseType, k -> new HashSet<>()).add(type); + } + } + // find more container types by checking whether a type has a field of a container type. + Set newlyFound = new HashSet<>(); + containerType.addAll(ft2t.getOrDefault(RefType.v("java.lang.Object"), Collections.emptySet())); + for (Type t1 : containerType) { + for (Type t2 : ft2t.getOrDefault(t1, Collections.emptySet())) { + if (!containerType.contains(t2)) { + newlyFound.add(t2); + } + } + } + while (!newlyFound.isEmpty()) { + containerType.addAll(newlyFound); + Set tmp = new HashSet<>(); + for (Type t1 : newlyFound) { + for (Type t2 : ft2t.getOrDefault(t1, Collections.emptySet())) { + if (!containerType.contains(t2)) { + tmp.add(t2); + } + } + } + newlyFound.clear(); + newlyFound.addAll(tmp); + } + System.out.println("#ContainerType:" + containerType.size()); + } + + private void computeContextDependentObjects() { + for (AllocNode heap : pag.getAllocNodes()) { + if (containerType.contains(heap.getType())) { + ctxDepHeaps.add(heap); + } + } + System.out.println("#OBJECTS:" + pag.getAllocNodes().size()); + System.out.println("#CS:" + ctxDepHeaps.size()); + System.out.println("#CI:" + (pag.getAllocNodes().size() - ctxDepHeaps.size())); + } + + public void run() { + buildHeapFieldsMapping(); + computeContainerTypes(); + computeContextDependentObjects(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java new file mode 100644 index 00000000000..c614de0c3d6 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java @@ -0,0 +1,119 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.PTA; +import qilin.core.pag.AllocNode; +import qilin.core.pag.ArrayElement; +import qilin.core.pag.PAG; +import qilin.util.Stopwatch; +import soot.*; +import soot.jimple.IntConstant; +import soot.jimple.internal.JNewArrayExpr; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/* + * implementing rules for identifying container objects as shown in Figure 8 in the paper. + * */ +public class ContainerFinder { + protected final PTA pta; + protected final PAG pag; + private final Set notcontainers = ConcurrentHashMap.newKeySet(); + private final Map> containers = new ConcurrentHashMap<>(); + + private final XUtility utility; + + public ContainerFinder(PTA pta, XUtility utility) { + this.pta = pta; + this.pag = pta.getPag(); + this.utility = utility; + } + + /* + * classify objects into primitive containers, normal containers and notcontainers. + * */ + public void run() { + Stopwatch s1 = Stopwatch.newAndStart("pre-containerFinder"); + Set remainObjs = new HashSet<>(); + for (AllocNode heap : pag.getAllocNodes()) { + Type type = heap.getType(); + if (type instanceof ArrayType at) { + JNewArrayExpr nae = (JNewArrayExpr) heap.getNewExpr(); + Value vl = nae.getSize(); + if (utility.isCoarseType(at) && (!(vl instanceof IntConstant ic) || ic.value != 0)) { + containers.computeIfAbsent(heap, k -> new HashSet<>()).add(ArrayElement.v()); + } else { + notcontainers.add(heap); + } + } else if (type instanceof RefType refType) { + if (utility.isCoarseType(refType) && heap.getMethod() != null) { + remainObjs.add(heap); + } else { + notcontainers.add(heap); + } + } else { + throw new RuntimeException("invalid type for " + heap); + } + } + s1.stop(); + System.out.println(s1); + Stopwatch s2 = Stopwatch.newAndStart("mid-containerFinder"); + remainObjs.parallelStream().forEach(utility::getHCQ); + s2.stop(); + System.out.println(s2); + Stopwatch s3 = Stopwatch.newAndStart("remain-containerFinder"); + remainObjs.parallelStream().forEach(heap -> { + Set fields = utility.getFields(heap); + fields = fields.stream().filter(f -> utility.isCoarseType(f.getType())).collect(Collectors.toSet()); + HeapContainerQuery hcq = utility.getHCQ(heap); + for (SparkField field : fields) { + // check in + boolean hasIn = hasNonThisStoreOnField(heap, field, hcq); + if (!hasIn) { + continue; + } + // check out + boolean hasOut = hasNonThisLoadFromField(heap, field, hcq); + if (hasOut) { + containers.computeIfAbsent(heap, k -> new HashSet<>()).add(field); + } + } + if (!containers.containsKey(heap)) { + notcontainers.add(heap); + } + }); + s3.stop(); + System.out.println(s3); + System.out.println("#ObjectsNotAContainer:" + notcontainers.size()); + System.out.println("#Container:" + containers.size()); + } + + private boolean hasNonThisStoreOnField(AllocNode heap, SparkField field, HeapContainerQuery hcq) { + if (utility.hasNonThisStoreOnField(heap, field)) { + return true; + } + return hcq.hasParamsStoredInto(field); + } + + private boolean hasNonThisLoadFromField(AllocNode heap, SparkField field, HeapContainerQuery hcq) { + if (utility.hasNonThisLoadFromField(heap, field)) { + return true; + } + return hcq.hasOutMethodsWithRetOrParamValueFrom(field); + } + + public boolean isAContainer(AllocNode heap) { + if (this.containers.containsKey(heap)) { + return true; + } else if (heap.getMethod().getSignature().startsWith("") + || heap.getMethod().getSignature().startsWith("")) { + // We will remove such hacks in the future. The noise of [java.lang.String] types introduced by the resolving of reflection of + // Array.newInstance makes the whole analysis imprecise. Qilin's reflection mechanism causes this. One potential solution is + // not to resolve reflection for these two methods. + return true; + } + return false; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java new file mode 100644 index 00000000000..14be05aee0c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java @@ -0,0 +1,169 @@ +package qilin.pta.toolkits.debloaterx; + +import com.google.common.collect.Sets; +import qilin.core.PTA; +import qilin.core.pag.*; +import qilin.core.sets.PointsToSet; +import soot.*; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/* + * A container usage pattern-based approach to identifying context-independent objects for context debloating. + * Corresponding to Algorithm 1 in the paper. + * */ +public class DebloaterX { + private final PTA pta; + private final PAG pag; + private final ContainerFinder containerFinder; + private final XUtility utility; + + public DebloaterX(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + this.utility = new XUtility(pta); + this.containerFinder = new ContainerFinder(pta, utility); + this.containerFinder.run(); + } + + /* + * identifying factory-created containers (Fig 11 in the paper) + * */ + private boolean isAFactoryCreatedContainer(AllocNode heap, IntraFlowAnalysis mpag) { + SootMethod method = heap.getMethod(); + if (method.isStatic()) { + Type type = method.getReturnType(); + if (!(type instanceof RefLikeType)) { + return false; + } + MethodPAG methodPag = pag.getMethodPAG(method); + VarNode mRet = methodPag.nodeFactory().caseRet(); + if (pta.reachingObjects(mRet).toCIPointsToSet().toCollection().contains(heap)) { + return mpag.isDirectlyReturnedHeap(heap); + } + } + return false; + } + + /* + * identifying container wrappers (Fig 12 in the paper) + * */ + private boolean isAContainerWrapper(AllocNode heap, IntraFlowAnalysis mpag) { + SootMethod method = heap.getMethod(); + if (method.isStatic()) { + return false; + } + Type type = method.getReturnType(); + if (!(type instanceof RefLikeType)) { + return false; + } + MethodPAG methodPag = pag.getMethodPAG(method); + VarNode mRet = methodPag.nodeFactory().caseRet(); + PointsToSet pts = pta.reachingObjects(mRet); + Collection ptsSet = pts.toCIPointsToSet().toCollection(); + if (ptsSet.contains(heap)) { + if (mpag.isDirectlyReturnedHeap(heap)) { + return mpag.isContentFromParam(heap); + } + } + return false; + } + + /* + * identify inner containers (Fig 9 in the paper). + * */ + private boolean isAnInnerContainer(AllocNode heap, IntraFlowAnalysis mpag) { + SootMethod method = heap.getMethod(); + if (method.isStatic()) { + return false; + } + Set fields = mpag.retrieveStoreFields(heap); + if (fields.isEmpty()) { + return false; + } + Set objects = this.utility.getReceiverObjects(method); + for (AllocNode revobj : objects) { + if (revobj.getType() instanceof RefType) { + HeapContainerQuery hcq = this.utility.getHCQ(revobj); + for (SparkField field : fields) { + if (hcq.isCSField(field)) { + return true; + } + } + } + } + return false; + } + + protected final Set ctxDepHeaps = ConcurrentHashMap.newKeySet(); + protected final Set containerFactory = ConcurrentHashMap.newKeySet(); + protected final Set containerWrapper = ConcurrentHashMap.newKeySet(); + protected final Set innerContainer = ConcurrentHashMap.newKeySet(); + + /* + * Implementing Step 3 of Algorithm 1 (in the paper): finding context-dependent objects according to container-usage patterns + * */ + public void run() { + Map> m2o = new HashMap<>(); + for (AllocNode heap : pag.getAllocNodes()) { + SootMethod method = heap.getMethod(); + if (method == null || method.isStaticInitializer()) { + continue; + } + m2o.computeIfAbsent(method, k -> new HashSet<>()).add(heap); + } + m2o.keySet().parallelStream().forEach(method -> { + IntraFlowAnalysis ifa = new IntraFlowAnalysis(utility, method); + for (AllocNode heap : m2o.get(method)) { + if (!this.containerFinder.isAContainer(heap)) { + continue; + } + if (isAFactoryCreatedContainer(heap, ifa)) { + containerFactory.add(heap); + ctxDepHeaps.add(heap); + } + if (isAContainerWrapper(heap, ifa)) { + containerWrapper.add(heap); + ctxDepHeaps.add(heap); + } + if (isAnInnerContainer(heap, ifa)) { + innerContainer.add(heap); + ctxDepHeaps.add(heap); + } + } + }); + System.out.println("#OBJECTS:" + pag.getAllocNodes().size()); + System.out.println("#CS:" + ctxDepHeaps.size()); + System.out.println("#CI:" + (pag.getAllocNodes().size() - ctxDepHeaps.size())); + System.out.println("#ContainerFactory:" + containerFactory.size()); + System.out.println("#ContainerWrapper:" + containerWrapper.size()); + System.out.println("#InnerContainer:" + innerContainer.size()); + { + // for drawn venn3 figure. + int onlyInFactory = Sets.difference(Sets.difference(containerFactory, containerWrapper), innerContainer).size(); + int onlyInWrapper = Sets.difference(Sets.difference(containerWrapper, containerFactory), innerContainer).size(); + int onlyInInner = Sets.difference(Sets.difference(innerContainer, containerWrapper), containerFactory).size(); + int inAll = Sets.intersection(Sets.intersection(innerContainer, containerWrapper), containerFactory).size(); + int onlyInFactoryAndWrapper = Sets.difference(Sets.intersection(containerFactory, containerWrapper), innerContainer).size(); + int onlyInFactoryAndInner = Sets.difference(Sets.intersection(containerFactory, innerContainer), containerWrapper).size(); + int onlyInWrapperAndInner = Sets.difference(Sets.intersection(containerWrapper, innerContainer), containerFactory).size(); + System.out.println("#onlyInFactory:" + onlyInFactory); + System.out.println("#onlyInWrapper:" + onlyInWrapper); + System.out.println("#onlyInInner:" + onlyInInner); + System.out.println("#inAll:" + inAll); + System.out.println("#onlyInFactoryAndWrapper:" + onlyInFactoryAndWrapper); + System.out.println("#onlyInFactoryAndInner:" + onlyInFactoryAndInner); + System.out.println("#onlyInWrapperAndInner:" + onlyInWrapperAndInner); + System.out.println("#SUM:" + (onlyInFactory + onlyInWrapper + onlyInInner + inAll + onlyInFactoryAndWrapper + onlyInFactoryAndInner + onlyInWrapperAndInner)); + System.out.println("venn3(subsets = (" + onlyInFactory + "," + onlyInWrapper + "," + onlyInFactoryAndWrapper + "," + onlyInInner + "," + + onlyInFactoryAndInner + "," + onlyInWrapperAndInner + ", " + inAll + "))"); + } + } + + public Set getCtxDepHeaps() { + return ctxDepHeaps; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java new file mode 100644 index 00000000000..04f841c17d8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java @@ -0,0 +1,18 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.pag.Node; +import soot.jimple.spark.pag.SparkField; + +public class Edge { + Node from; + Node to; + SparkField field; + EdgeKind kind; + + Edge(Node from, Node to, SparkField f, EdgeKind kind) { + this.from = from; + this.to = to; + this.field = f; + this.kind = kind; + } +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java new file mode 100644 index 00000000000..8b6cc07db9d --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java @@ -0,0 +1,19 @@ +package qilin.pta.toolkits.debloaterx; + +public enum EdgeKind { + // "I" means inverse. + NEW, INEW, + // the following two used for normal assign, cast, and inter-procedural assign for invocations with "this" as the base variable. + // no global assignments are included. + ASSIGN, IASSIGN, + // the following four used only for normal Java store and load. + LOAD, ILOAD, + STORE, ISTORE, + // the following four model parameter passing for non-this invocation. + CLOAD, ICLOAD, + CSTORE, ICSTORE, + // the following three are self-loops. + THIS, ITHIS, + PARAM, + RETURN, +} \ No newline at end of file diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java new file mode 100644 index 00000000000..baab883355a --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java @@ -0,0 +1,77 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.util.PTAUtils; +import soot.*; +import soot.jimple.spark.pag.SparkField; + +import java.util.*; +import java.util.stream.Collectors; + +public class HeapContainerQuery { + private final PAG pag; + private final XUtility utility; + private final Set invokedMs; + private final Set params; + private final InterFlowAnalysis interfa; + private final AllocNode heap; + + + public HeapContainerQuery(XUtility utility, AllocNode heap) { + this.utility = utility; + this.pag = utility.getPta().getPag(); + this.heap = heap; + this.invokedMs = utility.getInvokedMethods(heap); + this.interfa = utility.getInterFlowAnalysis(); + this.params = getParameters(); + } + + /* computes input parameters for the class of refType */ + private Set getParameters() { + Set ret = new HashSet<>(); + for (SootMethod m : invokedMs) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + for (int i = 0; i < m.getParameterCount(); ++i) { + if (m.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(m.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) mthdNF.caseParm(i); + ret.add(param); + } + } + ret.add((LocalVarNode) mthdNF.caseThis()); + } + return ret; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* APIs for query */ + public boolean hasParamsStoredInto(SparkField field) { + Set tmp = interfa.getParamsStoredInto(field); + tmp = tmp.stream().filter(this.params::contains).collect(Collectors.toSet()); + return !tmp.isEmpty(); + } + + public Set getInParamsToCSFields() { + Set fields = utility.getFields(heap); + Set ret = new HashSet<>(); + for (SparkField field : fields) { + if (isCSField(field)) { + ret.addAll(interfa.getParamsStoredInto(field)); + } + } + ret = ret.stream().filter(this.params::contains).collect(Collectors.toSet()); + return ret; + } + + public boolean hasOutMethodsWithRetOrParamValueFrom(SparkField field) { + Set tmp = interfa.getOutMethodsWithRetOrParamValueFrom(field); + tmp = tmp.stream().filter(this.invokedMs::contains).collect(Collectors.toSet()); + return !tmp.isEmpty(); + } + + public boolean isCSField(SparkField field) { + boolean hasIn = utility.hasNonThisStoreOnField(this.heap, field) || hasParamsStoredInto(field); + boolean hasOut = utility.hasNonThisLoadFromField(this.heap, field) || hasOutMethodsWithRetOrParamValueFrom(field); + return hasIn && hasOut; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java new file mode 100644 index 00000000000..c25ae1eb244 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java @@ -0,0 +1,222 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.Node; +import qilin.util.Pair; +import qilin.util.queue.UniqueQueue; +import soot.SootMethod; +import soot.jimple.spark.pag.SparkField; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +public class InterFlowAnalysis { + protected final XUtility utility; + protected final XPAG xpag; + /* records the reachability info: given a field F, (1) which params could be saved into F + * (2) F could flows to which method's param or return node. + */ + protected final Map> field2InParams = new ConcurrentHashMap<>(); + protected final Map> field2OutParams = new ConcurrentHashMap<>(); + + public InterFlowAnalysis(XUtility utility) { + this.utility = utility; + this.xpag = utility.getXpag(); + reachabilityAnalysis(); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* reachability analysis: fill content in field2InParams and field2Outs + * This is the implementation of Algorithm 2 in the paper. + * */ + public void reachabilityAnalysis() { + Set fields = utility.getFields(); + fields.parallelStream().forEach(field -> { + // compute the value of field could be loaded to which outmethods. + Set retOrParams = runDFAandCollect(field, false); + if (!retOrParams.isEmpty()) { + field2OutParams.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).addAll(retOrParams); + } + // compute the params could be stored into the specified field. + Set params = runDFAandCollect(field, true); + if (!params.isEmpty()) { + field2InParams.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).addAll(params); + } + }); + } + + /* + * When isInflow = true, check whether the value in param could be stored into field. + * Otherwise, check whether the value in field could be loaded to any method's return value or params. + * */ + private Set runDFAandCollect(SparkField field, boolean isInflow) { + Set ret = new HashSet<>(); + Map> state2nodes = new HashMap<>(); + Queue> queue = new UniqueQueue<>(); + queue.add(new Pair<>(xpag.getDummyThis(), State.THIS)); + while (!queue.isEmpty()) { + Pair front = queue.poll(); + if (front.getSecond() == State.End) { + if (front.getFirst() instanceof LocalVarNode lvn) { + ret.add(lvn); + } + } + // visit the node and state. + visit(front, state2nodes); + Set> nexts = getNextNodeStates(front, field, isInflow); + for (Pair nodeState : nexts) { + if (!isVisited(nodeState, state2nodes)) { + queue.add(nodeState); + } + } + } + return ret; + } + + private Set> getNextNodeStates(Pair nodeState, SparkField field, boolean in) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + Set> ret = new HashSet<>(); + for (Edge edge : xpag.getOutEdges(node)) { + boolean mathched = edge.field != null && edge.field.equals(field); + State nextState; + if (in) { + nextState = nextStateForIn(state, edge.kind, mathched); + } else { + nextState = nextStateForOut(state, edge.kind, mathched); + } + if (nextState != State.Error) { + ret.add(new Pair<>(edge.to, nextState)); + } + } + return ret; + } + + /* + * This method describes another automaton and its transition function for checking whether the field value could be + * loaded to any method's return. + * Correspoing to the automaton given in Fig 7c in the paper. + * */ + private State nextStateForOut(State currState, EdgeKind kind, boolean fieldMatch) { + switch (currState) { + case THIS -> { + if (kind == EdgeKind.ITHIS) { + return State.ThisAlias; + } + } + case ThisAlias -> { + if (kind == EdgeKind.ASSIGN) { + return State.ThisAlias; + } else if (kind == EdgeKind.LOAD && fieldMatch) { + return State.VPlus; + } + } + case VPlus -> { + if (kind == EdgeKind.ASSIGN || kind == EdgeKind.LOAD || kind == EdgeKind.CLOAD) { + return State.VPlus; + } else if (kind == EdgeKind.RETURN) { + return State.End; + } else if (kind == EdgeKind.CSTORE || kind == EdgeKind.STORE || kind == EdgeKind.ICSTORE || kind == EdgeKind.ISTORE) { + //kind == EdgeKind.ICSTORE || kind == EdgeKind.ISTORE can be removed. + return State.VMinus; + } + } + case VMinus -> { + if (kind == EdgeKind.IASSIGN || kind == EdgeKind.ILOAD || kind == EdgeKind.ICLOAD) { + return State.VMinus; + } else if (kind == EdgeKind.INEW) { + return State.O; + } else if (kind == EdgeKind.PARAM) { + return State.End; + } + } + case O -> { + if (kind == EdgeKind.NEW) { + return State.VPlus; + } + } + } + return State.Error; + } + + private void visit(Pair nodeState, Map> state2nodes) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + state2nodes.computeIfAbsent(state, k -> new HashSet<>()).add(node); + } + + private boolean isVisited(Pair nodeState, Map> state2nodes) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + Set nodes = state2nodes.getOrDefault(state, Collections.emptySet()); + return nodes.contains(node); + } + + /* + * This method describes an automaton and its transition function for checking whether the value could be stored + * into any field. + * Correspoing to the automaton given in Fig 7b in the paper. + * */ + private State nextStateForIn(State currState, EdgeKind kind, boolean fieldMatch) { + switch (currState) { + case O -> { + if (kind == EdgeKind.NEW) { + return State.VPlus; + } + } + case THIS -> { + if (kind == EdgeKind.ITHIS) { + return State.ThisAlias; + } + } + case VPlus -> { + if (kind == EdgeKind.ASSIGN || kind == EdgeKind.LOAD || kind == EdgeKind.CLOAD) { + return State.VPlus; + } else if (kind == EdgeKind.ISTORE || kind == EdgeKind.STORE || kind == EdgeKind.ICSTORE || kind == EdgeKind.CSTORE) { + // kind == EdgeKind.STORE || kind == EdgeKind.ICSTORE can be deleted due to not occured in the real world. + return State.VMinus; + } + } + case VMinus -> { + if (kind == EdgeKind.IASSIGN || kind == EdgeKind.ILOAD || kind == EdgeKind.ICLOAD) { + return State.VMinus; + } else if (kind == EdgeKind.INEW) { + return State.O; + } else if (kind == EdgeKind.PARAM) { + return State.End; + } + } + case ThisAlias -> { + if (kind == EdgeKind.ASSIGN) { + return State.ThisAlias; + } else if (kind == EdgeKind.ISTORE) { + if (fieldMatch) { + return State.VMinus; + } + } else if (kind == EdgeKind.LOAD) { + if (fieldMatch) { + return State.VPlus; + } + } + } + } + return State.Error; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* APIs for query */ + public Set getParamsStoredInto(SparkField field) { + return this.field2InParams.getOrDefault(field, Collections.emptySet()); + } + + public Set getOutMethodsWithRetOrParamValueFrom(SparkField field) { + return field2OutParams.getOrDefault(field, Collections.emptySet()).stream().map(LocalVarNode::getMethod).collect(Collectors.toSet()); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java new file mode 100644 index 00000000000..65e78c70175 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java @@ -0,0 +1,298 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.util.PTAUtils; +import qilin.util.Pair; +import qilin.util.queue.UniqueQueue; +import soot.*; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.NullConstant; +import soot.jimple.Stmt; +import soot.jimple.spark.pag.SparkField; +import soot.util.NumberedString; +import soot.util.queue.QueueReader; + +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; + +/* + * Implementation of Algorithm 3 and Fig 10 in the paper. + * */ +public class IntraFlowAnalysis { + private final PAG pag; + private final XUtility utility; + private final SootMethod method; + protected final XPAG xpag; + protected final Set params = new HashSet<>(); + + public IntraFlowAnalysis(XUtility utility, SootMethod method) { + this.utility = utility; + this.pag = utility.getPta().getPag(); + this.method = method; + this.xpag = utility.getXpag(); + collectParams(); + } + + protected void collectParams() { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + VarNode thisNode = srcnf.caseThis(); + // handle parameters + for (int i = 0; i < method.getParameterCount(); ++i) { + if (method.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + this.params.add(param); + } + } + this.params.add((LocalVarNode) thisNode); + } + + ////////////////////////////////////////////////////////////////////////////////// + /* + * x = y = z = ... = node; + * */ + Set epsilon(Node node) { + Queue queue = new UniqueQueue<>(); + for (Edge edge : xpag.getOutEdges(node)) { + queue.add(edge.to); + } + Set visit = new HashSet<>(); + while (!queue.isEmpty()) { + Node front = queue.poll(); + visit.add(front); + for (Edge edge : xpag.getOutEdges(front)) { + if (edge.kind == EdgeKind.ASSIGN && !visit.contains(edge.to)) { + queue.add(edge.to); + } + } + } + return visit; + } + + /* + * t = new T; + * x = ... = t; + * return x; + * */ + public boolean isDirectlyReturnedHeap(AllocNode heap) { + Set visit = epsilon(heap); + boolean flag = false; + for (Node node : visit) { + if (node instanceof LocalVarNode lvn) { + if (lvn.isReturn()) { + flag = true; + } + } + } + return flag; + } + + public boolean isContentFromParam(AllocNode heap) { + Type heapType = heap.getType(); + if (heapType instanceof RefType) { + return isInstanceObjectContentFromParam(heap); + } else { + return isArrayContentFromParam(heap); + } + } + + /* + * return true iff heap.f comes from any parameter of heap.getMethod(). + * */ + private boolean isInstanceObjectContentFromParam(AllocNode heap) { + Set paramInArgs = collectParamInArguments(heap); + if (paramInArgs.isEmpty()) { + return false; + } + Queue queue = new UniqueQueue<>(); + Set visited = new HashSet<>(); + queue.addAll(params); + while (!queue.isEmpty()) { + Node front = queue.poll(); + if (paramInArgs.contains(front)) { + return true; + } + visited.add(front); + for (Edge edge : xpag.getOutEdges(front)) { + if (edge.kind == EdgeKind.ASSIGN || edge.kind == EdgeKind.CLOAD || edge.kind == EdgeKind.LOAD) { + if (!visited.contains(edge.to)) { + queue.add(edge.to); + } + } + } + } + return false; + } + + private Set collectParamInArguments(AllocNode heap) { + RefType type = (RefType) heap.getType(); + Set x = epsilon(heap); + Set ret = new HashSet<>(); + HeapContainerQuery hcq = this.utility.getHCQ(heap); + Set inParams = hcq.getInParamsToCSFields(); + MethodPAG srcmpag = pag.getMethodPAG(method); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); + if (!(ie instanceof InstanceInvokeExpr iie)) { + continue; + } + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + if (!x.contains(receiver)) { + continue; + } + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + continue; + } + args[i] = arg; + } + NumberedString subSig = iie.getMethodRef().getSubSignature(); + VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, method, iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); + QueueReader targets = PTAUtils.dispatch(type, virtualCallSite); + while (targets.hasNext()) { + SootMethod target = targets.next(); + MethodPAG tgtmpag = pag.getMethodPAG(target); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + int numParms = target.getParameterCount(); + if (numParms != numArgs) { + System.out.println(target); + } + for (int i = 0; i < numParms; i++) { + if (target.getParameterType(i) instanceof RefLikeType) { + if (args[i] != null) { + ValNode argNode = pag.findValNode(args[i]); + if (argNode instanceof LocalVarNode lvn) { + LocalVarNode param = (LocalVarNode) tgtnf.caseParm(i); + if (inParams.contains(param)) { + ret.add(lvn); + } + } + } + } + } + } + } + return ret; + } + + /* + * x = new T[] + * x[i] = param.*; + * */ + private boolean isArrayContentFromParam(AllocNode heap) { + if (!(heap.getType() instanceof ArrayType)) { + return false; + } + Set x = epsilon(heap); + Queue queue = new UniqueQueue<>(); + Set visited = new HashSet<>(); + queue.addAll(params); + while (!queue.isEmpty()) { + Node front = queue.poll(); + visited.add(front); + for (Edge edge : xpag.getOutEdges(front)) { + if (edge.kind == EdgeKind.ASSIGN || edge.kind == EdgeKind.CLOAD || edge.kind == EdgeKind.LOAD) { + if (!visited.contains(edge.to)) { + queue.add(edge.to); + } + } + if (edge.kind == EdgeKind.STORE) { + if (x.contains(edge.to)) { + return true; + } + } + } + } + return false; + } + + private State nextState(State currState, EdgeKind kind) { + switch (currState) { + case O -> { + if (kind == EdgeKind.NEW) { + return State.VPlus; + } + } + case VPlus -> { + if (kind == EdgeKind.ASSIGN) { + return State.VPlus; + } else if (kind == EdgeKind.STORE) { + return State.VMinus; + } + } + case VMinus -> { + if (kind == EdgeKind.IASSIGN) { + return State.VMinus; + } else if (kind == EdgeKind.ILOAD) { + return State.VMinus; + } else if (kind == EdgeKind.INEW) { + return State.O; + } + } + } + return State.Error; + } + + /* + * implementation of nextNodeStates in Algorithm 3 in the paper. It also encodes Fig 10 in the paper. + * */ + private Set> getNextNodeStates(Pair nodeState, Set thisAlias, Set stFields) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + Set> ret = new HashSet<>(); + for (Edge edge : xpag.getOutEdges(node)) { + State nextState = nextState(state, edge.kind); + if (nextState != State.Error) { + if (edge.kind == EdgeKind.STORE && thisAlias.contains(edge.to)) { + Type type = edge.field.getType(); + if (!utility.isCoarseType(type)) { + continue; + } + stFields.add(edge.field); + } else if (edge.kind == EdgeKind.ILOAD && thisAlias.contains(edge.to)) { + Type type = edge.field.getType(); + if (!utility.isCoarseType(type)) { + continue; + } + stFields.add(edge.field); + } else { + ret.add(new Pair<>(edge.to, nextState)); + } + } + } + return ret; + } + + /* + * Implementation of Algorithm 3 in the paper. + * */ + public Set retrieveStoreFields(AllocNode heap) { + Set ret = new HashSet<>(); + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + VarNode thisNode = srcnf.caseThis(); + Set thisAlias = epsilon(thisNode); + Queue> queue = new UniqueQueue<>(); + Set> visited = new HashSet<>(); + queue.add(new Pair<>(heap, State.O)); + while (!queue.isEmpty()) { + Pair front = queue.poll(); + visited.add(front); + Set> nextStates = getNextNodeStates(front, thisAlias, ret); + for (Pair nextState : nextStates) { + if (!visited.contains(nextState)) { + queue.add(nextState); + } + } + } + return ret; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java new file mode 100644 index 00000000000..210c4c10294 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java @@ -0,0 +1,5 @@ +package qilin.pta.toolkits.debloaterx; + +public enum State { + P, VPlus, VMinus, O, ThisAlias, THIS, End, Error +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java new file mode 100644 index 00000000000..a05706a3ef0 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -0,0 +1,267 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.PTA; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.util.PTAUtils; +import qilin.util.queue.UniqueQueue; +import soot.RefLikeType; +import soot.RefType; +import soot.SootMethod; +import soot.Unit; +import soot.Value; +import soot.jimple.*; +import soot.jimple.spark.pag.SparkField; +import soot.util.queue.QueueReader; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class XPAG { + /* record nodes and edges in the graph */ + protected final Map> outEdges = new ConcurrentHashMap<>(); + protected final PTA pta; + protected final PAG pag; + private final LocalVarNode dummyThis; + protected final XUtility utility; + + public XPAG(PTA pta, XUtility utility) { + this.pta = pta; + this.pag = pta.getPag(); + this.utility = utility; + this.dummyThis = new LocalVarNode("DUMMYTHIS", RefType.v("java.lang.Object"), null); + buildGraph(pta.getNakedReachableMethods()); + } + + /* + * Constructing the XPAG for a program (Figure 5 in the paper) + * */ + protected void buildGraph(Collection reachables) { + // add edges in each method + reachables.parallelStream().forEach(this::buildInternal); + } + + protected void buildInternal(SootMethod method) { + buildInternalWithInline(method); + } + + protected void buildInternalWithInline(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + VarNode thisNode = srcnf.caseThis(); + // add special ``this'' edge + addThisEdge((LocalVarNode) thisNode); + // add normal edges: NEW, ASSIGN, LOAD, STORE + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + } else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase(), fr.getField()); + } // local-global + + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to, fr.getField()); + } // global-local + } + // handle call statements. + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + continue; + args[i] = arg; + } + LocalVarNode retDest = null; + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + retDest = pag.findLocalVarNode(dest); + } + } + if (ie instanceof InstanceInvokeExpr iie) { + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + if (iie instanceof SpecialInvokeExpr sie) { + inline(s, sie.getMethod()); + } else { + /* instance call with non-this base variable are modeled as in Eagle/Turner. */ + modelVirtualCall(numArgs, args, receiver, retDest); + } + } else { + if (ie instanceof StaticInvokeExpr sie) { + SootMethod target = sie.getMethod(); + inline(s, target); + } + } + } + // handle parameters. + for (int i = 0; i < method.getParameterCount(); ++i) { + if (method.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + addParamEdge(param); + } + } + // treat this as a special parameter. + if (!method.isStatic()) { + addParamEdge((LocalVarNode) srcnf.caseThis()); + } + // handle returns + if (method.getReturnType() instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { + addReturnEdge((LocalVarNode) srcnf.caseRet()); + } + } + + private void modelVirtualCall(int numArgs, Value[] args, LocalVarNode receiver, LocalVarNode retDest) { + for (int i = 0; i < numArgs; i++) { + if (args[i] == null) { + continue; + } + ValNode argNode = pag.findValNode(args[i]); + if (argNode instanceof LocalVarNode) { + addCStoreEdge((LocalVarNode) argNode, receiver); + } + } + if (retDest != null) { + addCLoadEdge(receiver, retDest); + } + addCStoreEdge(receiver, receiver); + } + + private void inline(Stmt invokeStmt, SootMethod method) { + InvokeExpr ie = invokeStmt.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + continue; + args[i] = arg; + } + LocalVarNode retDest = null; + if (invokeStmt instanceof AssignStmt) { + Value dest = ((AssignStmt) invokeStmt).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { + retDest = pag.findLocalVarNode(dest); + } + } + LocalVarNode receiver = null; + if (ie instanceof InstanceInvokeExpr iie) { + receiver = pag.findLocalVarNode(iie.getBase()); + } + MethodPAG mpag = pag.getMethodPAG(method); + MethodNodeFactory nodeFactory = mpag.nodeFactory(); + if (numArgs != method.getParameterCount()) { + return; + } + // handle parameters + for (int i = 0; i < method.getParameterCount(); ++i) { + if (args[i] != null && method.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) nodeFactory.caseParm(i); + ValNode argVal = pag.findValNode(args[i]); + if (argVal instanceof LocalVarNode argNode) { + addAssignEdge(argNode, param); + } + } + } + // handle return node + if (retDest != null && method.getReturnType() instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { + addAssignEdge((LocalVarNode) nodeFactory.caseRet(), retDest); + } + // handle this node + if (receiver != null) { + addAssignEdge(receiver, (LocalVarNode) nodeFactory.caseThis()); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + protected void addNormalEdge(Edge edge) { + outEdges.computeIfAbsent(edge.from, k -> ConcurrentHashMap.newKeySet()).add(edge); + } + + /* methods for adding normal edges: NEW, ASSIGN, STORE, LOAD. */ + protected void addNewEdge(AllocNode from, LocalVarNode to) { + // skip merged heaps. + if (from.getMethod() == null && !(from instanceof ConstantNode)) { + return; + } + Edge newEdge = new Edge(from, to, null, EdgeKind.NEW); + addNormalEdge(newEdge); + Edge iNewEdge = new Edge(to, from, null, EdgeKind.INEW); + addNormalEdge(iNewEdge); + } + + protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { + Edge assignEdge = new Edge(from, to, null, EdgeKind.ASSIGN); + addNormalEdge(assignEdge); + Edge iAssignEdge = new Edge(to, from, null, EdgeKind.IASSIGN); + addNormalEdge(iAssignEdge); + } + + protected void addStoreEdge(LocalVarNode from, LocalVarNode base, SparkField field) { + Edge storeEdge = new Edge(from, base, field, EdgeKind.STORE); + addNormalEdge(storeEdge); + Edge iStoreEdge = new Edge(base, from, field, EdgeKind.ISTORE); + addNormalEdge(iStoreEdge); + } + + protected void addLoadEdge(LocalVarNode base, LocalVarNode to, SparkField field) { + Edge loadEdge = new Edge(base, to, field, EdgeKind.LOAD); + addNormalEdge(loadEdge); + Edge iLoadEdge = new Edge(to, base, field, EdgeKind.ILOAD); + addNormalEdge(iLoadEdge); + } + + /* methods for adding inter-procedural edges at non-this invocation site */ + protected void addCStoreEdge(LocalVarNode from, LocalVarNode base) { + Edge cstoreEdge = new Edge(from, base, null, EdgeKind.CSTORE); + addNormalEdge(cstoreEdge); + Edge iCstoreEdge = new Edge(base, from, null, EdgeKind.ICSTORE); + addNormalEdge(iCstoreEdge); + } + + protected void addCLoadEdge(LocalVarNode base, LocalVarNode to) { + Edge cLoadEdge = new Edge(base, to, null, EdgeKind.CLOAD); + addNormalEdge(cLoadEdge); + Edge iCloadEdge = new Edge(to, base, null, EdgeKind.ICLOAD); + addNormalEdge(iCloadEdge); + } + + /* this is a special edge */ + protected void addThisEdge(LocalVarNode thisNode) { + Edge thisEdge = new Edge(thisNode, dummyThis, null, EdgeKind.THIS); + addNormalEdge(thisEdge); + Edge ithisEdge = new Edge(dummyThis, thisNode, null, EdgeKind.ITHIS); + addNormalEdge(ithisEdge); + } + + /* methods for adding self-loop edges */ + protected void addParamEdge(LocalVarNode param) { + Edge paramEdge = new Edge(param, param, null, EdgeKind.PARAM); + addNormalEdge(paramEdge); + } + + protected void addReturnEdge(LocalVarNode ret) { + Edge retEdge = new Edge(ret, ret, null, EdgeKind.RETURN); + addNormalEdge(retEdge); + } + + public Set getOutEdges(Node node) { + return this.outEdges.getOrDefault(node, Collections.emptySet()); + } + + public LocalVarNode getDummyThis() { + return dummyThis; + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java new file mode 100644 index 00000000000..d6509569c82 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -0,0 +1,314 @@ +package qilin.pta.toolkits.debloaterx; + +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.core.builder.MethodNodeFactory; +import qilin.core.pag.*; +import qilin.util.PTAUtils; +import qilin.util.Stopwatch; +import soot.ArrayType; +import soot.RefType; +import soot.SootClass; +import soot.SootField; +import soot.SootMethod; +import soot.Type; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.Stmt; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.NumberedString; +import soot.util.queue.QueueReader; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +public class XUtility { + protected final PTA pta; + protected final PAG pag; + + protected final Map o2HCQ = new ConcurrentHashMap<>(); + /* records objects and their instance fields */ + protected final Map> o2Fields = new ConcurrentHashMap<>(); + protected final Map> t2Fields = new ConcurrentHashMap<>(); + protected final Map>> o2nonThisFStores = new ConcurrentHashMap<>(); + protected final Map>> t2nonThisFStores = new ConcurrentHashMap<>(); + protected final Map>> o2nonThisFLoads = new ConcurrentHashMap<>(); + protected final Map>> t2nonThisFLoads = new ConcurrentHashMap<>(); + + /* records the methods and their receiver objects and types */ + protected final Map> o2InvokedMethods = new HashMap<>(); + protected final Map> t2InvokedMethods = new HashMap<>(); + protected final Map> m2receiverObjects = new HashMap<>(); + + protected final Set rawOrPolyTypes = new HashSet<>(); + protected final XPAG xpag; + protected final InterFlowAnalysis interfa; + + public XUtility(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + Stopwatch stopwatch = Stopwatch.newAndStart("HackUtility construction"); + buildHeapFieldsMapping(); + buildHeapMethodsMapping(); + computeRawOrPolyTypes(); + this.xpag = new XPAG(pta, this); + this.interfa = new InterFlowAnalysis(this); + stopwatch.stop(); + System.out.println(stopwatch); + } + + public PTA getPta() { + return pta; + } + + public XPAG getXpag() { + return xpag; + } + + public InterFlowAnalysis getInterFlowAnalysis() { + return interfa; + } + + private boolean isImpreciseType(Type type) { + if (type == RefType.v("java.lang.Object")) { + return true; + } + if (type instanceof RefType refType) { + SootClass sc = refType.getSootClass(); + return sc.isAbstract() || sc.isInterface() || sc.getShortName().startsWith("Abstract"); + } + return false; + } + + /* Implemnting the rules for defining coarse types (Figure 6 in the paper) */ + public boolean isCoarseType(Type type) { + if (type instanceof ArrayType at) { + type = at.getElementType(); + } + return isImpreciseType(type) || rawOrPolyTypes().contains(type); + } + + private void computeRawOrPolyTypes() { + Set types = new HashSet<>(); + for (AllocNode heap : pag.getAllocNodes()) { + Type type = heap.getType(); + if (type instanceof ArrayType at) { + Type et = at.getElementType(); + if (isImpreciseType(et)) { + rawOrPolyTypes.add(et); + } else { + types.add(et); + } + } else { + for (SparkField field : getFields(heap)) { + Type ft = field.getType(); + if (ft instanceof ArrayType fat) { + ft = fat.getElementType(); + } + if (isImpreciseType(ft)) { + rawOrPolyTypes.add(ft); + rawOrPolyTypes.add(type); + } else { + types.add(type); + types.add(ft); + } + } + } + } + boolean continueUpdating = true; + while (continueUpdating) { + continueUpdating = false; + for (Type type : types) { + for (SparkField field : getFields(type)) { + Type ft = field.getType(); + if (isCoarseType(ft)) { + if (rawOrPolyTypes.add(type)) { + continueUpdating = true; + } + } + } + } + } + } + + private Set rawOrPolyTypes() { + return rawOrPolyTypes; + } + + /* record objects and their fields */ + private void buildHeapFieldsMappingIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + Set stores = new HashSet<>(); + Set loads = new HashSet<>(); + Set thisAliases = new HashSet<>(); + thisAliases.add(thisRef); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof FieldRefNode frn) { + stores.add(frn); + } + if (thisAliases.contains(from) && to instanceof LocalVarNode) { + thisAliases.add(to); + } + } else if (from instanceof FieldRefNode frn) { + loads.add(frn); + } + } + // handle STORE + for (FieldRefNode frn : stores) { + LocalVarNode storeBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + boolean isNonthisBase = !thisAliases.contains(storeBase); + for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { + o2Fields.computeIfAbsent(heap, k -> ConcurrentHashMap.newKeySet()).add(field); + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + if (isNonthisBase) { + Map> f2bs = o2nonThisFStores.computeIfAbsent(heap, k -> new ConcurrentHashMap<>()); + f2bs.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(storeBase); + Map> f2bsx = t2nonThisFStores.computeIfAbsent(heap.getType(), k -> new ConcurrentHashMap<>()); + f2bsx.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(storeBase); + } + } + } + // handle LOAD + for (FieldRefNode frn : loads) { + LocalVarNode loadBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + boolean isNonthisBase = !thisAliases.contains(loadBase); + for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { + o2Fields.computeIfAbsent(heap, k -> ConcurrentHashMap.newKeySet()).add(field); + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + if (isNonthisBase) { + Map> f2bs = o2nonThisFLoads.computeIfAbsent(heap, k -> new ConcurrentHashMap<>()); + f2bs.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(loadBase); + Map> f2bsx = t2nonThisFLoads.computeIfAbsent(heap.getType(), k -> new ConcurrentHashMap<>()); + f2bsx.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(loadBase); + } + } + } + } + + private void buildHeapFieldsMapping() { + pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(this::buildHeapFieldsMappingIn); + } + + /* records objects (together with their types) and their invoked methods */ + private void buildHeapMethodsMapping() { + CallGraph callgraph = pta.getCallGraph(); + // collect virtual callsites. + Set vcallsites = new HashSet<>(); + for (Edge edge : callgraph) { + SootMethod tgtM = edge.tgt(); + if (tgtM.isStatic() || tgtM.isPhantom()) { + continue; + } + final Stmt s = edge.srcStmt(); + InvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof InstanceInvokeExpr iie) { + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + NumberedString subSig = iie.getMethodRef().getSubSignature(); + VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, edge.src(), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); + vcallsites.add(virtualCallSite); + } else { + throw new RuntimeException("ie could not be of " + ie.getClass()); + } + } + // foreach virtualcallsite, we build mapping from their receiver objects. + for (VirtualCallSite vcallsite : vcallsites) { + InstanceInvokeExpr iie = vcallsite.iie(); + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + for (AllocNode heap : pta.reachingObjects(receiver).toCIPointsToSet().toCollection()) { + QueueReader reader = PTAUtils.dispatch(heap.getType(), vcallsite); + while (reader.hasNext()) { + SootMethod tgtM = reader.next(); + m2receiverObjects.computeIfAbsent(tgtM, k -> new HashSet<>()).add(heap); + o2InvokedMethods.computeIfAbsent(heap, k -> new HashSet<>()).add(tgtM); + t2InvokedMethods.computeIfAbsent(heap.getType(), k -> new HashSet<>()).add(tgtM); + } + } + } + } + + // Below are public APIs for access. + + public Set getReceiverObjects(SootMethod method) { + return m2receiverObjects.getOrDefault(method, Collections.emptySet()); + } + + public Set getInvokedMethods(AllocNode heap) { + return o2InvokedMethods.getOrDefault(heap, Collections.emptySet()); + } + + /* get or create TPAG for a given type */ + public HeapContainerQuery getHCQ(AllocNode heap) { + HeapContainerQuery hcq = o2HCQ.get(heap); + if (hcq == null) { + hcq = new HeapContainerQuery(this, heap); + o2HCQ.put(heap, hcq); + } + return hcq; + } + + public Set getFields() { + Set tmp = this.o2Fields.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + Set ret = new HashSet<>(); + for (SparkField field : tmp) { + Type type = field.getType(); + if (isCoarseType(type)) { + ret.add(field); + } + } + return ret; + } + + public Set getFields(AllocNode heap) { + return this.o2Fields.getOrDefault(heap, Collections.emptySet()); + } + + public Set getFields(Type type) { + if (type instanceof RefType refType) { + Set ret = this.t2Fields.get(refType); + if (ret != null) { + return ret; + } else { + ret = this.t2Fields.computeIfAbsent(refType, k -> new HashSet<>()); + for (AllocNode heap : this.o2Fields.keySet()) { + if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(heap.getType(), refType)) { + for (SparkField sparkField : this.o2Fields.get(heap)) { + if (sparkField instanceof Field f) { + SootField sf = f.getField(); + Type declType = sf.getDeclaringClass().getType(); + if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, declType)) { + ret.add(sparkField); + } + } else { + throw new RuntimeException(sparkField + ";" + sparkField.getClass()); + } + } + } + } + return ret; + } + } else { + return Collections.emptySet(); + } + } + + public boolean hasNonThisStoreOnField(AllocNode heap, SparkField field) { + Map> field2bases = this.o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); + return field2bases.containsKey(field); + } + + public boolean hasNonThisLoadFromField(AllocNode heap, SparkField field) { + Map> field2bases = this.o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()); + return field2bases.containsKey(field); + } + +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index c1c973becc3..c34d656a647 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -21,22 +21,20 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Util; -import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; +import soot.RefLikeType; +import soot.SootMethod; +import soot.Unit; +import soot.Value; +import soot.jimple.*; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.queue.QueueReader; import java.util.*; import java.util.stream.Collectors; @@ -264,9 +262,9 @@ public void buildGraph(PTA prePTA) { CallGraph callGraph = prePTA.getCallGraph(); for (SootMethod method : prePTA.getNakedReachableMethods()) { -// if (method.isPhantom()) { -// continue; -// } + if (method.isPhantom()) { + continue; + } MethodPAG srcmpag = prePAG.getMethodPAG(method); MethodNodeFactory srcnf = srcmpag.nodeFactory(); LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); @@ -303,11 +301,11 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); LocalVarNode[] parms = new LocalVarNode[numParms]; for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { + if (method.getParameterType(i) instanceof RefLikeType) { parms[i] = (LocalVarNode) srcnf.caseParm(i); } } - LocalVarNode mret = method.getReturnType() instanceof ReferenceType ? (LocalVarNode) srcnf.caseRet() : null; + LocalVarNode mret = method.getReturnType() instanceof RefLikeType ? (LocalVarNode) srcnf.caseRet() : null; LocalVarNode throwFinal = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); if (method.isStatic()) { pts.getOrDefault(thisRef, Collections.emptySet()).forEach(a -> { @@ -322,42 +320,43 @@ else if (to instanceof FieldRefNode fr) { } // add invoke edges - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { retDest = prePAG.findLocalVarNode(dest); } } LocalVarNode receiver; - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } else { // static call receiver = thisRef; } - for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { + for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) continue; ValNode argNode = prePAG.findValNode(args[i]); if (argNode instanceof LocalVarNode) { this.addStoreEdge((LocalVarNode) argNode, receiver); } } - if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { + if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { this.addLoadEdge(receiver, retDest); } LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java index 35e4830c93d..4c0bfa3be45 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java @@ -8,7 +8,7 @@ import qilin.pta.toolkits.mahjong.automata.DFAState; import qilin.pta.toolkits.common.FieldPointstoGraph; import qilin.util.UnionFindSet; -import sootup.core.types.Type; +import soot.Type; import java.util.Collection; import java.util.HashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java index a62de6109c7..58f2d1ecbfb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java @@ -1,6 +1,6 @@ package qilin.pta.toolkits.mahjong.automata; -import sootup.core.types.Type; +import soot.Type; import java.util.HashSet; import java.util.LinkedList; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java index e038c8605fa..a5ac0c4975c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; -import qilin.core.pag.SparkField; import qilin.util.Pair; import qilin.util.UnionFindSet; -import sootup.core.types.Type; +import soot.Type; +import soot.jimple.spark.pag.SparkField; import java.util.Collection; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java index 69ec2ad74fd..7fc1098883b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; -import qilin.core.pag.SparkField; import qilin.pta.toolkits.common.FieldPointstoGraph; -import sootup.core.types.Type; +import soot.Type; +import soot.jimple.spark.pag.SparkField; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java index 02e70604a48..329979293a1 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java @@ -1,8 +1,8 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; -import qilin.core.pag.SparkField; -import sootup.core.types.Type; +import soot.Type; +import soot.jimple.spark.pag.SparkField; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java index 067208c53a9..40bc237de4c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; -import qilin.core.pag.SparkField; import qilin.pta.toolkits.common.FieldPointstoGraph; -import sootup.core.types.Type; +import soot.Type; +import soot.jimple.spark.pag.SparkField; import java.util.Collections; import java.util.HashSet; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index 1b62abe8cf7..f4189f255e4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -25,17 +25,12 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.Edge; import qilin.core.pag.*; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; +import soot.*; +import soot.jimple.*; +import soot.jimple.spark.pag.SparkField; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.queue.QueueReader; public class Selectx { private final PTA prePTA; @@ -229,9 +224,9 @@ int getCallSiteNumber(CallSite callsite) { private void buildGraph() { for (SootMethod method : prePTA.getNakedReachableMethods()) { -// if (method.isPhantom()) { -// continue; -// } + if (method.isPhantom()) { + continue; + } MethodPAG srcmpag = prePAG.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -269,42 +264,44 @@ private void buildGraph() { // add invoke edges MethodNodeFactory srcnf = srcmpag.nodeFactory(); - for (final Stmt s : srcmpag.getInvokeStmts()) { - CallSite callSite = new CallSite(s); - AbstractInvokeExpr ie = s.getInvokeExpr(); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + CallSite callSite = new CallSite(u); + InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { continue; } args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { retDest = prePAG.findLocalVarNode(dest); } } LocalVarNode receiver = null; - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } - for (Iterator it = prePTA.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + for (Iterator it = prePTA.getCallGraph().edgesOutOf(u); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) { + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) { continue; } LocalVarNode parm = (LocalVarNode) tgtnf.caseParm(i); this.addEntryEdge((LocalVarNode) srcnf.getNode(args[i]), parm, callSite); } - if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { + if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { LocalVarNode ret = (LocalVarNode) tgtnf.caseRet(); this.addExitEdge(ret, retDest, callSite); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 90c01e9d0b1..0a9fa49aa2c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -21,20 +21,17 @@ import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.util.Pair; -import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; +import soot.RefLikeType; +import soot.SootMethod; +import soot.Unit; +import soot.Value; +import soot.jimple.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.queue.QueueReader; import java.util.*; @@ -153,25 +150,26 @@ else if (to instanceof FieldRefNode fr) { }); // add invoke edges - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { retDest = pag.findLocalVarNode(dest); } } LocalVarNode receiver; - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { receiver = pag.findLocalVarNode(iie.getBase()); } else { // static call @@ -179,7 +177,7 @@ else if (to instanceof FieldRefNode fr) { } Set targets = new HashSet<>(); - for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { + for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); targets.add(tgtmtd); @@ -193,7 +191,7 @@ else if (to instanceof FieldRefNode fr) { this.addStoreEdge((LocalVarNode) argNode, receiver); } } - if (retDest != null && retDest.getType() instanceof ReferenceType) { + if (retDest != null && retDest.getType() instanceof RefLikeType) { if (statisfyAddingLoadCondition(targets)) { this.addLoadEdge(receiver, retDest); } @@ -214,13 +212,13 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { + if (method.getParameterType(i) instanceof RefLikeType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); addNormalEdge(new TranEdge(param, param, DFA.TranCond.IPARAM)); } } - if (method.getReturnType() instanceof ReferenceType) { + if (method.getReturnType() instanceof RefLikeType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); addStoreEdge(mret, thisRef); } @@ -252,13 +250,13 @@ public void computeNodesInPrecisionLossPatterns() { workList.add(new Pair<>(thisRef, DFA.State.S)); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { + if (method.getParameterType(i) instanceof RefLikeType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); startState.add(param); workList.add(new Pair<>(param, DFA.State.S)); } } - if (method.getReturnType() instanceof ReferenceType) { + if (method.getReturnType() instanceof RefLikeType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); startState.add(mret); workList.add(new Pair<>(mret, DFA.State.S)); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java index 9c48031caa6..4efabcd814d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java @@ -18,10 +18,10 @@ package qilin.pta.toolkits.turner; -import qilin.core.callgraph.CallGraph; import qilin.util.graph.DirectedGraph; import qilin.util.graph.DirectedGraphImpl; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.jimple.toolkits.callgraph.CallGraph; import java.util.Collection; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java index b92a9ceb6b0..9a4f564be7c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java @@ -19,7 +19,7 @@ package qilin.pta.toolkits.turner; import qilin.core.PTA; -import sootup.core.model.SootMethod; +import soot.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java index 5a75da5531b..f3ecde8894c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -25,8 +25,8 @@ import qilin.core.pag.MethodPAG; import qilin.core.pag.Node; import qilin.util.graph.MergedNode; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; +import soot.RefLikeType; +import soot.SootMethod; import java.util.Set; @@ -47,10 +47,10 @@ public ModularMVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode protected boolean statisfyAddingLoadCondition(Set targets) { for (SootMethod tgtmtd : targets) { // the target method is in the same scc with current method. - if (/* tgtmtd.isPhantom() || */ sccNode.getContent().contains(tgtmtd)) { + if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { return true; } - if (!(tgtmtd.getReturnType() instanceof ReferenceType)) { + if (!(tgtmtd.getReturnType() instanceof RefLikeType)) { continue; } MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); @@ -69,7 +69,7 @@ protected boolean statisfyAddingLoadCondition(Set targets) { protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { for (SootMethod tgtmtd : targets) { // the target method is in the same scc with current method. - if (/* tgtmtd.isPhantom() || */ sccNode.getContent().contains(tgtmtd)) { + if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { return true; } MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); @@ -80,7 +80,7 @@ protected boolean satisfyAddingStoreCondition(int paramIndex, Set ta if (paramIndex == PointsToAnalysis.THIS_NODE) { parm = (LocalVarNode) tgtnf.caseThis(); } else { - if (tgtmtd.getParameterType(paramIndex) instanceof ReferenceType) { + if (tgtmtd.getParameterType(paramIndex) instanceof RefLikeType) { parm = (LocalVarNode) tgtnf.caseParm(paramIndex); } else { continue; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java index 8f7f4e3388a..18d34f64b07 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -24,11 +24,8 @@ import qilin.core.sets.PointsToSet; import qilin.pta.PTAConfig; import qilin.util.PTAUtils; -import sootup.core.model.SootMethod; -import sootup.core.types.ArrayType; -import sootup.core.types.PrimitiveType; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import soot.*; +import soot.jimple.spark.pag.SparkField; import java.util.*; @@ -58,7 +55,7 @@ protected void buildGraph() { SparkField f = contextField.getField(); if (f.getType() instanceof ArrayType at) { - if (at.getBaseType() instanceof PrimitiveType) { + if (at.baseType instanceof PrimType) { return; } } @@ -246,11 +243,11 @@ boolean isFactoryObject(AllocNode heap) { return false; } Type retType = method.getReturnType(); - if (!(retType instanceof ReferenceType)) { + if (!(retType instanceof RefLikeType)) { return false; } if (retType instanceof ArrayType at) { - if (at.getBaseType() instanceof PrimitiveType) { + if (at.baseType instanceof PrimType) { return false; } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java index 5528e73f1b9..fd65911cd11 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java @@ -21,12 +21,12 @@ import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; -import qilin.core.pag.SparkField; import qilin.pta.PTAConfig; import qilin.util.graph.MergedNode; import qilin.util.graph.SCCMergedGraph; import qilin.util.graph.TopologicalSorter; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.jimple.spark.pag.SparkField; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -167,25 +167,25 @@ private void statObjInOCG(Map ret) { } private Collection computeCtxLevelForVariables(SootMethod method) { -// if (method.isPhantom()) { -// return Collections.emptySet(); -// } else { + if (method.isPhantom()) { + return Collections.emptySet(); + } else { AbstractMVFG mvfg = MethodVFG.findOrCreateMethodVFG(prePTA, method, ocg); mvfg.computeNodesInPrecisionLossPatterns(); mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); return mvfg.getCSNodes(); -// } + } } private Collection computeCtxLevelForVariables(SootMethod method, MergedNode sccNode) { -// if (method.isPhantom()) { -// return Collections.emptySet(); -// } else { + if (method.isPhantom()) { + return Collections.emptySet(); + } else { AbstractMVFG mvfg = ModularMVFG.findOrCreateMethodVFG(prePTA, method, ocg, sccNode); mvfg.computeNodesInPrecisionLossPatterns(); mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); return mvfg.getCSNodes(); -// } + } } private void mergeNodeAndEdgeCount(int nodeCnt, int edgeCnt) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java index 33cb0d39f99..2b9bb933eed 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java @@ -22,7 +22,7 @@ import qilin.pta.toolkits.zipper.analysis.Zipper; import qilin.util.ANSIColor; import qilin.util.Stopwatch; -import sootup.core.model.SootMethod; +import soot.SootMethod; import java.util.Comparator; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java index c8936ade446..29c07f3f609 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java @@ -3,7 +3,6 @@ import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.AllocNode; -import qilin.core.pag.ContextMethod; import qilin.core.pag.VarNode; import qilin.core.sets.PointsToSet; import qilin.pta.toolkits.common.OAG; @@ -12,8 +11,8 @@ import qilin.util.graph.MergedNode; import qilin.util.graph.SCCMergedGraph; import qilin.util.graph.TopologicalSorter; -import sootup.core.model.SootMethod; -import sootup.core.types.Type; +import soot.SootMethod; +import soot.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -161,7 +160,7 @@ private Set invokedMethodsOf(final AllocNode obj) { while (!queue.isEmpty()) { final SootMethod method = queue.poll(); methods.add(method); - pta.getCallGraph().edgesOutOf(new ContextMethod(method, pta.emptyContext())).forEachRemaining(edge -> { + pta.getCallGraph().edgesOutOf(method).forEachRemaining(edge -> { SootMethod callee = edge.getTgt().method(); if (callee.isStatic() && !methods.contains(callee)) { queue.offer(callee); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java index 34cd145c0a5..06f061d6f04 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java @@ -10,9 +10,9 @@ import qilin.util.ANSIColor; import qilin.util.Stopwatch; import qilin.util.graph.ConcurrentDirectedGraphImpl; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.core.types.Type; +import soot.RefType; +import soot.SootMethod; +import soot.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -98,12 +98,12 @@ public static void outputObjectFlowGraphSize(ObjectFlowGraph ofg) { public Set analyze() { reset(); System.out.println("Building PFGs (Pollution Flow Graphs) and computing precision-critical methods ..."); - List types = pta.getPag().getAllocNodes().stream() + List types = pta.getPag().getAllocNodes().stream() .map(AllocNode::getType) .distinct() .sorted(Comparator.comparing(Type::toString)) - .filter(t -> t instanceof ClassType) - .map(t -> (ClassType) t) + .filter(t -> t instanceof RefType) + .map(t -> (RefType) t) .collect(Collectors.toList()); if (Global.getThread() == Global.UNDEFINE) { computePCM(types); @@ -126,12 +126,12 @@ public Set analyze() { return pcm; } - private void computePCM(List types) { + private void computePCM(List types) { FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); types.forEach(type -> analyze(type, fa)); } - private void computePCMConcurrent(List types, int nThread) { + private void computePCMConcurrent(List types, int nThread) { ExecutorService executorService = Executors.newFixedThreadPool(nThread); types.forEach(type -> executorService.execute(() -> { @@ -151,7 +151,7 @@ private void computePCMConcurrent(List types, int nThread) { * @param fa Compute the set of precision-critical methods for a class/type and add these methods * to the pcm collection. */ - private void analyze(ClassType type, FlowAnalysis fa) { + private void analyze(RefType type, FlowAnalysis fa) { if (Global.isDebug()) { System.out.println("----------------------------------------"); } @@ -185,12 +185,12 @@ private void analyze(ClassType type, FlowAnalysis fa) { // are also considered as the OUT methods of current type pce.PCEMethodsOf(type).stream() .filter(m -> !m.isPrivate() && !m.isStatic()) - .filter(m -> ToolUtil.isInnerType(pta.getPag().getView(), - m.getDeclaringClassType(), type)) + .filter(m -> ToolUtil.isInnerType( + m.getDeclaringClass().getType(), type)) .forEach(outms::add); pce.PCEMethodsOf(type).stream() .filter(m -> !m.isPrivate() && !m.isStatic()) - .filter(m -> m.getDeclaringClassType().equals(type) + .filter(m -> m.getDeclaringClass().getType().equals(type) && m.toString().contains("access$")) .forEach(outms::add); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java new file mode 100644 index 00000000000..2f1b0262ca3 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java @@ -0,0 +1,19 @@ +package qilin.pta.toolkits.zipper.cases; + +// NO IN , NO OUT, CASE 4. +public class CaseA { + static class A { + Object f; + } + + A create() { + return new A(); + } + + void foo() { + Object o = new Object(); + A a = create(); + a.f = o; + o = a.f; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java new file mode 100644 index 00000000000..0d3084bb9ad --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java @@ -0,0 +1,25 @@ +package qilin.pta.toolkits.zipper.cases; + +// No Out, case 2 +public class CaseB { + static class A { + Object f; + + void bar(Object q) { + this.f = q; + } + } + + void foo() { + Object oy = new Object(); + Object oz = new Object(); + + A a = new A(); + a.bar(oy); + Object o = a.f; + +// A a1 = new A(); +// a1.bar(oz); +// Object o1 = a1.f; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java new file mode 100644 index 00000000000..9a8eb9a75a8 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java @@ -0,0 +1,35 @@ +package qilin.pta.toolkits.zipper.cases; + +public class CaseC { + static class A { + Object f; + } + + A f; + + // case 2; + CaseC() { + A a = new A(); + this.f = a; + } + + // does not consider this_variable. + A getF() { + A r = this.f; + return r; + } + + void foo() { + Object o1 = new Object(); + CaseC c1 = new CaseC(); + A a1 = c1.getF(); + a1.f = o1; + Object o1x = a1.f; + +// Object o2 = new Object(); +// CaseC c2 = new CaseC(); +// A a2 = c2.getF(); +// a2.f = o2; +// Object o2x = a2.f; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java new file mode 100644 index 00000000000..f799dccea5c --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java @@ -0,0 +1,21 @@ +package qilin.pta.toolkits.zipper.cases; + +public class CaseD { + static class A { + Object f, g; + } + + Object id(Object p) { + A a = new A(); + a.f = p; + Object r = a.f; + return r; + } + + Object fakeId(Object p) { + A a = new A(); + a.f = p; + a.g = new Object(); + return a.g; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java index 39b29874e4a..9bfa4814b67 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -8,14 +8,11 @@ import qilin.util.ANSIColor; import qilin.util.graph.ConcurrentDirectedGraphImpl; import qilin.util.graph.Reachability; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import soot.*; +import soot.jimple.AssignStmt; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.Stmt; import java.util.*; import java.util.stream.Collectors; @@ -145,14 +142,14 @@ private void dfs(Node node) { pta.getCgb().getReceiverToSitesMap() .getOrDefault(var, Collections.emptySet()) .forEach(vcs -> { - Stmt callsiteStmt = vcs.getUnit(); - AbstractInvokeExpr invo = callsiteStmt.getInvokeExpr(); - if (!(invo instanceof AbstractInstanceInvokeExpr)) { + Stmt callsiteStmt = (Stmt) vcs.getUnit(); + InvokeExpr invo = callsiteStmt.getInvokeExpr(); + if (!(invo instanceof InstanceInvokeExpr)) { return; } - if (callsiteStmt instanceof JAssignStmt assignStmt) { + if (callsiteStmt instanceof AssignStmt assignStmt) { Value lv = assignStmt.getLeftOp(); - if (!(lv.getType() instanceof ReferenceType)) { + if (!(lv.getType() instanceof RefLikeType)) { return; } final VarNode to = (VarNode) pta.getPag().findValNode(lv); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java index 3d9a2b47d30..2be92fdf076 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java @@ -4,11 +4,9 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.pta.toolkits.zipper.Global; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; +import soot.SootMethod; +import soot.Value; +import soot.jimple.*; import java.util.*; @@ -108,9 +106,9 @@ private void init() { if (!callee.isStatic()) { MethodNodeFactory calleeNF = pta.getPag().getMethodPAG(callee).nodeFactory(); LocalVarNode thisVar = (LocalVarNode) calleeNF.caseThis(); - AbstractInvokeExpr ie = callsite.getInvokeExpr(); + InvokeExpr ie = callsite.getInvokeExpr(); Value base = null; - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { base = iie.getBase(); } if (base != null) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java index 6761cb10c11..af437b68ae4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java @@ -1,3 +1,21 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + package qilin.pta.tools; import qilin.CoreConfig; @@ -10,14 +28,11 @@ import qilin.stat.PTAEvaluator; import qilin.stat.SimplifiedEvaluator; import qilin.util.PTAUtils; -import sootup.core.views.View; public abstract class BasePTA extends CorePTA { protected IEvaluator evaluator; - protected View view; - public BasePTA(View view) { - this.view = view; + public BasePTA() { // this.evaluator = new PTAEvaluator(this); this.evaluator = new SimplifiedEvaluator(this); } @@ -28,7 +43,7 @@ public IEvaluator evaluator() { @Override protected PAG createPAG() { - return new PAG(view, this); + return new PAG(this); } @Override diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java index 50c36e7206f..86be816e2f9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java @@ -26,10 +26,8 @@ import qilin.parm.select.HeuristicSelector; import qilin.parm.select.PipelineSelector; import qilin.pta.PTAConfig; -import qilin.pta.StagedPTA; import qilin.pta.toolkits.bean.Bean; import qilin.util.Stopwatch; -import sootup.core.views.View; import java.util.HashMap; import java.util.Map; @@ -42,8 +40,7 @@ public class BeanPTA extends StagedPTA { // [current heap, [allocator heap, [heap ctx, new ctx]]] only for B-2obj; Map>> beanNexCtxMap = new HashMap<>(); - public BeanPTA(View view, CtxConstructor ctxCons) { - super(view); + public BeanPTA(CtxConstructor ctxCons) { this.ctxCons = ctxCons; CtxSelector us = new BeanSelector(pag, beanNexCtxMap); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { @@ -56,7 +53,7 @@ public BeanPTA(View view, CtxConstructor ctxCons) { } else { this.heapAbst = new AllocSiteAbstractor(); } - prePTA = new Spark(view); + prePTA = new Spark(); System.out.println("bean ..."); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java index eadcbabdd4f..1bdf094bb70 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java @@ -26,7 +26,6 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -import sootup.core.views.View; /* * refer to "Two approaches to interprocedural data flow analysis" (PFA 1981) @@ -34,8 +33,7 @@ public class CallSiteSensPTA extends BasePTA { - public CallSiteSensPTA(View view, int k, int hk) { - super(view); + public CallSiteSensPTA(int k, int hk) { this.ctxCons = new CallsiteCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java index 6d59f4bf66f..b43824e9783 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java @@ -26,7 +26,6 @@ import qilin.parm.select.PipelineSelector; import qilin.pta.PTAConfig; import qilin.pta.toolkits.dd.DataDrivenSelector; -import sootup.core.views.View; /* * Support Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017): * https://doi.org/10.1145/3133924 @@ -39,8 +38,7 @@ public class DataDrivenPTA extends BasePTA { - public DataDrivenPTA(View view, CtxConstructor ctxCons) { - super(view); + public DataDrivenPTA(CtxConstructor ctxCons) { this.ctxCons = ctxCons; CtxSelector us = new DataDrivenSelector(ctxCons.getClass()); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java index d46cf16af0f..4062da8ccde 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java @@ -18,7 +18,6 @@ package qilin.pta.tools; -import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.core.solver.Propagator; @@ -26,54 +25,94 @@ import qilin.parm.select.DebloatingSelector; import qilin.parm.select.PipelineSelector; import qilin.pta.PTAConfig; -import qilin.pta.StagedPTA; +import qilin.pta.toolkits.common.DebloatedOAG; +import qilin.pta.toolkits.common.OAG; +import qilin.pta.toolkits.debloaterx.CollectionHeuristic; +import qilin.pta.toolkits.debloaterx.DebloaterX; import qilin.pta.toolkits.conch.Conch; import qilin.stat.IEvaluator; import qilin.util.Stopwatch; -import sootup.core.jimple.basic.Local; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; +import soot.*; -import java.util.HashSet; -import java.util.Set; +import java.util.*; /* * refer to "Context Debloating for Object-Sensitive Pointer Analysis" (ASE'21) * */ public class DebloatedPTA extends StagedPTA { + public enum DebloatApproach { + CONCH, DEBLOATERX, COLLECTION + } + protected BasePTA basePTA; protected Set ctxDepHeaps = new HashSet<>(); + protected DebloatApproach debloatApproach = DebloatApproach.CONCH; /* * The debloating approach is currently for object-sensitive PTA only. * Thus the base PTA should be k-OBJ, Zipper-OBJ or Eagle-OBJ. * */ public DebloatedPTA(BasePTA basePTA) { - super(basePTA.view); this.basePTA = basePTA; CtxSelector debloatingSelector = new DebloatingSelector(ctxDepHeaps); basePTA.setContextSelector(new PipelineSelector(basePTA.ctxSelector(), debloatingSelector)); if (basePTA instanceof StagedPTA stagedPTA) { this.prePTA = stagedPTA.getPrePTA(); } else { - this.prePTA = new Spark(basePTA.view); + this.prePTA = new Spark(); } System.out.println("debloating ...."); } + /* this constructor is used to specify the debloating approach. */ + public DebloatedPTA(BasePTA basePTA, DebloatApproach approach) { + this(basePTA); + this.debloatApproach = approach; + } + @Override protected void preAnalysis() { Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); prePTA.pureRun(); sparkTimer.stop(); System.out.println(sparkTimer); - Stopwatch conchTimer = Stopwatch.newAndStart("Conch"); - Conch hc = new Conch(prePTA); - hc.runClassifier(); - this.ctxDepHeaps.addAll(hc.ctxDependentHeaps()); - System.out.println(); - conchTimer.stop(); - System.out.println(conchTimer); + if (debloatApproach == DebloatApproach.CONCH) { + Stopwatch conchTimer = Stopwatch.newAndStart("Conch"); + Conch hc = new Conch(prePTA); + hc.runClassifier(); + this.ctxDepHeaps.addAll(hc.ctxDependentHeaps()); + System.out.println(); + conchTimer.stop(); + System.out.println(conchTimer); + } else if (debloatApproach == DebloatApproach.DEBLOATERX) { + Stopwatch debloaterXTimer = Stopwatch.newAndStart("DebloaterX"); + DebloaterX debloaterX = new DebloaterX(prePTA); + debloaterX.run(); + Set mCtxDepHeaps = debloaterX.getCtxDepHeaps(); + for (AllocNode obj : mCtxDepHeaps) { + this.ctxDepHeaps.add(obj.getNewExpr()); + } + System.out.println(); + debloaterXTimer.stop(); + System.out.println(debloaterXTimer); + // stat OAG reductions + OAG oag = new OAG(prePTA); + oag.build(); + OAG doag1 = new DebloatedOAG(prePTA, mCtxDepHeaps); + doag1.build(); + System.out.println("OAG #node:" + oag.nodeSize() + "; #edge:" + oag.edgeSize()); + System.out.println("DebloaterX OAG #node:" + doag1.nodeSize() + "; #edge:" + doag1.edgeSize()); + } else { + assert (debloatApproach == DebloatApproach.COLLECTION); + Stopwatch collectionHeuristic = Stopwatch.newAndStart("COLLECTION"); + CollectionHeuristic ch = new CollectionHeuristic(prePTA); + ch.run(); + collectionHeuristic.stop(); + System.out.println(collectionHeuristic); + for (AllocNode obj : ch.getCtxDepHeaps()) { + this.ctxDepHeaps.add(obj.getNewExpr()); + } + } } @Override @@ -95,7 +134,7 @@ public Node parameterize(Node n, Context context) { } @Override - public ContextMethod parameterize(SootMethod method, Context context) { + public MethodOrMethodContext parameterize(SootMethod method, Context context) { return basePTA.parameterize(method, context); } @@ -115,15 +154,10 @@ public Context emptyContext() { } @Override - public Context createCalleeCtx(ContextMethod caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { return basePTA.createCalleeCtx(caller, receiverNode, callSite, target); } - @Override - public PointsToSet reachingObjectsInternal(PointsToSet s, SparkField f) { - return basePTA.reachingObjectsInternal(s, f); - } - @Override public PointsToSet reachingObjects(Local l) { return basePTA.reachingObjects(l); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java index ae95212cd6a..952a6e92fca 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java @@ -24,11 +24,10 @@ import qilin.pta.toolkits.eagle.Eagle; import qilin.util.Pair; import qilin.util.Stopwatch; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.common.expr.Expr; -import sootup.core.jimple.common.expr.JNewArrayExpr; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.views.View; +import soot.Local; +import soot.jimple.Expr; +import soot.jimple.NewArrayExpr; +import soot.jimple.Stmt; import java.io.FileNotFoundException; import java.io.PrintWriter; @@ -40,8 +39,8 @@ * (TOSEM'21) * */ public class EaglePTA extends PartialObjSensPTA { - public EaglePTA(View view, int ctxLen) { - super(view, ctxLen); + public EaglePTA(int ctxLen) { + super(ctxLen); System.out.println("Eagle ...."); } @@ -82,8 +81,8 @@ protected void writeToFile(Map partialResults) throws FileNotFo return; } String newExpr = heap.getNewExpr().toString(); - if (heap.getNewExpr() instanceof JNewArrayExpr nae) { - newExpr = "new " + nae.getBaseType() + "[]"; + if (heap.getNewExpr() instanceof NewArrayExpr nae) { + newExpr = "new " + nae.getBaseType().toString() + "[]"; } String heapSig = heap.getMethod().toString() + "/" + newExpr; heapWriter.write(heapSig); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java index e43cb5dc653..1ef7cef9008 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java @@ -26,15 +26,13 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -import sootup.core.views.View; /** * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) */ public class HybridObjectSensPTA extends BasePTA { - public HybridObjectSensPTA(View view, int k, int hk) { - super(view); + public HybridObjectSensPTA(int k, int hk) { this.ctxCons = new HybObjCtxConstructor(); CtxSelector us = new UniformSelector(k + 1, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java index 56b1017aff1..34db6856bde 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java @@ -26,7 +26,6 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -import sootup.core.views.View; /** * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) @@ -34,8 +33,7 @@ public class HybridTypeSensPTA extends BasePTA { - public HybridTypeSensPTA(View view, int k, int hk) { - super(view); + public HybridTypeSensPTA(int k, int hk) { this.ctxCons = new HybTypeCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java index ee98e173655..5dfbf69bab4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java @@ -25,9 +25,7 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -import qilin.pta.StagedPTA; import qilin.pta.toolkits.mahjong.Mahjong; -import sootup.core.views.View; import java.util.HashMap; import java.util.HashSet; @@ -42,8 +40,7 @@ public class MahjongPTA extends StagedPTA { public Set mergedHeap = new HashSet<>(); public Set csHeap = new HashSet<>(); - public MahjongPTA(View view, int k, int hk, CtxConstructor ctxCons) { - super(view); + public MahjongPTA(int k, int hk, CtxConstructor ctxCons) { this.ctxCons = ctxCons; CtxSelector us = new UniformSelector(k, hk); CtxSelector ds = new DebloatingSelector(csHeap); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java index 57a46da1e62..aaa9010bd48 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java @@ -26,14 +26,12 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -import sootup.core.views.View; /* * refer to "Parameterized object sensitivity for points-to analysis for Java" (TSE'05) * */ public class ObjectSensPTA extends BasePTA { - public ObjectSensPTA(View view, int k, int hk) { - super(view); + public ObjectSensPTA(int k, int hk) { this.ctxCons = new ObjCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index fb60b89c20d..27f081dd7c2 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -25,20 +25,11 @@ import qilin.parm.heapabst.HeuristicAbstractor; import qilin.parm.select.*; import qilin.pta.PTAConfig; -import qilin.pta.StagedPTA; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; -import sootup.core.views.View; +import soot.*; +import soot.jimple.*; +import soot.util.queue.QueueReader; import java.util.HashSet; import java.util.Map; @@ -54,8 +45,7 @@ public abstract class PartialCallSiteSensPTA extends StagedPTA { Set PCSM = new HashSet<>(); Set CSM = new HashSet<>(); - public PartialCallSiteSensPTA(View view, int ctxLen) { - super(view); + public PartialCallSiteSensPTA(int ctxLen) { this.ctxCons = new CallsiteCtxConstructor(); CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { @@ -119,12 +109,12 @@ protected void select() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for (ContextMethod momc : prePTA.getReachableMethods()) { + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); -// if (method.isPhantom()) { -// return; -// } + if (method.isPhantom()) { + return; + } MethodPAG srcmpag = pag.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -149,24 +139,26 @@ protected void extraStats() { } } } - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { continue; } nodes.add(arg); } - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { nodes.add(dest); } } - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { Value base = iie.getBase(); if (base instanceof Local) { nodes.add(base); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 57d9fafbbb7..4179803adb5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -27,19 +27,11 @@ import qilin.parm.select.PartialVarSelector; import qilin.parm.select.PipelineSelector; import qilin.pta.PTAConfig; -import qilin.pta.StagedPTA; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; -import sootup.core.views.View; +import soot.*; +import soot.jimple.*; +import soot.util.queue.QueueReader; import java.util.HashSet; import java.util.Map; @@ -54,8 +46,7 @@ public abstract class PartialObjSensPTA extends StagedPTA { Set PCSM = new HashSet<>(); Set CSM = new HashSet<>(); - public PartialObjSensPTA(View view, int ctxLen) { - super(view); + public PartialObjSensPTA(int ctxLen) { this.ctxCons = new ObjCtxConstructor(); CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { @@ -119,12 +110,12 @@ protected void select() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for (ContextMethod momc : prePTA.getReachableMethods()) { + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); -// if (method.isPhantom()) { -// return; -// } + if (method.isPhantom()) { + return; + } MethodPAG srcmpag = pag.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -149,26 +140,30 @@ protected void extraStats() { } } } - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { continue; } nodes.add(arg); } - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { nodes.add(dest); } } - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { Value base = iie.getBase(); - nodes.add(base); + if (base instanceof Local) { + nodes.add(base); + } } } for (Object o : nodes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java index 8b0dc824178..3640b614914 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java @@ -19,14 +19,13 @@ package qilin.pta.tools; import qilin.pta.toolkits.selectx.Selectx; -import sootup.core.views.View; import java.util.Map; public class SelectxPTA extends PartialCallSiteSensPTA { - public SelectxPTA(View view, int ctxLen) { - super(view, ctxLen); + public SelectxPTA(int ctxLen) { + super(ctxLen); System.out.println("selectx ... "); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java index 2ae32a37ff2..da0a21fb2fb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java @@ -23,14 +23,12 @@ import qilin.parm.heapabst.HeuristicAbstractor; import qilin.parm.select.InsenSelector; import qilin.pta.PTAConfig; -import sootup.core.views.View; /* * refer to "Scaling Java Points-To Analysis using SPARK" (CC'03) * */ public class Spark extends BasePTA { - public Spark(View view) { - super(view); + public Spark() { this.ctxCons = new InsensCtxConstructor(); this.ctxSel = new InsenSelector(); if (PTAConfig.v().getPtaConfig().mergeHeap) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java new file mode 100644 index 00000000000..11788894772 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java @@ -0,0 +1,49 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.pta.tools; + +import qilin.pta.PTAConfig; + +/* + * Many recent pointer analyses are two-staged analyses with a preanalysis and a main analysis. + * This class gives a structure for such kinds of analyses. + * */ +public abstract class StagedPTA extends BasePTA { + protected BasePTA prePTA; + + public BasePTA getPrePTA() { + return this.prePTA; + } + + protected abstract void preAnalysis(); + + protected void mainAnalysis() { + if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { + System.out.println("selective pta starts!"); + super.run(); + } + } + + @Override + public void run() { + preAnalysis(); + prePTA.getPag().resetPointsToSet(); + mainAnalysis(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java index 52cd6c232f7..dc02e2a5f15 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java @@ -27,7 +27,6 @@ import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; import qilin.pta.toolkits.dd.TunnelingConstructor; -import sootup.core.views.View; /* * This class support context tunneling from the paper "Precise and Scalable Points-to Analysis via Data-Driven @@ -35,9 +34,8 @@ * not show the claimed effectiveness. Maybe we should train the benchmarks to get new formulas? * */ public class TunnelingPTA extends BasePTA { - public TunnelingPTA(View view, CtxConstructor ctxCons, int k, int hk) { - super(view); - this.ctxCons = new TunnelingConstructor(view, ctxCons); + public TunnelingPTA(CtxConstructor ctxCons, int k, int hk) { + this.ctxCons = new TunnelingConstructor(ctxCons); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java index bf34a6f1343..cb159f3397c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java @@ -19,7 +19,6 @@ package qilin.pta.tools; import qilin.pta.toolkits.turner.Turner; -import sootup.core.views.View; import java.util.Map; @@ -29,8 +28,8 @@ public class TurnerPTA extends PartialObjSensPTA { private final int k; - public TurnerPTA(View view, int k) { - super(view, k); + public TurnerPTA(int k) { + super(k); this.k = k; System.out.println("Turner ..."); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java index 62c659e8391..022996b4743 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java @@ -26,15 +26,13 @@ import qilin.parm.select.PipelineSelector; import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -import sootup.core.views.View; /* * refer to "Pick Your Contexts Well: Understanding Object-Sensitivity" (PLDI'11) * */ public class TypeSensPTA extends BasePTA { - public TypeSensPTA(View view, int k, int hk) { - super(view); + public TypeSensPTA(int k, int hk) { this.ctxCons = new TypeCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index 55a9e6194ec..d9a85739a54 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -27,20 +27,11 @@ import qilin.parm.select.PartialMethodLvSelector; import qilin.parm.select.PipelineSelector; import qilin.pta.PTAConfig; -import qilin.pta.StagedPTA; import qilin.pta.toolkits.zipper.Main; import qilin.util.Stopwatch; -import qilin.util.queue.QueueReader; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.NullConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; -import sootup.core.views.View; +import soot.*; +import soot.jimple.*; +import soot.util.queue.QueueReader; import java.util.HashSet; import java.util.Set; @@ -56,8 +47,7 @@ public class ZipperPTA extends StagedPTA { * Zipper support object-sensitivity, callsite-sensitivity by using corresponding * context-constructor. * */ - public ZipperPTA(View view, int k, int hk, CtxConstructor ctxCons) { - super(view); + public ZipperPTA(int k, int hk, CtxConstructor ctxCons) { this.ctxCons = ctxCons; CtxSelector us = new PartialMethodLvSelector(k, hk, PCMs); if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { @@ -70,7 +60,7 @@ public ZipperPTA(View view, int k, int hk, CtxConstructor ctxCons) { } else { this.heapAbst = new AllocSiteAbstractor(); } - this.prePTA = new Spark(view); + this.prePTA = new Spark(); } @Override @@ -89,13 +79,13 @@ protected void preAnalysis() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1]; int[] totalN = new int[1]; - for (ContextMethod momc : prePTA.getReachableMethods()) { + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); -// if (method.isPhantom()) { -// return; -// } + if (method.isPhantom()) { + return; + } MethodPAG srcmpag = pag.getMethodPAG(method); QueueReader reader = srcmpag.getInternalReader().clone(); while (reader.hasNext()) { @@ -120,24 +110,26 @@ protected void extraStats() { } } } - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + + InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { continue; } nodes.add(arg); } - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { + if (s instanceof AssignStmt) { + Value dest = ((AssignStmt) s).getLeftOp(); + if (dest.getType() instanceof RefLikeType) { nodes.add(dest); } } - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { Value base = iie.getBase(); if (base instanceof Local) { nodes.add(base); diff --git a/sootup.qilin/src/main/java/qilin/stat/AliasStat.java b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java new file mode 100644 index 00000000000..bbba2aa827e --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java @@ -0,0 +1,177 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.stat; + +import qilin.core.PTA; +import qilin.core.pag.FieldRefNode; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.MethodPAG; +import qilin.core.pag.Node; +import qilin.core.pag.VarNode; +import qilin.core.sets.PointsToSet; +import qilin.util.Pair; +import qilin.util.Util; +import soot.Local; +import soot.SootMethod; +import soot.jimple.spark.pag.SparkField; +import soot.util.queue.QueueReader; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class AliasStat implements AbstractStat { + private final PTA pta; + Map> assignMap = new HashMap<>(); + Map>> globalMap = new HashMap<>(); + private int intraAlias = 0, intraAlias_incstst = 0, globalAlias = 0, globalAlias_incstst = 0; + private int intraAlias_app = 0, intraAlias_incstst_app = 0, globalAlias_app = 0, globalAlias_incstst_app = 0; + + public AliasStat(PTA pta) { + this.pta = pta; + } + + private Pair recordAndComputeIntraAliases(Set reachableMethods) { + int intraAlias = 0; + int intraAlias_incstst = 0; + for (SootMethod m : reachableMethods) { + Map>> localMap = new HashMap<>(); + MethodPAG srcmpag = pta.getPag().getMethodPAG(m); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + if (!(((VarNode) from).getVariable() instanceof Local)) + continue; + if (!(((VarNode) to).getVariable() instanceof Local)) + continue; + Util.addToMap(assignMap, (LocalVarNode) from, (LocalVarNode) to); + Util.addToMap(assignMap, (LocalVarNode) to, (LocalVarNode) from); + } else if (to instanceof FieldRefNode fr) { + LocalVarNode base = (LocalVarNode) fr.getBase(); + if (!(base.getVariable() instanceof Local)) + continue; + addToMap(globalMap, fr.getField(), true, base); + addToMap(localMap, fr.getField(), true, base); + }//else//local-global + } else if (from instanceof FieldRefNode fr) { + LocalVarNode base = (LocalVarNode) fr.getBase(); + if (!(base.getVariable() instanceof Local)) + continue; + addToMap(globalMap, fr.getField(), false, base); + addToMap(localMap, fr.getField(), false, base); + }//else//global-local or new + } + + int methodAlias = 0, methodAlias_incstst = 0; + for (Map> subMap : localMap.values()) { + Set storeSet = subMap.getOrDefault(true, Collections.emptySet()); + Set loadSet = subMap.getOrDefault(false, Collections.emptySet()); + int stld = checkAlias(storeSet, loadSet, assignMap) + checkAlias(loadSet, storeSet, assignMap); + int stst = checkAlias(storeSet, storeSet, assignMap); + methodAlias += stld; + methodAlias_incstst += stld + stst; + } + + intraAlias += methodAlias; + intraAlias_incstst += methodAlias_incstst; + } + return new Pair<>(intraAlias, intraAlias_incstst); + } + + private Pair computeInterAliases() { + int globalAlias = 0; + int globalAlias_incstst = 0; + for (Map> subMap : globalMap.values()) { + Set storeSet = subMap.getOrDefault(true, Collections.emptySet()); + Set loadSet = subMap.getOrDefault(false, Collections.emptySet()); + int stld = checkAlias(storeSet, loadSet, assignMap) + checkAlias(loadSet, storeSet, assignMap); + int stst = checkAlias(storeSet, storeSet, assignMap); + globalAlias += stld; + globalAlias_incstst += stld + stst; + } + return new Pair<>(globalAlias, globalAlias_incstst); + } + + private int checkAlias(Set set1, Set set2, Map> exclMap) { + int num = 0; + for (LocalVarNode l1 : set1) { + Set exclSet = exclMap.getOrDefault(l1, Collections.emptySet()); + int l1Hashcode = l1.hashCode(); + for (LocalVarNode l2 : set2) { + int l2Hashcode = l2.hashCode(); + if (l2Hashcode <= l1Hashcode || exclSet.contains(l2)) { + continue; + } + if (checkAlias(l1, l2)) { + num++; + } + } + } + return num; + } + + private boolean checkAlias(LocalVarNode l1, LocalVarNode l2) { + PointsToSet pts1 = pta.reachingObjects((Local) l1.getVariable()); + PointsToSet pts2 = pta.reachingObjects((Local) l2.getVariable()); + return pts1.hasNonEmptyIntersection(pts2); + } + + public static boolean addToMap(Map>> m, K key1, T key2, V value) { + Map> subMap = m.computeIfAbsent(key1, k -> new HashMap<>()); + return Util.addToMap(subMap, key2, value); + } + + public void aliasesProcessing() { + Collection reachableMethods = pta.getNakedReachableMethods(); + Pair r1 = recordAndComputeIntraAliases(reachableMethods.stream().filter(m -> m.getDeclaringClass().isApplicationClass()).collect(Collectors.toSet())); + this.intraAlias_app = r1.getFirst(); + this.intraAlias_incstst_app = r1.getSecond(); + Pair r2 = computeInterAliases(); + this.globalAlias_app = r2.getFirst(); + this.globalAlias_incstst_app = r2.getSecond(); + Pair r3 = recordAndComputeIntraAliases(reachableMethods.stream().filter(m -> !m.getDeclaringClass().isApplicationClass()).collect(Collectors.toSet())); + this.intraAlias = this.intraAlias_app + r3.getFirst(); + this.intraAlias_incstst = this.intraAlias_incstst_app + r3.getSecond(); + Pair r4 = computeInterAliases(); + this.globalAlias = r4.getFirst(); + this.globalAlias_incstst = r4.getSecond(); + } + + public int getGlobalAliasesIncludingStSt() { + return globalAlias_incstst; + } + + @Override + public void export(Exporter exporter) { + aliasesProcessing(); + exporter.collectMetric("#intraAlias(App):", String.valueOf(intraAlias_app)); + exporter.collectMetric("#intraAlias_incstst(App):", String.valueOf(intraAlias_incstst_app)); + exporter.collectMetric("#globalAlias(App):", String.valueOf(globalAlias_app)); + exporter.collectMetric("#globalAlias_incstst(App):", String.valueOf(globalAlias_incstst_app)); + exporter.collectMetric("#intraAlias:", String.valueOf(intraAlias)); + exporter.collectMetric("#intraAlias_incstst:", String.valueOf(intraAlias_incstst)); + exporter.collectMetric("#globalAlias:", String.valueOf(globalAlias)); + exporter.collectMetric("#globalAlias_incstst:", String.valueOf(globalAlias_incstst)); + } +} diff --git a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java index 614af1d2320..f8fb91bf805 100644 --- a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java @@ -21,9 +21,8 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; +import soot.SootClass; +import soot.SootMethod; import java.util.Set; import java.util.stream.Collectors; @@ -44,12 +43,8 @@ public BenchmarkStat(PTA pta) { init(); } - private SootClass getDeclaringClass(SootMethod method) { - ClassType classType = method.getDeclaringClassType(); - return (SootClass) pta.getPag().getView().getClass(classType).get(); - } private void init() { - reachableClasses = pta.getNakedReachableMethods().stream().map(this::getDeclaringClass) + reachableClasses = pta.getNakedReachableMethods().stream().map(SootMethod::getDeclaringClass) .collect(Collectors.toSet()); reachableAppClasses = reachableClasses.stream().filter(SootClass::isApplicationClass) .collect(Collectors.toSet()); diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index 609baad11a6..cb30261f5dc 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -22,15 +22,12 @@ import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.FakeMainFactory; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; -import qilin.core.pag.ContextMethod; import qilin.core.pag.ContextVarNode; import qilin.core.pag.LocalVarNode; -import qilin.util.PTAUtils; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; +import soot.MethodOrMethodContext; +import soot.SootMethod; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; import java.util.HashSet; import java.util.Iterator; @@ -41,8 +38,8 @@ public class CallGraphStat implements AbstractStat { private final Set reachableMethods = new HashSet<>(); private int reachableStatic = 0; - private final Set reachableParameterizedMethods = new HashSet<>(); - private final Set reachableAppParameterizedMethods = new HashSet<>(); + private final Set reachableParameterizedMethods = new HashSet<>(); + private final Set reachableAppParameterizedMethods = new HashSet<>(); private final Set reachableAppMethods = new HashSet<>(); private int reachableAppStatic = 0; private int CSCallEdges = 0; @@ -72,10 +69,9 @@ public CallGraphStat(PTA pta) { private void init() { CallGraph csCallGraph = pta.getCgb().getCallGraph(); CSCallEdges = csCallGraph.size(); - for (final ContextMethod momc : pta.getCgb().getReachableMethods()) { + for (final MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { final SootMethod m = momc.method(); - SootClass declClass = PTAUtils.getDeclaringClass(pta.getPag().getView(), m); - boolean toApp = declClass.isApplicationClass(); + boolean toApp = m.getDeclaringClass().isApplicationClass(); reachableParameterizedMethods.add(momc); reachableMethods.add(m); // if (m.toString().equals("")) { @@ -90,8 +86,7 @@ private void init() { for (Iterator iterator = csCallGraph.edgesInto(momc); iterator.hasNext(); ) { Edge e = iterator.next(); final SootMethod srcm = e.getSrc().method(); - SootClass sc = PTAUtils.getDeclaringClass(pta.getPag().getView(), srcm); - boolean fromApp = sc.isApplicationClass(); + boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); if (fromApp && toApp) { CSApp2app++; } else if (fromApp) { @@ -117,20 +112,20 @@ private void init() { CallGraph ciCallGraph = pta.getCallGraph(); CICallEdges = ciCallGraph.size(); for (SootMethod sm : reachableMethods) { - boolean toApp = PTAUtils.getDeclaringClass(pta.getPag().getView(), sm).isApplicationClass(); + boolean toApp = sm.getDeclaringClass().isApplicationClass(); if (sm.isStatic()) { reachableStatic++; if (toApp) { reachableAppStatic++; } } - for (Iterator iterator = ciCallGraph.edgesInto(new ContextMethod(sm, pta.emptyContext())); iterator.hasNext(); ) { + for (Iterator iterator = ciCallGraph.edgesInto(sm); iterator.hasNext(); ) { Edge e = iterator.next(); final SootMethod srcm = e.getSrc().method(); // if (sm.toString().equals("")) { // System.out.println("from:" + srcm); // } - boolean fromApp = PTAUtils.getDeclaringClass(pta.getPag().getView(), srcm).isApplicationClass(); + boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); if (fromApp && toApp) { CIApp2app++; } else if (fromApp) { diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index 4f9c7256568..ad206904c8e 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -20,21 +20,20 @@ import qilin.CoreConfig; import qilin.core.PTA; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; import qilin.core.pag.AllocNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.Parm; import qilin.core.sets.PointsToSet; import qilin.util.Util; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JCastExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.signatures.MethodSignature; -import sootup.core.types.Type; +import soot.SootClass; +import soot.SootMethod; +import soot.Type; +import soot.jimple.AssignStmt; +import soot.jimple.CastExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.Stmt; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; import java.io.BufferedWriter; import java.io.File; @@ -82,7 +81,7 @@ private String getFilePath(String fileName) { private void dumpMethods(Collection methods, String fileName) { StringBuilder builder = new StringBuilder(); for (SootMethod sm : methods) { - String sig = sm.getSignature().toString(); + String sig = sm.getSignature(); sig = Util.stripQuotes(sig); builder.append(sig); builder.append("\n"); @@ -127,11 +126,11 @@ public void dumpClassTypes(Collection classes) { Util.writeToFile(finalPath, builder.toString()); } - public void dumpPolyCalls(Map polys) { + public void dumpPolyCalls(Map polys) { StringBuilder builder = new StringBuilder(); - for (AbstractInvokeExpr ie : polys.keySet()) { - MethodSignature tgtSig = ie.getMethodSignature(); - String polySig = polys.get(ie).getSignature() + "/" + tgtSig.getDeclClassType() + "." + tgtSig.getName() + "\n"; + for (InvokeExpr ie : polys.keySet()) { + SootMethod tgt = ie.getMethod(); + String polySig = polys.get(ie).getSignature() + "/" + tgt.getDeclaringClass() + "." + tgt.getName() + "\n"; builder.append(polySig); } String polyCalls = "PolyCalls.csv"; @@ -143,16 +142,16 @@ public void dumpMayFailCasts(Map> casts) { StringBuilder builder = new StringBuilder(); for (SootMethod sm : casts.keySet()) { for (Stmt stmt : casts.get(sm)) { - JAssignStmt as = (JAssignStmt) stmt; - JCastExpr ce = (JCastExpr) as.getRightOp(); - final Type targetType = ce.getType(); + AssignStmt as = (AssignStmt) stmt; + CastExpr ce = (CastExpr) as.getRightOp(); + final Type targetType = ce.getCastType(); builder.append(sm.toString()); builder.append("\t"); - builder.append(targetType); + builder.append(targetType.toString()); builder.append("\t"); builder.append(sm).append("/").append(ce.getOp().toString()); builder.append("\t"); - builder.append(sm).append("/").append(as.getLeftOp()); + builder.append(sm).append("/").append(as.getLeftOp().toString()); builder.append("\n"); } } @@ -176,7 +175,7 @@ public void dumpMethodThrowPointsto(Map m2pts) { StringBuilder builder = new StringBuilder(); builder.append(n.toString()); builder.append("\t"); - String sig = Util.stripQuotes(sm.getSignature().toString()); + String sig = Util.stripQuotes(sm.getSignature()); builder.append(sig); builder.append("\n"); try { @@ -202,8 +201,8 @@ public void dumpInsensCallGraph(CallGraph ciCallGraph) { mfile.createNewFile(); BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); for (Edge edge : ciCallGraph) { - String srcSig = Util.stripQuotes(edge.src().getSignature().toString()); - String dstSig = Util.stripQuotes(edge.tgt().getSignature().toString()); + String srcSig = Util.stripQuotes(edge.src().getSignature()); + String dstSig = Util.stripQuotes(edge.tgt().getSignature()); String str = edge.srcStmt() + " in method " + srcSig + "\t" + dstSig + "\n"; writer.write(str); } diff --git a/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java index dc69afbb9d8..f5a1db92707 100644 --- a/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java @@ -1,3 +1,21 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + package qilin.stat; public interface IEvaluator { diff --git a/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java index d19a9131657..187c7852eb9 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java @@ -61,10 +61,6 @@ public void begin() { runtimeStat.begin(); } - protected PointsToStat createPointsToStat() { - return new PointsToStat(pta); - } - /** * Note the end of a qilin.pta run. */ @@ -79,7 +75,8 @@ public void end() { BenchmarkStat benchmarkStat = new BenchmarkStat(pta); CallGraphStat callGraphStat = new CallGraphStat(pta); TypeClientStat typeClientStat = new TypeClientStat(pta); - PointsToStat ptsStat = createPointsToStat(); + PointsToStat ptsStat = new PointsToStat(pta); + AliasStat aliasStat = new AliasStat(pta); YummyStat yummyStat = new YummyStat(pta); runtimeStat.export(exporter); // memory stats @@ -100,6 +97,8 @@ public void end() { ptsStat.export(exporter); exporter.addLine(" ====== Assignments ======"); pagStat.export(exporter); + exporter.addLine(" ====== Aliases ======"); + aliasStat.export(exporter); exporter.addLine(" ====== Classes ======"); benchmarkStat.export(exporter); diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java index d75c4a0d023..3ff9a9d5459 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -21,17 +21,10 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; -import qilin.core.context.Context; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; -import sootup.core.jimple.basic.Local; -import sootup.core.model.SootClass; -import sootup.core.model.SootField; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import soot.*; import java.util.*; @@ -146,10 +139,7 @@ private void init() { if (!handledNatives.contains(lvn.getMethod().toString())) { mLocalVarNodesNoNative.add(lvn); } - SootMethod method = lvn.getMethod(); - ClassType classType = method.getDeclaringClassType(); - SootClass sootClass = (SootClass) pag.getView().getClass(classType).get(); - boolean app = sootClass.isApplicationClass(); + boolean app = lvn.getMethod().getDeclaringClass().isApplicationClass(); totalLocalPointersCi++; if (app) { appLocalPointersCi++; @@ -222,7 +212,7 @@ private void init() { } for (int i = 0; i < sm.getParameterCount(); ++i) { Type mType = sm.getParameterType(i); - if (mType instanceof ReferenceType) { + if (mType instanceof RefLikeType) { mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); if (!handledNatives.contains(sm.toString())) { mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseParm(i)); diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index e5b9fc7d0e8..d166b059f90 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -1,24 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + package qilin.stat; import qilin.core.PTA; import qilin.core.builder.FakeMainFactory; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JCastExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import soot.*; +import soot.jimple.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; import java.util.*; @@ -50,7 +60,7 @@ public void end() { // loop over all reachable method's statement to find casts, local // references, virtual call sites Set reachableMethods = new HashSet<>(); - for (ContextMethod momc : pta.getCgb().getReachableMethods()) { + for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { final SootMethod sm = momc.method(); reachableMethods.add(sm); } @@ -58,11 +68,12 @@ public void end() { int totalCastsMayFail = 0; for (SootMethod sm : reachableMethods) { // All the statements in the method - for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { + for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { + Stmt st = (Stmt) unit; // virtual calls if (st.containsInvokeExpr()) { - AbstractInvokeExpr ie = st.getInvokeExpr(); - if (!(ie instanceof JStaticInvokeExpr)) { + InvokeExpr ie = st.getInvokeExpr(); + if (!(ie instanceof StaticInvokeExpr)) { // Virtual, Special or Instance // have to check target soot method, cannot just // count edges @@ -73,12 +84,12 @@ public void end() { totalPolyCalls++; } } - } else if (st instanceof JAssignStmt) { - Value rhs = ((JAssignStmt) st).getRightOp(); - Value lhs = ((JAssignStmt) st).getLeftOp(); - if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = ((JCastExpr) rhs).getType(); - Value v = ((JCastExpr) rhs).getOp(); + } else if (st instanceof AssignStmt) { + Value rhs = ((AssignStmt) st).getRightOp(); + Value lhs = ((AssignStmt) st).getLeftOp(); + if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { + final Type targetType = ((CastExpr) rhs).getCastType(); + Value v = ((CastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; } @@ -97,9 +108,11 @@ public void end() { } } } + AliasStat aliasStat = new AliasStat(pta); + aliasStat.aliasesProcessing(); exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail)); exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls)); - + exporter.collectMetric("#globalAlias_incstst:", String.valueOf(aliasStat.getGlobalAliasesIncludingStSt())); ptsStat(); } @@ -129,7 +142,7 @@ private void ptsStat() { } for (int i = 0; i < sm.getParameterCount(); ++i) { Type mType = sm.getParameterType(i); - if (mType instanceof ReferenceType) { + if (mType instanceof RefLikeType) { mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); } } diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index f72201d83b9..4386eca2762 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -21,23 +21,12 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.FakeMainFactory; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; import qilin.core.pag.AllocNode; -import qilin.core.pag.ContextMethod; import qilin.util.PTAUtils; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JCastExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.types.ClassType; -import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import soot.*; +import soot.jimple.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; import java.util.*; @@ -55,7 +44,7 @@ public class TypeClientStat implements AbstractStat { private int totalStaticCalls = 0; private int totalPolyCallTargets = 0; private int unreachable = 0; - private final Map polyCalls = new HashMap<>(); + private final Map polyCalls = new HashMap<>(); private final Map> mayFailCasts = new HashMap<>(); public TypeClientStat(PTA pta) { @@ -69,22 +58,22 @@ private void init() { // loop over all reachable method's statement to find casts, local // references, virtual call sites Set reachableMethods = new HashSet<>(); - for (ContextMethod momc : pta.getCgb().getReachableMethods()) { + for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { final SootMethod sm = momc.method(); reachableMethods.add(sm); } for (SootMethod sm : reachableMethods) { - ClassType declClassType = sm.getDeclaringClassType(); - SootClass declClass = (SootClass) pta.getPag().getView().getClass(declClassType).get(); - boolean app = declClass.isApplicationClass(); + boolean app = sm.getDeclaringClass().isApplicationClass(); // All the statements in the method - for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { + for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { + Stmt st = (Stmt) unit; + // virtual calls if (st.containsInvokeExpr()) { - AbstractInvokeExpr ie = st.getInvokeExpr(); - if (ie instanceof JStaticInvokeExpr) { + InvokeExpr ie = st.getInvokeExpr(); + if (ie instanceof StaticInvokeExpr) { totalStaticCalls++; } else {// Virtual, Special or Instance totalVirtualCalls++; @@ -109,12 +98,12 @@ private void init() { } } } - } else if (st instanceof JAssignStmt) { - Value rhs = ((JAssignStmt) st).getRightOp(); - Value lhs = ((JAssignStmt) st).getLeftOp(); - if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = rhs.getType(); - Value v = ((JCastExpr) rhs).getOp(); + } else if (st instanceof AssignStmt) { + Value rhs = ((AssignStmt) st).getRightOp(); + Value lhs = ((AssignStmt) st).getLeftOp(); + if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { + final Type targetType = ((CastExpr) rhs).getCastType(); + Value v = ((CastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; } diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java index ba0eae9ee40..040caedfe1f 100644 --- a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -21,12 +21,12 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; -import qilin.core.pag.ContextMethod; import qilin.core.sets.PointsToSet; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.SootMethod; +import soot.MethodOrMethodContext; +import soot.SootMethod; +import soot.Unit; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; import java.util.HashMap; import java.util.HashSet; @@ -48,10 +48,10 @@ public YummyStat(PTA pta) { } private void init() { - Map> target2callsites = new HashMap<>(); + Map> target2callsites = new HashMap<>(); CallGraph ciCallGraph = pta.getCallGraph(); for (Edge edge : ciCallGraph) { - Stmt callUnit = edge.srcUnit(); + Unit callUnit = edge.srcUnit(); SootMethod target = edge.tgt(); if (callUnit != null && target != null) { target2callsites.computeIfAbsent(target, k -> new HashSet<>()).add(callUnit); @@ -67,9 +67,9 @@ private void init() { Set instanceReachables = new HashSet<>(); - for (final ContextMethod momc : pta.getReachableMethods()) { + for (final MethodOrMethodContext momc : pta.getReachableMethods()) { SootMethod method = momc.method(); - if (/*!method.isPhantom() && */!method.isStatic()) { + if (!method.isPhantom() && !method.isStatic()) { instanceReachables.add(method); } } diff --git a/sootup.qilin/src/main/java/qilin/util/DataFactory.java b/sootup.qilin/src/main/java/qilin/util/DataFactory.java index d9fde14c613..e9db175be98 100644 --- a/sootup.qilin/src/main/java/qilin/util/DataFactory.java +++ b/sootup.qilin/src/main/java/qilin/util/DataFactory.java @@ -1,11 +1,24 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + package qilin.util; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class DataFactory { public static List createList() { diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index a9195460323..44ef0d51916 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -25,39 +25,22 @@ import qilin.core.PTAScene; import qilin.core.VirtualCalls; import qilin.core.builder.MethodNodeFactory; -import qilin.core.callgraph.CallGraph; -import qilin.core.callgraph.Edge; -import qilin.core.callgraph.Kind; -import qilin.core.context.Context; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.core.sets.PointsToSetInternal; -import qilin.util.queue.ChunkedQueue; -import qilin.util.queue.QueueReader; import qilin.util.queue.UniqueQueue; -import sootup.core.IdentifierFactory; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.IntConstant; -import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; -import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JNewArrayExpr; -import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.model.Body; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.signatures.MethodSubSignature; -import sootup.core.types.ArrayType; -import sootup.core.types.ClassType; -import sootup.core.types.NullType; -import sootup.core.types.PrimitiveType; -import sootup.core.types.Type; -import sootup.core.views.View; -import sootup.java.core.JavaIdentifierFactory; +import soot.*; +import soot.jimple.*; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; +import soot.util.NumberedString; +import soot.util.dot.DotGraph; +import soot.util.dot.DotGraphConstants; +import soot.util.dot.DotGraphNode; +import soot.util.queue.ChunkedQueue; +import soot.util.queue.QueueReader; import java.io.*; import java.net.URL; @@ -69,12 +52,7 @@ public final class PTAUtils { private static final Logger logger = LoggerFactory.getLogger(PTAUtils.class); static final String output_dir = CoreConfig.v().getOutConfig().outDir; static Map nodes = new TreeMap<>(); - private static final ClassType clRunnable = (ClassType) JavaIdentifierFactory.getInstance().getType("java.lang.Runnable"); - - public static SootClass getDeclaringClass(View view, SootMethod method) { - ClassType classType = method.getDeclaringClassType(); - return (SootClass) view.getClass(classType).get(); - } + private static final RefType clRunnable = RefType.v("java.lang.Runnable"); public static Map> calcStaticThisPTS(PTA pta) { Map> pts = new HashMap<>(); @@ -87,10 +65,11 @@ public static Map> calcStaticThisPTS(PTA pta) { LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); final PointsToSet other = pta.reachingObjects(thisRef).toCIPointsToSet(); - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof JStaticInvokeExpr) { - for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof StaticInvokeExpr) { + for (Iterator it = pta.getCallGraph().edgesOutOf(u); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); @@ -120,10 +99,11 @@ public static Map> calcStaticThisPTS(PTA pta) { LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); final Set other = pts.computeIfAbsent(thisRef, k -> new HashSet<>()); - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof JStaticInvokeExpr) { - for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + for (final Unit u : srcmpag.getInvokeStmts()) { + final Stmt s = (Stmt) u; + InvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof StaticInvokeExpr) { + for (Iterator it = pta.getCallGraph().edgesOutOf(u); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); @@ -178,10 +158,10 @@ public static void dumpCallGraph(Iterable callgraph, boolean appOnly) { List methodList = new ArrayList<>(); for (Edge edge : callgraph) { - ContextMethod srcmtd = edge.getSrc(); + MethodOrMethodContext srcmtd = edge.getSrc(); if (appOnly && !srcmtd.method().getDeclaringClass().isApplicationClass()) continue; - ContextMethod dstmtd = edge.getTgt(); + MethodOrMethodContext dstmtd = edge.getTgt(); String srcName = srcmtd.toString(); if (methodSet.add(srcName)) { @@ -211,12 +191,12 @@ public static void dumpCallGraph(Iterable callgraph, boolean appOnly) { /** * slice a callgrph, put nodes &edges related to method into set1&set2 */ - private static void slice(CallGraph callgraph, ContextMethod method, Set set1, + private static void slice(CallGraph callgraph, MethodOrMethodContext method, Set set1, Set set2) { for (Iterator it = callgraph.edgesInto(method); it.hasNext(); ) { Edge edge = it.next(); set2.add(edge); - ContextMethod src = edge.getSrc(); + MethodOrMethodContext src = edge.getSrc(); if (set1.add(src)) slice(callgraph, src, set1, set2); } @@ -226,8 +206,8 @@ private static void slice(CallGraph callgraph, ContextMethod method, Set tgts = new HashSet<>(); + public static void dumpSlicedCallGraph(CallGraph callgraph, MethodOrMethodContext method) { + Set tgts = new HashSet<>(); Set edges = new HashSet<>(); tgts.add(method); slice(callgraph, method, tgts, edges); @@ -238,16 +218,16 @@ public static void dumpSlicedCallGraph(CallGraph callgraph, ContextMethod method /** * dump callgraph from entry to the method */ - public static void dumpSlicedCallGraph2(CallGraph callgraph, ContextMethod method) { + public static void dumpSlicedCallGraph2(CallGraph callgraph, MethodOrMethodContext method) { Set edges = new HashSet<>(); - Set visited = new HashSet<>(); - Queue queue = new UniqueQueue<>(); + Set visited = new HashSet<>(); + Queue queue = new UniqueQueue<>(); queue.add(method); while (!queue.isEmpty()) { - ContextMethod front = queue.poll(); + MethodOrMethodContext front = queue.poll(); for (Iterator it = callgraph.edgesInto(front); it.hasNext(); ) { Edge edge = it.next(); - ContextMethod src = edge.getSrc(); + MethodOrMethodContext src = edge.getSrc(); if (visited.add(src)) { queue.add(src); edges.add(edge); @@ -262,11 +242,11 @@ public static boolean isUnresolved(Type type) { if (type instanceof ArrayType at) { type = at.getArrayElementType(); } - if (!(type instanceof ClassType rt)) + if (!(type instanceof RefType rt)) return false; - if (!rt.hasSootClass()) { - return true; - } +// if (!rt.hasSootClass()) { +// return true; +// } SootClass cl = rt.getSootClass(); return cl.resolvingLevel() < SootClass.HIERARCHY; } @@ -282,12 +262,12 @@ public static boolean castNeverFails(Type src, Type dst) { return true; if (src instanceof NullType) return true; -// if (src instanceof AnySubType) -// return true; + if (src instanceof AnySubType) + return true; if (dst instanceof NullType) return false; -// if (dst instanceof AnySubType) -// throw new RuntimeException("oops src=" + src + " dst=" + dst); + if (dst instanceof AnySubType) + throw new RuntimeException("oops src=" + src + " dst=" + dst); return PTAScene.v().getOrMakeFastHierarchy().canStoreType(src, dst); } @@ -297,9 +277,9 @@ public static QueueReader dispatch(Type type, VirtualCallSite site) if (site.kind() == Kind.THREAD && !PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, clRunnable)) { return targets; } - ContextMethod container = site.container(); - if (site.iie() instanceof JSpecialInvokeExpr sie && site.kind() != Kind.THREAD) { - SootMethod target = VirtualCalls.v().resolveSpecial(sie, site.subSig(), container.method()); + MethodOrMethodContext container = site.container(); + if (site.iie() instanceof SpecialInvokeExpr && site.kind() != Kind.THREAD) { + SootMethod target = VirtualCalls.v().resolveSpecial((SpecialInvokeExpr) site.iie(), site.subSig(), container.method()); // if the call target resides in a phantom class then // "target" will be null, simply do not add the target in that case if (target != null) { @@ -551,15 +531,14 @@ private static void drawInvPAGMap(DotGraph canvas, Map")) { + if (finalizeMethod != null && finalizeMethod.toString().equals("")) { return false; } return finalizeMethod != null; @@ -640,14 +618,14 @@ private static void initEmptyHeapContextTypes() { public static boolean isOfPrimitiveBaseType(AllocNode heap) { if (heap.getType() instanceof ArrayType arrayType) { - return arrayType.getBaseType() instanceof PrimitiveType; + return arrayType.baseType instanceof PrimType; } return false; } public static boolean isPrimitiveArrayType(Type type) { if (type instanceof ArrayType arrayType) { - return arrayType.getArrayElementType() instanceof PrimitiveType; + return arrayType.getArrayElementType() instanceof PrimType; } return false; } @@ -660,7 +638,7 @@ public static boolean isPrimitiveArrayType(Type type) { public static boolean enforceEmptyContext(AllocNode probe) { // primitive array objects should be context-insenstive. if (probe.getType() instanceof ArrayType arrayType) { - if (arrayType.getArrayElementType() instanceof PrimitiveType) { + if (arrayType.getArrayElementType() instanceof PrimType) { return true; } } @@ -683,12 +661,12 @@ public static boolean enforceEmptyContext(AllocNode probe) { public static void writeJimple(String parentDir, SootClass clz) { File packageDirectory = new File( - parentDir + File.separator + clz.getType().getPackageName().toString().replace(".", File.separator)); + parentDir + File.separator + clz.getPackageName().replace(".", File.separator)); try { packageDirectory.mkdirs(); OutputStream streamOut = new FileOutputStream( - packageDirectory + File.separator + clz.getName() + ".jimple"); + packageDirectory + File.separator + clz.getShortName() + ".jimple"); PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut)); Printer.v().printTo(clz, writerOut); writerOut.flush(); @@ -774,10 +752,10 @@ public static String findMainFromMetaInfo(String appPath) { public static SootClass getSootClass(Type type) { SootClass allocated = null; - if (type instanceof ClassType classType) { - allocated = classType.getSootClass(); - } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof ClassType classType) { - allocated = classType.getSootClass(); + if (type instanceof RefType) { + allocated = ((RefType) type).getSootClass(); + } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof RefType) { + allocated = ((RefType) ((ArrayType) type).getArrayElementType()).getSootClass(); } return allocated; } @@ -790,9 +768,9 @@ public static Body getMethodBody(SootMethod m) { synchronized (PTAUtils.class) { if (body == null) { if (m.isConcrete()) { - body = m.getBody(); + body = m.retrieveActiveBody(); } else { - body = Body.builder().setMethodSignature(m.getSignature()).build(); + body = new JimpleBody(m); } methodToBody.putIfAbsent(m, body); } @@ -803,10 +781,10 @@ public static Body getMethodBody(SootMethod m) { public static boolean isEmptyArray(AllocNode heap) { Object var = heap.getNewExpr(); - if (var instanceof JNewArrayExpr nae) { + if (var instanceof NewArrayExpr nae) { Value sizeVal = nae.getSize(); if (sizeVal instanceof IntConstant size) { - return size.getValue() == 0; + return size.value == 0; } } return false; @@ -814,11 +792,11 @@ public static boolean isEmptyArray(AllocNode heap) { public static LocalVarNode paramToArg(PAG pag, Stmt invokeStmt, MethodPAG srcmpag, VarNode pi) { MethodNodeFactory srcnf = srcmpag.nodeFactory(); - AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); + InvokeExpr ie = invokeStmt.getInvokeExpr(); Parm mPi = (Parm) pi.getVariable(); LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); LocalVarNode receiver; - if (ie instanceof AbstractInstanceInvokeExpr iie) { + if (ie instanceof InstanceInvokeExpr iie) { receiver = pag.findLocalVarNode(iie.getBase()); } else { // static call @@ -827,7 +805,7 @@ public static LocalVarNode paramToArg(PAG pag, Stmt invokeStmt, MethodPAG srcmpa if (mPi.isThis()) { return receiver; } else if (mPi.isReturn()) { - if (invokeStmt instanceof JAssignStmt assignStmt) { + if (invokeStmt instanceof AssignStmt assignStmt) { Value mR = assignStmt.getLeftOp(); return (LocalVarNode) pag.findValNode(mR); } else { @@ -855,7 +833,7 @@ public static Set clinitsOf(SootClass cl) { SootClass curr = cl; while (curr != null) { worklist.add(curr); - curr = (SootClass) curr.getSuperclass().get(); + curr = curr.getSuperclassUnsafe(); } while (!worklist.isEmpty()) { SootClass sc = worklist.poll(); @@ -864,8 +842,7 @@ public static Set clinitsOf(SootClass cl) { } } for (SootClass sc : visit) { - MethodSubSignature msubsig = JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); - final SootMethod initStart = (SootMethod) sc.getMethod(msubsig).get(); + final SootMethod initStart = sc.getMethodUnsafe(Scene.v().getSubSigNumberer().findOrAdd("void ()")); if (initStart != null) { ret.add(initStart); } diff --git a/sootup.qilin/src/main/java/qilin/util/Util.java b/sootup.qilin/src/main/java/qilin/util/Util.java index 325c959f18f..bb94314934f 100644 --- a/sootup.qilin/src/main/java/qilin/util/Util.java +++ b/sootup.qilin/src/main/java/qilin/util/Util.java @@ -21,11 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; diff --git a/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java b/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java index 75dc1771121..9e7b888c0ff 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java @@ -18,12 +18,7 @@ package qilin.util.graph; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class Reachability { private final DirectedGraph graph; diff --git a/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java b/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java index 6856417ab22..2be136e2feb 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java @@ -18,11 +18,7 @@ package qilin.util.graph; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; public class SCCMergedGraph implements DirectedGraph> { private Set> nodes; diff --git a/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java b/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java index 521da7517e1..3b256448a00 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java @@ -18,11 +18,7 @@ package qilin.util.graph; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; +import java.util.*; public class StronglyConnectedComponents { private final List> componentList; diff --git a/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java b/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java index 85d2db37a3d..c257438b48f 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java @@ -18,11 +18,7 @@ package qilin.util.graph; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; +import java.util.*; public class TopologicalSorter { private DirectedGraph graph; diff --git a/sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java b/sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java deleted file mode 100644 index 03c7af54f57..00000000000 --- a/sootup.qilin/src/main/java/qilin/util/queue/ChunkedQueue.java +++ /dev/null @@ -1,98 +0,0 @@ -package qilin.util.queue; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2003 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -/** - * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary - * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not - * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the - * QueueReader was created. - * - * @author Ondrej Lhotak - */ -@SuppressWarnings("unchecked") -public class ChunkedQueue { - - protected static final Object NULL_CONST = new Object(); - protected static final Object DELETED_CONST = new Object(); - - protected static final int LENGTH = 60; - protected Object[] q; - protected int index; - - public ChunkedQueue() { - q = new Object[LENGTH]; - index = 0; - } - - /** Add an object to the queue. */ - public void add(E o) { - if (o == null) { - o = (E) NULL_CONST; - } - if (index == LENGTH - 1) { - Object[] temp = new Object[LENGTH]; - q[index] = temp; - q = temp; - index = 0; - } - q[index++] = o; - } - - /** Create reader which will read objects from the queue. */ - public QueueReader reader() { - return new QueueReader((E[]) q, index); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - boolean isFirst = true; - - int idx = index; - Object[] curArray = q; - while (idx < curArray.length) { - Object curObj = curArray[idx]; - if (curObj == null) { - break; - } - if (isFirst) { - isFirst = false; - } else { - sb.append(", "); - } - if (curObj instanceof Object[]) { - curArray = (Object[]) curObj; - idx = 0; - } else { - sb.append(curObj.toString()); - idx++; - } - } - sb.append("]"); - return sb.toString(); - } - -} - diff --git a/sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java b/sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java deleted file mode 100644 index 8fea82b164b..00000000000 --- a/sootup.qilin/src/main/java/qilin/util/queue/QueueReader.java +++ /dev/null @@ -1,194 +0,0 @@ -package qilin.util.queue; - -import java.util.Collection; -import java.util.Collections; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2003 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import java.util.NoSuchElementException; - -/** - * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary - * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not - * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the - * QueueReader was created. - * - * @author Ondrej Lhotak - */ -public class QueueReader implements java.util.Iterator { - protected E[] q; - protected int index; - - protected QueueReader(E[] q, int index) { - this.q = q; - this.index = index; - } - - /** - * Returns (and removes) the next object in the queue, or null if there are none. - */ - @SuppressWarnings("unchecked") - public E next() { - Object ret = null; - do { - if (q[index] == null) { - throw new NoSuchElementException(); - } - if (index == q.length - 1) { - q = (E[]) q[index]; - index = 0; - if (q[index] == null) { - throw new NoSuchElementException(); - } - } - ret = q[index]; - if (ret == ChunkedQueue.NULL_CONST) { - ret = null; - } - index++; - } while (skip(ret)); - return (E) ret; - } - - protected boolean skip(Object ret) { - return ret == ChunkedQueue.DELETED_CONST; - } - - /** Returns true iff there is currently another object in the queue. */ - @SuppressWarnings("unchecked") - public boolean hasNext() { - do { - E ret = q[index]; - if (ret == null) { - return false; - } - if (index == q.length - 1) { - q = (E[]) ret; - index = 0; - if (q[index] == null) { - return false; - } - } - if (skip(ret)) { - index++; - } else { - return true; - } - } while (true); - } - - /** - * Removes an element from the underlying queue. This operation can only delete elements that have not yet been consumed by - * this reader. - * - * @param o - * The element to remove - */ - public void remove(E o) { - if (o instanceof Invalidable) { - ((Invalidable) o).invalidate(); - return; - } - remove(Collections.singleton(o)); - } - - /** - * Removes elements from the underlying queue. This operation can only delete elements that have not yet been consumed by - * this reader. - * - * @param toRemove - * The elements to remove - */ - @SuppressWarnings("unchecked") - public void remove(Collection toRemove) { - boolean allInvalidable = true; - for (E o : toRemove) { - if (!(o instanceof Invalidable)) { - allInvalidable = false; - continue; - } - - ((Invalidable) o).invalidate(); - } - if (allInvalidable) { - return; - } - int idx = 0; - Object[] curQ = q; - while (curQ[idx] != null) { - // Do we need to switch to a new list? - if (idx == curQ.length - 1) { - curQ = (E[]) curQ[idx]; - idx = 0; - } - - // Is this the element to delete? - if (toRemove.contains(curQ[idx])) { - curQ[idx] = ChunkedQueue.DELETED_CONST; - } - - // Next element - idx++; - } - } - - @SuppressWarnings("unchecked") - public void remove() { - q[index - 1] = (E) ChunkedQueue.DELETED_CONST; - } - - public QueueReader clone() { - return new QueueReader(q, index); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - boolean isFirst = true; - - int idx = index; - Object[] curArray = q; - while (idx < curArray.length) { - Object curObj = curArray[idx]; - if (curObj == null) { - break; - } - if (isFirst) { - isFirst = false; - } else { - sb.append(", "); - } - if (curObj instanceof Object[]) { - curArray = (Object[]) curObj; - idx = 0; - } else { - sb.append(curObj.toString()); - idx++; - } - } - sb.append("]"); - return sb.toString(); - } - -} diff --git a/sootup.qilin/src/main/java/soot/Context.java b/sootup.qilin/src/main/java/soot/Context.java new file mode 100644 index 00000000000..2cff77aea3d --- /dev/null +++ b/sootup.qilin/src/main/java/soot/Context.java @@ -0,0 +1,30 @@ +package soot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A context in a context-sensitive all graph. May be a unit (in a 1CFA call graph) or a Spark AllocNode (in an + * object-sensitive call graph). + */ +public interface Context { +} diff --git a/sootup.qilin/src/main/java/soot/MethodOrMethodContext.java b/sootup.qilin/src/main/java/soot/MethodOrMethodContext.java new file mode 100644 index 00000000000..9b765866cc4 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/MethodOrMethodContext.java @@ -0,0 +1,37 @@ +package soot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import sootup.core.model.SootMethod; + +/** + * A common interface for either just a method, or a method with context. + * + * @author Ondrej Lhotak + */ +public interface MethodOrMethodContext { + public SootMethod method(); + + public Context context(); +} + diff --git a/sootup.qilin/src/main/java/soot/util/Numberable.java b/sootup.qilin/src/main/java/soot/util/Numberable.java new file mode 100644 index 00000000000..5321ce05753 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/Numberable.java @@ -0,0 +1,36 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A class that numbers objects, so they can be placed in bitsets. + * + * @author Ondrej Lhotak + */ + +public interface Numberable { + public void setNumber(int number); + + public int getNumber(); +} + diff --git a/sootup.qilin/src/main/java/soot/util/NumberedString.java b/sootup.qilin/src/main/java/soot/util/NumberedString.java new file mode 100644 index 00000000000..05e5216b8fe --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/NumberedString.java @@ -0,0 +1,88 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A class that assigns integers to java.lang.Strings. + * + * @author Ondrej Lhotak + */ +public final class NumberedString implements Numberable { + + private final String s; + private volatile int number; + + public NumberedString(String s) { + this.s = s; + } + + @Override + public final void setNumber(int number) { + this.number = number; + } + + @Override + public final int getNumber() { + return number; + } + + @Override + public final String toString() { + return getString(); + } + + public final String getString() { + if (number == 0) { + throw new RuntimeException("oops"); + } + return s; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + number; + result = prime * result + ((s == null) ? 0 : s.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + NumberedString other = (NumberedString) obj; + if (this.number != other.number) { + return false; + } + if (this.s == null) { + return other.s == null; + } else { + return this.s.equals(other.s); + } + } +} diff --git a/sootup.qilin/src/main/java/soot/util/StringNumberer.java b/sootup.qilin/src/main/java/soot/util/StringNumberer.java new file mode 100644 index 00000000000..785aa81af74 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/StringNumberer.java @@ -0,0 +1,54 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import heros.ThreadSafe; + +import java.util.HashMap; +import java.util.Map; + +/** + * A class that numbers strings, so they can be placed in bitsets. + * + * @author Ondrej Lhotak + */ +@ThreadSafe +public class StringNumberer extends ArrayNumberer { + + private final Map stringToNumbered = new HashMap(1024); + + public synchronized NumberedString findOrAdd(String s) { + NumberedString ret = stringToNumbered.get(s); + if (ret == null) { + ret = new NumberedString(s); + stringToNumbered.put(s, ret); + add(ret); + } + return ret; + } + + public NumberedString find(String s) { + return stringToNumbered.get(s); + } +} + diff --git a/sootup.qilin/src/test/java/qilin/test/FlowSensTests.java b/sootup.qilin/src/test/java/qilin/test/FlowSensTests.java new file mode 100644 index 00000000000..05a39cd234b --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/FlowSensTests.java @@ -0,0 +1,55 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test; + +import org.junit.Ignore; +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class FlowSensTests extends JunitTests { + @Test + public void testLoops() { + checkAssertions(run("qilin.microben.flowsens.Loops")); + } + + @Ignore + public void testFlowSens0() { + checkAssertions(run("qilin.microben.flowsens.FlowSens0")); + } + + @Ignore + public void testInstanceOf0() { + checkAssertions(run("qilin.microben.flowsens.InstanceOf0")); + } + + @Ignore + public void testBranching1() { + checkAssertions(run("qilin.microben.flowsens.Branching1")); + } + + @Ignore + public void testStrongUpdate1() { + checkAssertions(run("qilin.microben.flowsens.StrongUpdate1")); + } + + @Ignore + public void testStrongUpdate2() { + checkAssertions(run("qilin.microben.flowsens.StrongUpdate2")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/context/CFATests.java b/sootup.qilin/src/test/java/qilin/test/context/CFATests.java new file mode 100644 index 00000000000..4da40496480 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/context/CFATests.java @@ -0,0 +1,45 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.context; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class CFATests extends JunitTests { + + @Test + public void testCFA1k0() { + checkAssertions(run("qilin.microben.context.cfa.CFA1k0", "1c")); + } + + @Test + public void testCFA1k1() { + checkAssertions(run("qilin.microben.context.cfa.CFA1k1", "1c")); + } + + @Test + public void testCFA1k2() { + checkAssertions(run("qilin.microben.context.cfa.CFA1k2", "1c")); + } + + @Test + public void testCFA2k() { + checkAssertions(run("qilin.microben.context.cfa.CFA2k", "2c")); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java b/sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java new file mode 100644 index 00000000000..067865f9812 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java @@ -0,0 +1,74 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.context; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class CollectionsTests extends JunitTests { + @Test + public void testArrayList0() { + checkAssertions(run("qilin.microben.context.collections.ArrayList0", "2o")); + } + + @Test + public void testLinkedList0() { + checkAssertions(run("qilin.microben.context.collections.LinkedList0", "2o")); + } + + @Test + public void testVector0() { + checkAssertions(run("qilin.microben.context.collections.Vector0", "2o")); + } + + @Test + public void testHashMap0() { + checkAssertions(run("qilin.microben.context.collections.HashMap0", "2o")); + } + + @Test + public void testTreeMap0() { + checkAssertions(run("qilin.microben.context.collections.TreeMap0", "2o")); + } + + @Test + public void testHashSet0() { + checkAssertions(run("qilin.microben.context.collections.HashSet0", "3o")); + } + + @Test + public void testTreeSet0() { + checkAssertions(run("qilin.microben.context.collections.TreeSet0", "3o")); + } + + @Test + public void testHashTable0() { + checkAssertions(run("qilin.microben.context.collections.HashTable0", "2o")); + } + + @Test + public void testPriorityQueue0() { + checkAssertions(run("qilin.microben.context.collections.PriorityQueue0", "2o")); + } + + @Test + public void testStack0() { + checkAssertions(run("qilin.microben.context.collections.Stack0", "2o")); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/test/context/HybTests.java b/sootup.qilin/src/test/java/qilin/test/context/HybTests.java new file mode 100644 index 00000000000..f34e0f11fbb --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/context/HybTests.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.context; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class HybTests extends JunitTests { + @Test + public void testHyb0() { + checkAssertions(run("qilin.microben.context.hyb.Hyb0", "1h")); + } + + @Test + public void testHyb1() { + checkAssertions(run("qilin.microben.context.hyb.Hyb1", "1h")); + } + + @Test + public void testHyb2() { + checkAssertions(run("qilin.microben.context.hyb.Hyb2", "2h")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/context/OBJTests.java b/sootup.qilin/src/test/java/qilin/test/context/OBJTests.java new file mode 100644 index 00000000000..3c117bffec0 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/context/OBJTests.java @@ -0,0 +1,70 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.context; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class OBJTests extends JunitTests { + @Test + public void testOBJ1k0() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k0", "1o")); + } + + @Test + public void testOBJ1k1() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k1", "1o")); + } + + @Test + public void testOBJ1k2() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k2", "1o")); + } + + @Test + public void testOBJ1k3() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k3", "1o")); + } + + @Test + public void testOBJ1k4() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k4", "1o")); + } + + @Test + public void testOBJ1k5() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k5", "1o")); + } + + @Test + public void testOBJ2k0() { + checkAssertions(run("qilin.microben.context.obj.OBJ2k0", "2o")); + } + + @Test + public void testOBJ2k1() { + checkAssertions(run("qilin.microben.context.obj.OBJ2k1", "2o")); + } + + @Test + public void testOBJ2k2() { + checkAssertions(run("qilin.microben.context.obj.OBJ2k2", "2o")); + } + +} \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/test/context/TypeTests.java b/sootup.qilin/src/test/java/qilin/test/context/TypeTests.java new file mode 100644 index 00000000000..2209e615bc4 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/context/TypeTests.java @@ -0,0 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.context; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class TypeTests extends JunitTests { + @Test + public void testType1k0() { + checkAssertions(run("qilin.microben.context.type.Type1k0", "1t")); + } + + @Test + public void testType2k0() { + checkAssertions(run("qilin.microben.context.type.Type2k0", "2t")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java b/sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java new file mode 100644 index 00000000000..ef61af62f71 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java @@ -0,0 +1,49 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class ArrayTests extends JunitTests { + @Test + public void testArrayIndex() { + checkAssertions(run("qilin.microben.core.array.ArrayIndex")); + } + + @Test + public void testMultiArraySimple() { + checkAssertions(run("qilin.microben.core.array.MultiArraySimple")); + } + + @Test + public void testMultiArrayComplex() { + checkAssertions(run("qilin.microben.core.array.MultiArrayComplex")); + } + + @Test + public void testArrayCopy() { + checkAssertions(run("qilin.microben.core.array.ArrayCopy")); + } + + @Test + public void testArrayElemTypeFiltering() { + checkAssertions(run("qilin.microben.core.array.ArrayElemTypeFiltering")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/AssignTests.java b/sootup.qilin/src/test/java/qilin/test/core/AssignTests.java new file mode 100644 index 00000000000..188c5a3620a --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/AssignTests.java @@ -0,0 +1,89 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.pta.PTAConfig; +import qilin.test.util.JunitTests; + +public class AssignTests extends JunitTests { + @Test + public void testCastFail() { + checkAssertions(run("qilin.microben.core.assign.CastFail")); + } + + @Test + public void testCastSucc() { + checkAssertions(run("qilin.microben.core.assign.CastSucc")); + } + + @Test + public void testReceiver2This() { + checkAssertions(run("qilin.microben.core.assign.Receiver2This")); + } + + @Test + public void testSimpleAssign() { + checkAssertions(run("qilin.microben.core.assign.SimpleAssign")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } + + @Test + public void testReturnValue0() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue0")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } + + @Test + public void testReturnValue1() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue1")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } + + @Test + public void testReturnValue2() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue2")); + } + + @Test + public void testReturnValue3() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue3")); + } + + @Test + public void testInterAssign() { + checkAssertions(run("qilin.microben.core.assign.InterAssign")); + } + + @Test + public void testStaticParameter() { + checkAssertions(run("qilin.microben.core.assign.StaticParameter")); + } + + @Test + public void testNullPointer() { + checkAssertions(run("qilin.microben.core.assign.NullPointer")); + } + + @Test + public void testRecursion() { + checkAssertions(run("qilin.microben.core.assign.Recursion")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/CallTests.java b/sootup.qilin/src/test/java/qilin/test/core/CallTests.java new file mode 100644 index 00000000000..61cf8127993 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/CallTests.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class CallTests extends JunitTests { + @Test + public void testVirtualCall0() { + checkAssertions(run("qilin.microben.core.call.VirtualCall0")); + } + + @Test + public void testVirtualCall1() { + checkAssertions(run("qilin.microben.core.call.VirtualCall1")); + } + + @Test + public void testStaticCall() { + checkAssertions(run("qilin.microben.core.call.StaticCall")); + } + +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java b/sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java new file mode 100644 index 00000000000..751e0b99dd5 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java @@ -0,0 +1,44 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class ClinitTests extends JunitTests { + @Test + public void testClinitNewExpr() { + checkAssertions(run("qilin.microben.core.clinit.ClinitNewExpr")); + } + + @Test + public void testClinitStaticCall() { + checkAssertions(run("qilin.microben.core.clinit.ClinitStaticCall")); + } + + @Test + public void testClinitStaticLoad() { + checkAssertions(run("qilin.microben.core.clinit.ClinitStaticLoad")); + } + + @Test + public void testClinitStaticStore() { + checkAssertions(run("qilin.microben.core.clinit.ClinitStaticStore")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java b/sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java new file mode 100644 index 00000000000..a60d92ebb26 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class ExceptionTests extends JunitTests { + @Test + public void testSimpleException() { + checkAssertions(run("qilin.microben.core.exception.SimpleException")); + } + + @Test + public void testExceptionChain() { + checkAssertions(run("qilin.microben.core.exception.ExceptionChain")); + } + + @Test + public void testMethodThrow() { + checkAssertions(run("qilin.microben.core.exception.MethodThrow")); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/test/core/FieldTests.java b/sootup.qilin/src/test/java/qilin/test/core/FieldTests.java new file mode 100644 index 00000000000..3cff7804e51 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/FieldTests.java @@ -0,0 +1,44 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class FieldTests extends JunitTests { + @Test + public void testInstanceLoad() { + checkAssertions(run("qilin.microben.core.field.InstanceLoad")); + } + + @Test + public void testInstanceStore() { + checkAssertions(run("qilin.microben.core.field.InstanceStore")); + } + + @Test + public void testFieldSensitivity1() { + checkAssertions(run("qilin.microben.core.field.FieldSensitivity1")); + } + + @Test + public void testFieldSensitivity2() { + checkAssertions(run("qilin.microben.core.field.FieldSensitivity2")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java b/sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java new file mode 100644 index 00000000000..1f95e50c783 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class GlobalTests extends JunitTests { + @Test + public void testStaticLoad() { + checkAssertions(run("qilin.microben.core.global.StaticLoad")); + } + + @Test + public void testStaticStore() { + checkAssertions(run("qilin.microben.core.global.StaticStore")); + } + + @Test + public void testStringConstant() { + checkAssertions(run("qilin.microben.core.global.StringConstant")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/NativeTests.java b/sootup.qilin/src/test/java/qilin/test/core/NativeTests.java new file mode 100644 index 00000000000..77e1087e4be --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/NativeTests.java @@ -0,0 +1,91 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Ignore; +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class NativeTests extends JunitTests { + @Test + public void testArrayCopy() { + checkAssertions(run("qilin.microben.core.natives.ArrayCopy")); + } + + @Test + public void testObjectClone() { + checkAssertions(run("qilin.microben.core.natives.ObjectClone")); + } + + @Test + public void testPrivilegedActions0() { + checkAssertions(run("qilin.microben.core.natives.PrivilegedActions0")); + } + + @Test + public void testPrivilegedActions1() { + checkAssertions(run("qilin.microben.core.natives.PrivilegedActions1")); + } + + @Test + public void testPrivilegedActions2() { + checkAssertions(run("qilin.microben.core.natives.PrivilegedActions2", "2o")); + } + + @Test + public void testSystemIn() { + checkAssertions(run("qilin.microben.core.natives.SystemIn")); + } + + @Test + public void testSystemOut() { + checkAssertions(run("qilin.microben.core.natives.SystemOut")); + } + + @Test + public void testSystemErr() { + checkAssertions(run("qilin.microben.core.natives.SystemErr")); + } + + @Test + public void testFinalize() { + checkAssertions(run("qilin.microben.core.natives.Finalize")); + } + + @Test + public void testTreadRun() { + checkAssertions(run("qilin.microben.core.natives.TreadRun")); + } + + @Test + @Ignore + public void testCurrentThread() { + checkAssertions(run("qilin.microben.core.natives.CurrentThread")); + } + + @Test + public void testRefArrayGet() { + checkAssertions(run("qilin.microben.core.natives.RefArrayGet")); + } + + @Test + public void testRefArraySet() { + checkAssertions(run("qilin.microben.core.natives.RefArraySet")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java b/sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java new file mode 100644 index 00000000000..06b9c4091b9 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java @@ -0,0 +1,88 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.core; + +import org.junit.Test; +import qilin.core.PTA; +import qilin.test.util.JunitTests; + +public class ReflogTests extends JunitTests { + @Test + public void testFieldGetStatic() { + checkAssertions(run("qilin.microben.core.reflog.FieldGetStatic")); + } + + @Test + public void testFieldGet() { + checkAssertions(run("qilin.microben.core.reflog.FieldGet")); + } + + @Test + public void testFieldSetStatic() { + checkAssertions(run("qilin.microben.core.reflog.FieldSetStatic")); + } + + @Test + public void testFieldSet() { + checkAssertions(run("qilin.microben.core.reflog.FieldSet")); + } + + @Test + public void testArrayNewInstance() { + checkAssertions(run("qilin.microben.core.reflog.ArrayNewInstance")); + } + + @Test + public void testConstructorNewInstance() { + checkAssertions(run("qilin.microben.core.reflog.ConstructorNewInstance")); + } + + @Test + public void testMethodInvokeStatic() { + checkAssertions(run("qilin.microben.core.reflog.MethodInvokeStatic")); + } + + @Test + public void testMethodInvoke() { + checkAssertions(run("qilin.microben.core.reflog.MethodInvoke")); + } + + @Test + public void testClassNewInstance() { + checkAssertions(run("qilin.microben.core.reflog.ClassNewInstance")); + } + + @Test + public void testDoopRefBug() { + PTA pta = run("qilin.microben.core.reflog.DoopRefBug"); + checkAssertions(pta); + } + + @Test + public void testClassForName() { + PTA pta = run("qilin.microben.core.reflog.ClassForName"); + checkAssertions(pta); + } + + @Test + public void testClassForName1() { + PTA pta = run("qilin.microben.core.reflog.ClassForName1"); + checkAssertions(pta); + } +} \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java b/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java new file mode 100644 index 00000000000..a6ff745166a --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java @@ -0,0 +1,118 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.util; + +import qilin.core.PTA; +import qilin.core.sets.PointsToSet; +import qilin.pta.PTAConfig; +import qilin.util.PTAUtils; +import soot.Local; +import soot.SootMethod; +import soot.Value; +import soot.jimple.ClassConstant; +import soot.jimple.NullConstant; +import soot.jimple.Stmt; +import soot.jimple.StringConstant; + +import java.util.Objects; + +public class AliasAssertion implements IAssertion { + private final PTA pta; + private final SootMethod sm; + private final Stmt stmt; + private final Value va; + private final Value vb; + private final boolean groundTruth; + + public AliasAssertion(PTA pta, SootMethod sm, Stmt stmt, Value va, Value vb, boolean groundTruth) { + this.pta = pta; + this.sm = sm; + this.stmt = stmt; + this.va = va; + this.vb = vb; + this.groundTruth = groundTruth; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AliasAssertion that = (AliasAssertion) o; + return groundTruth == that.groundTruth && + Objects.equals(sm, that.sm) && + Objects.equals(stmt, that.stmt) && + Objects.equals(va, that.va) && + Objects.equals(vb, that.vb); + } + + @Override + public int hashCode() { + return Objects.hash(sm, stmt, va, vb, groundTruth); + } + + @Override + public boolean check() { + return isMayAlias(pta, va, vb) == groundTruth; + } + + private static boolean DEBUG = true; + + protected boolean isMayAlias(PTA pta, Value va, Value vb) { + if (va instanceof NullConstant && vb instanceof NullConstant) { + return true; + } + if (va instanceof NullConstant || vb instanceof NullConstant) { + return false; + } + if (va instanceof StringConstant && vb instanceof StringConstant) { + return va.equals(vb); + } else if (va instanceof StringConstant) { + String s = ((StringConstant) va).value; + if (!PTAConfig.v().getPtaConfig().stringConstants) { + s = "STRING_NODE"; + } + PointsToSet pts = pta.reachingObjects((Local) vb).toCIPointsToSet(); + return pts.possibleStringConstants().contains(s); + } else if (vb instanceof StringConstant) { + String s = ((StringConstant) vb).value; + if (!PTAConfig.v().getPtaConfig().stringConstants) { + s = "STRING_NODE"; + } + PointsToSet pts = pta.reachingObjects((Local) va).toCIPointsToSet(); + return pts.possibleStringConstants().contains(s); + } else if (va instanceof ClassConstant) { + PointsToSet pts = pta.reachingObjects((Local) vb).toCIPointsToSet(); + return pts.possibleClassConstants().contains(va); + } else if (vb instanceof ClassConstant) { + PointsToSet pts = pta.reachingObjects((Local) va).toCIPointsToSet(); + return pts.possibleClassConstants().contains(vb); + } + PointsToSet pts1 = pta.reachingObjects((Local) va).toCIPointsToSet(); + if (DEBUG) { + System.out.println("va points to: " + PTAUtils.getNodeLabel(pta.getPag().findLocalVarNode(va)) + pta.getPag().findLocalVarNode(va)); + PTAUtils.printPts(pta, pts1); + } + PointsToSet pts2 = pta.reachingObjects((Local) vb).toCIPointsToSet(); + if (DEBUG) { + System.out.println("vb points to: " + PTAUtils.getNodeLabel(pta.getPag().findLocalVarNode(vb)) + pta.getPag().findLocalVarNode(vb)); + PTAUtils.printPts(pta, pts2); + } + return pts1.hasNonEmptyIntersection(pts2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java b/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java new file mode 100644 index 00000000000..60da49f282e --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java @@ -0,0 +1,68 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.util; + +import qilin.core.PTA; +import qilin.util.PTAUtils; +import soot.SootMethod; +import soot.Unit; +import soot.jimple.InvokeExpr; +import soot.jimple.StaticInvokeExpr; +import soot.jimple.Stmt; + +import java.util.HashSet; +import java.util.Set; + +public class AssertionsParser { + protected static String mayAliasSig = ""; + protected static String notAliasSig = ""; + + public static Set retrieveQueryInfo(PTA pta) { + Set aliasAssertionSet = new HashSet<>(); + for (SootMethod sm : pta.getNakedReachableMethods()) { + if (sm.isNative() || sm.isPhantom()) { + continue; + } + +// if (sm.getSignature().equals("")) { +// System.out.println(sm); +// System.out.println(PTAUtils.getMethodBody(sm)); +// PTAUtils.dumpMPAG(pta, sm); +// System.out.println("================================================================="); +// } + for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { + final Stmt stmt = (Stmt) unit; + if (stmt.containsInvokeExpr()) { + InvokeExpr ie = stmt.getInvokeExpr(); + if (ie instanceof StaticInvokeExpr) { + final String calleeSig = ie.getMethodRef().getSignature(); + if (calleeSig.equals(mayAliasSig)) { + aliasAssertionSet.add(new AliasAssertion(pta, sm, stmt, ie.getArg(0), ie.getArg(1), true)); + } else if (calleeSig.equals(notAliasSig)) { + aliasAssertionSet.add(new AliasAssertion(pta, sm, stmt, ie.getArg(0), ie.getArg(1), false)); + } + } + } + } + } + System.out.println("#alias queries: " + aliasAssertionSet.size()); + return aliasAssertionSet; + } + +} diff --git a/sootup.qilin/src/test/java/qilin/test/util/IAssertion.java b/sootup.qilin/src/test/java/qilin/test/util/IAssertion.java new file mode 100644 index 00000000000..964f7ed8621 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/util/IAssertion.java @@ -0,0 +1,23 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.util; + +public interface IAssertion { + boolean check(); +} diff --git a/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java new file mode 100644 index 00000000000..fb341a6a02c --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java @@ -0,0 +1,110 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.test.util; + +import driver.Main; +import driver.PTAFactory; +import driver.PTAOption; +import driver.PTAPattern; +import org.junit.Before; +import org.junit.BeforeClass; +import qilin.core.PTA; +import qilin.core.PTAScene; +import qilin.pta.PTAConfig; +import soot.options.Options; + +import java.io.File; +import java.io.IOException; +import java.util.Set; + +import static org.junit.Assert.assertTrue; + +public abstract class JunitTests { + protected static String appPath, jrePath, refLogPath; + protected static boolean isSetUp = false; + @BeforeClass + public static void setUp() throws IOException { + if (isSetUp) { + return; + } + File rootDir = new File("../"); + File testDir = new File(rootDir, "qilin.microben" + File.separator + "build" + File.separator + "classes" + File.separator + "java" + File.separator + "main"); + appPath = testDir.getCanonicalPath(); + System.out.println("APP_PATH:" + appPath); + File refLogDir = new File(rootDir, "qilin.microben" + File.separator + "src" + File.separator + "qilin" + File.separator + "microben" + File.separator + "core" + File.separator + "reflog"); + refLogPath = refLogDir.getCanonicalPath(); + File jreFile = new File(".." + File.separator + "artifact" + File.separator + "benchmarks" + + File.separator + "JREs" + File.separator + "jre1.6.0_45"); + jrePath = jreFile.getCanonicalPath(); + String[] args = generateArgumentsx(); + PTAOption ptaOption = new PTAOption(); + ptaOption.parseCommandLine(args); + Main.setupSoot(); + isSetUp = true; + } + + @Before + public void reset() { + PTAScene.junitReset(); + } + + public PTA run(String mainClass) { + return run(mainClass, "insens"); + } + + public PTA run(String mainClass, String ptaPattern) { + PTAConfig.v().getAppConfig().MAIN_CLASS = mainClass; + Options.v().set_main_class(mainClass); + PTAScene.v().setMainClass(PTAScene.v().getSootClass(mainClass)); + PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPattern); + PTAConfig.v().getPtaConfig().ptaName = PTAConfig.v().getPtaConfig().ptaPattern.toString(); + System.out.println(PTAConfig.v().getAppConfig().APP_PATH); + PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + pta.pureRun(); + return pta; + } + + public static String[] generateArgumentsx() { + return new String[]{ + "-singleentry", + "-apppath", + appPath, + "-mainclass", + "qilin.microben.core.exception.SimpleException", + "-se", + "-jre=" + jrePath, + "-clinit=ONFLY", + "-lcs", + "-mh", + "-pae", + "-pe", + "-reflectionlog", + refLogPath + File.separator + "Reflection.log" + }; + } + + protected void checkAssertions(PTA pta) { + Set aliasAssertionSet = AssertionsParser.retrieveQueryInfo(pta); + for (IAssertion mAssert : aliasAssertionSet) { + boolean answer = mAssert.check(); + System.out.println("Assertion is " + answer); + assertTrue(answer); + } + } +} From 3dae5a1caa3f9af5f29bf93ae354146dbd2612ec Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sat, 16 Sep 2023 14:39:13 +1000 Subject: [PATCH 008/145] add soot.util classes, change imports --- sootup.qilin/.DS_Store | Bin 6148 -> 0 bytes sootup.qilin/src/.DS_Store | Bin 6148 -> 0 bytes sootup.qilin/src/main/.DS_Store | Bin 8196 -> 0 bytes sootup.qilin/src/main/java/.DS_Store | Bin 6148 -> 0 bytes .../src/main/java/driver/PTAComparator.java | 2 +- .../java/qilin/core/ArtificialMethod.java | 8 +- .../src/main/java/qilin/core/CorePTA.java | 1 + .../src/main/java/qilin/core/PTA.java | 8 +- .../src/main/java/qilin/core/PTAScene.java | 7 +- .../java/qilin/core/PointsToAnalysis.java | 4 +- .../main/java/qilin/core/VirtualCalls.java | 11 +- .../qilin/core/builder/CallGraphBuilder.java | 10 +- .../qilin/core/builder/ExceptionHandler.java | 6 +- .../qilin/core/builder/FakeMainFactory.java | 8 +- .../qilin/core/builder/MethodNodeFactory.java | 14 +- .../core/context/TypeContextElement.java | 6 +- .../JavaIoFileSystemGetFileSystemNative.java | 4 +- .../natives/JavaIoFileSystemListNative.java | 4 +- .../natives/JavaLangObjectCloneNative.java | 5 +- ...efFinalizerInvokeFinalizeMethodNative.java | 4 +- .../core/natives/JavaLangReflectArrayGet.java | 4 +- .../core/natives/JavaLangReflectArraySet.java | 4 +- .../JavaLangSystemArraycopyNative.java | 4 +- .../natives/JavaLangSystemSetErr0Native.java | 4 +- .../natives/JavaLangSystemSetIn0Native.java | 4 +- .../natives/JavaLangSystemSetOut0Native.java | 5 +- .../natives/JavaLangThreadCurrentThread.java | 4 +- .../natives/JavaLangThreadStart0Native.java | 4 +- ...ityAccessControllerDoPrivilegedNative.java | 4 +- ...ontrollerDoPrivileged_ExceptionNative.java | 4 +- .../java/qilin/core/natives/NativeMethod.java | 4 +- .../core/natives/NativeMethodDriver.java | 4 +- .../main/java/qilin/core/pag/AllocNode.java | 4 +- .../java/qilin/core/pag/ArrayElement.java | 3 +- .../qilin/core/pag/ClassConstantNode.java | 2 +- .../java/qilin/core/pag/ConstantNode.java | 4 +- .../java/qilin/core/pag/ContextField.java | 5 +- .../java/qilin/core/pag/ContextMethod.java | 2 +- .../src/main/java/qilin/core/pag/Field.java | 5 +- .../java/qilin/core/pag/FieldRefNode.java | 1 - .../java/qilin/core/pag/FieldValNode.java | 2 - .../java/qilin/core/pag/GlobalVarNode.java | 11 +- .../java/qilin/core/pag/LocalVarNode.java | 5 +- .../main/java/qilin/core/pag/MethodPAG.java | 7 +- .../src/main/java/qilin/core/pag/Node.java | 2 +- .../src/main/java/qilin/core/pag/PAG.java | 13 +- .../src/main/java/qilin/core/pag/Parm.java | 6 +- .../main/java/qilin/core/pag/SparkField.java | 36 ++ .../qilin/core/pag/StringConstantNode.java | 4 +- .../src/main/java/qilin/core/pag/ValNode.java | 2 +- .../src/main/java/qilin/core/pag/VarNode.java | 3 +- .../java/qilin/core/pag/VirtualCallSite.java | 2 +- .../core/reflection/NopReflectionModel.java | 2 +- .../core/reflection/ReflectionModel.java | 4 +- .../qilin/core/reflection/TamiflexModel.java | 9 +- .../java/qilin/core/sets/PointsToSet.java | 4 +- .../core/sets/UnmodifiablePointsToSet.java | 4 +- .../main/java/qilin/core/solver/Solver.java | 9 +- .../parm/ctxcons/CallsiteCtxConstructor.java | 2 +- .../qilin/parm/ctxcons/CtxConstructor.java | 2 +- .../parm/ctxcons/HybObjCtxConstructor.java | 2 +- .../parm/ctxcons/HybTypeCtxConstructor.java | 2 +- .../parm/ctxcons/InsensCtxConstructor.java | 2 +- .../qilin/parm/ctxcons/ObjCtxConstructor.java | 2 +- .../parm/ctxcons/TypeCtxConstructor.java | 2 +- .../parm/heapabst/HeuristicAbstractor.java | 3 +- .../parm/heapabst/MahjongAbstractor.java | 4 +- .../java/qilin/parm/select/BeanSelector.java | 2 +- .../java/qilin/parm/select/CtxSelector.java | 2 +- .../qilin/parm/select/DebloatingSelector.java | 2 +- .../parm/select/FullMethodLvSelector.java | 2 +- .../qilin/parm/select/HeuristicSelector.java | 2 +- .../java/qilin/parm/select/InsenSelector.java | 2 +- .../parm/select/PartialMethodLvSelector.java | 2 +- .../qilin/parm/select/PartialVarSelector.java | 2 +- .../qilin/parm/select/PipelineSelector.java | 2 +- .../qilin/parm/select/UniformSelector.java | 2 +- .../java/qilin/parm/select/VarLvSelector.java | 2 +- .../toolkits/common/FieldPointstoGraph.java | 2 +- .../java/qilin/pta/toolkits/common/OAG.java | 2 +- .../qilin/pta/toolkits/common/ToolUtil.java | 4 +- .../pta/toolkits/conch/AbstractConch.java | 11 +- .../qilin/pta/toolkits/conch/AbstractPAG.java | 4 +- .../java/qilin/pta/toolkits/conch/Conch.java | 7 +- .../toolkits/conch/DepOnParamAnalysis.java | 4 +- .../pta/toolkits/conch/LeakAnalysis.java | 4 +- .../dd/CtxTunnelingFeaturesTrueTable.java | 6 +- .../pta/toolkits/dd/DataDrivenSelector.java | 2 +- .../pta/toolkits/dd/FeaturesTrueTable.java | 4 +- .../pta/toolkits/dd/TunnelingConstructor.java | 2 +- .../debloaterx/CollectionHeuristic.java | 10 +- .../toolkits/debloaterx/ContainerFinder.java | 10 +- .../pta/toolkits/debloaterx/DebloaterX.java | 4 +- .../qilin/pta/toolkits/debloaterx/Edge.java | 2 +- .../debloaterx/HeapContainerQuery.java | 3 +- .../debloaterx/InterFlowAnalysis.java | 4 +- .../debloaterx/IntraFlowAnalysis.java | 8 +- .../qilin/pta/toolkits/debloaterx/XPAG.java | 6 +- .../pta/toolkits/debloaterx/XUtility.java | 14 +- .../java/qilin/pta/toolkits/eagle/Eagle.java | 6 +- .../pta/toolkits/mahjong/HeapAbstraction.java | 2 +- .../pta/toolkits/mahjong/automata/DFA.java | 2 +- .../automata/DFAEquivalenceChecker.java | 4 +- .../toolkits/mahjong/automata/DFAFactory.java | 4 +- .../toolkits/mahjong/automata/DFAState.java | 4 +- .../pta/toolkits/mahjong/automata/NFA.java | 4 +- .../qilin/pta/toolkits/selectx/Selectx.java | 5 +- .../pta/toolkits/turner/AbstractMVFG.java | 5 +- .../toolkits/turner/MethodLevelCallGraph.java | 2 +- .../qilin/pta/toolkits/turner/MethodVFG.java | 2 +- .../pta/toolkits/turner/ModularMVFG.java | 2 +- .../java/qilin/pta/toolkits/turner/OCG.java | 5 +- .../qilin/pta/toolkits/turner/Turner.java | 4 +- .../java/qilin/pta/toolkits/zipper/Main.java | 2 +- .../analysis/PotentialContextElement.java | 4 +- .../pta/toolkits/zipper/analysis/Zipper.java | 8 +- .../zipper/flowgraph/FlowAnalysis.java | 6 +- .../zipper/flowgraph/ObjectFlowGraph.java | 5 +- .../java/qilin/pta/tools/DebloatedPTA.java | 6 +- .../main/java/qilin/pta/tools/EaglePTA.java | 4 +- .../pta/tools/PartialCallSiteSensPTA.java | 6 +- .../qilin/pta/tools/PartialObjSensPTA.java | 6 +- .../main/java/qilin/pta/tools/ZipperPTA.java | 6 +- .../src/main/java/qilin/stat/AliasStat.java | 6 +- .../main/java/qilin/stat/BenchmarkStat.java | 4 +- .../main/java/qilin/stat/CallGraphStat.java | 2 +- .../src/main/java/qilin/stat/Exporter.java | 8 +- .../main/java/qilin/stat/PointsToStat.java | 6 +- .../java/qilin/stat/SimplifiedEvaluator.java | 7 +- .../main/java/qilin/stat/TypeClientStat.java | 7 +- .../src/main/java/qilin/stat/YummyStat.java | 2 +- .../src/main/java/qilin/util/PTAUtils.java | 18 +- .../main/java/soot/util/ArrayNumberer.java | 154 ++++++ .../main/java/soot/util/BitSetIterator.java | 92 ++++ .../src/main/java/soot/util/BitVector.java | 463 ++++++++++++++++++ .../src/main/java/soot/util/Chain.java | 133 +++++ .../src/main/java/soot/util/Invalidable.java | 42 ++ .../main/java/soot/util/IterableNumberer.java | 36 ++ .../src/main/java/soot/util/Numberer.java | 53 ++ .../java/soot/util/queue/ChunkedQueue.java | 97 ++++ .../java/soot/util/queue/QueueReader.java | 202 ++++++++ 141 files changed, 1656 insertions(+), 238 deletions(-) delete mode 100644 sootup.qilin/.DS_Store delete mode 100644 sootup.qilin/src/.DS_Store delete mode 100644 sootup.qilin/src/main/.DS_Store delete mode 100644 sootup.qilin/src/main/java/.DS_Store create mode 100644 sootup.qilin/src/main/java/qilin/core/pag/SparkField.java create mode 100644 sootup.qilin/src/main/java/soot/util/ArrayNumberer.java create mode 100644 sootup.qilin/src/main/java/soot/util/BitSetIterator.java create mode 100644 sootup.qilin/src/main/java/soot/util/BitVector.java create mode 100644 sootup.qilin/src/main/java/soot/util/Chain.java create mode 100644 sootup.qilin/src/main/java/soot/util/Invalidable.java create mode 100644 sootup.qilin/src/main/java/soot/util/IterableNumberer.java create mode 100644 sootup.qilin/src/main/java/soot/util/Numberer.java create mode 100644 sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java create mode 100644 sootup.qilin/src/main/java/soot/util/queue/QueueReader.java diff --git a/sootup.qilin/.DS_Store b/sootup.qilin/.DS_Store deleted file mode 100644 index c87f3589a1a18943a30c12e170cbb0d69e9e0476..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK!EO^V5FIBW*{DLw0Ys0MxJIRbXjE}oLOF0{5gY)8-E34=xa%mpX^^5wdo4f1 zkw4*g;EnB8tx~QiLNn6%jmI-y``NPBM5M;c{4vphh$1LstB>Lq;da(7X$4Ogs9Yc4 z=#0#3W2c$fiWbK%GQexsqd8fu+yPx%KbxV2x5W$S!EYz9h}u-qf~J0zucCh39+j=C zd1hSH&ungrsy;mYrCROIoo+AcMSIbwpyqcN}gX5;)I!_j*vE?Z|+(DOWO2N)4 z&8WT}&M6|ofG{8o>sjU%uyUKBgcA&TT{`)4@z zpY-pPH@icm1h`eGpdD%U?as&A^Q859h)8vZ=_XN&h^?p3w>a>GTot;TL81Hs=+d*e%dopSIs~t$=&*(IKFEG=oyrS<7$g01%q72X2MtT8q^4U Y0Z)LTU~Lf=i2D&RG`PVr@T?5n0Y^fiX8-^I diff --git a/sootup.qilin/src/main/.DS_Store b/sootup.qilin/src/main/.DS_Store deleted file mode 100644 index ee3c7b448f0296c4b6b93350c8053674b2eb3590..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMO>h)N6z*>llAeLU1PEl1#l>JG5JDgXh$w7+knp2HHY6bgmff9!j7(IRA*9ii{j7w^`;_)nkteYd$!$jvKhhEKgqbSAeji|gpj160%1y0m?BIu5M~Y#<}{xO*G~v3%o&0=({sW%Bg{|`CLV|f z%NY_vMs0*Zguu-R__=!}dxE7|k)?0Q-#clp}{4X*&%XGcg)(em- zDrZzx^J+emA4rZm<4G^=72K|Le!oBJcN{BI>ZdaUrZJvU=XX1{mo{x99~hXrK}$vk zOi^5fe#|5hq<8u2F^~(O}Zq~}s_xZDBrR5g8g_9L^B`1F@IVmeMwSmDQC8f?S zk|%vR&va~ez{tBKQ|cU-Jl>vl?A>|8pC8ORR$>W3CZ*;I|x@N{Q`t9_XA*++})PjZeHQFL= zacM@Zo3`U>10O16%qI(`cYI2nJ*P&|;!9<&em0`hXFclZ{)_ZrM$_W=bH3l#cjpai zg<8>?R**ru-zCq)Bb1iavaGuOM`_E2snWKN%c{QDN@ol!RBh}a)y~19fHzb=yqU|j zXdcQsV`Jo|E7V$7H|OfPgZ{gBrCqNtXV~Sh>e|NnusfR08-3%%xst_B&Vwx@y>GHr zH$5jW0EugTobU4=)~W0CoSKF83m)I2X|ykJOarhQtc7D*><#iB>U^ z>2}jt3*BYCY=jvs$Bwg?*(7_9onoJ}Z`gVEJ-f($Vwc!u_6z%sU15Kq0+pyjHB@L= zgnJOf3bbJz+R=#}*oj?u3`vaO01o014A^jxLmtQQ44%bvcmc2AExe6)@Gd^aDV)Y9 zID@nJ7T@7KF5nV=#${Z=pZE)ZOI)gzmPw7$1JZJ-Nm?sykP_n4rBVb9i*c!y{L|su zUHyoDryCVQ4q6QTWqDGf{Vchr9)9GDWK#jjhLz^o3~JSO{y$-O=qk-ruxzGFL-)} zeaX(Ub8L!u`YSQ?cXkyVvr&&FXvA_fp&6^N9vjhtO?U`fu?@WePx~=|LF~gYvc%HE z7==kJ^-w?&PX}Cmp1ArdUc>8n18-sy@8bh}h>rr+eu}Sd;NgxE1BJxb*YdEK%-fb@ zA0b_dx7RO^M$-sXh;F@~|8Kqh@Bh;VQ7=LuLg0Ug04jTuJzeD1?T$=8*N#&?MAa|; wx(Oiz6KaBVoMe!WlPv$kkos|2>f0njIUyuzsQl+Y1Vs0LbpHp;yStlz04@AIH~;_u diff --git a/sootup.qilin/src/main/java/.DS_Store b/sootup.qilin/src/main/java/.DS_Store deleted file mode 100644 index 52b7655e678acbaa1c43548818d2ad2b85b25057..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~K~LK-6vv+-Kstm}O-$oxY1e2=soD&2i8^-Rx=iE1P}h)(MayEAr1TI~%5~cZ z+OGQ&d>wetHYjNahaI4r{3`qJ*zYBIza(}I0BkUcIsk0|u(6O@Pq6xn(KwX_ThTof z$K*N2kR2xCG)zRe;B7h#0YhNf2++5?4iRJ!!v!?IUz`-!Qyl+uB~9LX!#AAf=lWa! z9iAs~UbyZhTUoW%);H`8d(%D%K8tBkjEYG<7-h$F^j?T0ylIcZ5Ak?9Y;V62X)%h^ zaV7)eXpAl&kK!~E(}9?zQ7&TxHDI^w*08-(mYu%q@LuQj%;BZCOYLrFHf!0>UcB0W zH~f-(O~nrdoZ^M z!*{(taoO|s9Pagd|G=e|QIwx1AwD_GxsGHGmIXNo{1tPk2=dF?OLXg31NG~{U!dn@ z+4UUWb$j=4`c4_+)4uEdq4(=HojDvba)~RQlfAjb_h@d-5HJKDhXBnF91E$hwNfgl z4y@!B0M){7Y1pQ{1jTTzzSc@9j-W9WimF1H-eNEnj{RKw`C2QbDjb;Jd@y}wrgtbz zULDWRr8_WRsi_SCL!e1uRUNiz{eOG+{=XSyjtl`q;J+fktb^cSfGO#") && subSig != Scene.v().getSubSigNumberer().findOrAdd("void ()")) { diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index b866ac1b761..6df7dfa1c3a 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -26,7 +26,8 @@ import qilin.core.sets.PointsToSetInternal; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.*; +import soot.Context; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.jimple.internal.JInvokeStmt; import soot.jimple.internal.JStaticInvokeExpr; @@ -34,6 +35,11 @@ import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; @@ -132,7 +138,7 @@ protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { while (targets.hasNext()) { SootMethod target = targets.next(); if (site.iie() instanceof SpecialInvokeExpr) { - Type calleeDeclType = target.getDeclaringClass().getType(); + Type calleeDeclType = target.getDeclaringClassType(); if (!Scene.v().getFastHierarchy().canStoreType(type, calleeDeclType)) { continue; } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index 9bd3d76ec94..2d561450fba 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -24,8 +24,12 @@ import qilin.core.sets.P2SetVisitor; import qilin.core.sets.PointsToSetInternal; import qilin.util.DataFactory; -import soot.*; +import soot.Context; +import soot.MethodOrMethodContext; import soot.jimple.IdentityStmt; +import sootup.core.jimple.basic.Trap; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index 669201cf005..6414f71986d 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -21,13 +21,19 @@ import qilin.CoreConfig; import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; -import soot.*; import soot.jimple.JimpleBody; +import sootup.core.jimple.basic.Value; +import sootup.core.model.Modifier; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap.VoidType; + public class FakeMainFactory extends ArtificialMethod { public static FakeMainFactory instance; diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index edecc349dbc..29709a74821 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -24,9 +24,19 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.*; import soot.jimple.*; import soot.jimple.internal.JNewArrayExpr; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Modifier; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; /** * @author Ondrej Lhotak @@ -233,7 +243,7 @@ private VarNode caseCastExpr(CastExpr ce) { } public VarNode caseThis() { - Type type = method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClass().getType(); + Type type = method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THIS_NODE), type, method); ret.setInterProcTarget(); return ret; diff --git a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java index 135d00bae0f..afad26ac036 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java +++ b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java @@ -22,8 +22,8 @@ import qilin.core.pag.ClassConstantNode; import qilin.core.pag.StringConstantNode; import soot.RefType; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; /** * Type based context element in the points to analysis. @@ -40,7 +40,7 @@ public static TypeContextElement getTypeContextElement(AllocNode a) { SootMethod declaringMethod = a.getMethod(); Type declType = RefType.v("java.lang.Object"); if (declaringMethod != null) { - declType = declaringMethod.getDeclaringClass().getType(); + declType = declaringMethod.getDeclaringClassType(); } else if (a instanceof ClassConstantNode) { declType = RefType.v("java.lang.System"); } else if (a instanceof StringConstantNode) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index 72a3c1ec335..2d343905b88 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -19,8 +19,8 @@ package qilin.core.natives; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaIoFileSystemGetFileSystemNative extends NativeMethod { public JavaIoFileSystemGetFileSystemNative(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java index 9aa887897a7..dd9e0771858 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -19,8 +19,8 @@ package qilin.core.natives; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaIoFileSystemListNative extends NativeMethod { public JavaIoFileSystemListNative(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java index 2015305c614..996a49745e9 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java @@ -18,8 +18,9 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; + +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangObjectCloneNative extends NativeMethod { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java index 88c109910de..833399c4dd7 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangRefFinalizerInvokeFinalizeMethodNative extends NativeMethod { public JavaLangRefFinalizerInvokeFinalizeMethodNative(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index 829f8bab37a..b2180119e8e 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -20,8 +20,8 @@ import soot.ArrayType; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; /* * diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java index c608b635fc8..b5ca730795c 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -20,8 +20,8 @@ import soot.ArrayType; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; /* * handle diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java index f03dcfc9c81..6a19deb4f6a 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -20,8 +20,8 @@ import soot.ArrayType; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; /* * This file will be temporarily discarded. Yes, it is correct but need one more level of context. diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java index 84d5f0786e5..632ebf1cbfc 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangSystemSetErr0Native extends NativeMethod { public JavaLangSystemSetErr0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java index e6d36202de4..d427bca5444 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangSystemSetIn0Native extends NativeMethod { public JavaLangSystemSetIn0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java index 203a5f0ce0f..7356f3f3fd3 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java @@ -18,8 +18,9 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; + +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangSystemSetOut0Native extends NativeMethod { public JavaLangSystemSetOut0Native(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java index c8eda289ed1..bf91333b96e 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -20,8 +20,8 @@ import qilin.core.PTAScene; import soot.RefType; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangThreadCurrentThread extends NativeMethod { JavaLangThreadCurrentThread(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java index c1dd4da9507..be330b7d483 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java @@ -19,8 +19,8 @@ package qilin.core.natives; import qilin.core.PTAScene; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaLangThreadStart0Native extends NativeMethod { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java index 3ff7f9d4c31..f9c6b6f5d08 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java @@ -17,8 +17,8 @@ */ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaSecurityAccessControllerDoPrivilegedNative extends NativeMethod { public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java index dee72f7f120..088995fddc1 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java @@ -18,8 +18,8 @@ package qilin.core.natives; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public class JavaSecurityAccessControllerDoPrivileged_ExceptionNative extends NativeMethod { public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java index d54d470b0a5..5d95b132cfe 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java @@ -20,8 +20,8 @@ import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.Value; +import sootup.core.jimple.basic.Value; +import sootup.core.model.SootMethod; public abstract class NativeMethod extends ArtificialMethod { diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java index aaa70916b69..5be8c9372b5 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java @@ -19,14 +19,14 @@ package qilin.core.natives; import qilin.core.PTAScene; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class NativeMethodDriver { public void buildNative(SootMethod method) { if (!PTAScene.v().nativeBuilt.add(method)) { return; } - String sig = method.getSignature(); + String sig = method.getSignature().toString(); switch (sig) { case "": case "": diff --git a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java index 264a17f0153..1fdd2553719 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java @@ -21,9 +21,9 @@ import qilin.CoreConfig; import qilin.core.context.ContextElement; import soot.RefType; -import soot.SootMethod; -import soot.Type; import soot.util.Numberable; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; /** * Represents an allocation site node in the pointer assignment graph. diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java index 8498bb13ccb..d6b74fa2c2b 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java @@ -19,8 +19,7 @@ package qilin.core.pag; import soot.RefType; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; /** * Represents an array element. diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java index aabb2bddb8e..13ea835d895 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java @@ -19,7 +19,7 @@ package qilin.core.pag; import soot.RefType; -import soot.jimple.ClassConstant; +import sootup.core.jimple.common.constant.ClassConstant; /** * Represents an allocation site node the represents a known java.lang.Class object. diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java index 7901ba1844f..a1f9a72029c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java @@ -18,8 +18,8 @@ package qilin.core.pag; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; public abstract class ConstantNode extends AllocNode { protected ConstantNode(Object newExpr, Type t, SootMethod m) { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java index b640bc1dd46..181290f3333 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java @@ -21,11 +21,10 @@ import qilin.CoreConfig; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; -import soot.ArrayType; import soot.Context; import soot.RefType; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; public class ContextField extends ValNode { protected Context context; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java index 240e159af19..8ee8bb705d6 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java @@ -20,7 +20,7 @@ import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; public final class ContextMethod implements MethodOrMethodContext { private final SootMethod method; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Field.java b/sootup.qilin/src/main/java/qilin/core/pag/Field.java index 891f956c82d..683a27cce65 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Field.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Field.java @@ -18,9 +18,8 @@ package qilin.core.pag; -import soot.SootField; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootField; +import sootup.core.types.Type; import java.util.Objects; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java index 44ad12b8d1f..7fa4a8e3ad2 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java @@ -18,7 +18,6 @@ package qilin.core.pag; -import soot.jimple.spark.pag.SparkField; import soot.util.Numberable; /** diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java index 9cf03ecac92..390cbbd64f2 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java @@ -18,8 +18,6 @@ package qilin.core.pag; -import soot.jimple.spark.pag.SparkField; - public class FieldValNode extends ValNode { // note, field could only be ArrayElement or Field type. // Parm should be a local variable in some methods. diff --git a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java index 21303c257c5..9582d78217f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java @@ -18,9 +18,10 @@ package qilin.core.pag; -import soot.SootClass; -import soot.SootField; -import soot.Type; + +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.types.Type; /** * Represents a simple variable node in the pointer assignment graph that is not associated with any particular @@ -43,8 +44,8 @@ public String toString() { } public SootClass getDeclaringClass() { - if (variable instanceof SootField) { - return ((SootField) variable).getDeclaringClass(); + if (variable instanceof SootField sf) { + return sf.getDeclaringClass(); } return null; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java index 39796873515..7134e2139a6 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java @@ -18,8 +18,9 @@ package qilin.core.pag; -import soot.SootMethod; -import soot.Type; + +import sootup.core.model.SootMethod; +import sootup.core.types.Type; /** * @author Ondrej Lhotak diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index bd41e95d512..22098df7239 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -22,14 +22,17 @@ import qilin.util.DataFactory; import qilin.core.builder.MethodNodeFactory; import qilin.util.PTAUtils; -import soot.*; + import soot.jimple.Jimple; import soot.jimple.StaticFieldRef; -import soot.jimple.Stmt; import soot.jimple.ThrowStmt; import soot.util.Chain; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Trap; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootMethod; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Node.java b/sootup.qilin/src/main/java/qilin/core/pag/Node.java index 1707b0f76ad..b33cb5e002e 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Node.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Node.java @@ -20,8 +20,8 @@ import qilin.core.sets.DoublePointsToSet; import qilin.util.PTAUtils; -import soot.Type; import soot.util.Numberable; +import sootup.core.types.Type; /** * Represents every node in the pointer assignment graph. diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index c74bc62a75d..a9bf762b3f7 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -29,15 +29,24 @@ import qilin.parm.heapabst.HeapAbstractor; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.*; +import soot.Context; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.jimple.internal.JArrayRef; import soot.jimple.internal.JAssignStmt; import soot.jimple.internal.JimpleLocal; -import soot.jimple.spark.pag.SparkField; import soot.util.ArrayNumberer; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java index f35918a85c8..b62d33ba654 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java @@ -20,8 +20,8 @@ import qilin.core.PointsToAnalysis; import soot.RefType; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.Objects; @@ -69,7 +69,7 @@ public Type getType() { if (index == PointsToAnalysis.RETURN_NODE) { return method.getReturnType(); } else if (index == PointsToAnalysis.THIS_NODE) { - return method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClass().getType(); + return method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); } return method.getParameterType(index); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java new file mode 100644 index 00000000000..6427e6efce2 --- /dev/null +++ b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java @@ -0,0 +1,36 @@ +package qilin.core.pag; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import soot.util.Numberable; +import sootup.core.types.Type; + +/** + * Represents a field. + * + * @author Ondrej Lhotak + */ +public interface SparkField extends Numberable { + public Type getType(); +} + diff --git a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java index 1c5a574d99f..f67a74ff74b 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java @@ -19,7 +19,7 @@ package qilin.core.pag; import soot.RefType; -import soot.jimple.StringConstant; +import sootup.core.jimple.common.constant.StringConstant; /** * Represents an allocation site node the represents a constant string. @@ -36,6 +36,6 @@ public String toString() { } public String getString() { - return ((StringConstant) newExpr).value; + return ((StringConstant) newExpr).getValue(); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java index ea1690b5b23..f02e1e2b08c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java @@ -19,8 +19,8 @@ package qilin.core.pag; import qilin.core.sets.DoublePointsToSet; -import soot.Type; import soot.util.Numberable; +import sootup.core.types.Type; /** * Represents a simple of pointer node in the pointer assignment graph. diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java index 86e37d8cf4f..b2933621fb1 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java @@ -22,8 +22,7 @@ import soot.AnySubType; import soot.Context; import soot.RefLikeType; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; import java.util.Collection; import java.util.Collections; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java index b7c7aad4237..f4515be4a2f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java @@ -21,8 +21,8 @@ import soot.Kind; import soot.MethodOrMethodContext; import soot.jimple.InstanceInvokeExpr; -import soot.jimple.Stmt; import soot.util.NumberedString; +import sootup.core.jimple.common.stmt.Stmt; import java.util.Objects; diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java index d2a03d6cc1f..46cfb72c032 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java @@ -19,7 +19,7 @@ package qilin.core.reflection; import soot.Unit; -import soot.jimple.Stmt; +import sootup.core.jimple.common.stmt.Stmt; import java.util.Collection; import java.util.Collections; diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index 1c46a6fe5a8..c9366915777 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -21,11 +21,11 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.SootMethod; import soot.Unit; import soot.UnitPatchingChain; import soot.jimple.InvokeExpr; -import soot.jimple.Stmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.Collection; import java.util.Collections; diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index b120591f0d6..51f672a27eb 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -22,10 +22,17 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.*; import soot.jimple.*; import soot.jimple.internal.*; import soot.tagkit.LineNumberTag; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; import java.io.BufferedReader; import java.io.FileInputStream; diff --git a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java index e608a16a634..e70092569d4 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java @@ -19,8 +19,8 @@ package qilin.core.sets; import qilin.core.pag.AllocNode; -import soot.Type; -import soot.jimple.ClassConstant; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.types.Type; import java.util.Collection; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java index c820fbd7fe1..d03a797245e 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java @@ -24,8 +24,8 @@ import qilin.core.pag.Node; import qilin.core.pag.StringConstantNode; import soot.RefType; -import soot.Type; -import soot.jimple.ClassConstant; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.types.Type; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 075938491ef..2e2b1c02997 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -30,14 +30,17 @@ import qilin.core.sets.P2SetVisitor; import qilin.core.sets.PointsToSetInternal; import qilin.util.PTAUtils; -import soot.*; +import soot.Context; +import soot.MethodOrMethodContext; import soot.jimple.*; -import soot.jimple.spark.pag.SparkField; import soot.jimple.toolkits.callgraph.Edge; import soot.options.Options; import soot.util.NumberedString; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.*; @@ -115,7 +118,7 @@ public void processStmts(Iterator newRMs) { Iterator it = mpag.triggeredClinits(); while (it.hasNext()) { SootMethod sm = it.next(); - cgb.injectCallEdge(sm.getDeclaringClass().getType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); + cgb.injectCallEdge(sm.getDeclaringClassType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); } } recordCallStmts(momc, mpag.getInvokeStmts()); diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java index 5309b88908b..27211f4bf40 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java @@ -24,7 +24,7 @@ import qilin.core.pag.ContextAllocNode; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class CallsiteCtxConstructor implements CtxConstructor { diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java index c7cb8e5a990..691a3a39957 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java @@ -24,7 +24,7 @@ import qilin.core.pag.ContextAllocNode; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; public interface CtxConstructor { Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target); diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java index 32f6439254a..c1d44066c8d 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java @@ -24,7 +24,7 @@ import qilin.core.pag.ContextAllocNode; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; // implementation of selective hybrid context...(Yannis pldi'13) public class HybObjCtxConstructor implements CtxConstructor { diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java index 2e7cc3dbd5b..78553c791bf 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java @@ -25,7 +25,7 @@ import qilin.core.pag.ContextAllocNode; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; // implementation of selective hybrid context...(Yannis pldi'13) public class HybTypeCtxConstructor implements CtxConstructor { diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java index cdd393d9b10..39a111a800f 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java @@ -22,7 +22,7 @@ import qilin.core.pag.ContextAllocNode; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class InsensCtxConstructor implements CtxConstructor { diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java index 8b7131df7bb..79a973cd89c 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java @@ -24,7 +24,7 @@ import qilin.core.pag.ContextAllocNode; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; // implementation of obj context...(Ana Tosem'05) public class ObjCtxConstructor implements CtxConstructor { diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java index 6cf034383e4..4bbdbffe5c5 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java @@ -26,7 +26,7 @@ import qilin.core.pag.ContextAllocNode; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; // implementation of type context...(Yannis popl'11) public class TypeCtxConstructor implements CtxConstructor { diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java index ed388baa161..a3cd4e2fd5c 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -23,7 +23,8 @@ import qilin.core.pag.PAG; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.*; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java index 1f3ffe1689d..e822f6c5030 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java @@ -21,8 +21,8 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.Map; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java index ec804562d98..642fdd2b672 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java @@ -25,7 +25,7 @@ import qilin.core.pag.LocalVarNode; import qilin.core.pag.PAG; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java index c549881c9d4..b7144776919 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java @@ -25,7 +25,7 @@ import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public abstract class CtxSelector { public abstract Context select(SootMethod m, Context context); diff --git a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java index 83476653680..6b7aeba44c0 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java @@ -23,7 +23,7 @@ import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java index 0244781aaa9..fbbecc78cda 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java @@ -22,7 +22,7 @@ import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java index ec0479c0238..94fdf2eaa1d 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java @@ -24,7 +24,7 @@ import qilin.parm.ctxcons.CtxConstructor; import qilin.util.PTAUtils; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class HeuristicSelector extends CtxSelector { diff --git a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java index ead5ce4c20e..637279bab33 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java @@ -23,7 +23,7 @@ import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class InsenSelector extends CtxSelector { @Override diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java index e81c93d89b3..93ed4142a68 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java @@ -23,7 +23,7 @@ import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java index d5f7a5af813..97e1d5348bd 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java @@ -23,7 +23,7 @@ import qilin.core.pag.LocalVarNode; import qilin.parm.ctxcons.CtxConstructor; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java index 4528c0a8523..630b0b4b279 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java @@ -22,7 +22,7 @@ import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; /* * A pipeline context selector which selects context by firstly using ctxSelA and then ctxSelB. diff --git a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java index c3ee0b8fc05..c5e3c3ea26f 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java @@ -22,7 +22,7 @@ import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; public class UniformSelector extends CtxSelector { private final int k; diff --git a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java index d8f0b02bcf2..4f49bdaee19 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java @@ -22,7 +22,7 @@ import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java index 2dc40e83df9..37e6d39b0a5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java @@ -21,8 +21,8 @@ import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; +import qilin.core.pag.SparkField; import qilin.core.sets.PointsToSet; -import soot.jimple.spark.pag.SparkField; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java index e1018e6a66c..09229b65257 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java @@ -26,8 +26,8 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.graph.DirectedGraph; -import soot.SootMethod; import soot.util.queue.QueueReader; +import sootup.core.model.SootMethod; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index e542c95bfe6..244434c27f3 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -25,8 +25,8 @@ import qilin.core.pag.VarNode; import soot.RefLikeType; import soot.RefType; -import soot.SootClass; -import soot.SootMethod; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; import java.util.Collections; import java.util.HashSet; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java index 5af968d47c5..ef18a73d290 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java @@ -24,10 +24,9 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.ArrayType; -import soot.PrimType; -import soot.SootMethod; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.PrimitiveType; import java.util.*; @@ -166,14 +165,14 @@ private void collectStoresIn(SootMethod method) { private boolean primitiveField(SparkField f) { String s = "java.lang.String"; - if (f.getType() instanceof PrimType) { + if (f.getType() instanceof PrimitiveType) { return true; } else if (f.getType() instanceof ArrayType at) { /* * here, we let primitive array as primitive type as that in Turner. * this wont hurt precision of clients. * */ - return at.baseType instanceof PrimType; + return at.getBaseType() instanceof PrimitiveType; } else return f.getType().toString().equals(s); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java index 514c5841096..fa1e47f57ba 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -25,10 +25,10 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import soot.RefLikeType; -import soot.SootMethod; -import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.CallGraph; import soot.util.queue.QueueReader; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.Collection; import java.util.Collections; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index deaad929bfe..23e982f744c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -24,14 +24,13 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.SootMethod; import soot.Unit; -import soot.Value; import soot.jimple.InvokeExpr; import soot.jimple.InvokeStmt; import soot.jimple.SpecialInvokeExpr; -import soot.jimple.Stmt; -import soot.jimple.spark.pag.SparkField; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index b99aaefd3f5..27c74a83221 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -22,10 +22,10 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.SootMethod; import soot.jimple.AssignStmt; -import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.Collections; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java index dcee2a57e59..3d1b300cea0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -21,9 +21,9 @@ import qilin.core.PTA; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.Collections; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index 585feb7432a..ba2a306ecd5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -19,8 +19,12 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import soot.*; import soot.jimple.*; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.model.Body; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; /* * features and formulas used in "Precise and Scalable Points-to Analysis via Data-Driven diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java index bad5177c403..cdc6bf5b8a4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java @@ -27,7 +27,7 @@ import qilin.parm.ctxcons.TypeCtxConstructor; import qilin.parm.select.CtxSelector; import soot.Context; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.HashMap; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java index da07066824d..a912855965d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -19,10 +19,10 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import soot.Body; -import soot.SootMethod; import soot.Unit; import soot.jimple.*; +import sootup.core.model.Body; +import sootup.core.model.SootMethod; /* * features and formulas used in "Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017)" diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java index 4b0eac23b04..95b24f85025 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java @@ -23,7 +23,7 @@ import qilin.parm.ctxcons.*; import soot.Context; import soot.MethodOrMethodContext; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.HashMap; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java index b0512b8d6c2..d3f69698ca3 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java @@ -7,13 +7,13 @@ import qilin.core.pag.MethodPAG; import qilin.core.pag.Node; import qilin.core.pag.PAG; -import soot.ArrayType; +import qilin.core.pag.SparkField; import soot.RefType; -import soot.SootClass; -import soot.SootMethod; -import soot.Type; -import soot.jimple.spark.pag.SparkField; import soot.util.queue.QueueReader; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; import java.util.Collections; import java.util.HashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java index c614de0c3d6..7e164345f0e 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java @@ -4,11 +4,13 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.ArrayElement; import qilin.core.pag.PAG; +import qilin.core.pag.SparkField; import qilin.util.Stopwatch; -import soot.*; -import soot.jimple.IntConstant; import soot.jimple.internal.JNewArrayExpr; -import soot.jimple.spark.pag.SparkField; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -42,7 +44,7 @@ public void run() { if (type instanceof ArrayType at) { JNewArrayExpr nae = (JNewArrayExpr) heap.getNewExpr(); Value vl = nae.getSize(); - if (utility.isCoarseType(at) && (!(vl instanceof IntConstant ic) || ic.value != 0)) { + if (utility.isCoarseType(at) && (!(vl instanceof IntConstant ic) || ic.getValue() != 0)) { containers.computeIfAbsent(heap, k -> new HashSet<>()).add(ArrayElement.v()); } else { notcontainers.add(heap); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java index 14be05aee0c..cefcb10f017 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java @@ -4,8 +4,8 @@ import qilin.core.PTA; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; -import soot.*; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java index 04f841c17d8..3ad90a44fbe 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java @@ -1,7 +1,7 @@ package qilin.pta.toolkits.debloaterx; import qilin.core.pag.Node; -import soot.jimple.spark.pag.SparkField; +import qilin.core.pag.SparkField; public class Edge { Node from; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java index baab883355a..80ac17f608b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java @@ -3,8 +3,7 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.*; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java index c25ae1eb244..7d4402ea114 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java @@ -2,10 +2,10 @@ import qilin.core.pag.LocalVarNode; import qilin.core.pag.Node; +import qilin.core.pag.SparkField; import qilin.util.Pair; import qilin.util.queue.UniqueQueue; -import soot.SootMethod; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; import java.util.Collections; import java.util.HashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java index 65e78c70175..1d41b8ada6b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java @@ -5,14 +5,16 @@ import qilin.util.PTAUtils; import qilin.util.Pair; import qilin.util.queue.UniqueQueue; -import soot.*; import soot.jimple.InstanceInvokeExpr; import soot.jimple.InvokeExpr; import soot.jimple.NullConstant; -import soot.jimple.Stmt; -import soot.jimple.spark.pag.SparkField; import soot.util.NumberedString; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; import java.util.HashSet; import java.util.Queue; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index a05706a3ef0..a2693f05862 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -7,12 +7,12 @@ import qilin.util.queue.UniqueQueue; import soot.RefLikeType; import soot.RefType; -import soot.SootMethod; import soot.Unit; -import soot.Value; import soot.jimple.*; -import soot.jimple.spark.pag.SparkField; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.*; import java.util.concurrent.ConcurrentHashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index d6509569c82..e988ad9942d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -6,20 +6,18 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.ArrayType; import soot.RefType; -import soot.SootClass; -import soot.SootField; -import soot.SootMethod; -import soot.Type; import soot.jimple.InstanceInvokeExpr; import soot.jimple.InvokeExpr; -import soot.jimple.Stmt; -import soot.jimple.spark.pag.SparkField; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.NumberedString; import soot.util.queue.QueueReader; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -284,7 +282,7 @@ public Set getFields(Type type) { for (SparkField sparkField : this.o2Fields.get(heap)) { if (sparkField instanceof Field f) { SootField sf = f.getField(); - Type declType = sf.getDeclaringClass().getType(); + Type declType = sf.getDeclaringClassType(); if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, declType)) { ret.add(sparkField); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index c34d656a647..4cb5bb8b9eb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -27,14 +27,14 @@ import qilin.util.Util; import qilin.util.queue.UniqueQueue; import soot.RefLikeType; -import soot.SootMethod; import soot.Unit; -import soot.Value; import soot.jimple.*; -import soot.jimple.spark.pag.SparkField; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java index 4c0bfa3be45..35e4830c93d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java @@ -8,7 +8,7 @@ import qilin.pta.toolkits.mahjong.automata.DFAState; import qilin.pta.toolkits.common.FieldPointstoGraph; import qilin.util.UnionFindSet; -import soot.Type; +import sootup.core.types.Type; import java.util.Collection; import java.util.HashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java index 58f2d1ecbfb..a62de6109c7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java @@ -1,6 +1,6 @@ package qilin.pta.toolkits.mahjong.automata; -import soot.Type; +import sootup.core.types.Type; import java.util.HashSet; import java.util.LinkedList; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java index a5ac0c4975c..e038c8605fa 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; +import qilin.core.pag.SparkField; import qilin.util.Pair; import qilin.util.UnionFindSet; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; import java.util.Collection; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java index 7fc1098883b..69ec2ad74fd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; +import qilin.core.pag.SparkField; import qilin.pta.toolkits.common.FieldPointstoGraph; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java index 329979293a1..02e70604a48 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java @@ -1,8 +1,8 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import qilin.core.pag.SparkField; +import sootup.core.types.Type; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java index 40bc237de4c..067208c53a9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java @@ -1,9 +1,9 @@ package qilin.pta.toolkits.mahjong.automata; import qilin.core.pag.AllocNode; +import qilin.core.pag.SparkField; import qilin.pta.toolkits.common.FieldPointstoGraph; -import soot.Type; -import soot.jimple.spark.pag.SparkField; +import sootup.core.types.Type; import java.util.Collections; import java.util.HashSet; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index f4189f255e4..936b7d170e8 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -26,11 +26,12 @@ import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; -import soot.*; import soot.jimple.*; -import soot.jimple.spark.pag.SparkField; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; public class Selectx { private final PTA prePTA; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 0a9fa49aa2c..2efc7687f17 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -25,13 +25,14 @@ import qilin.util.Pair; import qilin.util.queue.UniqueQueue; import soot.RefLikeType; -import soot.SootMethod; import soot.Unit; -import soot.Value; import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java index 4efabcd814d..e91354a5dd9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java @@ -20,8 +20,8 @@ import qilin.util.graph.DirectedGraph; import qilin.util.graph.DirectedGraphImpl; -import soot.SootMethod; import soot.jimple.toolkits.callgraph.CallGraph; +import sootup.core.model.SootMethod; import java.util.Collection; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java index 9a4f564be7c..b92a9ceb6b0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java @@ -19,7 +19,7 @@ package qilin.pta.toolkits.turner; import qilin.core.PTA; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java index f3ecde8894c..c1ba8a67baa 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -26,7 +26,7 @@ import qilin.core.pag.Node; import qilin.util.graph.MergedNode; import soot.RefLikeType; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java index 18d34f64b07..8c20211b81e 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -24,8 +24,9 @@ import qilin.core.sets.PointsToSet; import qilin.pta.PTAConfig; import qilin.util.PTAUtils; -import soot.*; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java index fd65911cd11..3f45885e976 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java @@ -21,12 +21,12 @@ import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; +import qilin.core.pag.SparkField; import qilin.pta.PTAConfig; import qilin.util.graph.MergedNode; import qilin.util.graph.SCCMergedGraph; import qilin.util.graph.TopologicalSorter; -import soot.SootMethod; -import soot.jimple.spark.pag.SparkField; +import sootup.core.model.SootMethod; import java.util.*; import java.util.concurrent.ConcurrentHashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java index 2b9bb933eed..33cb0d39f99 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java @@ -22,7 +22,7 @@ import qilin.pta.toolkits.zipper.analysis.Zipper; import qilin.util.ANSIColor; import qilin.util.Stopwatch; -import soot.SootMethod; +import sootup.core.model.SootMethod; import java.util.Comparator; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java index 29c07f3f609..ebc86bc094d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java @@ -11,8 +11,8 @@ import qilin.util.graph.MergedNode; import qilin.util.graph.SCCMergedGraph; import qilin.util.graph.TopologicalSorter; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java index 06f061d6f04..68125ac21b5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java @@ -11,8 +11,8 @@ import qilin.util.Stopwatch; import qilin.util.graph.ConcurrentDirectedGraphImpl; import soot.RefType; -import soot.SootMethod; -import soot.Type; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -186,11 +186,11 @@ private void analyze(RefType type, FlowAnalysis fa) { pce.PCEMethodsOf(type).stream() .filter(m -> !m.isPrivate() && !m.isStatic()) .filter(m -> ToolUtil.isInnerType( - m.getDeclaringClass().getType(), type)) + m.getDeclaringClassType(), type)) .forEach(outms::add); pce.PCEMethodsOf(type).stream() .filter(m -> !m.isPrivate() && !m.isStatic()) - .filter(m -> m.getDeclaringClass().getType().equals(type) + .filter(m -> m.getDeclaringClassType().equals(type) && m.toString().contains("access$")) .forEach(outms::add); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java index 9bfa4814b67..2d86c7039e5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -8,11 +8,13 @@ import qilin.util.ANSIColor; import qilin.util.graph.ConcurrentDirectedGraphImpl; import qilin.util.graph.Reachability; -import soot.*; import soot.jimple.AssignStmt; import soot.jimple.InstanceInvokeExpr; import soot.jimple.InvokeExpr; -import soot.jimple.Stmt; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java index 2be92fdf076..890f94a3d4a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java @@ -4,9 +4,10 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.pta.toolkits.zipper.Global; -import soot.SootMethod; -import soot.Value; import soot.jimple.*; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java index 4062da8ccde..a7b1ee37aa0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java @@ -32,7 +32,11 @@ import qilin.pta.toolkits.conch.Conch; import qilin.stat.IEvaluator; import qilin.util.Stopwatch; -import soot.*; +import soot.Context; +import soot.MethodOrMethodContext; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java index 952a6e92fca..61acc05840e 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java @@ -24,10 +24,10 @@ import qilin.pta.toolkits.eagle.Eagle; import qilin.util.Pair; import qilin.util.Stopwatch; -import soot.Local; import soot.jimple.Expr; import soot.jimple.NewArrayExpr; -import soot.jimple.Stmt; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.common.stmt.Stmt; import java.io.FileNotFoundException; import java.io.PrintWriter; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index 27f081dd7c2..31f34f7a4a5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -27,9 +27,13 @@ import qilin.pta.PTAConfig; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.*; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.HashSet; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 4179803adb5..2e501f5c507 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -29,9 +29,13 @@ import qilin.pta.PTAConfig; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.*; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.HashSet; import java.util.Map; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index d9a85739a54..82cee5ed6b0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -29,9 +29,13 @@ import qilin.pta.PTAConfig; import qilin.pta.toolkits.zipper.Main; import qilin.util.Stopwatch; -import soot.*; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.HashSet; import java.util.Set; diff --git a/sootup.qilin/src/main/java/qilin/stat/AliasStat.java b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java index bbba2aa827e..60f265cc1a3 100644 --- a/sootup.qilin/src/main/java/qilin/stat/AliasStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java @@ -23,14 +23,14 @@ import qilin.core.pag.LocalVarNode; import qilin.core.pag.MethodPAG; import qilin.core.pag.Node; +import qilin.core.pag.SparkField; import qilin.core.pag.VarNode; import qilin.core.sets.PointsToSet; import qilin.util.Pair; import qilin.util.Util; -import soot.Local; -import soot.SootMethod; -import soot.jimple.spark.pag.SparkField; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootMethod; import java.util.Collection; import java.util.Collections; diff --git a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java index f8fb91bf805..c4073bf5843 100644 --- a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java @@ -21,8 +21,8 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; -import soot.SootClass; -import soot.SootMethod; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; import java.util.Set; import java.util.stream.Collectors; diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index cb30261f5dc..ec9ff2ccfda 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -25,9 +25,9 @@ import qilin.core.pag.ContextVarNode; import qilin.core.pag.LocalVarNode; import soot.MethodOrMethodContext; -import soot.SootMethod; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.model.SootMethod; import java.util.HashSet; import java.util.Iterator; diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index ad206904c8e..4f3c93ff3fc 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -25,15 +25,15 @@ import qilin.core.pag.Parm; import qilin.core.sets.PointsToSet; import qilin.util.Util; -import soot.SootClass; -import soot.SootMethod; -import soot.Type; import soot.jimple.AssignStmt; import soot.jimple.CastExpr; import soot.jimple.InvokeExpr; -import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.io.BufferedWriter; import java.io.File; diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java index 3ff9a9d5459..bc6261846b4 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -24,7 +24,11 @@ import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; -import soot.*; +import soot.Context; +import sootup.core.jimple.basic.Local; +import sootup.core.model.SootField; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index d166b059f90..3a291004b35 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -25,10 +25,15 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.*; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index 4386eca2762..6725aaf15a8 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -23,10 +23,15 @@ import qilin.core.builder.FakeMainFactory; import qilin.core.pag.AllocNode; import qilin.util.PTAUtils; -import soot.*; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.types.Type; import java.util.*; diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java index 040caedfe1f..abbdbedb9a9 100644 --- a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -23,10 +23,10 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.sets.PointsToSet; import soot.MethodOrMethodContext; -import soot.SootMethod; import soot.Unit; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.model.SootMethod; import java.util.HashMap; import java.util.HashSet; diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 44ef0d51916..71c5ce4c15c 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -31,7 +31,8 @@ import qilin.core.sets.PointsToSet; import qilin.core.sets.PointsToSetInternal; import qilin.util.queue.UniqueQueue; -import soot.*; +import soot.Context; +import soot.MethodOrMethodContext; import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; @@ -41,6 +42,15 @@ import soot.util.dot.DotGraphNode; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; +import sootup.core.types.Type; import java.io.*; import java.net.URL; @@ -67,7 +77,7 @@ public static Map> calcStaticThisPTS(PTA pta) { for (final Unit u : srcmpag.getInvokeStmts()) { final Stmt s = (Stmt) u; - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); if (ie instanceof StaticInvokeExpr) { for (Iterator it = pta.getCallGraph().edgesOutOf(u); it.hasNext(); ) { Edge e = it.next(); @@ -101,7 +111,7 @@ public static Map> calcStaticThisPTS(PTA pta) { for (final Unit u : srcmpag.getInvokeStmts()) { final Stmt s = (Stmt) u; - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); if (ie instanceof StaticInvokeExpr) { for (Iterator it = pta.getCallGraph().edgesOutOf(u); it.hasNext(); ) { Edge e = it.next(); @@ -784,7 +794,7 @@ public static boolean isEmptyArray(AllocNode heap) { if (var instanceof NewArrayExpr nae) { Value sizeVal = nae.getSize(); if (sizeVal instanceof IntConstant size) { - return size.value == 0; + return size.getValue() == 0; } } return false; diff --git a/sootup.qilin/src/main/java/soot/util/ArrayNumberer.java b/sootup.qilin/src/main/java/soot/util/ArrayNumberer.java new file mode 100644 index 00000000000..ca2a95159b9 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/ArrayNumberer.java @@ -0,0 +1,154 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Arrays; +import java.util.BitSet; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A class that numbers objects, so they can be placed in bitsets. + * + * @author Ondrej Lhotak + * @author xiao, generalize it. + */ +public class ArrayNumberer implements IterableNumberer { + + protected E[] numberToObj; + protected int lastNumber; + protected BitSet freeNumbers; + + @SuppressWarnings("unchecked") + public ArrayNumberer() { + this.numberToObj = (E[]) new Numberable[1024]; + this.lastNumber = 0; + } + + public ArrayNumberer(E[] elements) { + this.numberToObj = elements; + this.lastNumber = elements.length; + } + + private void resize(int n) { + numberToObj = Arrays.copyOf(numberToObj, n); + } + + @Override + public synchronized void add(E o) { + if (o.getNumber() != 0) { + return; + } + + // In case we removed entries from the numberer, we want to re-use the free space + int chosenNumber = -1; + if (freeNumbers != null) { + int ns = freeNumbers.nextSetBit(0); + if (ns != -1) { + chosenNumber = ns; + freeNumbers.clear(ns); + } + } + if (chosenNumber == -1) { + chosenNumber = ++lastNumber; + } + if (chosenNumber >= numberToObj.length) { + resize(numberToObj.length * 2); + } + numberToObj[chosenNumber] = o; + o.setNumber(chosenNumber); + } + + @Override + public long get(E o) { + if (o == null) { + return 0; + } + int ret = o.getNumber(); + if (ret == 0) { + throw new RuntimeException("unnumbered: " + o); + } + return ret; + } + + @Override + public E get(long number) { + if (number == 0) { + return null; + } + E ret = numberToObj[(int) number]; + if (ret == null) { + return null; + } + return ret; + } + + @Override + public int size() { + return lastNumber; + } + + @Override + public Iterator iterator() { + return new Iterator() { + int cur = 1; + + @Override + public final boolean hasNext() { + return cur <= lastNumber && cur < numberToObj.length && numberToObj[cur] != null; + } + + @Override + public final E next() { + if (hasNext()) { + return numberToObj[cur++]; + } + throw new NoSuchElementException(); + } + + @Override + public final void remove() { + ArrayNumberer.this.remove(numberToObj[cur - 1]); + } + }; + } + + @Override + public boolean remove(E o) { + if (o == null) { + return false; + } + + int num = o.getNumber(); + if (num == 0) { + return false; + } + if (freeNumbers == null) { + freeNumbers = new BitSet(2 * num); + } + numberToObj[num] = null; + o.setNumber(0); + freeNumbers.set(num); + return true; + } +} diff --git a/sootup.qilin/src/main/java/soot/util/BitSetIterator.java b/sootup.qilin/src/main/java/soot/util/BitSetIterator.java new file mode 100644 index 00000000000..3b3fb5d2b70 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/BitSetIterator.java @@ -0,0 +1,92 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2001 Felix Kwok + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.NoSuchElementException; + +/** + * A fast enumerator for sparse bit sets. When the enumerator is created, it takes a snapshot of the underlying BitVector, + * and iterates through the set bits. Note that this class almost implements the Iterator interface, but it doesn't because + * the return type of next is int rather than Object. + */ +public class BitSetIterator { + + long[] bits; // Bits inherited from the underlying BitVector + int index; // The 64-bit block currently being examined + long save = 0; // A copy of the 64-bit block (for fast access) + + /* + * Computes log_2(x) modulo 67. This uses the fact that 2 is a primitive root modulo 67 + */ + final static int[] lookup = { -1, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, -1, 13, 10, 17, 62, 60, 28, + 42, 30, 20, 51, 25, 44, 55, 47, 5, 32, -1, 38, 14, 22, 11, 58, 18, 53, -1, 9, 61, 27, 29, 50, 43, 46, 31, 37, 21, 57, + 52, 8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33 }; + + /** Creates a new BitSetIterator */ + BitSetIterator(long[] bits) { + // this.bits = new long[bits.length]; + // System.arraycopy(bits,0,this.bits,0,bits.length); + this.bits = bits; + index = 0; + + /* Zip through empty blocks */ + while (index < bits.length && bits[index] == 0L) { + index++; + } + if (index < bits.length) { + save = bits[index]; + } + } + + /** Returns true if there are more set bits in the BitVector; false otherwise. */ + public boolean hasNext() { + return index < bits.length; + } + + /** + * Returns the index of the next set bit. Note that the return type is int, and not Object. + */ + public int next() { + if (index >= bits.length) { + throw new NoSuchElementException(); + } + + long k = (save & (save - 1)); // Clears the last non-zero bit. save is guaranteed non-zero. + long diff = save ^ k; // Finds out which bit it is. diff has exactly one bit set. + save = k; + + // Computes the position of the set bit. + int result = (diff < 0) ? 64 * index + 63 : 64 * index + lookup[(int) (diff % 67)]; + + if (save == 0) { + index++; + while (index < bits.length && bits[index] == 0L) { + index++; + } + if (index < bits.length) { + save = bits[index]; + } + } + return result; + } +} diff --git a/sootup.qilin/src/main/java/soot/util/BitVector.java b/sootup.qilin/src/main/java/soot/util/BitVector.java new file mode 100644 index 00000000000..34e7bf27307 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/BitVector.java @@ -0,0 +1,463 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * This is the Soot internal implementation of java.util.BitSet with Felix and Jerome's clever efficient iterator. It was + * re-implemented from scratch by Ondrej Lhotak to avoid licence issues. It was named BitVector rather than BitSet to avoid a + * name clash with the one in the standard Java library. + * + * @author Ondrej Lhotak + */ +public class BitVector { + + private long[] bits; + + public BitVector() { + this(64); + } + + /** Copy constructor */ + // Added by Adam Richard. More efficient than clone(), and easier to extend + public BitVector(BitVector other) { + final long[] otherBits = other.bits; + bits = new long[otherBits.length]; + System.arraycopy(otherBits, 0, bits, 0, otherBits.length); + } + + public BitVector(int numBits) { + int lastIndex = indexOf(numBits - 1); + bits = new long[lastIndex + 1]; + } + + private int indexOf(int bit) { + return bit >> 6; + } + + private long mask(int bit) { + return 1L << (bit & 63); + } + + public void and(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int numToAnd = otherBits.length; + if (bits.length < numToAnd) { + numToAnd = bits.length; + } + int i; + for (i = 0; i < numToAnd; i++) { + bits[i] = bits[i] & otherBits[i]; + } + for (; i < bits.length; i++) { + bits[i] = 0L; + } + } + + public void andNot(BitVector other) { + final long[] otherBits = other.bits; + int numToAnd = otherBits.length; + if (bits.length < numToAnd) { + numToAnd = bits.length; + } + for (int i = 0; i < numToAnd; i++) { + bits[i] = bits[i] & ~otherBits[i]; + } + } + + public void clear(int bit) { + if (indexOf(bit) < bits.length) { + bits[indexOf(bit)] &= ~mask(bit); + } + } + + @Override + public Object clone() { + try { + BitVector ret = (BitVector) super.clone(); + System.arraycopy(bits, 0, ret.bits, 0, ret.bits.length); + return ret; + } catch (CloneNotSupportedException e) { + // cannot occur + throw new RuntimeException(e); + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof BitVector)) { + return false; + } + final long[] otherBits = ((BitVector) o).bits; + long[] longer = otherBits; + int min = bits.length; + if (otherBits.length < min) { + min = otherBits.length; + longer = bits; + } + int i; + for (i = 0; i < min; i++) { + if (bits[i] != otherBits[i]) { + return false; + } + } + for (; i < longer.length; i++) { + if (longer[i] != 0L) { + return false; + } + } + return true; + } + + public boolean get(int bit) { + if (indexOf(bit) >= bits.length) { + return false; + } + return (bits[indexOf(bit)] & mask(bit)) != 0L; + } + + @Override + public int hashCode() { + long ret = 0; + for (long element : bits) { + ret ^= element; + } + return (int) ((ret >> 32) ^ ret); + } + + /** Returns index of highest-numbered one bit. */ + public int length() { + int i; + for (i = bits.length - 1; i >= 0; i--) { + if (bits[i] != 0L) { + break; + } + } + if (i < 0) { + return 0; + } + long j = bits[i]; + i++; + i <<= 6; + for (long k = 1L << 63; (k & j) == 0L; k >>= 1, i--) { + } + return i; + } + + public void copyFrom(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + int i = j + 1; + for (; j >= 0; j--) { + bits[j] = otherBits[j]; + } + for (; i < bits.length; i++) { + bits[i] = 0L; + } + } + + public void or(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + for (; j >= 0; j--) { + bits[j] |= otherBits[j]; + } + } + + /** + * Count the number of ones in the bitvector. + * + * @author Adam Richard This is Brian Kernighan's algorithm from: http://graphics.stanford.edu/~seander/bithacks.html and + * is efficient for sparse bit sets. + */ + public int cardinality() { + int c = 0; + for (long v : bits) { + while (v != 0) { + v &= v - 1; + ++c; + } + } + return c; + } + + /** + * Returns true if the both the current and the specified bitvectors have at least one bit set in common. + * + * @author Quentin Sabah Inspired by the BitVector.and method. + */ + public boolean intersects(BitVector other) { + final long[] otherBits = other.bits; + int numToCheck = otherBits.length; + if (bits.length < numToCheck) { + numToCheck = bits.length; + } + int i; + for (i = 0; i < numToCheck; i++) { + if ((bits[i] & otherBits[i]) != 0) { + return true; + } + } + return false; + } + + private void expand(int bit) { + int n = indexOf(bit) + 1; + if (n <= bits.length) { + return; + } + if (bits.length * 2 > n) { + n = bits.length * 2; + } + long[] newBits = new long[n]; + System.arraycopy(bits, 0, newBits, 0, bits.length); + bits = newBits; + } + + public void xor(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + for (; j >= 0; j--) { + bits[j] ^= otherBits[j]; + } + } + + public boolean set(int bit) { + expand(bit); + boolean ret = !get(bit); + bits[indexOf(bit)] |= mask(bit); + return ret; + } + + /** Returns number of bits in the underlying array. */ + public int size() { + return bits.length << 6; + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + ret.append('{'); + boolean start = true; + for (BitSetIterator it = new BitSetIterator(bits); it.hasNext();) { + int bit = it.next(); + if (start) { + start = false; + } else { + ret.append(", "); + } + ret.append(bit); + } + ret.append('}'); + return ret.toString(); + } + + /** + * Computes this = this OR ((orset AND andset ) AND (NOT andnotset)) Returns true iff this is modified. + */ + public boolean orAndAndNot(BitVector orset, BitVector andset, BitVector andnotset) { + final long[] a, b, c, d; + final int al, bl, cl, dl; + { + a = this.bits; + al = a.length; + } + if (orset == null) { + b = null; + bl = 0; + } else { + b = orset.bits; + bl = b.length; + } + if (andset == null) { + c = null; + cl = 0; + } else { + c = andset.bits; + cl = c.length; + } + if (andnotset == null) { + d = null; + dl = 0; + } else { + d = andnotset.bits; + dl = d.length; + } + + final long[] e; + if (al < bl) { + e = new long[bl]; + System.arraycopy(a, 0, e, 0, al); + this.bits = e; + } else { + e = a; + } + + boolean ret = false; + if (c == null) { + if (dl <= bl) { + int i = 0; + for (; i < dl; i++) { + long l = b[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + for (; i < bl; i++) { + long l = b[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else { + for (int i = 0; i < bl; i++) { + long l = b[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } + } else if (bl <= cl && bl <= dl) { + // bl is the shortest + for (int i = 0; i < bl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else if (cl <= bl && cl <= dl) { + // cl is the shortest + for (int i = 0; i < cl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else { + // dl is the shortest + int i = 0; + for (; i < dl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + for (int shorter = (bl < cl) ? bl : cl; i < shorter; i++) { + long l = b[i] & c[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } + + return ret; + } + + public static BitVector and(BitVector set1, BitVector set2) { + int min = set1.size(); + { + int max = set2.size(); + if (min > max) { + min = max; + } + // max is not necessarily correct at this point, so let it go + // out of scope + } + + BitVector ret = new BitVector(min); + long[] retbits = ret.bits; + long[] bits1 = set1.bits; + long[] bits2 = set2.bits; + min >>= 6; + for (int i = 0; i < min; i++) { + retbits[i] = bits1[i] & bits2[i]; + } + return ret; + } + + public static BitVector or(BitVector set1, BitVector set2) { + int min = set1.size(); + int max = set2.size(); + if (min > max) { + min = max; + max = set1.size(); + } + + BitVector ret = new BitVector(max); + long[] retbits = ret.bits; + long[] bits1 = set1.bits; + long[] bits2 = set2.bits; + min >>= 6; + max >>= 6; + for (int i = 0; i < min; i++) { + retbits[i] = bits1[i] | bits2[i]; + } + if (bits1.length == min) { + System.arraycopy(bits2, min, retbits, min, max - min); + } else { + System.arraycopy(bits1, min, retbits, min, max - min); + } + return ret; + } + + public BitSetIterator iterator() { + return new BitSetIterator(bits); + } +} + diff --git a/sootup.qilin/src/main/java/soot/util/Chain.java b/sootup.qilin/src/main/java/soot/util/Chain.java new file mode 100644 index 00000000000..4b7b39390a3 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/Chain.java @@ -0,0 +1,133 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 1999 Patrice Pominville + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * Augmented data type guaranteeing O(1) insertion and removal from a set of ordered, unique elements. + * + * @param + * element type + */ +public interface Chain extends Collection, Serializable { + + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(E toInsert, E point); + + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(E toInsert, E point); + + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(Chain toInsert, E point); + + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(Chain toInsert, E point); + + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(List toInsert, E point); + + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(List toInsert, E point); + + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(Collection toInsert, E point); + + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(Collection toInsert, E point); + + /** Replaces out in the Chain by in. */ + public void swapWith(E out, E in); + + /** + * Removes the given object from this Chain. Parameter has to be of type {@link Object} to be compatible with the + * {@link Collection} interface. + */ + @Override + public boolean remove(Object u); + + /** Adds the given object at the beginning of the Chain. */ + public void addFirst(E u); + + /** Adds the given object at the end of the Chain. */ + public void addLast(E u); + + /** Removes the first object contained in this Chain. */ + public void removeFirst(); + + /** Removes the last object contained in this Chain. */ + public void removeLast(); + + /** + * Returns true if object someObject follows object someReferenceObject in the Chain, i.e. + * someReferenceObject comes first and then someObject. + */ + public boolean follows(E someObject, E someReferenceObject); + + /** Returns the first object in this Chain. */ + public E getFirst(); + + /** Returns the last object in this Chain. */ + public E getLast(); + + /** Returns the object immediately following point. */ + public E getSuccOf(E point); + + /** Returns the object immediately preceding point. */ + public E getPredOf(E point); + + /** + * Returns an iterator over a copy of this chain. This avoids ConcurrentModificationExceptions from being thrown if the + * underlying Chain is modified during iteration. Do not use this to remove elements which have not yet been iterated over! + */ + public Iterator snapshotIterator(); + + /** Returns an iterator over this Chain. */ + @Override + public Iterator iterator(); + + /** Returns an iterator over this Chain, starting at the given object. */ + public Iterator iterator(E u); + + /** Returns an iterator over this Chain, starting at head and reaching tail (inclusive). */ + public Iterator iterator(E head, E tail); + + /** Returns the size of this Chain. */ + @Override + public int size(); + + /** Returns the number of times this chain has been modified. */ + long getModificationCount(); + + /** + * Gets all elements in the chain. There is no guarantee on sorting. On the other hand, the collection returned by this + * method is thread-safe. You can iterate over it even in the case of concurrent modifications to the underlying chain. + * + * @return All elements in the chain in an unsorted collection + */ + public Collection getElementsUnsorted(); + +} diff --git a/sootup.qilin/src/main/java/soot/util/Invalidable.java b/sootup.qilin/src/main/java/soot/util/Invalidable.java new file mode 100644 index 00000000000..208fc07fb18 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/Invalidable.java @@ -0,0 +1,42 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2005 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A class implementing this interface can be invalidated. The invalidation state can be retrieved by other classes. + * + * @author Marc Miltenberger + */ +public interface Invalidable { + /** + * Return true if the object is invalid. + * + * @return true if the object is invalid. + */ + public boolean isInvalid(); + + /** + * Invalidates the object. Does nothing if the object is already invalid. + */ + public void invalidate(); +} diff --git a/sootup.qilin/src/main/java/soot/util/IterableNumberer.java b/sootup.qilin/src/main/java/soot/util/IterableNumberer.java new file mode 100644 index 00000000000..a4e57582dd5 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/IterableNumberer.java @@ -0,0 +1,36 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2005 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Iterator; + +/** + * A numberer which also supports an iterator on newly-added objects. + * + * @author xiao, generalize the interface + */ +public interface IterableNumberer extends Numberer, Iterable { + /** Returns an iterator over all objects added to the numberer. */ + @Override + Iterator iterator(); +} diff --git a/sootup.qilin/src/main/java/soot/util/Numberer.java b/sootup.qilin/src/main/java/soot/util/Numberer.java new file mode 100644 index 00000000000..51ba04cafc9 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/Numberer.java @@ -0,0 +1,53 @@ +package soot.util; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2004 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A numberer converts objects to unique non-negative integers, and vice-versa. + * + * @author xiao, generalize the interface + */ +public interface Numberer { + /** Tells the numberer that a new object needs to be assigned a number. */ + public void add(E o); + + /** + * Removes the number for a given object. + * + * @param o + * the element + * @return true if the removal was successful, false when not + */ + public boolean remove(E o); + + /** + * Should return the number that was assigned to object o that was previously passed as an argument to add(). + */ + public long get(E o); + + /** Should return the object that was assigned the number number. */ + public E get(long number); + + /** Should return the number of objects that have been assigned numbers. */ + public int size(); +} diff --git a/sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java b/sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java new file mode 100644 index 00000000000..3bb23c22277 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java @@ -0,0 +1,97 @@ +package soot.util.queue; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary + * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not + * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the + * QueueReader was created. + * + * @author Ondrej Lhotak + */ +@SuppressWarnings("unchecked") +public class ChunkedQueue { + + protected static final Object NULL_CONST = new Object(); + protected static final Object DELETED_CONST = new Object(); + + protected static final int LENGTH = 60; + protected Object[] q; + protected int index; + + public ChunkedQueue() { + q = new Object[LENGTH]; + index = 0; + } + + /** Add an object to the queue. */ + public void add(E o) { + if (o == null) { + o = (E) NULL_CONST; + } + if (index == LENGTH - 1) { + Object[] temp = new Object[LENGTH]; + q[index] = temp; + q = temp; + index = 0; + } + q[index++] = o; + } + + /** Create reader which will read objects from the queue. */ + public QueueReader reader() { + return new QueueReader((E[]) q, index); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + boolean isFirst = true; + + int idx = index; + Object[] curArray = q; + while (idx < curArray.length) { + Object curObj = curArray[idx]; + if (curObj == null) { + break; + } + if (isFirst) { + isFirst = false; + } else { + sb.append(", "); + } + if (curObj instanceof Object[]) { + curArray = (Object[]) curObj; + idx = 0; + } else { + sb.append(curObj.toString()); + idx++; + } + } + sb.append("]"); + return sb.toString(); + } + +} diff --git a/sootup.qilin/src/main/java/soot/util/queue/QueueReader.java b/sootup.qilin/src/main/java/soot/util/queue/QueueReader.java new file mode 100644 index 00000000000..b6c647fc9ad --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/queue/QueueReader.java @@ -0,0 +1,202 @@ +package soot.util.queue; + +import java.util.Collection; +import java.util.Collections; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.NoSuchElementException; + +import soot.util.Invalidable; + +/** + * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary + * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not + * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the + * QueueReader was created. + * + * @author Ondrej Lhotak + */ +public class QueueReader implements java.util.Iterator { + protected E[] q; + protected int index; + + protected QueueReader(E[] q, int index) { + this.q = q; + this.index = index; + } + + /** + * Returns (and removes) the next object in the queue, or null if there are none. + */ + @SuppressWarnings("unchecked") + public E next() { + Object ret = null; + do { + if (q[index] == null) { + throw new NoSuchElementException(); + } + if (index == q.length - 1) { + q = (E[]) q[index]; + index = 0; + if (q[index] == null) { + throw new NoSuchElementException(); + } + } + ret = q[index]; + if (ret == ChunkedQueue.NULL_CONST) { + ret = null; + } + index++; + } while (skip(ret)); + return (E) ret; + } + + protected boolean skip(Object ret) { + if (ret instanceof Invalidable) { + final Invalidable invalidable = (Invalidable) ret; + if (invalidable.isInvalid()) { + return true; + } + } + return ret == ChunkedQueue.DELETED_CONST; + } + + /** Returns true iff there is currently another object in the queue. */ + @SuppressWarnings("unchecked") + public boolean hasNext() { + do { + E ret = q[index]; + if (ret == null) { + return false; + } + if (index == q.length - 1) { + q = (E[]) ret; + index = 0; + if (q[index] == null) { + return false; + } + } + if (skip(ret)) { + index++; + } else { + return true; + } + } while (true); + } + + /** + * Removes an element from the underlying queue. This operation can only delete elements that have not yet been consumed by + * this reader. + * + * @param o + * The element to remove + */ + public void remove(E o) { + if (o instanceof Invalidable) { + ((Invalidable) o).invalidate(); + return; + } + remove(Collections.singleton(o)); + } + + /** + * Removes elements from the underlying queue. This operation can only delete elements that have not yet been consumed by + * this reader. + * + * @param toRemove + * The elements to remove + */ + @SuppressWarnings("unchecked") + public void remove(Collection toRemove) { + boolean allInvalidable = true; + for (E o : toRemove) { + if (!(o instanceof Invalidable)) { + allInvalidable = false; + continue; + } + + ((Invalidable) o).invalidate(); + } + if (allInvalidable) { + return; + } + int idx = 0; + Object[] curQ = q; + while (curQ[idx] != null) { + // Do we need to switch to a new list? + if (idx == curQ.length - 1) { + curQ = (E[]) curQ[idx]; + idx = 0; + } + + // Is this the element to delete? + if (toRemove.contains(curQ[idx])) { + curQ[idx] = ChunkedQueue.DELETED_CONST; + } + + // Next element + idx++; + } + } + + @SuppressWarnings("unchecked") + public void remove() { + q[index - 1] = (E) ChunkedQueue.DELETED_CONST; + } + + public QueueReader clone() { + return new QueueReader(q, index); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + boolean isFirst = true; + + int idx = index; + Object[] curArray = q; + while (idx < curArray.length) { + Object curObj = curArray[idx]; + if (curObj == null) { + break; + } + if (isFirst) { + isFirst = false; + } else { + sb.append(", "); + } + if (curObj instanceof Object[]) { + curArray = (Object[]) curObj; + idx = 0; + } else { + sb.append(curObj.toString()); + idx++; + } + } + sb.append("]"); + return sb.toString(); + } + +} From ee9ee9646deeaf8b0ec99f488a97ca332bec426a Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sat, 16 Sep 2023 15:31:37 +1000 Subject: [PATCH 009/145] add dots and callgraph classes --- sootup.qilin/src/main/java/soot/Kind.java | 281 ++++++++++++ .../jimple/toolkits/callgraph/CallGraph.java | 414 ++++++++++++++++++ .../soot/jimple/toolkits/callgraph/Edge.java | 304 +++++++++++++ .../util/dot/AbstractDotGraphElement.java | 139 ++++++ .../src/main/java/soot/util/dot/DotGraph.java | 326 ++++++++++++++ .../java/soot/util/dot/DotGraphAttribute.java | 53 +++ .../java/soot/util/dot/DotGraphCommand.java | 57 +++ .../java/soot/util/dot/DotGraphConstants.java | 3 + .../main/java/soot/util/dot/DotGraphEdge.java | 101 +++++ .../main/java/soot/util/dot/DotGraphNode.java | 80 ++++ .../java/soot/util/dot/DotGraphUtility.java | 128 ++++++ .../main/java/soot/util/dot/Renderable.java | 30 ++ 12 files changed, 1916 insertions(+) create mode 100644 sootup.qilin/src/main/java/soot/Kind.java create mode 100644 sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java create mode 100644 sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/DotGraph.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java create mode 100644 sootup.qilin/src/main/java/soot/util/dot/Renderable.java diff --git a/sootup.qilin/src/main/java/soot/Kind.java b/sootup.qilin/src/main/java/soot/Kind.java new file mode 100644 index 00000000000..cac962fe303 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/Kind.java @@ -0,0 +1,281 @@ +package soot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import soot.util.Numberable; + +/** + * Enumeration type representing the kind of a call graph edge. + * + * @author Ondrej Lhotak + */ +public final class Kind implements Numberable { + + public static final Kind INVALID = new Kind("INVALID"); + /** + * Due to explicit invokestatic instruction. + */ + public static final Kind STATIC = new Kind("STATIC"); + /** + * Due to explicit invokevirtual instruction. + */ + public static final Kind VIRTUAL = new Kind("VIRTUAL"); + /** + * Due to explicit invokeinterface instruction. + */ + public static final Kind INTERFACE = new Kind("INTERFACE"); + /** + * Due to explicit invokespecial instruction. + */ + public static final Kind SPECIAL = new Kind("SPECIAL"); + /** + * Implicit call to static initializer. + */ + public static final Kind CLINIT = new Kind("CLINIT"); + /** + * Fake edges from our generic callback model. + */ + public static final Kind GENERIC_FAKE = new Kind("GENERIC_FAKE"); + /** + * Implicit call to Thread.run() due to Thread.start() call. + */ + public static final Kind THREAD = new Kind("THREAD"); + /** + * Implicit call to java.lang.Runnable.run() due to Executor.execute() call. + */ + public static final Kind EXECUTOR = new Kind("EXECUTOR"); + /** + * Implicit call to AsyncTask.doInBackground() due to AsyncTask.execute() call. + */ + public static final Kind ASYNCTASK = new Kind("ASYNCTASK"); + /** + * Implicit call to java.lang.ref.Finalizer.register from new bytecode. + */ + public static final Kind FINALIZE = new Kind("FINALIZE"); + /** + * Implicit call to Handler.handleMessage(android.os.Message) due to Handler.sendxxxxMessagexxxx() call. + */ + public static final Kind HANDLER = new Kind("HANDLER"); + /** + * Implicit call to finalize() from java.lang.ref.Finalizer.invokeFinalizeMethod(). + */ + public static final Kind INVOKE_FINALIZE = new Kind("INVOKE_FINALIZE"); + /** + * Implicit call to run() through AccessController.doPrivileged(). + */ + public static final Kind PRIVILEGED = new Kind("PRIVILEGED"); + /** + * Implicit call to constructor from java.lang.Class.newInstance(). + */ + public static final Kind NEWINSTANCE = new Kind("NEWINSTANCE"); + /** + * Due to call to Method.invoke(..). + */ + public static final Kind REFL_INVOKE = new Kind("REFL_METHOD_INVOKE"); + /** + * Due to call to Constructor.newInstance(..). + */ + public static final Kind REFL_CONSTR_NEWINSTANCE = new Kind("REFL_CONSTRUCTOR_NEWINSTANCE"); + /** + * Due to call to Class.newInstance(..) when reflection log is enabled. + */ + public static final Kind REFL_CLASS_NEWINSTANCE = new Kind("REFL_CLASS_NEWINSTANCE"); + + private final String name; + private int num; + + private Kind(String name) { + this.name = name; + } + + public String name() { + return name; + } + + @Override + public int getNumber() { + return num; + } + + @Override + public void setNumber(int num) { + this.num = num; + } + + @Override + public String toString() { + return name(); + } + + public boolean passesParameters() { + return passesParameters(this); + } + + public boolean isFake() { + return isFake(this); + } + + /** + * Returns true if the call is due to an explicit invoke statement. + */ + public boolean isExplicit() { + return isExplicit(this); + } + + /** + * Returns true if the call is due to an explicit instance invoke statement. + */ + public boolean isInstance() { + return isInstance(this); + } + + /** + * Returns true if the call is due to an explicit virtual invoke statement. + */ + public boolean isVirtual() { + return isVirtual(this); + } + + public boolean isSpecial() { + return isSpecial(this); + } + + /** + * Returns true if the call is to static initializer. + */ + public boolean isClinit() { + return isClinit(this); + } + + /** + * Returns true if the call is due to an explicit static invoke statement. + */ + public boolean isStatic() { + return isStatic(this); + } + + public boolean isThread() { + return isThread(this); + } + + public boolean isExecutor() { + return isExecutor(this); + } + + public boolean isAsyncTask() { + return isAsyncTask(this); + } + + public boolean isPrivileged() { + return isPrivileged(this); + } + + public boolean isReflection() { + return isReflection(this); + } + + public boolean isReflInvoke() { + return isReflInvoke(this); + } + + public boolean isHandler() { + return isHandler(this); + } + + public static boolean passesParameters(Kind k) { + return isExplicit(k) || k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == FINALIZE || k == PRIVILEGED + || k == NEWINSTANCE || k == INVOKE_FINALIZE || k == REFL_INVOKE || k == REFL_CONSTR_NEWINSTANCE + || k == REFL_CLASS_NEWINSTANCE || k == GENERIC_FAKE; + } + + public static boolean isFake(Kind k) { + return k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == PRIVILEGED || k == HANDLER || k == GENERIC_FAKE; + } + + /** + * Returns true if the call is due to an explicit invoke statement. + */ + public static boolean isExplicit(Kind k) { + return isInstance(k) || isStatic(k); + } + + /** + * Returns true if the call is due to an explicit instance invoke statement. + */ + public static boolean isInstance(Kind k) { + return k == VIRTUAL || k == INTERFACE || k == SPECIAL; + } + + /** + * Returns true if the call is due to an explicit virtual invoke statement. + */ + public static boolean isVirtual(Kind k) { + return k == VIRTUAL; + } + + public static boolean isSpecial(Kind k) { + return k == SPECIAL; + } + + /** + * Returns true if the call is to static initializer. + */ + public static boolean isClinit(Kind k) { + return k == CLINIT; + } + + /** + * Returns true if the call is due to an explicit static invoke statement. + */ + public static boolean isStatic(Kind k) { + return k == STATIC; + } + + public static boolean isThread(Kind k) { + return k == THREAD; + } + + public static boolean isExecutor(Kind k) { + return k == EXECUTOR; + } + + public static boolean isAsyncTask(Kind k) { + return k == ASYNCTASK; + } + + public static boolean isPrivileged(Kind k) { + return k == PRIVILEGED; + } + + public static boolean isReflection(Kind k) { + return k == REFL_CLASS_NEWINSTANCE || k == REFL_CONSTR_NEWINSTANCE || k == REFL_INVOKE; + } + + public static boolean isReflInvoke(Kind k) { + return k == REFL_INVOKE; + } + + public static boolean isHandler(Kind k) { + return k == HANDLER; + } +} diff --git a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java new file mode 100644 index 00000000000..d839eb0dc23 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java @@ -0,0 +1,414 @@ +package soot.jimple.toolkits.callgraph; + +import java.util.Collection; +import java.util.HashSet; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import soot.Kind; +import soot.MethodOrMethodContext; +import soot.Unit; +import soot.util.queue.ChunkedQueue; +import soot.util.queue.QueueReader; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; + +/** + * Represents the edges in a call graph. This class is meant to act as only a container of edges; code for various call graph + * builders should be kept out of it, as well as most code for accessing the edges. + * + * @author Ondrej Lhotak + */ +public class CallGraph implements Iterable { + protected Set edges = new LinkedHashSet(); + protected ChunkedQueue stream = new ChunkedQueue(); + protected QueueReader reader = stream.reader(); + protected Map srcMethodToEdge = new LinkedHashMap(); + protected Map srcUnitToEdge = new LinkedHashMap(); + protected Map tgtToEdge = new LinkedHashMap(); + protected Edge dummy = new Edge(null, null, null, Kind.INVALID); + + /** + * Used to add an edge to the call graph. Returns true iff the edge was not already present. + */ + public boolean addEdge(Edge e) { + if (!edges.add(e)) { + return false; + } + + stream.add(e); + + Edge position = srcUnitToEdge.get(e.srcUnit()); + if (position == null) { + srcUnitToEdge.put(e.srcUnit(), e); + position = dummy; + } + e.insertAfterByUnit(position); + + position = srcMethodToEdge.get(e.getSrc()); + if (position == null) { + srcMethodToEdge.put(e.getSrc(), e); + position = dummy; + } + e.insertAfterBySrc(position); + + position = tgtToEdge.get(e.getTgt()); + if (position == null) { + tgtToEdge.put(e.getTgt(), e); + position = dummy; + } + e.insertAfterByTgt(position); + return true; + } + + /** + * Removes all outgoing edges that start at the given unit + * + * @param u + * The unit from which to remove all outgoing edges + * @return True if at least one edge has been removed, otherwise false + */ + public boolean removeAllEdgesOutOf(Unit u) { + boolean hasRemoved = false; + Set edgesToRemove = new HashSet<>(); + for (QueueReader edgeRdr = listener(); edgeRdr.hasNext();) { + Edge e = edgeRdr.next(); + if (e.srcUnit() == u) { + e.remove(); + removeEdge(e, false); + edgesToRemove.add(e); + hasRemoved = true; + } + } + if (hasRemoved) { + reader.remove(edgesToRemove); + } + return hasRemoved; + } + + /** + * Swaps an invocation statement. All edges that previously went from the given statement to some callee now go from the + * new statement to the same callee. This method is intended to be used when a Jimple statement is replaced, but the + * replacement does not semantically affect the edges. + * + * @param out + * The old statement + * @param in + * The new statement + * @return True if at least one edge was affected by this operation + */ + public boolean swapEdgesOutOf(Stmt out, Stmt in) { + boolean hasSwapped = false; + for (Iterator edgeRdr = edgesOutOf(out); edgeRdr.hasNext();) { + Edge e = edgeRdr.next(); + MethodOrMethodContext src = e.getSrc(); + MethodOrMethodContext tgt = e.getTgt(); + removeEdge(e); + e.remove(); + addEdge(new Edge(src, in, tgt)); + hasSwapped = true; + } + return hasSwapped; + } + + /** + * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. + */ + public boolean removeEdge(Edge e) { + return removeEdge(e, true); + } + + /** + * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. + * + * @param e + * the edge + * @param removeInEdgeList + * when true (recommended), it is ensured that the edge reader is informed about the removal + * @return whether the removal was successful. + */ + public boolean removeEdge(Edge e, boolean removeInEdgeList) { + if (!edges.remove(e)) { + return false; + } + e.remove(); + + if (srcUnitToEdge.get(e.srcUnit()) == e) { + if (e.nextByUnit().srcUnit() == e.srcUnit()) { + srcUnitToEdge.put(e.srcUnit(), e.nextByUnit()); + } else { + srcUnitToEdge.remove(e.srcUnit()); + } + } + + if (srcMethodToEdge.get(e.getSrc()) == e) { + if (e.nextBySrc().getSrc() == e.getSrc()) { + srcMethodToEdge.put(e.getSrc(), e.nextBySrc()); + } else { + srcMethodToEdge.remove(e.getSrc()); + } + } + + if (tgtToEdge.get(e.getTgt()) == e) { + if (e.nextByTgt().getTgt() == e.getTgt()) { + tgtToEdge.put(e.getTgt(), e.nextByTgt()); + } else { + tgtToEdge.remove(e.getTgt()); + } + } + // This is an linear operation, so we want to avoid it if possible. + if (removeInEdgeList) { + reader.remove(e); + } + return true; + } + + /** + * Removes the edges from the call graph. Returns true iff one edge was originally present in the call graph. + * + * @param edges + * the edges + * @return whether the removal was successful. + */ + public boolean removeEdges(Collection edges) { + if (!this.edges.removeAll(edges)) { + return false; + } + for (Edge e : edges) { + removeEdge(e, false); + } + reader.remove(edges); + return true; + } + + /** + * Does this method have no incoming edge? + * + * @param method + * @return + */ + public boolean isEntryMethod(SootMethod method) { + return !tgtToEdge.containsKey(method); + } + + /** + * Find the specific call edge that is going out from the callsite u and the call target is callee. Without advanced data + * structure, we can only sequentially search for the match. Fortunately, the number of outgoing edges for a unit is not + * too large. + * + * @param u + * @param callee + * @return + */ + public Edge findEdge(Unit u, SootMethod callee) { + Edge e = srcUnitToEdge.get(u); + if (e != null) { + while (e.srcUnit() == u && e.kind() != Kind.INVALID) { + if (e.tgt() == callee) { + return e; + } + e = e.nextByUnit(); + } + } + return null; + } + + /** + * Returns an iterator over all methods that are the sources of at least one edge. + */ + public Iterator sourceMethods() { + return srcMethodToEdge.keySet().iterator(); + } + + /** + * Returns an iterator over all edges that have u as their source unit. + */ + public Iterator edgesOutOf(Unit u) { + return new TargetsOfUnitIterator(u); + } + + class TargetsOfUnitIterator implements Iterator { + private final Unit u; + private Edge position; + + TargetsOfUnitIterator(Unit u) { + this.u = u; + if (u == null) { + throw new RuntimeException(); + } + this.position = srcUnitToEdge.get(u); + if (position == null) { + position = dummy; + } + } + + @Override + public boolean hasNext() { + if (position.srcUnit() != u) { + return false; + } + return position.kind() != Kind.INVALID; + } + + @Override + public Edge next() { + Edge ret = position; + position = position.nextByUnit(); + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns an iterator over all edges that have m as their source method. + */ + public Iterator edgesOutOf(MethodOrMethodContext m) { + return new TargetsOfMethodIterator(m); + } + + class TargetsOfMethodIterator implements Iterator { + private final MethodOrMethodContext m; + private Edge position; + + TargetsOfMethodIterator(MethodOrMethodContext m) { + this.m = m; + if (m == null) { + throw new RuntimeException(); + } + this.position = srcMethodToEdge.get(m); + if (position == null) { + position = dummy; + } + } + + @Override + public boolean hasNext() { + if (position.getSrc() != m) { + return false; + } + return position.kind() != Kind.INVALID; + } + + @Override + public Edge next() { + Edge ret = position; + position = position.nextBySrc(); + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns an iterator over all edges that have m as their target method. + */ + public Iterator edgesInto(MethodOrMethodContext m) { + return new CallersOfMethodIterator(m); + } + + class CallersOfMethodIterator implements Iterator { + private final MethodOrMethodContext m; + private Edge position; + + CallersOfMethodIterator(MethodOrMethodContext m) { + this.m = m; + if (m == null) { + throw new RuntimeException(); + } + this.position = tgtToEdge.get(m); + if (position == null) { + position = dummy; + } + } + + @Override + public boolean hasNext() { + if (position.getTgt() != m) { + return false; + } + return position.kind() != Kind.INVALID; + } + + @Override + public Edge next() { + Edge ret = position; + position = position.nextByTgt(); + return ret; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns a QueueReader object containing all edges added so far, and which will be informed of any new edges that are + * later added to the graph. + */ + public QueueReader listener() { + return reader.clone(); + } + + /** + * Returns a QueueReader object which will contain ONLY NEW edges which will be added to the graph. + */ + public QueueReader newListener() { + return stream.reader(); + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + for (QueueReader reader = listener(); reader.hasNext();) { + Edge e = reader.next(); + out.append(e.toString()).append('\n'); + } + return out.toString(); + } + + /** + * Returns the number of edges in the call graph. + */ + public int size() { + return edges.size(); + } + + @Override + public Iterator iterator() { + return edges.iterator(); + } +} diff --git a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java new file mode 100644 index 00000000000..6af3a9983e0 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java @@ -0,0 +1,304 @@ +package soot.jimple.toolkits.callgraph; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2003 Ondrej Lhotak + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import soot.Context; +import soot.Kind; +import soot.MethodOrMethodContext; +import soot.Unit; +import soot.jimple.InterfaceInvokeExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.SpecialInvokeExpr; +import soot.jimple.StaticInvokeExpr; +import soot.jimple.VirtualInvokeExpr; +import soot.util.Invalidable; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; + +/** + * Represents a single edge in a call graph. + * + * @author Ondrej Lhotak + */ +public final class Edge implements Invalidable { + + /** + * The method in which the call occurs; may be null for calls not occurring in a specific method (eg. implicit calls by the + * VM) + */ + private MethodOrMethodContext src; + + /** + * The target method of the call edge. + */ + private MethodOrMethodContext tgt; + + /** + * The unit at which the call occurs; may be null for calls not occurring at a specific statement (eg. calls in native + * code) + */ + private Unit srcUnit; + + /** + * The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as isExplicit() should be + * added. + */ + private final Kind kind; + + private boolean invalid = false; + + public Edge(MethodOrMethodContext src, Unit srcUnit, MethodOrMethodContext tgt, Kind kind) { + this.src = src; + this.srcUnit = srcUnit; + this.tgt = tgt; + this.kind = kind; + } + + public Edge(MethodOrMethodContext src, Stmt srcUnit, MethodOrMethodContext tgt) { + this.kind = ieToKind(srcUnit.getInvokeExpr()); + this.src = src; + this.srcUnit = srcUnit; + this.tgt = tgt; + } + + public SootMethod src() { + return (src == null) ? null : src.method(); + } + + public Context srcCtxt() { + return (src == null) ? null : src.context(); + } + + public MethodOrMethodContext getSrc() { + return src; + } + + public Unit srcUnit() { + return srcUnit; + } + + public Stmt srcStmt() { + return (Stmt) srcUnit; + } + + public SootMethod tgt() { + return (tgt == null) ? null : tgt.method(); + } + + public Context tgtCtxt() { + return (tgt == null) ? null : tgt.context(); + } + + public MethodOrMethodContext getTgt() { + return tgt; + } + + public Kind kind() { + return kind; + } + + public static Kind ieToKind(InvokeExpr ie) { + if (ie instanceof VirtualInvokeExpr) { + return Kind.VIRTUAL; + } else if (ie instanceof SpecialInvokeExpr) { + return Kind.SPECIAL; + } else if (ie instanceof InterfaceInvokeExpr) { + return Kind.INTERFACE; + } else if (ie instanceof StaticInvokeExpr) { + return Kind.STATIC; + } else { + throw new RuntimeException(); + } + } + + /** + * Returns true if the call is due to an explicit invoke statement. + */ + public boolean isExplicit() { + return Kind.isExplicit(this.kind); + } + + /** + * Returns true if the call is due to an explicit instance invoke statement. + */ + public boolean isInstance() { + return Kind.isInstance(this.kind); + } + + public boolean isVirtual() { + return Kind.isVirtual(this.kind); + } + + public boolean isSpecial() { + return Kind.isSpecial(this.kind); + } + + /** + * Returns true if the call is to static initializer. + */ + public boolean isClinit() { + return Kind.isClinit(this.kind); + } + + /** + * Returns true if the call is due to an explicit static invoke statement. + */ + public boolean isStatic() { + return Kind.isStatic(this.kind); + } + + public boolean isThreadRunCall() { + return Kind.isThread(this.kind); + } + + public boolean passesParameters() { + return Kind.passesParameters(this.kind); + } + + @Override + public boolean isInvalid() { + return invalid; + } + + @Override + public void invalidate() { + // Since the edge remains in the QueueReaders for a while, the GC could not claim old units. + src = null; + srcUnit = null; + tgt = null; + invalid = true; + } + + @Override + public int hashCode() { + if (invalid) { + return 0; + } + int ret = (tgt.hashCode() + 20) + (kind == null ? 0 : kind.getNumber()); + if (src != null) { + ret = ret * 32 + src.hashCode(); + } + if (srcUnit != null) { + ret = ret * 32 + srcUnit.hashCode(); + } + return ret; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Edge)) { + return false; + } + Edge o = (Edge) other; + return (o.src == this.src) && (o.srcUnit == srcUnit) && (o.tgt == tgt) && (o.kind == kind); + } + + @Override + public String toString() { + return String.valueOf(this.kind) + " edge: " + srcUnit + " in " + src + " ==> " + tgt; + } + + private Edge nextByUnit = this; + private Edge prevByUnit = this; + private Edge nextBySrc = this; + private Edge prevBySrc = this; + private Edge nextByTgt = this; + private Edge prevByTgt = this; + + void insertAfterByUnit(Edge other) { + nextByUnit = other.nextByUnit; + nextByUnit.prevByUnit = this; + other.nextByUnit = this; + prevByUnit = other; + } + + void insertAfterBySrc(Edge other) { + nextBySrc = other.nextBySrc; + nextBySrc.prevBySrc = this; + other.nextBySrc = this; + prevBySrc = other; + } + + void insertAfterByTgt(Edge other) { + nextByTgt = other.nextByTgt; + nextByTgt.prevByTgt = this; + other.nextByTgt = this; + prevByTgt = other; + } + + void insertBeforeByUnit(Edge other) { + prevByUnit = other.prevByUnit; + prevByUnit.nextByUnit = this; + other.prevByUnit = this; + nextByUnit = other; + } + + void insertBeforeBySrc(Edge other) { + prevBySrc = other.prevBySrc; + prevBySrc.nextBySrc = this; + other.prevBySrc = this; + nextBySrc = other; + } + + void insertBeforeByTgt(Edge other) { + prevByTgt = other.prevByTgt; + prevByTgt.nextByTgt = this; + other.prevByTgt = this; + nextByTgt = other; + } + + void remove() { + invalid = true; + nextByUnit.prevByUnit = prevByUnit; + prevByUnit.nextByUnit = nextByUnit; + nextBySrc.prevBySrc = prevBySrc; + prevBySrc.nextBySrc = nextBySrc; + nextByTgt.prevByTgt = prevByTgt; + prevByTgt.nextByTgt = nextByTgt; + } + + Edge nextByUnit() { + return nextByUnit; + } + + Edge nextBySrc() { + return nextBySrc; + } + + Edge nextByTgt() { + return nextByTgt; + } + + Edge prevByUnit() { + return prevByUnit; + } + + Edge prevBySrc() { + return prevBySrc; + } + + Edge prevByTgt() { + return prevByTgt; + } +} + diff --git a/sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java b/sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java new file mode 100644 index 00000000000..48fa2ee94ac --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java @@ -0,0 +1,139 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; + +/** + * @author Timothy Hoffman + */ +public abstract class AbstractDotGraphElement { + + private LinkedHashMap attributes; + + /** + * Sets an attribute for this dot element. + * + * @param id + * the attribute id to be set + * @param value + * the attribute value + */ + public void setAttribute(String id, String value) { + this.setAttribute(new DotGraphAttribute(id, value)); + } + + /** + * Sets an attribute for this dot element. + * + * @param attr + * {@link DotGraphAttribute} specifying the attribute name and value + */ + public void setAttribute(DotGraphAttribute attr) { + LinkedHashMap attrs = this.attributes; + if (attrs == null) { + this.attributes = attrs = new LinkedHashMap(); + } + attrs.put(attr.getID(), attr); + } + + /** + * @return unmodifiable {@link Collection} of {@link DotGraphAttribute} for this {@link AbstractDotGraphElement} + */ + public Collection getAttributes() { + LinkedHashMap attrs = this.attributes; + return attrs == null ? Collections.emptyList() : Collections.unmodifiableCollection(attrs.values()); + } + + /** + * @param id + * @return the {@link DotGraphAttribute} with the given {@code id} + */ + public DotGraphAttribute getAttribute(String id) { + LinkedHashMap attrs = this.attributes; + return attrs == null ? null : attrs.get(id); + } + + /** + * @param id + * @return the value for the {@link DotGraphAttribute} with the given {@code id} + */ + public String getAttributeValue(String id) { + DotGraphAttribute attr = getAttribute(id); + return attr == null ? null : attr.getValue(); + } + + /** + * Removes the attribute with the given {@link id} from this dot element. + * + * @param id + */ + public void removeAttribute(String id) { + LinkedHashMap attrs = this.attributes; + if (attrs != null) { + attrs.remove(id); + } + } + + /** + * Removes the given attribute from this dot element. + * + * @param attr + * {@link DotGraphAttribute} specifying the attribute to remove + */ + public void removeAttribute(DotGraphAttribute attr) { + LinkedHashMap attrs = this.attributes; + if (attrs != null) { + attrs.remove(attr.getID(), attr); + } + } + + /** + * Removes all attributes from this dot element. + */ + public void removeAllAttributes() { + this.attributes = null; + } + + /** + * Sets the label for this dot element. + * + * @param label + * a label string + */ + public void setLabel(String label) { + label = DotGraphUtility.replaceQuotes(label); + label = DotGraphUtility.replaceReturns(label); + this.setAttribute("label", "\"" + label + "\""); + } + + /** + * @return the label for this dot element + */ + public String getLabel() { + return this.getAttributeValue("label"); + } +} + diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraph.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraph.java new file mode 100644 index 00000000000..d5baff15a6c --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraph.java @@ -0,0 +1,326 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Allow a serialized drawing, following steps: + *
    + *
  1. new DotGraph
  2. + *
  3. draw(Directed/Undirected)Edge, attachAttributes, addNode
  4. + *
  5. plot
  6. + *
+ */ +public class DotGraph extends AbstractDotGraphElement implements Renderable { + private static final Logger logger = LoggerFactory.getLogger(DotGraph.class); + + /** + * The extension added to output files, exported so that clients can search for the filenames. + */ + public static final String DOT_EXTENSION = ".dot"; + + private final HashMap nodes; + /* draw elements are sub graphs, edges, commands */ + private final List drawElements; + + private final boolean isSubGraph; + + private boolean dontQuoteNodeNames; + + private String graphname; + + private DotGraph(String graphname, boolean isSubGraph) { + this.graphname = graphname; + this.isSubGraph = isSubGraph; + this.nodes = new HashMap(100); + this.drawElements = new LinkedList(); + this.dontQuoteNodeNames = false; + } + + /** + * Creates a new graph for drawing. + * + * @param graphname, + * the name used to identify the graph in the dot source. + */ + public DotGraph(String graphname) { + this(graphname, false); + } + + /** + * Generates the drawing on canvas to the dot file. + * + * @param filename + * the name for the output file. By convention, it should end with DOT_EXTENSION, but this is not enforced. + */ + public void plot(String filename) { + try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename))) { + render(out, 0); + } catch (IOException ioe) { + logger.debug(ioe.getMessage()); + } + } + + /** + * Draws a directed edge (including the source and end nodes, if they have not already been drawn). + * + * @param from, + * the source node + * @param to, + * the end node + * @return a directed graph edge connecting {@code from} with {@code to} + */ + public DotGraphEdge drawEdge(String from, String to) { + return drawEdge(from, to, true); + } + + /** + * Draws a undirected edge (including the nodes, if they have not already been drawn). + * + * @param node1 + * @param node2 + * + * @return an undirected graph edge connecting {@code node1} with {@code node2} + */ + public DotGraphEdge drawUndirectedEdge(String node1, String node2) { + return drawEdge(node1, node2, false); + } + + private DotGraphEdge drawEdge(String from, String to, boolean directed) { + DotGraphNode src = drawNode(from); + DotGraphNode dst = drawNode(to); + DotGraphEdge edge = new DotGraphEdge(src, dst, directed); + + this.drawElements.add(edge); + + return edge; + } + + /** + * Draws a node. + * + * @param name, + * the node to draw. + * @return the {@link DotGraphNode} corresponding to the specified name. + */ + public DotGraphNode drawNode(String name) { + DotGraphNode node = getNode(name); + + if (node == null) { + throw new RuntimeException("Assertion failed."); + } + + if (!this.drawElements.contains(node)) { + this.drawElements.add(node); + } + + return node; + } + + /** + * Gets the graph node by name. + * + * @param name, + * unique name of the node. + * @return the node with the specified name, adding a new node to the graph if there is no such node. + */ + public DotGraphNode getNode(String name) { + if (name == null) { + return null; + } + + DotGraphNode node = nodes.get(name); + if (node == null) { + node = new DotGraphNode(name, dontQuoteNodeNames); + nodes.put(name, node); + } + return node; + } + + /** + * Checks if the graph already contains the node with the specified name. + * + * @param name, + * unique name of the node. + * + * @return true if the node with the specified name is already in the graph, false otherwise + */ + public boolean containsNode(String name) { + return name != null && nodes.containsKey(name); + } + + /** + * Checks if the graph already contains the given {@link DotGraphNode}. + * + * @param node + * + * @return true if the node is already in the graph, false otherwise + */ + public boolean containsNode(DotGraphNode node) { + return this.drawElements.contains(node); + } + + /** + * NOTE: default is true + * + * @param value + */ + public void quoteNodeNames(boolean value) { + this.dontQuoteNodeNames = !value; + } + + /** + * Sets all node shapes, see the list of node shapes in DotGraphConstants. + * + * @param shape, + * the node shape + */ + public void setNodeShape(String shape) { + String command = "node [shape=" + shape + "];"; + this.drawElements.add(new DotGraphCommand(command)); + } + + /** + * Sets all node styles + * + * @param style, + * the node style + */ + public void setNodeStyle(String style) { + String command = "node [style=" + style + "];"; + this.drawElements.add(new DotGraphCommand(command)); + } + + /** + * sets the size of drawing area, in inches + */ + public void setGraphSize(double width, double height) { + String size = "\"" + width + "," + height + "\""; + this.setAttribute("size", size); + } + + /** + * sets the pages size, once this is set, the generated graph will be broken into several pages. + */ + public void setPageSize(double width, double height) { + String size = "\"" + width + ", " + height + "\""; + this.setAttribute("page", size); + } + + /** + * sets the graph rotation angles + */ + public void setOrientation(String orientation) { + this.setAttribute("orientation", orientation); + } + + /** + * sets the graph name + */ + public void setGraphName(String name) { + this.graphname = name; + } + + /** + * NOTE: Alias for {@link #setLabel(java.lang.String)}. + */ + public void setGraphLabel(String label) { + this.setLabel(label); + } + + /** + * sets any general attributes + * + * NOTE: Alias for {@link #setAttribute(java.lang.String, java.lang.String)}. + * + * @param id + * is the attribute name. + * @param value + * is the attribute value. + */ + public void setGraphAttribute(String id, String value) { + this.setAttribute(id, value); + } + + /** + * sets any general attributes + * + * NOTE: Alias for {@link #setAttribute(soot.util.dot.DotGraphAttribute)}. + * + * @param attr + * a {@link DotGraphAttribute} specifying the attribute name and value. + */ + public void setGraphAttribute(DotGraphAttribute attr) { + this.setAttribute(attr); + } + + /** + * creates a sub graph. + * + * NOTE: Some renderers require subgraph labels to start with "cluster". + * + * @return the newly created sub graph. + */ + public DotGraph createSubGraph(String label) { + // file name is used as label of sub graph. + DotGraph subgraph = new DotGraph(label, true); + + this.drawElements.add(subgraph); + + return subgraph; + } + + /* implements renderable interface. */ + @Override + public void render(OutputStream out, int indent) throws IOException { + // header + if (!isSubGraph) { + DotGraphUtility.renderLine(out, "digraph \"" + this.graphname + "\" {", indent); + } else { + DotGraphUtility.renderLine(out, "subgraph \"" + this.graphname + "\" {", indent); + } + + /* render graph attributes */ + for (DotGraphAttribute attr : this.getAttributes()) { + DotGraphUtility.renderLine(out, attr.toString() + ';', indent + 4); + } + + /* render elements */ + for (Renderable element : this.drawElements) { + element.render(out, indent + 4); + } + + // close the description + DotGraphUtility.renderLine(out, "}", indent); + } +} diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java new file mode 100644 index 00000000000..fe3797eb77d --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java @@ -0,0 +1,53 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * A class for specifying Dot graph attributes. + * + * @author Feng Qian + */ +public class DotGraphAttribute { + + private final String id; + private final String value; + + public DotGraphAttribute(String id, String v) { + this.id = id; + this.value = v; + } + + @Override + public String toString() { + return this.id + '=' + this.value; + } + + public String getID() { + return this.id; + } + + public String getValue() { + return this.value; + } +} + diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java new file mode 100644 index 00000000000..12e30951266 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java @@ -0,0 +1,57 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Encodes general Dot commands. + */ +public class DotGraphCommand implements Renderable { + + private final String command; + + /** + * @param cmd + * a dot dommand string + */ + public DotGraphCommand(String cmd) { + this.command = cmd; + } + + /** + * Implements Renderable interface. + * + * @param out + * the output stream + * @param indent + * the number of indent space + * @see Renderable + */ + @Override + public void render(OutputStream out, int indent) throws IOException { + DotGraphUtility.renderLine(out, command, indent); + } +} + diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java new file mode 100644 index 00000000000..0b92f7dc2bc --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java @@ -0,0 +1,3 @@ +package soot.util.dot; +public class DotGraphConstants { +} diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java new file mode 100644 index 00000000000..6fde5176408 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java @@ -0,0 +1,101 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; + +/** + * Graph edges are the major elements of a graph + * + * @author Feng Qian + */ +public class DotGraphEdge extends AbstractDotGraphElement implements Renderable { + + private final DotGraphNode start; + private final DotGraphNode end; + private final boolean isDirected; + + /** + * Draws a directed edge. + * + * @param src, + * the source node + * @param dst, + * the end node + */ + public DotGraphEdge(DotGraphNode src, DotGraphNode dst) { + this.start = src; + this.end = dst; + this.isDirected = true; + } + + /** + * Draws a graph edge by specifying directed or undirected. + * + * @param src, + * the source node + * @param dst, + * the end node + * @param directed, + * the edge is directed or not + */ + public DotGraphEdge(DotGraphNode src, DotGraphNode dst, boolean directed) { + this.start = src; + this.end = dst; + this.isDirected = directed; + } + + /** + * Sets the edge style. + * + * @param style, + * a style of edge + * @see DotGraphConstants + */ + public void setStyle(String style) { + this.setAttribute("style", style); + } + + @Override + public void render(OutputStream out, int indent) throws IOException { + StringBuilder line = new StringBuilder(); + line.append(this.start.getName()); + line.append(this.isDirected ? "->" : "--"); + line.append(this.end.getName()); + + Collection attrs = this.getAttributes(); + if (!attrs.isEmpty()) { + line.append(" ["); + for (DotGraphAttribute attr : attrs) { + line.append(attr.toString()).append(','); + } + line.append(']'); + } + line.append(';'); + + DotGraphUtility.renderLine(out, line.toString(), indent); + } +} + diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java new file mode 100644 index 00000000000..f00ed6cae4c --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java @@ -0,0 +1,80 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; + +/** + * A Dot graph node with various attributes. + */ +public class DotGraphNode extends AbstractDotGraphElement implements Renderable { + + private final String name; + + public DotGraphNode(String name) { + // make any illegal name to be legal + this.name = '"' + DotGraphUtility.replaceQuotes(name) + '"'; + } + + public DotGraphNode(String name, boolean dontQuoteName) { + this.name = dontQuoteName ? DotGraphUtility.replaceQuotes(name) : '"' + DotGraphUtility.replaceQuotes(name) + '"'; + } + + public String getName() { + return this.name; + } + + public void setHTMLLabel(String label) { + label = DotGraphUtility.replaceReturns(label); + this.setAttribute("label", label); + } + + public void setShape(String shape) { + this.setAttribute("shape", shape); + } + + public void setStyle(String style) { + this.setAttribute("style", style); + } + + @Override + public void render(OutputStream out, int indent) throws IOException { + StringBuilder line = new StringBuilder(); + line.append(this.getName()); + + Collection attrs = this.getAttributes(); + if (!attrs.isEmpty()) { + line.append(" ["); + for (DotGraphAttribute attr : attrs) { + line.append(attr.toString()).append(','); + } + line.append(']'); + } + line.append(';'); + + DotGraphUtility.renderLine(out, line.toString(), indent); + } +} + diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java new file mode 100644 index 00000000000..b12c214b11f --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java @@ -0,0 +1,128 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DotGraphUtility { + private static final Logger logger = LoggerFactory.getLogger(DotGraphUtility.class); + + /** + * Replace any {@code "} with {@code \"}. If the {@code "} character was already escaped (i.e. {@code \"}), then the escape + * character is also escaped (i.e. {@code \\\"}). + * + * @param original + * + * @return + */ + public static String replaceQuotes(String original) { + byte[] ord = original.getBytes(); + int quotes = 0; + boolean escapeActive = false; + for (byte element : ord) { + switch (element) { + case '\\': + escapeActive = true; + break; + case '\"': + quotes++; + if (escapeActive) { + quotes++; + } + // fallthrough + default: + escapeActive = false; + break; + } + } + + if (quotes == 0) { + return original; + } + + byte[] newsrc = new byte[ord.length + quotes]; + for (int i = 0, j = 0, n = ord.length; i < n; i++, j++) { + if (ord[i] == '\"') { + if (i > 0 && ord[i - 1] == '\\') { + newsrc[j++] = (byte) '\\'; + } + newsrc[j++] = (byte) '\\'; + } + newsrc[j] = ord[i]; + } + + /* + * logger.debug("before "+original); logger.debug("after "+(new String(newsrc))); + */ + return new String(newsrc); + } + + /** + * Replace any return ({@code \n}) with {@code \\n}. + * + * @param original + * + * @return + */ + public static String replaceReturns(String original) { + byte[] ord = original.getBytes(); + int quotes = 0; + for (byte element : ord) { + if (element == '\n') { + quotes++; + } + } + + if (quotes == 0) { + return original; + } + + byte[] newsrc = new byte[ord.length + quotes]; + for (int i = 0, j = 0, n = ord.length; i < n; i++, j++) { + if (ord[i] == '\n') { + newsrc[j++] = (byte) '\\'; + newsrc[j] = (byte) 'n'; + } else { + newsrc[j] = ord[i]; + } + } + + /* + * logger.debug("before "+original); logger.debug("after "+(new String(newsrc))); + */ + return new String(newsrc); + } + + public static void renderLine(OutputStream out, String content, int indent) throws IOException { + char[] indentChars = new char[indent]; + Arrays.fill(indentChars, ' '); + StringBuilder sb = new StringBuilder(); + sb.append(indentChars).append(content).append('\n'); + out.write(sb.toString().getBytes()); + } +} diff --git a/sootup.qilin/src/main/java/soot/util/dot/Renderable.java b/sootup.qilin/src/main/java/soot/util/dot/Renderable.java new file mode 100644 index 00000000000..2ce0ac63651 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/util/dot/Renderable.java @@ -0,0 +1,30 @@ +package soot.util.dot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Feng Qian + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.io.IOException; +import java.io.OutputStream; + +public interface Renderable { + public void render(OutputStream device, int indent) throws IOException; +} From 8f93ee4c2934d91b0e162a40bbe90fc1bb648d5c Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sat, 16 Sep 2023 20:28:32 +1000 Subject: [PATCH 010/145] replace RefType with ClassType; replace PrimType with PrimitiveType; --- .../java/qilin/core/ArtificialMethod.java | 7 ++-- .../src/main/java/qilin/core/PTA.java | 4 ++- .../src/main/java/qilin/core/PTAScene.java | 6 ++++ .../main/java/qilin/core/VirtualCalls.java | 21 +++++++----- .../qilin/core/builder/CallGraphBuilder.java | 1 + .../qilin/core/builder/FakeMainFactory.java | 34 +++++++++---------- .../qilin/core/builder/MethodNodeFactory.java | 17 +++++----- .../core/context/TypeContextElement.java | 8 ++--- .../JavaIoFileSystemGetFileSystemNative.java | 4 +-- .../natives/JavaIoFileSystemListNative.java | 6 ++-- .../core/natives/JavaLangReflectArrayGet.java | 8 +++-- .../core/natives/JavaLangReflectArraySet.java | 6 ++-- .../JavaLangSystemArraycopyNative.java | 10 +++--- .../natives/JavaLangThreadCurrentThread.java | 4 +-- .../main/java/qilin/core/pag/AllocNode.java | 13 +++++-- .../java/qilin/core/pag/ArrayElement.java | 4 +-- .../qilin/core/pag/ClassConstantNode.java | 4 +-- .../java/qilin/core/pag/ContextField.java | 4 +-- .../main/java/qilin/core/pag/MethodPAG.java | 2 +- .../src/main/java/qilin/core/pag/PAG.java | 4 +-- .../src/main/java/qilin/core/pag/Parm.java | 4 +-- .../qilin/core/pag/StringConstantNode.java | 4 +-- .../qilin/core/reflection/TamiflexModel.java | 2 +- .../core/sets/UnmodifiablePointsToSet.java | 11 ++++-- .../main/java/qilin/core/solver/Solver.java | 1 + .../parm/heapabst/HeuristicAbstractor.java | 4 +-- .../qilin/pta/toolkits/common/ToolUtil.java | 3 +- .../dd/CtxTunnelingFeaturesTrueTable.java | 3 +- .../pta/toolkits/dd/FeaturesTrueTable.java | 3 +- .../debloaterx/CollectionHeuristic.java | 19 ++++++----- .../toolkits/debloaterx/ContainerFinder.java | 7 ++-- .../pta/toolkits/debloaterx/DebloaterX.java | 3 +- .../qilin/pta/toolkits/debloaterx/XPAG.java | 4 +-- .../pta/toolkits/debloaterx/XUtility.java | 9 ++--- .../pta/toolkits/turner/AbstractMVFG.java | 1 + .../pta/toolkits/zipper/analysis/Zipper.java | 14 ++++---- .../pta/tools/PartialCallSiteSensPTA.java | 1 + .../qilin/pta/tools/PartialObjSensPTA.java | 1 + .../main/java/qilin/pta/tools/ZipperPTA.java | 1 + .../src/main/java/qilin/util/PTAUtils.java | 28 +++++++++------ 40 files changed, 167 insertions(+), 123 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index 5e012d97902..563342db3bd 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -27,6 +27,7 @@ import sootup.core.jimple.basic.Value; import sootup.core.model.Body; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import sootup.core.types.Type; import java.util.Arrays; @@ -42,7 +43,7 @@ public abstract class ArtificialMethod { protected Value getThis() { if (thisLocal == null) { - RefType type = method.getDeclaringClassType(); + ClassType type = method.getDeclaringClassType(); Value thisRef = new ThisRef(type); thisLocal = getLocal(type, 0); addIdentity(thisLocal, thisRef); @@ -74,14 +75,14 @@ private void addIdentity(Value lValue, Value rValue) { body.getUnits().add(new JIdentityStmt(lValue, rValue)); } - protected Value getNew(RefType type) { + protected Value getNew(ClassType type) { Value newExpr = new JNewExpr(type); Value local = getNextLocal(type); addAssign(local, newExpr); return local; } - protected Value getNewArray(RefType type) { + protected Value getNewArray(ClassType type) { Value newExpr = new JNewArrayExpr(type, IntConstant.v(1)); Value local = getNextLocal(ArrayType.v(type, 1)); addAssign(local, newExpr); diff --git a/sootup.qilin/src/main/java/qilin/core/PTA.java b/sootup.qilin/src/main/java/qilin/core/PTA.java index 420695324ad..08cd5c6325a 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTA.java +++ b/sootup.qilin/src/main/java/qilin/core/PTA.java @@ -27,8 +27,10 @@ import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.HeapAbstractor; import qilin.parm.select.CtxSelector; +import qilin.util.PTAUtils; import soot.Context; import soot.MethodOrMethodContext; +import soot.jimple.toolkits.callgraph.CallGraph; import sootup.core.jimple.basic.Local; import sootup.core.model.SootField; import sootup.core.model.SootMethod; @@ -49,7 +51,7 @@ public PTA() { this.pag = createPAG(); this.cgb = createCallGraphBuilder(); this.eh = new ExceptionHandler(this); - AllocNode rootBase = pag.makeAllocNode("ROOT", RefType.v("java.lang.Object"), null); + AllocNode rootBase = pag.makeAllocNode("ROOT", PTAUtils.getClassType("java.lang.Object"), null); this.rootNode = new ContextAllocNode(rootBase, CtxConstructor.emptyContext); } diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java index bf53d72cb54..84df8712081 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTAScene.java +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -30,12 +30,14 @@ import sootup.core.model.SootField; import sootup.core.model.SootMethod; import sootup.core.types.Type; +import sootup.core.views.View; import java.util.Set; public class PTAScene { private static volatile PTAScene instance = null; private final Scene sootScene; + private final View view; private final FakeMainFactory fakeMainFactory; public static PTAScene v() { @@ -96,6 +98,10 @@ public void setCallGraph(CallGraph cg) { sootScene.setCallGraph(cg); } + public View getView() { + return view; + } + public CallGraph getCallGraph() { return sootScene.getCallGraph(); } diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index 18dece37f6f..c6b5a7c7deb 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -19,12 +19,15 @@ package qilin.core; import qilin.util.DataFactory; +import qilin.util.PTAUtils; import soot.jimple.SpecialInvokeExpr; import soot.util.*; import soot.util.queue.ChunkedQueue; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; +import sootup.core.types.NullType; import sootup.core.types.Type; import java.util.HashSet; @@ -79,11 +82,11 @@ public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, S } } - public SootMethod resolveNonSpecial(RefType t, NumberedString subSig) { + public SootMethod resolveNonSpecial(ClassType t, NumberedString subSig) { return resolveNonSpecial(t, subSig, false); } - public SootMethod resolveNonSpecial(RefType t, NumberedString subSig, boolean appOnly) { + public SootMethod resolveNonSpecial(ClassType t, NumberedString subSig, boolean appOnly) { Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); SootMethod ret = vtbl.get(subSig); if (ret != null) { @@ -125,13 +128,13 @@ public void resolve(Type t, Type declaredType, Type sigType, NumberedString subS public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, ChunkedQueue targets, boolean appOnly) { if (declaredType instanceof ArrayType) { - declaredType = RefType.v("java.lang.Object"); + declaredType = PTAUtils.getClassType("java.lang.Object"); } if (sigType instanceof ArrayType) { - sigType = RefType.v("java.lang.Object"); + sigType = PTAUtils.getClassType("java.lang.Object"); } if (t instanceof ArrayType) { - t = RefType.v("java.lang.Object"); + t = PTAUtils.getClassType("java.lang.Object"); } if (declaredType != null && !Scene.v().getFastHierarchy().canStoreType(t, declaredType)) { @@ -140,13 +143,13 @@ public void resolve(Type t, Type declaredType, Type sigType, NumberedString subS if (sigType != null && !Scene.v().getFastHierarchy().canStoreType(t, sigType)) { return; } - if (t instanceof RefType) { - SootMethod target = resolveNonSpecial((RefType) t, subSig, appOnly); + if (t instanceof ClassType) { + SootMethod target = resolveNonSpecial((ClassType) t, subSig, appOnly); if (target != null) { targets.add(target); } } else if (t instanceof AnySubType) { - RefType base = ((AnySubType) t).getBase(); + ClassType base = ((AnySubType) t).getBase(); /* * Whenever any sub type of a specific type is considered as receiver for a method to call and the base type is an @@ -167,7 +170,7 @@ public void resolve(Type t, Type declaredType, Type sigType, NumberedString subS } protected void resolveAnySubType(Type declaredType, Type sigType, NumberedString subSig, SootMethod container, - ChunkedQueue targets, boolean appOnly, RefType base) { + ChunkedQueue targets, boolean appOnly, ClassType base) { { Set subTypes = baseToSubTypes.get(base); if (subTypes != null && !subTypes.isEmpty()) { diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 6df7dfa1c3a..9b50a50a23b 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -27,6 +27,7 @@ import qilin.util.DataFactory; import qilin.util.PTAUtils; import soot.Context; +import soot.Kind; import soot.MethodOrMethodContext; import soot.jimple.*; import soot.jimple.internal.JInvokeStmt; diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index 6414f71986d..ec3c26c6644 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -104,8 +104,8 @@ private void makeFakeMain() { for (SootMethod entry : getEntryPoints()) { if (entry.isStatic()) { if (entry.getSubSignature().equals("void main(java.lang.String[])")) { - Value mockStr = getNew(RefType.v("java.lang.String")); - Value strArray = getNewArray(RefType.v("java.lang.String")); + Value mockStr = getNew(PTAUtils.getClassType("java.lang.String")); + Value strArray = getNewArray(PTAUtils.getClassType("java.lang.String")); addAssign(getArrayRef(strArray), mockStr); addInvoke(entry.getSignature(), strArray); implicitCallEdges++; @@ -119,42 +119,42 @@ private void makeFakeMain() { if (CoreConfig.v().getPtaConfig().singleentry) { return; } - Value sv = getNextLocal(RefType.v("java.lang.String")); - Value mainThread = getNew(RefType.v("java.lang.Thread")); - Value mainThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); - Value systemThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + Value sv = getNextLocal(PTAUtils.getClassType("java.lang.String")); + Value mainThread = getNew(PTAUtils.getClassType("java.lang.Thread")); + Value mainThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); + Value systemThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); Value gCurrentThread = getFieldCurrentThread(); addAssign(gCurrentThread, mainThread); // Store - Value vRunnable = getNextLocal(RefType.v("java.lang.Runnable")); + Value vRunnable = getNextLocal(PTAUtils.getClassType("java.lang.Runnable")); - Value lThreadGroup = getNextLocal(RefType.v("java.lang.ThreadGroup")); + Value lThreadGroup = getNextLocal(PTAUtils.getClassType("java.lang.ThreadGroup")); addInvoke(mainThread, "(java.lang.ThreadGroup,java.lang.String)>", mainThreadGroup, sv); - Value tmpThread = getNew(RefType.v("java.lang.Thread")); + Value tmpThread = getNew(PTAUtils.getClassType("java.lang.Thread")); addInvoke(tmpThread, "(java.lang.ThreadGroup,java.lang.Runnable)>", lThreadGroup, vRunnable); addInvoke(tmpThread, ""); addInvoke(systemThreadGroup, "()>"); addInvoke(mainThreadGroup, "(java.lang.ThreadGroup,java.lang.String)>", systemThreadGroup, sv); - Value lThread = getNextLocal(RefType.v("java.lang.Thread")); - Value lThrowable = getNextLocal(RefType.v("java.lang.Throwable")); - Value tmpThreadGroup = getNew(RefType.v("java.lang.ThreadGroup")); + Value lThread = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); + Value lThrowable = getNextLocal(PTAUtils.getClassType("java.lang.Throwable")); + Value tmpThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); addInvoke(tmpThreadGroup, "", lThread, lThrowable); // TODO. // ClassLoader - Value defaultClassLoader = getNew(RefType.v("sun.misc.Launcher$AppClassLoader")); + Value defaultClassLoader = getNew(PTAUtils.getClassType("sun.misc.Launcher$AppClassLoader")); addInvoke(defaultClassLoader, "()>"); - Value vClass = getNextLocal(RefType.v("java.lang.Class")); - Value vDomain = getNextLocal(RefType.v("java.security.ProtectionDomain")); + Value vClass = getNextLocal(PTAUtils.getClassType("java.lang.Class")); + Value vDomain = getNextLocal(PTAUtils.getClassType("java.security.ProtectionDomain")); addInvoke(defaultClassLoader, "", sv); addInvoke(defaultClassLoader, "", vClass, vDomain); addInvoke(defaultClassLoader, "", vClass); // PrivilegedActionException - Value privilegedActionException = getNew(RefType.v("java.security.PrivilegedActionException")); - Value gLthrow = getNextLocal(RefType.v("java.lang.Exception")); + Value privilegedActionException = getNew(PTAUtils.getClassType("java.security.PrivilegedActionException")); + Value gLthrow = getNextLocal(PTAUtils.getClassType("java.lang.Exception")); addInvoke(privilegedActionException, "(java.lang.Exception)>", gLthrow); } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index 29709a74821..232267bf366 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -24,11 +24,10 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.jimple.*; -import soot.jimple.internal.JNewArrayExpr; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Modifier; @@ -243,7 +242,7 @@ private VarNode caseCastExpr(CastExpr ce) { } public VarNode caseThis() { - Type type = method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); + Type type = method.isStatic() ? PTAUtils.getClassType("java.lang.Object") : method.getDeclaringClassType(); VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THIS_NODE), type, method); ret.setInterProcTarget(); return ret; @@ -262,7 +261,7 @@ public VarNode caseRet() { } public VarNode caseMethodThrow() { - VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), RefType.v("java.lang.Throwable"), method); + VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), PTAUtils.getClassType("java.lang.Throwable"), method); ret.setInterProcSource(); return ret; } @@ -298,22 +297,22 @@ private Node caseNullConstant(NullConstant nr) { private VarNode caseStringConstant(StringConstant sc) { AllocNode stringConstantNode = pag.makeStringConstantNode(sc); - VarNode stringConstantVar = pag.makeGlobalVarNode(sc, RefType.v("java.lang.String")); + VarNode stringConstantVar = pag.makeGlobalVarNode(sc, PTAUtils.getClassType("java.lang.String")); mpag.addInternalEdge(stringConstantNode, stringConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), RefType.v("java.lang.String"), method); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), PTAUtils.getClassType("java.lang.String"), method); mpag.addInternalEdge(stringConstantVar, vn); return vn; } public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { - return pag.makeLocalVarNode(invoke, RefType.v("java.lang.Throwable"), method); + return pag.makeLocalVarNode(invoke, PTAUtils.getClassType("java.lang.Throwable"), method); } final public VarNode caseClassConstant(ClassConstant cc) { AllocNode classConstant = pag.makeClassConstantNode(cc); - VarNode classConstantVar = pag.makeGlobalVarNode(cc, RefType.v("java.lang.Class")); + VarNode classConstantVar = pag.makeGlobalVarNode(cc, PTAUtils.getClassType("java.lang.Class")); mpag.addInternalEdge(classConstant, classConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), RefType.v("java.lang.Class"), method); + VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), PTAUtils.getClassType("java.lang.Class"), method); mpag.addInternalEdge(classConstantVar, vn); return vn; } diff --git a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java index afad26ac036..9c50aef412a 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java +++ b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java @@ -21,7 +21,7 @@ import qilin.core.pag.AllocNode; import qilin.core.pag.ClassConstantNode; import qilin.core.pag.StringConstantNode; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.Type; @@ -38,13 +38,13 @@ private TypeContextElement(Type type) { public static TypeContextElement getTypeContextElement(AllocNode a) { SootMethod declaringMethod = a.getMethod(); - Type declType = RefType.v("java.lang.Object"); + Type declType = PTAUtils.getClassType("java.lang.Object"); if (declaringMethod != null) { declType = declaringMethod.getDeclaringClassType(); } else if (a instanceof ClassConstantNode) { - declType = RefType.v("java.lang.System"); + declType = PTAUtils.getClassType("java.lang.System"); } else if (a instanceof StringConstantNode) { - declType = RefType.v("java.lang.String"); + declType = PTAUtils.getClassType("java.lang.String"); } return new TypeContextElement(declType); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index 2d343905b88..0e165bb7b05 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -18,7 +18,7 @@ package qilin.core.natives; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -35,7 +35,7 @@ public JavaIoFileSystemGetFileSystemNative(SootMethod method) { * only exists in old version of JDK(e.g., JDK6). */ public void simulate() { - Value newLocal0 = getNew(RefType.v("java.io.UnixFileSystem")); + Value newLocal0 = getNew(PTAUtils.getClassType("java.io.UnixFileSystem")); addInvoke(newLocal0, "()>"); addReturn(newLocal0); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java index dd9e0771858..b8a27c97419 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -18,7 +18,7 @@ package qilin.core.natives; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -33,8 +33,8 @@ public JavaIoFileSystemListNative(SootMethod method) { * only exists in old JDK(e.g., JDK6). */ public void simulate() { - Value arrLocal = getNewArray(RefType.v("java.lang.String")); - Value elem = getNew(RefType.v("java.lang.String")); + Value arrLocal = getNewArray(PTAUtils.getClassType("java.lang.String")); + Value elem = getNew(PTAUtils.getClassType("java.lang.String")); // addInvoke(elem, "()>"); addAssign(getArrayRef(arrLocal), elem); addReturn(arrLocal); diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index b2180119e8e..b953b6626e2 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -18,10 +18,11 @@ package qilin.core.natives; +import qilin.util.PTAUtils; import soot.ArrayType; -import soot.RefType; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; /* * @@ -34,9 +35,10 @@ public class JavaLangReflectArrayGet extends NativeMethod { @Override void simulate() { - Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + ClassType objType = PTAUtils.getClassType("java.lang.Object"); + Value arrayBase = getPara(0, ArrayType.v(objType, 1)); Value arrayRef = getArrayRef(arrayBase); - Value ret = getNextLocal(RefType.v("java.lang.Object")); + Value ret = getNextLocal(objType); addAssign(ret, arrayRef); addReturn(ret); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java index b5ca730795c..a9be9d18b03 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -18,10 +18,11 @@ package qilin.core.natives; +import qilin.util.PTAUtils; import soot.ArrayType; -import soot.RefType; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; /* * handle @@ -34,7 +35,8 @@ public class JavaLangReflectArraySet extends NativeMethod { @Override void simulate() { - Value arrayBase = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); + ClassType objType = PTAUtils.getClassType("java.lang.Object"); + Value arrayBase = getPara(0, ArrayType.v(objType, 1)); Value rightValue = getPara(2); Value arrayRef = getArrayRef(arrayBase); addAssign(arrayRef, rightValue); // a[] = b; diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java index 6a19deb4f6a..d5faee69851 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -18,10 +18,11 @@ package qilin.core.natives; +import qilin.util.PTAUtils; import soot.ArrayType; -import soot.RefType; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; /* * This file will be temporarily discarded. Yes, it is correct but need one more level of context. @@ -39,11 +40,12 @@ public JavaLangSystemArraycopyNative(SootMethod method) { public void simulate() { // Value srcArr = getPara(0); // Value dstArr = getPara(2); - Value srcArr = getPara(0, ArrayType.v(RefType.v("java.lang.Object"), 1)); - Value dstArr = getPara(2, ArrayType.v(RefType.v("java.lang.Object"), 1)); + ClassType objType = PTAUtils.getClassType("java.lang.Object"); + Value srcArr = getPara(0, ArrayType.v(objType, 1)); + Value dstArr = getPara(2, ArrayType.v(objType, 1)); Value src = getArrayRef(srcArr); Value dst = getArrayRef(dstArr); - Value temp = getNextLocal(RefType.v("java.lang.Object")); + Value temp = getNextLocal(objType); addAssign(temp, src); addAssign(dst, temp); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java index bf91333b96e..9d521d5dc8e 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -19,7 +19,7 @@ package qilin.core.natives; import qilin.core.PTAScene; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -30,7 +30,7 @@ public class JavaLangThreadCurrentThread extends NativeMethod { @Override void simulate() { - Value lv = getNextLocal(RefType.v("java.lang.Thread")); + Value lv = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); Value rv = PTAScene.v().getFieldCurrentThread(); addAssign(lv, rv); addReturn(lv); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java index 1fdd2553719..189626009aa 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java @@ -19,11 +19,16 @@ package qilin.core.pag; import qilin.CoreConfig; +import qilin.core.PTAScene; import qilin.core.context.ContextElement; -import soot.RefType; import soot.util.Numberable; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import sootup.core.types.Type; +import sootup.core.views.View; + +import java.util.Optional; /** * Represents an allocation site node in the pointer assignment graph. @@ -37,8 +42,10 @@ public class AllocNode extends Node implements ContextElement, Numberable { public AllocNode(Object newExpr, Type t, SootMethod m) { super(t); this.method = m; - if (t instanceof RefType rt) { - if (rt.getSootClass().isAbstract()) { + if (t instanceof ClassType rt) { + View view = PTAScene.v().getView(); + Optional osc = view.getClass(rt); + if (osc.isPresent() && osc.get().isAbstract()) { boolean usesReflectionLog = CoreConfig.v().getAppConfig().REFLECTION_LOG != null; if (!usesReflectionLog) { throw new RuntimeException("Attempt to create allocnode with abstract type " + t); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java index d6b74fa2c2b..6d488276b32 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java @@ -18,7 +18,7 @@ package qilin.core.pag; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.types.Type; /** @@ -50,6 +50,6 @@ public final void setNumber(int number) { } public Type getType() { - return RefType.v("java.lang.Object"); + return PTAUtils.getClassType("java.lang.Object"); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java index 13ea835d895..a5274720c15 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java @@ -18,7 +18,7 @@ package qilin.core.pag; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.jimple.common.constant.ClassConstant; /** @@ -28,7 +28,7 @@ */ public class ClassConstantNode extends ConstantNode { public ClassConstantNode(ClassConstant cc) { - super(cc, RefType.v("java.lang.Class"), null); + super(cc, PTAUtils.getClassType("java.lang.Class"), null); } public String toString() { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java index 181290f3333..684da80d0b7 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java @@ -21,8 +21,8 @@ import qilin.CoreConfig; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; +import qilin.util.PTAUtils; import soot.Context; -import soot.RefType; import sootup.core.types.ArrayType; import sootup.core.types.Type; @@ -38,7 +38,7 @@ public ContextField(Context context, SparkField field) { private static Type refineFieldType(Context context, SparkField field) { if (!CoreConfig.v().getPtaConfig().preciseArrayElement) { - return RefType.v("java.lang.Object"); + return PTAUtils.getClassType("java.lang.Object"); } if (field instanceof ArrayElement) { ContextElement[] contextElements = ((ContextElements) context).getElements(); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index 22098df7239..fd5d13d9306 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -114,7 +114,7 @@ protected void buildException() { if (!CoreConfig.v().getPtaConfig().preciseExceptions) { return; } - Chain traps = body.getTraps(); + List traps = body.getTraps(); PatchingChain units = body.getUnits(); Set inTraps = DataFactory.createSet(); /* diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index a9bf762b3f7..c55493fbfb8 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -565,7 +565,7 @@ private void handleArrayCopy(SootMethod method) { if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { continue; } - Type objType = RefType.v("java.lang.Object"); + Type objType = PTAUtils.getClassType("java.lang.Object"); if (srcArr.getType() == objType) { Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); body.getLocals().add(localSrc); @@ -598,7 +598,7 @@ private void handleArrayCopy(SootMethod method) { } public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { - return makeLocalVarNode(invoke, RefType.v("java.lang.Throwable"), method); + return makeLocalVarNode(invoke, PTAUtils.getClassType("java.lang.Throwable"), method); } public HeapAbstractor heapAbstractor() { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java index b62d33ba654..9275248b75f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java @@ -19,7 +19,7 @@ package qilin.core.pag; import qilin.core.PointsToAnalysis; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.Type; @@ -69,7 +69,7 @@ public Type getType() { if (index == PointsToAnalysis.RETURN_NODE) { return method.getReturnType(); } else if (index == PointsToAnalysis.THIS_NODE) { - return method.isStatic() ? RefType.v("java.lang.Object") : method.getDeclaringClassType(); + return method.isStatic() ? PTAUtils.getClassType("java.lang.Object") : method.getDeclaringClassType(); } return method.getParameterType(index); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java index f67a74ff74b..4d36b647df2 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java @@ -18,7 +18,7 @@ package qilin.core.pag; -import soot.RefType; +import qilin.util.PTAUtils; import sootup.core.jimple.common.constant.StringConstant; /** @@ -28,7 +28,7 @@ */ public class StringConstantNode extends ConstantNode { public StringConstantNode(StringConstant sc) { - super(sc, RefType.v("java.lang.String"), null); + super(sc, PTAUtils.getClassType("java.lang.String"), null); } public String toString() { diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index 51f672a27eb..e778fa35b71 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -61,7 +61,7 @@ Collection transformClassForName(Stmt s) { if (classForNames.containsKey(s)) { Collection fornames = classForNames.get(s); for (String clazz : fornames) { - Type refType = RefType.v(clazz); + Type refType = PTAUtils.getClassType(clazz); ClassConstant cc = ClassConstant.fromType(refType); if (s instanceof AssignStmt) { Value lvalue = ((AssignStmt) s).getLeftOp(); diff --git a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java index d03a797245e..971c69730c9 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java @@ -19,13 +19,16 @@ package qilin.core.sets; import qilin.core.PTA; +import qilin.core.PTAScene; import qilin.core.pag.AllocNode; import qilin.core.pag.ClassConstantNode; import qilin.core.pag.Node; import qilin.core.pag.StringConstantNode; -import soot.RefType; import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; import sootup.core.types.Type; +import sootup.core.views.View; import java.util.*; @@ -62,8 +65,10 @@ public Set possibleTypes() { pts.forall(new P2SetVisitor(pta) { public void visit(Node n) { Type t = n.getType(); - if (t instanceof RefType rt) { - if (rt.getSootClass().isAbstract()) { + if (t instanceof ClassType rt) { + View view = PTAScene.v().getView(); + Optional osc = (Optional) view.getClass(rt); + if (osc.isPresent() && osc.get().isAbstract()) { return; } } diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 2e2b1c02997..24a7886ec65 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -31,6 +31,7 @@ import qilin.core.sets.PointsToSetInternal; import qilin.util.PTAUtils; import soot.Context; +import soot.Kind; import soot.MethodOrMethodContext; import soot.jimple.*; import soot.jimple.toolkits.callgraph.Edge; diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java index a3cd4e2fd5c..73f0a7bdbcb 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -34,8 +34,8 @@ public class HeuristicAbstractor implements HeapAbstractor { public HeuristicAbstractor(PAG pag) { this.pag = pag; - mergedTypes.add(RefType.v("java.lang.StringBuffer")); - mergedTypes.add(RefType.v("java.lang.StringBuilder")); + mergedTypes.add(PTAUtils.getClassType("java.lang.StringBuffer")); + mergedTypes.add(PTAUtils.getClassType("java.lang.StringBuilder")); } @Override diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index 244434c27f3..32e84f6760d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -27,6 +27,7 @@ import soot.RefType; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import java.util.Collections; import java.util.HashSet; @@ -68,7 +69,7 @@ public static int pointsToSetSizeOf(final PTA pta, VarNode var) { * @param pOuter potential outer class * @return whether pInner is an inner class of pOuter */ - public static boolean isInnerType(final RefType pInner, RefType pOuter) { + public static boolean isInnerType(final ClassType pInner, ClassType pOuter) { final String pInnerStr = pInner.toString(); while (!pInnerStr.startsWith(pOuter.toString() + "$")) { SootClass sc = pOuter.getSootClass(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index ba2a306ecd5..861856458fd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -19,7 +19,6 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import soot.jimple.*; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.Body; @@ -34,7 +33,7 @@ public class CtxTunnelingFeaturesTrueTable { private final boolean[] f = new boolean[24]; public CtxTunnelingFeaturesTrueTable(SootMethod sm) { - String sig = sm.getSignature(); + String sig = sm.getSignature().toString(); // the 10 atomic signature features. this.f[1] = sig.contains("java"); this.f[2] = sig.contains("lang"); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java index a912855965d..c7f866bc71a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -20,7 +20,6 @@ import qilin.util.PTAUtils; import soot.Unit; -import soot.jimple.*; import sootup.core.model.Body; import sootup.core.model.SootMethod; @@ -31,7 +30,7 @@ public class FeaturesTrueTable { private final boolean[] features = new boolean[26]; public FeaturesTrueTable(SootMethod sm) { - String sig = sm.getSignature(); + String sig = sm.getSignature().toString(); this.features[1] = sig.contains("java"); this.features[2] = sig.contains("lang"); this.features[3] = sig.contains("sun"); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java index d3f69698ca3..a4162e89643 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java @@ -8,11 +8,12 @@ import qilin.core.pag.Node; import qilin.core.pag.PAG; import qilin.core.pag.SparkField; -import soot.RefType; +import qilin.util.PTAUtils; import soot.util.queue.QueueReader; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; import sootup.core.types.Type; import java.util.Collections; @@ -103,7 +104,7 @@ private boolean isImplementingCollection(SootClass sc) { allInterfaces.addAll(worklist); boolean flag = false; for (SootClass interf : allInterfaces) { - if (interf.getType() == RefType.v("java.util.Collection") + if (interf.getType() == PTAUtils.getClassType("java.util.Collection") // || interf.getType() == RefType.v("java.util.Map") ) { flag = true; @@ -125,20 +126,20 @@ private boolean isNestedInClassImplementCollection(SootClass sc) { private void computeContainerTypes() { for (Type type : t2Fields.keySet()) { - if (type instanceof RefType refType) { + if (type instanceof ClassType refType) { SootClass sc = refType.getSootClass(); if (isImplementingCollection(sc) || isNestedInClassImplementCollection(sc)) { containerType.add(type); } else { for (SparkField sf : t2Fields.get(type)) { - if (sf.getType() == RefType.v("java.lang.Object")) { + if (sf.getType() == PTAUtils.getClassType("java.lang.Object")) { containerType.add(type); break; } } } } else if (type instanceof ArrayType at) { - if (at.baseType == RefType.v("java.lang.Object")) { + if (at.getBaseType() == PTAUtils.getClassType("java.lang.Object")) { containerType.add(at); } } else { @@ -148,21 +149,21 @@ private void computeContainerTypes() { // build a mapping from any field type to their containing type. Map> ft2t = new HashMap<>(); for (Type type : t2Fields.keySet()) { - if (type instanceof RefType) { + if (type instanceof ClassType) { for (SparkField sf : t2Fields.get(type)) { Type sft = sf.getType(); if (sft instanceof ArrayType at) { - sft = at.baseType; + sft = at.getBaseType(); } ft2t.computeIfAbsent(sft, k -> new HashSet<>()).add(type); } } else if (type instanceof ArrayType at) { - ft2t.computeIfAbsent(at.baseType, k -> new HashSet<>()).add(type); + ft2t.computeIfAbsent(at.getBaseType(), k -> new HashSet<>()).add(type); } } // find more container types by checking whether a type has a field of a container type. Set newlyFound = new HashSet<>(); - containerType.addAll(ft2t.getOrDefault(RefType.v("java.lang.Object"), Collections.emptySet())); + containerType.addAll(ft2t.getOrDefault(PTAUtils.getClassType("java.lang.Object"), Collections.emptySet())); for (Type t1 : containerType) { for (Type t2 : ft2t.getOrDefault(t1, Collections.emptySet())) { if (!containerType.contains(t2)) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java index 7e164345f0e..3d094076901 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java @@ -10,6 +10,7 @@ import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.IntConstant; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; import sootup.core.types.Type; import java.util.*; @@ -49,7 +50,7 @@ public void run() { } else { notcontainers.add(heap); } - } else if (type instanceof RefType refType) { + } else if (type instanceof ClassType refType) { if (utility.isCoarseType(refType) && heap.getMethod() != null) { remainObjs.add(heap); } else { @@ -109,8 +110,8 @@ private boolean hasNonThisLoadFromField(AllocNode heap, SparkField field, HeapCo public boolean isAContainer(AllocNode heap) { if (this.containers.containsKey(heap)) { return true; - } else if (heap.getMethod().getSignature().startsWith("") - || heap.getMethod().getSignature().startsWith("")) { + } else if (heap.getMethod().getSignature().toString().startsWith("") + || heap.getMethod().getSignature().toString().startsWith("")) { // We will remove such hacks in the future. The noise of [java.lang.String] types introduced by the resolving of reflection of // Array.newInstance makes the whole analysis imprecise. Qilin's reflection mechanism causes this. One potential solution is // not to resolve reflection for these two methods. diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java index cefcb10f017..7e966c036ca 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java @@ -5,6 +5,7 @@ import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import sootup.core.types.Type; import java.util.*; @@ -85,7 +86,7 @@ private boolean isAnInnerContainer(AllocNode heap, IntraFlowAnalysis mpag) { } Set objects = this.utility.getReceiverObjects(method); for (AllocNode revobj : objects) { - if (revobj.getType() instanceof RefType) { + if (revobj.getType() instanceof ClassType) { HeapContainerQuery hcq = this.utility.getHCQ(revobj); for (SparkField field : fields) { if (hcq.isCSField(field)) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index a2693f05862..29034902c68 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -6,11 +6,11 @@ import qilin.util.PTAUtils; import qilin.util.queue.UniqueQueue; import soot.RefLikeType; -import soot.RefType; import soot.Unit; import soot.jimple.*; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -29,7 +29,7 @@ public XPAG(PTA pta, XUtility utility) { this.pta = pta; this.pag = pta.getPag(); this.utility = utility; - this.dummyThis = new LocalVarNode("DUMMYTHIS", RefType.v("java.lang.Object"), null); + this.dummyThis = new LocalVarNode("DUMMYTHIS", PTAUtils.getClassType("java.lang.Object"), null); buildGraph(pta.getNakedReachableMethods()); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index e988ad9942d..37fe6cd0616 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -6,17 +6,18 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.RefType; import soot.jimple.InstanceInvokeExpr; import soot.jimple.InvokeExpr; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.NumberedString; import soot.util.queue.QueueReader; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; import sootup.core.types.Type; import java.util.*; @@ -71,10 +72,10 @@ public InterFlowAnalysis getInterFlowAnalysis() { } private boolean isImpreciseType(Type type) { - if (type == RefType.v("java.lang.Object")) { + if (type == PTAUtils.getClassType("java.lang.Object")) { return true; } - if (type instanceof RefType refType) { + if (type instanceof ClassType refType) { SootClass sc = refType.getSootClass(); return sc.isAbstract() || sc.isInterface() || sc.getShortName().startsWith("Abstract"); } @@ -271,7 +272,7 @@ public Set getFields(AllocNode heap) { } public Set getFields(Type type) { - if (type instanceof RefType refType) { + if (type instanceof ClassType refType) { Set ret = this.t2Fields.get(refType); if (ret != null) { return ret; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 2efc7687f17..54d2d3bc40d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -31,6 +31,7 @@ import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java index 68125ac21b5..067dfff3acd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java @@ -10,8 +10,8 @@ import qilin.util.ANSIColor; import qilin.util.Stopwatch; import qilin.util.graph.ConcurrentDirectedGraphImpl; -import soot.RefType; import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import sootup.core.types.Type; import java.util.*; @@ -98,12 +98,12 @@ public static void outputObjectFlowGraphSize(ObjectFlowGraph ofg) { public Set analyze() { reset(); System.out.println("Building PFGs (Pollution Flow Graphs) and computing precision-critical methods ..."); - List types = pta.getPag().getAllocNodes().stream() + List types = pta.getPag().getAllocNodes().stream() .map(AllocNode::getType) .distinct() .sorted(Comparator.comparing(Type::toString)) - .filter(t -> t instanceof RefType) - .map(t -> (RefType) t) + .filter(t -> t instanceof ClassType) + .map(t -> (ClassType) t) .collect(Collectors.toList()); if (Global.getThread() == Global.UNDEFINE) { computePCM(types); @@ -126,12 +126,12 @@ public Set analyze() { return pcm; } - private void computePCM(List types) { + private void computePCM(List types) { FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); types.forEach(type -> analyze(type, fa)); } - private void computePCMConcurrent(List types, int nThread) { + private void computePCMConcurrent(List types, int nThread) { ExecutorService executorService = Executors.newFixedThreadPool(nThread); types.forEach(type -> executorService.execute(() -> { @@ -151,7 +151,7 @@ private void computePCMConcurrent(List types, int nThread) { * @param fa Compute the set of precision-critical methods for a class/type and add these methods * to the pcm collection. */ - private void analyze(RefType type, FlowAnalysis fa) { + private void analyze(ClassType type, FlowAnalysis fa) { if (Global.isDebug()) { System.out.println("----------------------------------------"); } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index 31f34f7a4a5..e43103c2842 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -32,6 +32,7 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 2e501f5c507..b099f6a9d9a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -34,6 +34,7 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index 82cee5ed6b0..c3c81e8f75b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -34,6 +34,7 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 71c5ce4c15c..b4eb88655ce 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -33,7 +33,6 @@ import qilin.util.queue.UniqueQueue; import soot.Context; import soot.MethodOrMethodContext; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.NumberedString; @@ -50,7 +49,10 @@ import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; +import sootup.core.types.PrimitiveType; import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; import java.io.*; import java.net.URL; @@ -62,7 +64,11 @@ public final class PTAUtils { private static final Logger logger = LoggerFactory.getLogger(PTAUtils.class); static final String output_dir = CoreConfig.v().getOutConfig().outDir; static Map nodes = new TreeMap<>(); - private static final RefType clRunnable = RefType.v("java.lang.Runnable"); + private static final ClassType clRunnable = getClassType("java.lang.Runnable"); + + public static ClassType getClassType(String fullyQualifiedClassName) { + return JavaIdentifierFactory.getInstance().getClassType(fullyQualifiedClassName); + } public static Map> calcStaticThisPTS(PTA pta) { Map> pts = new HashMap<>(); @@ -548,7 +554,7 @@ public static boolean isThrowable(Type type) { } public static boolean subtypeOfAbstractStringBuilder(Type t) { - if (!(t instanceof RefType rt)) { + if (!(t instanceof ClassType rt)) { return false; } String s = rt.toString(); @@ -558,7 +564,7 @@ public static boolean subtypeOfAbstractStringBuilder(Type t) { public static boolean supportFinalize(AllocNode heap) { NumberedString sigFinalize = PTAScene.v().getSubSigNumberer().findOrAdd("void finalize()"); Type type = heap.getType(); - if (type instanceof RefType refType && type != RefType.v("java.lang.Object")) { + if (type instanceof ClassType refType && type != PTAUtils.getClassType("java.lang.Object")) { SootMethod finalizeMethod = VirtualCalls.v().resolveNonSpecial(refType, sigFinalize); if (finalizeMethod != null && finalizeMethod.toString().equals("")) { return false; @@ -628,14 +634,14 @@ private static void initEmptyHeapContextTypes() { public static boolean isOfPrimitiveBaseType(AllocNode heap) { if (heap.getType() instanceof ArrayType arrayType) { - return arrayType.baseType instanceof PrimType; + return arrayType.getBaseType() instanceof PrimitiveType; } return false; } public static boolean isPrimitiveArrayType(Type type) { if (type instanceof ArrayType arrayType) { - return arrayType.getArrayElementType() instanceof PrimType; + return arrayType.getArrayElementType() instanceof PrimitiveType; } return false; } @@ -648,7 +654,7 @@ public static boolean isPrimitiveArrayType(Type type) { public static boolean enforceEmptyContext(AllocNode probe) { // primitive array objects should be context-insenstive. if (probe.getType() instanceof ArrayType arrayType) { - if (arrayType.getArrayElementType() instanceof PrimType) { + if (arrayType.getArrayElementType() instanceof PrimitiveType) { return true; } } @@ -762,10 +768,10 @@ public static String findMainFromMetaInfo(String appPath) { public static SootClass getSootClass(Type type) { SootClass allocated = null; - if (type instanceof RefType) { - allocated = ((RefType) type).getSootClass(); - } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof RefType) { - allocated = ((RefType) ((ArrayType) type).getArrayElementType()).getSootClass(); + if (type instanceof ClassType) { + allocated = ((ClassType) type).getSootClass(); + } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof ClassType) { + allocated = ((ClassType) ((ArrayType) type).getArrayElementType()).getSootClass(); } return allocated; } From 44f851ce1fab7c6219098b5dd62805b2bea21a04 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sat, 16 Sep 2023 21:28:45 +1000 Subject: [PATCH 011/145] replace Unit with Stmt --- .../qilin/core/builder/ExceptionHandler.java | 3 +- .../main/java/qilin/core/pag/CallSite.java | 8 +-- .../qilin/core/pag/ExceptionThrowSite.java | 8 +-- .../main/java/qilin/core/pag/MethodPAG.java | 18 +++---- .../src/main/java/qilin/core/pag/PAG.java | 17 +++---- .../core/reflection/NopReflectionModel.java | 19 ++++--- .../core/reflection/ReflectionModel.java | 32 ++++++------ .../qilin/core/reflection/TamiflexModel.java | 51 ++++++++++--------- .../main/java/qilin/core/solver/Solver.java | 5 +- .../java/qilin/pta/toolkits/conch/Conch.java | 3 +- .../toolkits/conch/DepOnParamAnalysis.java | 2 +- .../dd/CtxTunnelingFeaturesTrueTable.java | 3 +- .../pta/toolkits/dd/FeaturesTrueTable.java | 4 +- .../qilin/pta/toolkits/debloaterx/XPAG.java | 3 +- .../java/qilin/pta/toolkits/eagle/Eagle.java | 4 +- .../qilin/pta/toolkits/selectx/Selectx.java | 9 ++-- .../pta/toolkits/turner/AbstractMVFG.java | 6 +-- .../java/qilin/pta/toolkits/turner/OCG.java | 5 +- .../pta/tools/PartialCallSiteSensPTA.java | 5 +- .../qilin/pta/tools/PartialObjSensPTA.java | 5 +- .../main/java/qilin/pta/tools/ZipperPTA.java | 5 +- .../src/main/java/qilin/stat/Exporter.java | 6 +-- .../java/qilin/stat/SimplifiedEvaluator.java | 3 +- .../main/java/qilin/stat/TypeClientStat.java | 4 +- .../src/main/java/qilin/stat/YummyStat.java | 6 +-- .../src/main/java/qilin/util/PTAUtils.java | 18 +++---- .../jimple/toolkits/callgraph/CallGraph.java | 13 +++-- .../soot/jimple/toolkits/callgraph/Edge.java | 9 ++-- 28 files changed, 126 insertions(+), 148 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index 2d561450fba..5def737b49a 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -28,6 +28,7 @@ import soot.MethodOrMethodContext; import soot.jimple.IdentityStmt; import sootup.core.jimple.basic.Trap; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.Type; @@ -74,7 +75,7 @@ public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { List trapList = mpag.stmt2wrapperedTraps.getOrDefault(site.getUnit(), Collections.emptyList()); for (Trap trap : trapList) { if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, trap.getException().getType())) { - Unit handler = trap.getHandlerUnit(); + Stmt handler = trap.getHandlerUnit(); assert handler instanceof IdentityStmt; IdentityStmt handlerStmt = (IdentityStmt) handler; Node caughtParam = nodeFactory.getNode(handlerStmt.getRightOp()); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java index 3bd957c380c..8e31efd4d52 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java @@ -19,20 +19,20 @@ package qilin.core.pag; import qilin.core.context.ContextElement; -import soot.Unit; +import sootup.core.jimple.common.stmt.Stmt; /** * callsite based context element in the points to analysis. */ public class CallSite implements ContextElement { - private final Unit unit; + private final Stmt unit; - public CallSite(Unit unit) { + public CallSite(Stmt unit) { this.unit = unit; } - public Unit getUnit() { + public Stmt getUnit() { return unit; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java index e9d8fbc5350..554997ebc29 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java @@ -19,16 +19,16 @@ package qilin.core.pag; import soot.MethodOrMethodContext; -import soot.Unit; +import sootup.core.jimple.common.stmt.Stmt; import java.util.Objects; public class ExceptionThrowSite { - private final Unit unit; + private final Stmt unit; private final VarNode throwNode; private final MethodOrMethodContext container; - public ExceptionThrowSite(VarNode throwNode, Unit unit, MethodOrMethodContext container) { + public ExceptionThrowSite(VarNode throwNode, Stmt unit, MethodOrMethodContext container) { this.unit = unit; this.container = container; this.throwNode = throwNode; @@ -42,7 +42,7 @@ public VarNode getThrowNode() { return throwNode; } - public Unit getUnit() { + public Stmt getUnit() { return unit; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index fd5d13d9306..3389a17f598 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -45,7 +45,7 @@ public class MethodPAG { private final ChunkedQueue internalEdges = new ChunkedQueue<>(); private final QueueReader internalReader = internalEdges.reader(); private final Set clinits = DataFactory.createSet(); - private final Collection invokeStmts = DataFactory.createSet(); + private final Collection invokeStmts = DataFactory.createSet(); public Body body; /** * Since now the exception analysis is handled on-the-fly, we should record the @@ -78,11 +78,11 @@ public MethodNodeFactory nodeFactory() { return nodeFactory; } - public Collection getInvokeStmts() { + public Collection getInvokeStmts() { return invokeStmts; } - public boolean addCallStmt(Unit unit) { + public boolean addCallStmt(Stmt unit) { return this.invokeStmts.add(unit); } @@ -100,9 +100,9 @@ protected void buildNormal() { if (method.isStatic()) { PTAUtils.clinitsOf(method.getDeclaringClass()).forEach(this::addTriggeredClinit); } - for (Unit unit : body.getUnits()) { + for (Stmt unit : body.getStmts()) { try { - nodeFactory.handleStmt((Stmt) unit); + nodeFactory.handleStmt(unit); } catch (Exception e) { System.out.println("Warning:" + e); } @@ -115,8 +115,8 @@ protected void buildException() { return; } List traps = body.getTraps(); - PatchingChain units = body.getUnits(); - Set inTraps = DataFactory.createSet(); + List units = body.getStmts(); + Set inTraps = DataFactory.createSet(); /* * The traps is already visited in order. , ; implies is a previous Trap of . * */ @@ -140,11 +140,11 @@ protected void buildException() { }); }); - for (Unit unit : body.getUnits()) { + for (Stmt unit : body.getStmts()) { if (inTraps.contains(unit)) { continue; } - Stmt stmt = (Stmt) unit; + Stmt stmt = unit; Node src = null; if (stmt.containsInvokeExpr()) { src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index c55493fbfb8..f9e42e5387d 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -551,10 +551,9 @@ public MethodPAG getMethodPAG(SootMethod m) { } private void handleArrayCopy(SootMethod method) { - Map> newUnits = DataFactory.createMap(); + Map> newUnits = DataFactory.createMap(); Body body = PTAUtils.getMethodBody(method); - for (Unit unit : body.getUnits()) { - Stmt s = (Stmt) unit; + for (Stmt s : body.getStmts()) { if (s.containsInvokeExpr()) { InvokeExpr invokeExpr = s.getInvokeExpr(); if (invokeExpr instanceof StaticInvokeExpr sie) { @@ -569,7 +568,7 @@ private void handleArrayCopy(SootMethod method) { if (srcArr.getType() == objType) { Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); body.getLocals().add(localSrc); - newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr)); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr)); srcArr = localSrc; } Value dstArr = sie.getArg(2); @@ -579,20 +578,20 @@ private void handleArrayCopy(SootMethod method) { if (dstArr.getType() == objType) { Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); body.getLocals().add(localDst); - newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr)); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr)); dstArr = localDst; } Value src = new JArrayRef(srcArr, IntConstant.v(0)); Value dst = new JArrayRef(dstArr, IntConstant.v(0)); - Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), RefType.v("java.lang.Object")); + Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), PTAUtils.getClassType("java.lang.Object")); body.getLocals().add(local); - newUnits.computeIfAbsent(unit, k -> DataFactory.createSet()).add(new JAssignStmt(local, src)); - newUnits.computeIfAbsent(unit, k -> DataFactory.createSet()).add(new JAssignStmt(dst, local)); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(local, src)); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(dst, local)); } } } } - for (Unit unit : newUnits.keySet()) { + for (Stmt unit : newUnits.keySet()) { body.getUnits().insertAfter(newUnits.get(unit), unit); } } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java index 46cfb72c032..86cedb19b89 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java @@ -18,7 +18,6 @@ package qilin.core.reflection; -import soot.Unit; import sootup.core.jimple.common.stmt.Stmt; import java.util.Collection; @@ -31,47 +30,47 @@ public class NopReflectionModel extends ReflectionModel { @Override - Collection transformClassForName(Stmt s) { + Collection transformClassForName(Stmt s) { return Collections.emptySet(); } @Override - Collection transformClassNewInstance(Stmt s) { + Collection transformClassNewInstance(Stmt s) { return Collections.emptySet(); } @Override - Collection transformContructorNewInstance(Stmt s) { + Collection transformContructorNewInstance(Stmt s) { return Collections.emptySet(); } @Override - Collection transformMethodInvoke(Stmt s) { + Collection transformMethodInvoke(Stmt s) { return Collections.emptySet(); } @Override - Collection transformFieldSet(Stmt s) { + Collection transformFieldSet(Stmt s) { return Collections.emptySet(); } @Override - Collection transformFieldGet(Stmt s) { + Collection transformFieldGet(Stmt s) { return Collections.emptySet(); } @Override - Collection transformArrayNewInstance(Stmt s) { + Collection transformArrayNewInstance(Stmt s) { return Collections.emptySet(); } @Override - Collection transformArrayGet(Stmt s) { + Collection transformArrayGet(Stmt s) { return Collections.emptySet(); } @Override - Collection transformArraySet(Stmt s) { + Collection transformArraySet(Stmt s) { return Collections.emptySet(); } } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index c9366915777..53bf448b626 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -21,7 +21,6 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.Unit; import soot.UnitPatchingChain; import soot.jimple.InvokeExpr; import sootup.core.jimple.common.stmt.Stmt; @@ -51,7 +50,7 @@ public abstract class ReflectionModel { protected final String sigReifiedMethodArray = ""; protected final String sigReifiedDeclaredMethodArray = ""; - private Collection transform(Stmt s) { + private Collection transform(Stmt s) { InvokeExpr ie = s.getInvokeExpr(); return switch (ie.getMethodRef().getSignature()) { case sigForName, sigForName2 -> transformClassForName(s); @@ -74,34 +73,33 @@ public void buildReflection(SootMethod m) { if (!PTAScene.v().reflectionBuilt.add(m)) { return; } - Map> newUnits = DataFactory.createMap(); + Map> newUnits = DataFactory.createMap(); UnitPatchingChain units = PTAUtils.getMethodBody(m).getUnits(); - for (final Unit u : units) { - final Stmt s = (Stmt) u; - if (s.containsInvokeExpr()) { - newUnits.put(u, transform(s)); + for (final Stmt u : units) { + if (u.containsInvokeExpr()) { + newUnits.put(u, transform(u)); } } - for (Unit unit : newUnits.keySet()) { + for (Stmt unit : newUnits.keySet()) { units.insertAfter(newUnits.get(unit), unit); } } - abstract Collection transformClassForName(Stmt s); + abstract Collection transformClassForName(Stmt s); - abstract Collection transformClassNewInstance(Stmt s); + abstract Collection transformClassNewInstance(Stmt s); - abstract Collection transformContructorNewInstance(Stmt s); + abstract Collection transformContructorNewInstance(Stmt s); - abstract Collection transformMethodInvoke(Stmt s); + abstract Collection transformMethodInvoke(Stmt s); - abstract Collection transformFieldSet(Stmt s); + abstract Collection transformFieldSet(Stmt s); - abstract Collection transformFieldGet(Stmt s); + abstract Collection transformFieldGet(Stmt s); - abstract Collection transformArrayNewInstance(Stmt s); + abstract Collection transformArrayNewInstance(Stmt s); - abstract Collection transformArrayGet(Stmt s); + abstract Collection transformArrayGet(Stmt s); - abstract Collection transformArraySet(Stmt s); + abstract Collection transformArraySet(Stmt s); } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index e778fa35b71..db9c8279c59 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -25,11 +25,14 @@ import soot.jimple.*; import soot.jimple.internal.*; import soot.tagkit.LineNumberTag; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; +import sootup.core.model.SootField; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; import sootup.core.types.Type; @@ -53,10 +56,10 @@ public TamiflexModel() { } @Override - Collection transformClassForName(Stmt s) { + Collection transformClassForName(Stmt s) { // // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> classForNames = reflectionMap.getOrDefault(ReflectionKind.ClassForName, Collections.emptyMap()); if (classForNames.containsKey(s)) { Collection fornames = classForNames.get(s); @@ -73,13 +76,13 @@ Collection transformClassForName(Stmt s) { } @Override - protected Collection transformClassNewInstance(Stmt s) { + protected Collection transformClassNewInstance(Stmt s) { // if (!(s instanceof AssignStmt)) { return Collections.emptySet(); } Value lvalue = ((AssignStmt) s).getLeftOp(); - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> classNewInstances = reflectionMap.getOrDefault(ReflectionKind.ClassNewInstance, Collections.emptyMap()); if (classNewInstances.containsKey(s)) { Collection classNames = classNewInstances.get(s); @@ -97,13 +100,13 @@ protected Collection transformClassNewInstance(Stmt s) { } @Override - protected Collection transformContructorNewInstance(Stmt s) { + protected Collection transformContructorNewInstance(Stmt s) { // if (!(s instanceof AssignStmt)) { return Collections.emptySet(); } Value lvalue = ((AssignStmt) s).getLeftOp(); - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> constructorNewInstances = reflectionMap.getOrDefault(ReflectionKind.ConstructorNewInstance, Collections.emptyMap()); if (constructorNewInstances.containsKey(s)) { Collection constructorSignatures = constructorNewInstances.get(s); @@ -129,9 +132,9 @@ protected Collection transformContructorNewInstance(Stmt s) { } @Override - protected Collection transformMethodInvoke(Stmt s) { + protected Collection transformMethodInvoke(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> methodInvokes = reflectionMap.getOrDefault(ReflectionKind.MethodInvoke, Collections.emptyMap()); if (methodInvokes.containsKey(s)) { Collection methodSignatures = methodInvokes.get(s); @@ -172,9 +175,9 @@ protected Collection transformMethodInvoke(Stmt s) { } @Override - protected Collection transformFieldSet(Stmt s) { + protected Collection transformFieldSet(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> fieldSets = reflectionMap.getOrDefault(ReflectionKind.FieldSet, Collections.emptyMap()); if (fieldSets.containsKey(s)) { Collection fieldSignatures = fieldSets.get(s); @@ -199,9 +202,9 @@ protected Collection transformFieldSet(Stmt s) { } @Override - protected Collection transformFieldGet(Stmt s) { + protected Collection transformFieldGet(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> fieldGets = reflectionMap.getOrDefault(ReflectionKind.FieldGet, Collections.emptyMap()); if (fieldGets.containsKey(s) && s instanceof AssignStmt) { Collection fieldSignatures = fieldGets.get(s); @@ -228,9 +231,9 @@ protected Collection transformFieldGet(Stmt s) { } @Override - protected Collection transformArrayNewInstance(Stmt s) { + protected Collection transformArrayNewInstance(Stmt s) { // - Collection ret = DataFactory.createSet(); + Collection ret = DataFactory.createSet(); Map> mappedToArrayTypes = reflectionMap.getOrDefault(ReflectionKind.ArrayNewInstance, Collections.emptyMap()); Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); for (String arrayType : arrayTypes) { @@ -245,8 +248,8 @@ protected Collection transformArrayNewInstance(Stmt s) { } @Override - Collection transformArrayGet(Stmt s) { - Collection ret = DataFactory.createSet(); + Collection transformArrayGet(Stmt s) { + Collection ret = DataFactory.createSet(); InvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); if (s instanceof AssignStmt) { @@ -267,8 +270,8 @@ Collection transformArrayGet(Stmt s) { } @Override - Collection transformArraySet(Stmt s) { - Collection ret = DataFactory.createSet(); + Collection transformArraySet(Stmt s) { + Collection ret = DataFactory.createSet(); InvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); if (base.getType() instanceof ArrayType) { @@ -377,13 +380,11 @@ private Collection inferSourceStmt(String inClzDotMthd, ReflectionKind kin Collection sourceMethods = inferSourceMethod(inClzDotMthd); for (SootMethod sm : sourceMethods) { Body body = PTAUtils.getMethodBody(sm); - for (Unit u : body.getUnits()) { - if (u instanceof Stmt stmt) { - if (stmt.containsInvokeExpr()) { - String methodSig = stmt.getInvokeExpr().getMethodRef().getSignature(); - if (matchReflectionKind(kind, methodSig)) { - potential.add(stmt); - } + for (Stmt stmt : body.getStmts()) { + if (stmt.containsInvokeExpr()) { + String methodSig = stmt.getInvokeExpr().getMethodRef().getSignature(); + if (matchReflectionKind(kind, methodSig)) { + potential.add(stmt); } } } diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 24a7886ec65..5bcf1998c6d 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -127,9 +127,8 @@ public void processStmts(Iterator newRMs) { } } - private void recordCallStmts(MethodOrMethodContext m, Collection units) { - for (final Unit u : units) { - final Stmt s = (Stmt) u; + private void recordCallStmts(MethodOrMethodContext m, Collection units) { + for (final Stmt s : units) { if (s.containsInvokeExpr()) { InvokeExpr ie = s.getInvokeExpr(); if (ie instanceof InstanceInvokeExpr iie) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index 23e982f744c..b55436d6c1a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -24,7 +24,6 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.Unit; import soot.jimple.InvokeExpr; import soot.jimple.InvokeStmt; import soot.jimple.SpecialInvokeExpr; @@ -68,7 +67,7 @@ private SootMethod findInvokedConstructorOf(AllocNode heap) { SootMethod containingMethod = heap.getMethod(); MethodPAG cmpag = pag.getMethodPAG(containingMethod); MethodNodeFactory nodeFactory = cmpag.nodeFactory(); - for (Unit unit : cmpag.getInvokeStmts()) { + for (Stmt unit : cmpag.getInvokeStmts()) { if (unit instanceof InvokeStmt invokeStmt) { InvokeExpr expr = invokeStmt.getInvokeExpr(); if (expr instanceof SpecialInvokeExpr iie) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index 27c74a83221..cca8dce7565 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -118,7 +118,7 @@ public void run() { SootMethod srcMethod = edge.src(); MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); MethodNodeFactory srcnf = srcmpag.nodeFactory(); - Stmt invokeStmt = (Stmt) edge.srcUnit(); + Stmt invokeStmt = edge.srcUnit(); if (invokeStmt instanceof AssignStmt assignStmt) { VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index 861856458fd..92eba5d716d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -21,6 +21,7 @@ import qilin.util.PTAUtils; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; @@ -52,7 +53,7 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm) { Body body = PTAUtils.getMethodBody(sm); this.f[15] = body.getLocalCount() > 0; int heapAllocCnt = 0; - for (Unit unit : body.getUnits()) { + for (Stmt unit : body.getStmts()) { if (unit instanceof AssignStmt assignStmt) { Value left = assignStmt.getLeftOp(); if (left instanceof Local) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java index c7f866bc71a..e7bd80278df 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -19,7 +19,7 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; -import soot.Unit; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootMethod; @@ -42,7 +42,7 @@ public FeaturesTrueTable(SootMethod sm) { this.features[9] = sig.contains("String"); this.features[10] = sig.contains("init"); Body body = PTAUtils.getMethodBody(sm); - for (Unit unit : body.getUnits()) { + for (Stmt unit : body.getStmts()) { if (unit instanceof AssignStmt) { this.features[11] = true; } else if (unit instanceof IdentityStmt) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index 29034902c68..9cff66d312b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -6,7 +6,6 @@ import qilin.util.PTAUtils; import qilin.util.queue.UniqueQueue; import soot.RefLikeType; -import soot.Unit; import soot.jimple.*; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; @@ -71,7 +70,7 @@ protected void buildInternalWithInline(SootMethod method) { } // global-local } // handle call statements. - for (final Unit u : srcmpag.getInvokeStmts()) { + for (final Stmt u : srcmpag.getInvokeStmts()) { final Stmt s = (Stmt) u; InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index 4cb5bb8b9eb..c1bda9c96e6 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -27,12 +27,12 @@ import qilin.util.Util; import qilin.util.queue.UniqueQueue; import soot.RefLikeType; -import soot.Unit; import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -320,7 +320,7 @@ else if (to instanceof FieldRefNode fr) { } // add invoke edges - for (final Unit u : srcmpag.getInvokeStmts()) { + for (final Stmt u : srcmpag.getInvokeStmts()) { final Stmt s = (Stmt) u; InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index 936b7d170e8..07c134149cd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -26,7 +26,6 @@ import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; @@ -265,10 +264,8 @@ private void buildGraph() { // add invoke edges MethodNodeFactory srcnf = srcmpag.nodeFactory(); - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - - CallSite callSite = new CallSite(u); + for (final Stmt s : srcmpag.getInvokeStmts()) { + CallSite callSite = new CallSite(s); InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; @@ -290,7 +287,7 @@ private void buildGraph() { if (ie instanceof InstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } - for (Iterator it = prePTA.getCallGraph().edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = prePTA.getCallGraph().edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 54d2d3bc40d..d1de2a3b402 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -25,7 +25,6 @@ import qilin.util.Pair; import qilin.util.queue.UniqueQueue; import soot.RefLikeType; -import soot.Unit; import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; @@ -152,8 +151,7 @@ else if (to instanceof FieldRefNode fr) { }); // add invoke edges - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; + for (final Stmt s : srcmpag.getInvokeStmts()) { InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; @@ -179,7 +177,7 @@ else if (to instanceof FieldRefNode fr) { } Set targets = new HashSet<>(); - for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); targets.add(tgtmtd); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java index 8c20211b81e..43d26b29d30 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -26,6 +26,7 @@ import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.PrimitiveType; import sootup.core.types.Type; import java.util.*; @@ -56,7 +57,7 @@ protected void buildGraph() { SparkField f = contextField.getField(); if (f.getType() instanceof ArrayType at) { - if (at.baseType instanceof PrimType) { + if (at.getBaseType() instanceof PrimitiveType) { return; } } @@ -248,7 +249,7 @@ boolean isFactoryObject(AllocNode heap) { return false; } if (retType instanceof ArrayType at) { - if (at.baseType instanceof PrimType) { + if (at.getBaseType() instanceof PrimitiveType) { return false; } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index e43103c2842..b2e4250d302 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -28,7 +28,6 @@ import qilin.util.PTAUtils; import qilin.util.Stopwatch; import soot.MethodOrMethodContext; -import soot.jimple.*; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; @@ -144,9 +143,7 @@ protected void extraStats() { } } } - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - + for (final Stmt s : srcmpag.getInvokeStmts()) { InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index b099f6a9d9a..21d69ae35f8 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -30,7 +30,6 @@ import qilin.util.PTAUtils; import qilin.util.Stopwatch; import soot.MethodOrMethodContext; -import soot.jimple.*; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; @@ -145,9 +144,7 @@ protected void extraStats() { } } } - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - + for (final Stmt s : srcmpag.getInvokeStmts()) { InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index c3c81e8f75b..1b524f8211f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -30,7 +30,6 @@ import qilin.pta.toolkits.zipper.Main; import qilin.util.Stopwatch; import soot.MethodOrMethodContext; -import soot.jimple.*; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; @@ -115,9 +114,7 @@ protected void extraStats() { } } } - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - + for (final Stmt s : srcmpag.getInvokeStmts()) { InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index 4f3c93ff3fc..5458c72d9f1 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -175,7 +175,7 @@ public void dumpMethodThrowPointsto(Map m2pts) { StringBuilder builder = new StringBuilder(); builder.append(n.toString()); builder.append("\t"); - String sig = Util.stripQuotes(sm.getSignature()); + String sig = Util.stripQuotes(sm.getSignature().toString()); builder.append(sig); builder.append("\n"); try { @@ -201,8 +201,8 @@ public void dumpInsensCallGraph(CallGraph ciCallGraph) { mfile.createNewFile(); BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); for (Edge edge : ciCallGraph) { - String srcSig = Util.stripQuotes(edge.src().getSignature()); - String dstSig = Util.stripQuotes(edge.tgt().getSignature()); + String srcSig = Util.stripQuotes(edge.src().getSignature().toString()); + String dstSig = Util.stripQuotes(edge.tgt().getSignature().toString()); String str = edge.srcStmt() + " in method " + srcSig + "\t" + dstSig + "\n"; writer.write(str); } diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index 3a291004b35..0db797b0c4d 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -73,8 +73,7 @@ public void end() { int totalCastsMayFail = 0; for (SootMethod sm : reachableMethods) { // All the statements in the method - for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { - Stmt st = (Stmt) unit; + for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { // virtual calls if (st.containsInvokeExpr()) { InvokeExpr ie = st.getInvokeExpr(); diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index 6725aaf15a8..738eb792454 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -72,9 +72,7 @@ private void init() { boolean app = sm.getDeclaringClass().isApplicationClass(); // All the statements in the method - for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { - Stmt st = (Stmt) unit; - + for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { // virtual calls if (st.containsInvokeExpr()) { InvokeExpr ie = st.getInvokeExpr(); diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java index abbdbedb9a9..9fea2dc0db7 100644 --- a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -23,9 +23,9 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.sets.PointsToSet; import soot.MethodOrMethodContext; -import soot.Unit; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import java.util.HashMap; @@ -48,10 +48,10 @@ public YummyStat(PTA pta) { } private void init() { - Map> target2callsites = new HashMap<>(); + Map> target2callsites = new HashMap<>(); CallGraph ciCallGraph = pta.getCallGraph(); for (Edge edge : ciCallGraph) { - Unit callUnit = edge.srcUnit(); + Stmt callUnit = edge.srcUnit(); SootMethod target = edge.tgt(); if (callUnit != null && target != null) { target2callsites.computeIfAbsent(target, k -> new HashSet<>()).add(callUnit); diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index b4eb88655ce..b0f2ee765fc 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -32,6 +32,7 @@ import qilin.core.sets.PointsToSetInternal; import qilin.util.queue.UniqueQueue; import soot.Context; +import soot.Kind; import soot.MethodOrMethodContext; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; @@ -50,6 +51,7 @@ import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; +import sootup.core.types.NullType; import sootup.core.types.PrimitiveType; import sootup.core.types.Type; import sootup.java.core.JavaIdentifierFactory; @@ -81,11 +83,10 @@ public static Map> calcStaticThisPTS(PTA pta) { LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); final PointsToSet other = pta.reachingObjects(thisRef).toCIPointsToSet(); - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; + for (final Stmt s : srcmpag.getInvokeStmts()) { AbstractInvokeExpr ie = s.getInvokeExpr(); if (ie instanceof StaticInvokeExpr) { - for (Iterator it = pta.getCallGraph().edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); @@ -115,11 +116,10 @@ public static Map> calcStaticThisPTS(PTA pta) { LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); final Set other = pts.computeIfAbsent(thisRef, k -> new HashSet<>()); - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; + for (final Stmt s : srcmpag.getInvokeStmts()) { AbstractInvokeExpr ie = s.getInvokeExpr(); if (ie instanceof StaticInvokeExpr) { - for (Iterator it = pta.getCallGraph().edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); @@ -258,7 +258,7 @@ public static boolean isUnresolved(Type type) { if (type instanceof ArrayType at) { type = at.getArrayElementType(); } - if (!(type instanceof RefType rt)) + if (!(type instanceof ClassType rt)) return false; // if (!rt.hasSootClass()) { // return true; @@ -547,8 +547,8 @@ private static void drawInvPAGMap(DotGraph canvas, Map { protected ChunkedQueue stream = new ChunkedQueue(); protected QueueReader reader = stream.reader(); protected Map srcMethodToEdge = new LinkedHashMap(); - protected Map srcUnitToEdge = new LinkedHashMap(); + protected Map srcUnitToEdge = new LinkedHashMap(); protected Map tgtToEdge = new LinkedHashMap(); protected Edge dummy = new Edge(null, null, null, Kind.INVALID); @@ -94,7 +93,7 @@ public boolean addEdge(Edge e) { * The unit from which to remove all outgoing edges * @return True if at least one edge has been removed, otherwise false */ - public boolean removeAllEdgesOutOf(Unit u) { + public boolean removeAllEdgesOutOf(Stmt u) { boolean hasRemoved = false; Set edgesToRemove = new HashSet<>(); for (QueueReader edgeRdr = listener(); edgeRdr.hasNext();) { @@ -226,7 +225,7 @@ public boolean isEntryMethod(SootMethod method) { * @param callee * @return */ - public Edge findEdge(Unit u, SootMethod callee) { + public Edge findEdge(Stmt u, SootMethod callee) { Edge e = srcUnitToEdge.get(u); if (e != null) { while (e.srcUnit() == u && e.kind() != Kind.INVALID) { @@ -249,15 +248,15 @@ public Iterator sourceMethods() { /** * Returns an iterator over all edges that have u as their source unit. */ - public Iterator edgesOutOf(Unit u) { + public Iterator edgesOutOf(Stmt u) { return new TargetsOfUnitIterator(u); } class TargetsOfUnitIterator implements Iterator { - private final Unit u; + private final Stmt u; private Edge position; - TargetsOfUnitIterator(Unit u) { + TargetsOfUnitIterator(Stmt u) { this.u = u; if (u == null) { throw new RuntimeException(); diff --git a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java index 6af3a9983e0..89bdc379335 100644 --- a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java +++ b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java @@ -25,7 +25,6 @@ import soot.Context; import soot.Kind; import soot.MethodOrMethodContext; -import soot.Unit; import soot.jimple.InterfaceInvokeExpr; import soot.jimple.InvokeExpr; import soot.jimple.SpecialInvokeExpr; @@ -57,7 +56,7 @@ public final class Edge implements Invalidable { * The unit at which the call occurs; may be null for calls not occurring at a specific statement (eg. calls in native * code) */ - private Unit srcUnit; + private Stmt srcUnit; /** * The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as isExplicit() should be @@ -67,7 +66,7 @@ public final class Edge implements Invalidable { private boolean invalid = false; - public Edge(MethodOrMethodContext src, Unit srcUnit, MethodOrMethodContext tgt, Kind kind) { + public Edge(MethodOrMethodContext src, Stmt srcUnit, MethodOrMethodContext tgt, Kind kind) { this.src = src; this.srcUnit = srcUnit; this.tgt = tgt; @@ -93,12 +92,12 @@ public MethodOrMethodContext getSrc() { return src; } - public Unit srcUnit() { + public Stmt srcUnit() { return srcUnit; } public Stmt srcStmt() { - return (Stmt) srcUnit; + return srcUnit; } public SootMethod tgt() { From 366fd3a9d353a5669f28d0f927256bfa68fa8902 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 17 Sep 2023 09:41:40 +1000 Subject: [PATCH 012/145] replace RefLikeType with ReferenceType --- .../qilin/core/builder/CallGraphBuilder.java | 18 ++++--- .../java/qilin/core/pag/MergedNewExpr.java | 10 ++-- .../src/main/java/qilin/core/pag/VarNode.java | 3 +- .../core/reflection/ReflectionModel.java | 4 +- .../parm/heapabst/HeuristicAbstractor.java | 3 +- .../qilin/pta/toolkits/common/ToolUtil.java | 7 ++- .../qilin/pta/toolkits/conch/AbstractPAG.java | 6 +-- .../java/qilin/pta/toolkits/conch/Conch.java | 5 +- .../pta/toolkits/debloaterx/DebloaterX.java | 5 +- .../debloaterx/HeapContainerQuery.java | 3 +- .../qilin/pta/toolkits/debloaterx/XPAG.java | 21 ++++---- .../java/qilin/pta/toolkits/eagle/Eagle.java | 20 ++++--- .../qilin/pta/toolkits/selectx/Selectx.java | 10 ++-- .../pta/toolkits/turner/AbstractMVFG.java | 16 +++--- .../pta/toolkits/turner/ModularMVFG.java | 6 +-- .../java/qilin/pta/toolkits/turner/OCG.java | 3 +- .../zipper/flowgraph/FlowAnalysis.java | 3 +- .../pta/tools/PartialCallSiteSensPTA.java | 5 +- .../qilin/pta/tools/PartialObjSensPTA.java | 5 +- .../main/java/qilin/pta/tools/ZipperPTA.java | 5 +- .../main/java/qilin/stat/PointsToStat.java | 3 +- .../java/qilin/stat/SimplifiedEvaluator.java | 6 +-- .../main/java/qilin/stat/TypeClientStat.java | 4 +- .../java/soot/util/dot/DotGraphConstants.java | 53 ++++++++++++++++++- 24 files changed, 142 insertions(+), 82 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 9b50a50a23b..34bdca1c33a 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -38,8 +38,10 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.*; @@ -99,12 +101,12 @@ public CallGraph getCICallGraph() { private void constructCallGraph() { cicg = new CallGraph(); - Map>> map = DataFactory.createMap(); + Map>> map = DataFactory.createMap(); calledges.forEach(e -> { PTAScene.v().getCallGraph().addEdge(e); SootMethod src = e.src(); SootMethod tgt = e.tgt(); - Unit unit = e.srcUnit(); + Stmt unit = e.srcUnit(); Map> submap = map.computeIfAbsent(unit, k -> DataFactory.createMap()); Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); if (set.add(tgt)) { @@ -148,7 +150,7 @@ protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { } } - private void addVirtualEdge(MethodOrMethodContext caller, Unit callStmt, SootMethod callee, Kind kind, AllocNode receiverNode) { + private void addVirtualEdge(MethodOrMethodContext caller, Stmt callStmt, SootMethod callee, Kind kind, AllocNode receiverNode) { Context tgtContext = pta.createCalleeCtx(caller, receiverNode, new CallSite(callStmt), callee); MethodOrMethodContext cstarget = pta.parameterize(callee, tgtContext); handleCallEdge(new Edge(caller, callStmt, cstarget, kind)); @@ -167,7 +169,7 @@ public void injectCallEdge(Object heapOrType, MethodOrMethodContext callee, Kind } } - public void addStaticEdge(MethodOrMethodContext caller, Unit callStmt, SootMethod calleem, Kind kind) { + public void addStaticEdge(MethodOrMethodContext caller, Stmt callStmt, SootMethod calleem, Kind kind) { Context typeContext = pta.createCalleeCtx(caller, null, new CallSite(callStmt), calleem); MethodOrMethodContext callee = pta.parameterize(calleem, typeContext); handleCallEdge(new Edge(caller, callStmt, callee, kind)); @@ -215,11 +217,11 @@ private void processCallAssign(Edge e) { int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } Type tgtType = tgtmtd.getParameterType(i); - if (!(tgtType instanceof RefLikeType)) { + if (!(tgtType instanceof ReferenceType)) { continue; } Node argNode = srcnf.getNode(arg); @@ -232,10 +234,10 @@ private void processCallAssign(Edge e) { if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { Node destNode = srcnf.getNode(dest); destNode = pta.parameterize(destNode, srcContext); - if (tgtmtd.getReturnType() instanceof RefLikeType) { + if (tgtmtd.getReturnType() instanceof ReferenceType) { Node retNode = tgtnf.caseRet(); retNode = pta.parameterize(retNode, tgtContext); pag.addEdge(retNode, destNode); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java index e8229b92e8c..1ef0701580e 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java @@ -19,19 +19,19 @@ package qilin.core.pag; import qilin.util.DataFactory; -import soot.RefLikeType; +import sootup.core.types.ReferenceType; import java.util.Map; public class MergedNewExpr { - private final RefLikeType type; - private static final Map map = DataFactory.createMap(); + private final ReferenceType type; + private static final Map map = DataFactory.createMap(); - private MergedNewExpr(RefLikeType type) { + private MergedNewExpr(ReferenceType type) { this.type = type; } - public static MergedNewExpr v(RefLikeType type) { + public static MergedNewExpr v(ReferenceType type) { return map.computeIfAbsent(type, k -> new MergedNewExpr(type)); } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java index b2933621fb1..691c1541f69 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java @@ -22,6 +22,7 @@ import soot.AnySubType; import soot.Context; import soot.RefLikeType; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.Collection; @@ -42,7 +43,7 @@ public abstract class VarNode extends ValNode { protected VarNode(Object variable, Type t) { super(t); - if (!(t instanceof RefLikeType) || t instanceof AnySubType) { + if (!(t instanceof ReferenceType) || t instanceof AnySubType) { throw new RuntimeException("Attempt to create VarNode of type " + t); } this.variable = variable; diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index 53bf448b626..b026bfdbfbd 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -21,13 +21,13 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.UnitPatchingChain; import soot.jimple.InvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; public abstract class ReflectionModel { @@ -74,7 +74,7 @@ public void buildReflection(SootMethod m) { return; } Map> newUnits = DataFactory.createMap(); - UnitPatchingChain units = PTAUtils.getMethodBody(m).getUnits(); + List units = PTAUtils.getMethodBody(m).getStmts(); for (final Stmt u : units) { if (u.containsInvokeExpr()) { newUnits.put(u, transform(u)); diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java index 73f0a7bdbcb..575282f9503 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -24,6 +24,7 @@ import qilin.util.DataFactory; import qilin.util.PTAUtils; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.Set; @@ -43,7 +44,7 @@ public AllocNode abstractHeap(AllocNode heap) { Type type = heap.getType(); SootMethod m = heap.getMethod(); if (mergedTypes.contains(type) || (PTAUtils.isThrowable(type) && mergedTypes.add(type))) { - return pag.makeAllocNode(MergedNewExpr.v((RefLikeType) type), type, null); + return pag.makeAllocNode(MergedNewExpr.v((ReferenceType) type), type, null); } else { return heap; } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index 32e84f6760d..a2d3c0d287e 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -23,11 +23,10 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.PAG; import qilin.core.pag.VarNode; -import soot.RefLikeType; -import soot.RefType; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.types.ClassType; +import sootup.core.types.ReferenceType; import java.util.Collections; import java.util.HashSet; @@ -43,7 +42,7 @@ public static Set getParameters(PAG pag, SootMethod m) { MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); Set ret = new HashSet<>(); for (int i = 0; i < m.getParameterCount(); ++i) { - if (m.getParameterType(i) instanceof RefLikeType) { + if (m.getParameterType(i) instanceof ReferenceType) { qilin.core.pag.VarNode param = mthdNF.caseParm(i); ret.add(param); } @@ -53,7 +52,7 @@ public static Set getParameters(PAG pag, SootMethod m) { public static Set getRetVars(PAG pag, SootMethod m) { MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); - if (m.getReturnType() instanceof RefLikeType) { + if (m.getReturnType() instanceof ReferenceType) { VarNode ret = mthdNF.caseRet(); return Collections.singleton(ret); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java index fa1e47f57ba..d83e0aba27a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -24,11 +24,11 @@ import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; -import soot.RefLikeType; import soot.jimple.toolkits.callgraph.CallGraph; import soot.util.queue.QueueReader; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.Collection; import java.util.Collections; @@ -101,12 +101,12 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); addParamEdge(param); } } - if (method.getReturnType() instanceof RefLikeType) { + if (method.getReturnType() instanceof ReferenceType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); addReturnEdge(mret); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index b55436d6c1a..5431744b590 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -88,7 +88,7 @@ private SootMethod findInvokedConstructorOf(SootMethod outerInit) { MethodPAG cmpag = pag.getMethodPAG(outerInit); MethodNodeFactory nodeFactory = cmpag.nodeFactory(); VarNode thisNode = nodeFactory.caseThis(); - for (Unit unit : cmpag.getInvokeStmts()) { + for (Stmt unit : cmpag.getInvokeStmts()) { if (unit instanceof InvokeStmt invokeStmt) { InvokeExpr expr = invokeStmt.getInvokeExpr(); if (expr instanceof SpecialInvokeExpr iie) { @@ -122,8 +122,7 @@ private ArrayList recoverConstructorChain(SootMethod sm, AllocNode h private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMethod curr, SootMethod caller) { MethodPAG cmpag = pag.getMethodPAG(caller); Set ret = new HashSet<>(); - for (Unit unit : cmpag.getInvokeStmts()) { - Stmt stmt = (Stmt) unit; + for (Stmt stmt : cmpag.getInvokeStmts()) { if (!(stmt.getInvokeExpr() instanceof SpecialInvokeExpr)) { continue; } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java index 7e966c036ca..92e37fc7dea 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java @@ -6,6 +6,7 @@ import qilin.core.sets.PointsToSet; import sootup.core.model.SootMethod; import sootup.core.types.ClassType; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.*; @@ -36,7 +37,7 @@ private boolean isAFactoryCreatedContainer(AllocNode heap, IntraFlowAnalysis mpa SootMethod method = heap.getMethod(); if (method.isStatic()) { Type type = method.getReturnType(); - if (!(type instanceof RefLikeType)) { + if (!(type instanceof ReferenceType)) { return false; } MethodPAG methodPag = pag.getMethodPAG(method); @@ -57,7 +58,7 @@ private boolean isAContainerWrapper(AllocNode heap, IntraFlowAnalysis mpag) { return false; } Type type = method.getReturnType(); - if (!(type instanceof RefLikeType)) { + if (!(type instanceof ReferenceType)) { return false; } MethodPAG methodPag = pag.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java index 80ac17f608b..51d5413dd6f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java @@ -4,6 +4,7 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.*; import java.util.stream.Collectors; @@ -32,7 +33,7 @@ private Set getParameters() { for (SootMethod m : invokedMs) { MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); for (int i = 0; i < m.getParameterCount(); ++i) { - if (m.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(m.getParameterType(i))) { + if (m.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(m.getParameterType(i))) { LocalVarNode param = (LocalVarNode) mthdNF.caseParm(i); ret.add(param); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index 9cff66d312b..27086cd22ec 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -5,13 +5,13 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.queue.UniqueQueue; -import soot.RefLikeType; import soot.jimple.*; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -70,21 +70,20 @@ protected void buildInternalWithInline(SootMethod method) { } // global-local } // handle call statements. - for (final Stmt u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; + for (final Stmt s : srcmpag.getInvokeStmts()) { InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { retDest = pag.findLocalVarNode(dest); } } @@ -105,7 +104,7 @@ protected void buildInternalWithInline(SootMethod method) { } // handle parameters. for (int i = 0; i < method.getParameterCount(); ++i) { - if (method.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + if (method.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); addParamEdge(param); } @@ -115,7 +114,7 @@ protected void buildInternalWithInline(SootMethod method) { addParamEdge((LocalVarNode) srcnf.caseThis()); } // handle returns - if (method.getReturnType() instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { + if (method.getReturnType() instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { addReturnEdge((LocalVarNode) srcnf.caseRet()); } } @@ -142,14 +141,14 @@ private void inline(Stmt invokeStmt, SootMethod method) { Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; if (invokeStmt instanceof AssignStmt) { Value dest = ((AssignStmt) invokeStmt).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { retDest = pag.findLocalVarNode(dest); } } @@ -164,7 +163,7 @@ private void inline(Stmt invokeStmt, SootMethod method) { } // handle parameters for (int i = 0; i < method.getParameterCount(); ++i) { - if (args[i] != null && method.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + if (args[i] != null && method.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { LocalVarNode param = (LocalVarNode) nodeFactory.caseParm(i); ValNode argVal = pag.findValNode(args[i]); if (argVal instanceof LocalVarNode argNode) { @@ -173,7 +172,7 @@ private void inline(Stmt invokeStmt, SootMethod method) { } } // handle return node - if (retDest != null && method.getReturnType() instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { + if (retDest != null && method.getReturnType() instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { addAssignEdge((LocalVarNode) nodeFactory.caseRet(), retDest); } // handle this node diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index c1bda9c96e6..d944ecad303 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -26,8 +26,6 @@ import qilin.util.PTAUtils; import qilin.util.Util; import qilin.util.queue.UniqueQueue; -import soot.RefLikeType; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; @@ -35,6 +33,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.*; import java.util.stream.Collectors; @@ -301,11 +300,11 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); LocalVarNode[] parms = new LocalVarNode[numParms]; for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { parms[i] = (LocalVarNode) srcnf.caseParm(i); } } - LocalVarNode mret = method.getReturnType() instanceof RefLikeType ? (LocalVarNode) srcnf.caseRet() : null; + LocalVarNode mret = method.getReturnType() instanceof ReferenceType ? (LocalVarNode) srcnf.caseRet() : null; LocalVarNode throwFinal = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); if (method.isStatic()) { pts.getOrDefault(thisRef, Collections.emptySet()).forEach(a -> { @@ -320,21 +319,20 @@ else if (to instanceof FieldRefNode fr) { } // add invoke edges - for (final Stmt u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; + for (final Stmt s : srcmpag.getInvokeStmts()) { InvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { retDest = prePAG.findLocalVarNode(dest); } } @@ -345,18 +343,18 @@ else if (to instanceof FieldRefNode fr) { // static call receiver = thisRef; } - for (Iterator it = callGraph.edgesOutOf(u); it.hasNext(); ) { + for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) continue; ValNode argNode = prePAG.findValNode(args[i]); if (argNode instanceof LocalVarNode) { this.addStoreEdge((LocalVarNode) argNode, receiver); } } - if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { + if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { this.addLoadEdge(receiver, retDest); } LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index 07c134149cd..90262126233 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -29,8 +29,10 @@ import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; public class Selectx { private final PTA prePTA; @@ -271,7 +273,7 @@ private void buildGraph() { Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } args[i] = arg; @@ -279,7 +281,7 @@ private void buildGraph() { LocalVarNode retDest = null; if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { retDest = prePAG.findLocalVarNode(dest); } } @@ -293,13 +295,13 @@ private void buildGraph() { MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof RefLikeType)) { + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) { continue; } LocalVarNode parm = (LocalVarNode) tgtnf.caseParm(i); this.addEntryEdge((LocalVarNode) srcnf.getNode(args[i]), parm, callSite); } - if (retDest != null && tgtmtd.getReturnType() instanceof RefLikeType) { + if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { LocalVarNode ret = (LocalVarNode) tgtnf.caseRet(); this.addExitEdge(ret, retDest, callSite); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index d1de2a3b402..4b3b29e5edd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -24,7 +24,6 @@ import qilin.core.pag.*; import qilin.util.Pair; import qilin.util.queue.UniqueQueue; -import soot.RefLikeType; import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; @@ -33,6 +32,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.*; @@ -157,14 +157,14 @@ else if (to instanceof FieldRefNode fr) { Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; args[i] = arg; } LocalVarNode retDest = null; if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { retDest = pag.findLocalVarNode(dest); } } @@ -191,7 +191,7 @@ else if (to instanceof FieldRefNode fr) { this.addStoreEdge((LocalVarNode) argNode, receiver); } } - if (retDest != null && retDest.getType() instanceof RefLikeType) { + if (retDest != null && retDest.getType() instanceof ReferenceType) { if (statisfyAddingLoadCondition(targets)) { this.addLoadEdge(receiver, retDest); } @@ -212,13 +212,13 @@ else if (to instanceof FieldRefNode fr) { int numParms = method.getParameterCount(); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); addNormalEdge(new TranEdge(param, param, DFA.TranCond.IPARAM)); } } - if (method.getReturnType() instanceof RefLikeType) { + if (method.getReturnType() instanceof ReferenceType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); addStoreEdge(mret, thisRef); } @@ -250,13 +250,13 @@ public void computeNodesInPrecisionLossPatterns() { workList.add(new Pair<>(thisRef, DFA.State.S)); for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof RefLikeType) { + if (method.getParameterType(i) instanceof ReferenceType) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); startState.add(param); workList.add(new Pair<>(param, DFA.State.S)); } } - if (method.getReturnType() instanceof RefLikeType) { + if (method.getReturnType() instanceof ReferenceType) { LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); startState.add(mret); workList.add(new Pair<>(mret, DFA.State.S)); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java index c1ba8a67baa..18ed2b167f8 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -25,8 +25,8 @@ import qilin.core.pag.MethodPAG; import qilin.core.pag.Node; import qilin.util.graph.MergedNode; -import soot.RefLikeType; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.Set; @@ -50,7 +50,7 @@ protected boolean statisfyAddingLoadCondition(Set targets) { if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { return true; } - if (!(tgtmtd.getReturnType() instanceof RefLikeType)) { + if (!(tgtmtd.getReturnType() instanceof ReferenceType)) { continue; } MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); @@ -80,7 +80,7 @@ protected boolean satisfyAddingStoreCondition(int paramIndex, Set ta if (paramIndex == PointsToAnalysis.THIS_NODE) { parm = (LocalVarNode) tgtnf.caseThis(); } else { - if (tgtmtd.getParameterType(paramIndex) instanceof RefLikeType) { + if (tgtmtd.getParameterType(paramIndex) instanceof ReferenceType) { parm = (LocalVarNode) tgtnf.caseParm(paramIndex); } else { continue; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java index 43d26b29d30..8f7f4e3388a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -27,6 +27,7 @@ import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; import sootup.core.types.PrimitiveType; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.*; @@ -245,7 +246,7 @@ boolean isFactoryObject(AllocNode heap) { return false; } Type retType = method.getReturnType(); - if (!(retType instanceof RefLikeType)) { + if (!(retType instanceof ReferenceType)) { return false; } if (retType instanceof ArrayType at) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java index 2d86c7039e5..7448dbd9eb5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -14,6 +14,7 @@ import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.*; @@ -151,7 +152,7 @@ private void dfs(Node node) { } if (callsiteStmt instanceof AssignStmt assignStmt) { Value lv = assignStmt.getLeftOp(); - if (!(lv.getType() instanceof RefLikeType)) { + if (!(lv.getType() instanceof ReferenceType)) { return; } final VarNode to = (VarNode) pta.getPag().findValNode(lv); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index b2e4250d302..bbfbd88fe56 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -34,6 +34,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.HashSet; import java.util.Map; @@ -148,7 +149,7 @@ protected void extraStats() { int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } nodes.add(arg); @@ -156,7 +157,7 @@ protected void extraStats() { if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 21d69ae35f8..1dcc1c95abd 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -36,6 +36,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.HashSet; import java.util.Map; @@ -149,7 +150,7 @@ protected void extraStats() { int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } nodes.add(arg); @@ -157,7 +158,7 @@ protected void extraStats() { if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index 1b524f8211f..118c2f7e14f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -36,6 +36,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import java.util.HashSet; import java.util.Set; @@ -119,7 +120,7 @@ protected void extraStats() { int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } nodes.add(arg); @@ -127,7 +128,7 @@ protected void extraStats() { if (s instanceof AssignStmt) { Value dest = ((AssignStmt) s).getLeftOp(); - if (dest.getType() instanceof RefLikeType) { + if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java index bc6261846b4..d95921dddcb 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -28,6 +28,7 @@ import sootup.core.jimple.basic.Local; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.*; @@ -216,7 +217,7 @@ private void init() { } for (int i = 0; i < sm.getParameterCount(); ++i) { Type mType = sm.getParameterType(i); - if (mType instanceof RefLikeType) { + if (mType instanceof ReferenceType) { mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); if (!handledNatives.contains(sm.toString())) { mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseParm(i)); diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index 0db797b0c4d..c2b7fd63d5b 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -26,13 +26,13 @@ import qilin.util.PTAUtils; import qilin.util.Stopwatch; import soot.MethodOrMethodContext; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.*; @@ -91,7 +91,7 @@ public void end() { } else if (st instanceof AssignStmt) { Value rhs = ((AssignStmt) st).getRightOp(); Value lhs = ((AssignStmt) st).getLeftOp(); - if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { + if (rhs instanceof CastExpr && lhs.getType() instanceof ReferenceType) { final Type targetType = ((CastExpr) rhs).getCastType(); Value v = ((CastExpr) rhs).getOp(); if (!(v instanceof Local)) { @@ -146,7 +146,7 @@ private void ptsStat() { } for (int i = 0; i < sm.getParameterCount(); ++i) { Type mType = sm.getParameterType(i); - if (mType instanceof RefLikeType) { + if (mType instanceof ReferenceType) { mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); } } diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index 738eb792454..f78cb9a04df 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -24,13 +24,13 @@ import qilin.core.pag.AllocNode; import qilin.util.PTAUtils; import soot.MethodOrMethodContext; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.*; @@ -104,7 +104,7 @@ private void init() { } else if (st instanceof AssignStmt) { Value rhs = ((AssignStmt) st).getRightOp(); Value lhs = ((AssignStmt) st).getLeftOp(); - if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) { + if (rhs instanceof CastExpr && lhs.getType() instanceof ReferenceType) { final Type targetType = ((CastExpr) rhs).getCastType(); Value v = ((CastExpr) rhs).getOp(); if (!(v instanceof Local)) { diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java index 0b92f7dc2bc..5ea434b4af7 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java @@ -1,3 +1,54 @@ package soot.util.dot; -public class DotGraphConstants { + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2002 Sable Research Group + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +/** + * Defines several constants used to generate a Dot graph. + * + * @author Feng Qian + */ + +public interface DotGraphConstants { + public static final String NODE_SHAPE_BOX = "box"; + public static final String NODE_SHAPE_ELLIPSE = "ellipse"; + public static final String NODE_SHAPE_CIRCLE = "circle"; + public static final String NODE_SHAPE_DIAMOND = "diamond"; + public static final String NODE_SHAPE_PLAINTEXT = "plaintext"; + + public static final String NODE_STYLE_SOLID = "solid"; + public static final String NODE_STYLE_DASHED = "dashed"; + public static final String NODE_STYLE_DOTTED = "dotted"; + public static final String NODE_STYLE_BOLD = "bold"; + public static final String NODE_STYLE_INVISIBLE = "invis"; + public static final String NODE_STYLE_FILLED = "filled"; + public static final String NODE_STYLE_DIAGONALS = "diagonals"; + public static final String NODE_STYLE_ROUNDED = "rounded"; + + public static final String EDGE_STYLE_DOTTED = "dotted"; + public static final String EDGE_STYLE_SOLID = "solid"; + + public static final String GRAPH_ORIENT_PORTRAIT = "portrait"; + public static final String GRAPH_ORIENT_LANDSCAPE = "landscape"; + } + From c56b905cd1aa6321d36380036edf6ee92b55a9b4 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 17 Sep 2023 10:07:10 +1000 Subject: [PATCH 013/145] replace ArrayType.v() with new ArrayType() --- .../main/java/qilin/core/ArtificialMethod.java | 4 ++-- .../qilin/core/builder/MethodNodeFactory.java | 15 ++++++++------- .../core/natives/JavaLangReflectArrayGet.java | 4 ++-- .../core/natives/JavaLangReflectArraySet.java | 4 ++-- .../natives/JavaLangSystemArraycopyNative.java | 6 +++--- .../src/main/java/qilin/core/pag/PAG.java | 5 +++-- .../src/main/java/qilin/core/pag/VarNode.java | 1 - .../java/qilin/core/reflection/TamiflexModel.java | 11 ++++++----- .../java/qilin/pta/toolkits/debloaterx/XPAG.java | 2 -- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index 563342db3bd..84208f0b058 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -18,7 +18,6 @@ package qilin.core; -import soot.jimple.IntConstant; import soot.jimple.Jimple; import soot.jimple.ParameterRef; import soot.jimple.ThisRef; @@ -27,6 +26,7 @@ import sootup.core.jimple.basic.Value; import sootup.core.model.Body; import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.Type; @@ -84,7 +84,7 @@ protected Value getNew(ClassType type) { protected Value getNewArray(ClassType type) { Value newExpr = new JNewArrayExpr(type, IntConstant.v(1)); - Value local = getNextLocal(ArrayType.v(type, 1)); + Value local = getNextLocal(new ArrayType(type, 1)); addAssign(local, newExpr); return local; } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index 232267bf366..d20b563d6ae 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -35,6 +35,7 @@ import sootup.core.model.SootField; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; /** @@ -106,14 +107,14 @@ protected void handleInvokeStmt(Stmt s) { int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } getNode(arg); } if (s instanceof AssignStmt) { Value l = ((AssignStmt) s).getLeftOp(); - if ((l.getType() instanceof RefLikeType)) { + if ((l.getType() instanceof ReferenceType)) { getNode(l); } } @@ -140,15 +141,15 @@ public void caseAssignStmt(AssignStmt as) { resolveClinit((StaticFieldRef) r); } - if (!(l.getType() instanceof RefLikeType)) + if (!(l.getType() instanceof ReferenceType)) return; // check for improper casts, with mal-formed code we might get // l = (refliketype)int_type, if so just return - if (r instanceof CastExpr && (!(((CastExpr) r).getOp().getType() instanceof RefLikeType))) { + if (r instanceof CastExpr && (!(((CastExpr) r).getOp().getType() instanceof ReferenceType))) { return; } - if (!(r.getType() instanceof RefLikeType)) + if (!(r.getType() instanceof ReferenceType)) throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + as + " in method " + method.getSignature()); Node dest = getNode(l); @@ -157,14 +158,14 @@ public void caseAssignStmt(AssignStmt as) { } public void caseReturnStmt(ReturnStmt rs) { - if (!(rs.getOp().getType() instanceof RefLikeType)) + if (!(rs.getOp().getType() instanceof ReferenceType)) return; Node retNode = getNode(rs.getOp()); mpag.addInternalEdge(retNode, caseRet()); } public void caseIdentityStmt(IdentityStmt is) { - if (!(is.getLeftOp().getType() instanceof RefLikeType)) { + if (!(is.getLeftOp().getType() instanceof ReferenceType)) { return; } Node dest = getNode(is.getLeftOp()); diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index b953b6626e2..77a6fb8025d 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -19,9 +19,9 @@ package qilin.core.natives; import qilin.util.PTAUtils; -import soot.ArrayType; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; import sootup.core.types.ClassType; /* @@ -36,7 +36,7 @@ public class JavaLangReflectArrayGet extends NativeMethod { @Override void simulate() { ClassType objType = PTAUtils.getClassType("java.lang.Object"); - Value arrayBase = getPara(0, ArrayType.v(objType, 1)); + Value arrayBase = getPara(0, new ArrayType(objType, 1)); Value arrayRef = getArrayRef(arrayBase); Value ret = getNextLocal(objType); addAssign(ret, arrayRef); diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java index a9be9d18b03..c688f7154cb 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -19,9 +19,9 @@ package qilin.core.natives; import qilin.util.PTAUtils; -import soot.ArrayType; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; import sootup.core.types.ClassType; /* @@ -36,7 +36,7 @@ public class JavaLangReflectArraySet extends NativeMethod { @Override void simulate() { ClassType objType = PTAUtils.getClassType("java.lang.Object"); - Value arrayBase = getPara(0, ArrayType.v(objType, 1)); + Value arrayBase = getPara(0, new ArrayType(objType, 1)); Value rightValue = getPara(2); Value arrayRef = getArrayRef(arrayBase); addAssign(arrayRef, rightValue); // a[] = b; diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java index d5faee69851..6e8ca177e04 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -19,9 +19,9 @@ package qilin.core.natives; import qilin.util.PTAUtils; -import soot.ArrayType; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; import sootup.core.types.ClassType; /* @@ -41,8 +41,8 @@ public void simulate() { // Value srcArr = getPara(0); // Value dstArr = getPara(2); ClassType objType = PTAUtils.getClassType("java.lang.Object"); - Value srcArr = getPara(0, ArrayType.v(objType, 1)); - Value dstArr = getPara(2, ArrayType.v(objType, 1)); + Value srcArr = getPara(0, new ArrayType(objType, 1)); + Value dstArr = getPara(2, new ArrayType(objType, 1)); Value src = getArrayRef(srcArr); Value dst = getArrayRef(dstArr); Value temp = getNextLocal(objType); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index f9e42e5387d..2bb4afd242e 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -46,6 +46,7 @@ import sootup.core.model.Body; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.types.ArrayType; import sootup.core.types.Type; import java.util.*; @@ -566,7 +567,7 @@ private void handleArrayCopy(SootMethod method) { } Type objType = PTAUtils.getClassType("java.lang.Object"); if (srcArr.getType() == objType) { - Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); + Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); body.getLocals().add(localSrc); newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr)); srcArr = localSrc; @@ -576,7 +577,7 @@ private void handleArrayCopy(SootMethod method) { continue; } if (dstArr.getType() == objType) { - Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); + Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); body.getLocals().add(localDst); newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr)); dstArr = localDst; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java index 691c1541f69..1a9cb55091b 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java @@ -21,7 +21,6 @@ import qilin.util.DataFactory; import soot.AnySubType; import soot.Context; -import soot.RefLikeType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index db9c8279c59..503d3f0d0f2 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -35,6 +35,7 @@ import sootup.core.model.SootField; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.io.BufferedReader; @@ -113,7 +114,7 @@ protected Collection transformContructorNewInstance(Stmt s) { InvokeExpr iie = s.getInvokeExpr(); Value args = iie.getArg(0); ArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); - Value arg = new JimpleLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + Value arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); ret.add(new JAssignStmt(arg, arrayRef)); for (String constructorSignature : constructorSignatures) { SootMethod constructor = PTAScene.v().getMethod(constructorSignature); @@ -144,7 +145,7 @@ protected Collection transformMethodInvoke(Stmt s) { Value arg = null; if (args.getType() instanceof ArrayType) { ArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); - arg = new JimpleLocal("intermediate/" + arrayRef, RefType.v("java.lang.Object")); + arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); ret.add(new JAssignStmt(arg, arrayRef)); } @@ -221,7 +222,7 @@ protected Collection transformFieldGet(Stmt s) { assert !(base instanceof NullConstant); fieldRef = new JInstanceFieldRef(base, field.makeRef()); } - if (fieldRef.getType() instanceof RefLikeType) { + if (fieldRef.getType() instanceof ReferenceType) { Stmt stmt = new JAssignStmt(lvalue, fieldRef); ret.add(stmt); } @@ -257,8 +258,8 @@ Collection transformArrayGet(Stmt s) { Value arrayRef = null; if (base.getType() instanceof ArrayType) { arrayRef = new JArrayRef(base, IntConstant.v(0)); - } else if (base.getType() == RefType.v("java.lang.Object")) { - Local local = new JimpleLocal("intermediate/" + base, ArrayType.v(RefType.v("java.lang.Object"), 1)); + } else if (base.getType() == PTAUtils.getClassType("java.lang.Object")) { + Local local = new JimpleLocal("intermediate/" + base, new ArrayType(PTAUtils.getClassType("java.lang.Object"), 1)); ret.add(new JAssignStmt(local, base)); arrayRef = new JArrayRef(local, IntConstant.v(0)); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index 27086cd22ec..937c816011c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -4,8 +4,6 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; -import qilin.util.queue.UniqueQueue; -import soot.jimple.*; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; From cd263f8c6c2fc5f32375a81138f52281dc329e23 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 17 Sep 2023 11:17:58 +1000 Subject: [PATCH 014/145] replace exprs with their counterpart in sootup --- .../main/java/qilin/core/VirtualCalls.java | 6 +- .../qilin/core/builder/CallGraphBuilder.java | 13 ++-- .../qilin/core/builder/MethodNodeFactory.java | 70 +++++++++++-------- .../main/java/qilin/core/pag/MethodPAG.java | 5 +- .../src/main/java/qilin/core/pag/PAG.java | 11 +-- .../java/qilin/core/pag/VirtualCallSite.java | 8 +-- .../core/reflection/ReflectionModel.java | 4 +- .../qilin/core/reflection/TamiflexModel.java | 32 +++++---- .../main/java/qilin/core/solver/Solver.java | 13 ++-- .../java/qilin/pta/toolkits/conch/Conch.java | 11 +-- .../dd/CtxTunnelingFeaturesTrueTable.java | 27 ++++--- .../debloaterx/IntraFlowAnalysis.java | 25 +++---- .../qilin/pta/toolkits/debloaterx/XPAG.java | 16 +++-- .../pta/toolkits/debloaterx/XUtility.java | 10 +-- .../java/qilin/pta/toolkits/eagle/Eagle.java | 6 +- .../qilin/pta/toolkits/selectx/Selectx.java | 6 +- .../pta/toolkits/turner/AbstractMVFG.java | 7 +- .../zipper/flowgraph/FlowAnalysis.java | 10 +-- .../zipper/flowgraph/ObjectFlowGraph.java | 7 +- .../main/java/qilin/pta/tools/EaglePTA.java | 8 +-- .../pta/tools/PartialCallSiteSensPTA.java | 6 +- .../qilin/pta/tools/PartialObjSensPTA.java | 6 +- .../main/java/qilin/pta/tools/ZipperPTA.java | 6 +- .../java/qilin/stat/SimplifiedEvaluator.java | 13 ++-- .../main/java/qilin/stat/TypeClientStat.java | 15 ++-- .../src/main/java/qilin/util/PTAUtils.java | 18 +++-- .../soot/jimple/toolkits/callgraph/Edge.java | 20 +++--- 27 files changed, 219 insertions(+), 160 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index c6b5a7c7deb..85440402d99 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -20,9 +20,9 @@ import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.jimple.SpecialInvokeExpr; import soot.util.*; import soot.util.queue.ChunkedQueue; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; @@ -63,11 +63,11 @@ public static void reset() { instance = null; } - public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container) { + public SootMethod resolveSpecial(JSpecialInvokeExpr iie, NumberedString subSig, SootMethod container) { return resolveSpecial(iie, subSig, container, false); } - public SootMethod resolveSpecial(SpecialInvokeExpr iie, NumberedString subSig, SootMethod container, boolean appOnly) { + public SootMethod resolveSpecial(JSpecialInvokeExpr iie, NumberedString subSig, SootMethod container, boolean appOnly) { SootMethod target = iie.getMethod(); /* cf. JVM spec, invokespecial instruction */ if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClassType(), diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 34bdca1c33a..67c19ee0a67 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -29,9 +29,6 @@ import soot.Context; import soot.Kind; import soot.MethodOrMethodContext; -import soot.jimple.*; -import soot.jimple.internal.JInvokeStmt; -import soot.jimple.internal.JStaticInvokeExpr; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.ChunkedQueue; @@ -39,6 +36,10 @@ import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -140,7 +141,7 @@ protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { final QueueReader targets = PTAUtils.dispatch(type, site); while (targets.hasNext()) { SootMethod target = targets.next(); - if (site.iie() instanceof SpecialInvokeExpr) { + if (site.iie() instanceof JSpecialInvokeExpr) { Type calleeDeclType = target.getDeclaringClassType(); if (!Scene.v().getFastHierarchy().canStoreType(type, calleeDeclType)) { continue; @@ -162,7 +163,7 @@ private void addVirtualEdge(MethodOrMethodContext caller, Stmt callStmt, SootMet public void injectCallEdge(Object heapOrType, MethodOrMethodContext callee, Kind kind) { Map stmtMap = methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap()); if (!stmtMap.containsKey(heapOrType)) { - InvokeExpr ie = new JStaticInvokeExpr(callee.method().makeRef(), Collections.emptyList()); + AbstractInvokeExpr ie = new JStaticInvokeExpr(callee.method().makeRef(), Collections.emptyList()); JInvokeStmt stmt = new JInvokeStmt(ie); stmtMap.put(heapOrType, stmt); handleCallEdge(new Edge(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext()), stmtMap.get(heapOrType), callee, kind)); @@ -212,7 +213,7 @@ private void processCallAssign(Edge e) { MethodNodeFactory srcnf = srcmpag.nodeFactory(); MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); SootMethod tgtmtd = tgtmpag.getMethod(); - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); // add arg --> param edges. int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index d20b563d6ae..e694d345364 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -29,6 +29,18 @@ import sootup.core.jimple.common.constant.ClassConstant; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JNewMultiArrayExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JCaughtExceptionRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; +import sootup.core.jimple.common.ref.JParameterRef; +import sootup.core.jimple.common.ref.JStaticFieldRef; +import sootup.core.jimple.common.ref.JThisRef; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Modifier; import sootup.core.model.SootClass; @@ -55,31 +67,31 @@ public MethodNodeFactory(PAG pag, MethodPAG mpag) { public Node getNode(Value v) { if (v instanceof Local l) { return caseLocal(l); - } else if (v instanceof CastExpr castExpr) { + } else if (v instanceof JCastExpr castExpr) { return caseCastExpr(castExpr); - } else if (v instanceof NewExpr ne) { + } else if (v instanceof JNewExpr ne) { return caseNewExpr(ne); - } else if (v instanceof StaticFieldRef sfr) { + } else if (v instanceof JStaticFieldRef sfr) { return caseStaticFieldRef(sfr); - } else if (v instanceof NewArrayExpr nae) { + } else if (v instanceof JNewArrayExpr nae) { return caseNewArrayExpr(nae); - } else if (v instanceof ArrayRef ar) { + } else if (v instanceof JArrayRef ar) { return caseArrayRef(ar); } else if (v instanceof ClassConstant cc) { return caseClassConstant(cc); } else if (v instanceof StringConstant sc) { return caseStringConstant(sc); - } else if (v instanceof CaughtExceptionRef cef) { + } else if (v instanceof JCaughtExceptionRef cef) { return caseCaughtExceptionRef(cef); - } else if (v instanceof ParameterRef pr) { + } else if (v instanceof JParameterRef pr) { return caseParameterRef(pr); } else if (v instanceof NullConstant nc) { return caseNullConstant(nc); - } else if (v instanceof InstanceFieldRef ifr) { + } else if (v instanceof JInstanceFieldRef ifr) { return caseInstanceFieldRef(ifr); - } else if (v instanceof ThisRef) { + } else if (v instanceof JThisRef) { return caseThis(); - } else if (v instanceof NewMultiArrayExpr nmae) { + } else if (v instanceof JNewMultiArrayExpr nmae) { return caseNewMultiArrayExpr(nmae); } System.out.println(v + ";;" + v.getClass()); @@ -103,7 +115,7 @@ final public void handleStmt(Stmt s) { * the invoke method throws an Exception. */ protected void handleInvokeStmt(Stmt s) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); @@ -118,12 +130,12 @@ protected void handleInvokeStmt(Stmt s) { getNode(l); } } - if (ie instanceof InstanceInvokeExpr) { - getNode(((InstanceInvokeExpr) ie).getBase()); + if (ie instanceof AbstractInstanceInvokeExpr aie) { + getNode(aie.getBase()); } } - private void resolveClinit(StaticFieldRef staticFieldRef) { + private void resolveClinit(JStaticFieldRef staticFieldRef) { PTAUtils.clinitsOf(staticFieldRef.getField().getDeclaringClass()).forEach(mpag::addTriggeredClinit); } @@ -135,17 +147,17 @@ private void handleIntraStmt(Stmt s) { public void caseAssignStmt(AssignStmt as) { Value l = as.getLeftOp(); Value r = as.getRightOp(); - if (l instanceof StaticFieldRef) { - resolveClinit((StaticFieldRef) l); - } else if (r instanceof StaticFieldRef) { - resolveClinit((StaticFieldRef) r); + if (l instanceof JStaticFieldRef) { + resolveClinit((JStaticFieldRef) l); + } else if (r instanceof JStaticFieldRef) { + resolveClinit((JStaticFieldRef) r); } if (!(l.getType() instanceof ReferenceType)) return; // check for improper casts, with mal-formed code we might get // l = (refliketype)int_type, if so just return - if (r instanceof CastExpr && (!(((CastExpr) r).getOp().getType() instanceof ReferenceType))) { + if (r instanceof JCastExpr && (!(((JCastExpr) r).getOp().getType() instanceof ReferenceType))) { return; } @@ -185,17 +197,17 @@ private VarNode caseLocal(Local l) { return pag.makeLocalVarNode(l, l.getType(), method); } - private AllocNode caseNewArrayExpr(NewArrayExpr nae) { + private AllocNode caseNewArrayExpr(JNewArrayExpr nae) { return pag.makeAllocNode(nae, nae.getType(), method); } - private AllocNode caseNewExpr(NewExpr ne) { + private AllocNode caseNewExpr(JNewExpr ne) { SootClass cl = PTAScene.v().loadClassAndSupport(ne.getType().toString()); PTAUtils.clinitsOf(cl).forEach(mpag::addTriggeredClinit); return pag.makeAllocNode(ne, ne.getType(), method); } - private FieldRefNode caseInstanceFieldRef(InstanceFieldRef ifr) { + private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { SootField sf = ifr.getField(); if (sf == null) { sf = new SootField(ifr.getFieldRef().name(), ifr.getType(), Modifier.PUBLIC); @@ -206,7 +218,7 @@ private FieldRefNode caseInstanceFieldRef(InstanceFieldRef ifr) { return pag.makeFieldRefNode(pag.makeLocalVarNode(ifr.getBase(), ifr.getBase().getType(), method), new Field(sf)); } - private VarNode caseNewMultiArrayExpr(NewMultiArrayExpr nmae) { + private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { ArrayType type = (ArrayType) nmae.getType(); int pos = 0; AllocNode prevAn = pag.makeAllocNode(new JNewArrayExpr(type, nmae.getSize(pos)), type, method); @@ -235,7 +247,7 @@ private VarNode caseNewMultiArrayExpr(NewMultiArrayExpr nmae) { return ret; } - private VarNode caseCastExpr(CastExpr ce) { + private VarNode caseCastExpr(JCastExpr ce) { Node opNode = getNode(ce.getOp()); VarNode castNode = pag.makeLocalVarNode(ce, ce.getCastType(), method); mpag.addInternalEdge(opNode, castNode); @@ -271,7 +283,7 @@ final public FieldRefNode caseArray(VarNode base) { return pag.makeFieldRefNode(base, ArrayElement.v()); } - private Node caseCaughtExceptionRef(CaughtExceptionRef cer) { + private Node caseCaughtExceptionRef(JCaughtExceptionRef cer) { if (CoreConfig.v().getPtaConfig().preciseExceptions) { // we model caughtException expression as an local assignment. return pag.makeLocalVarNode(cer, cer.getType(), method); @@ -280,15 +292,15 @@ private Node caseCaughtExceptionRef(CaughtExceptionRef cer) { } } - private FieldRefNode caseArrayRef(ArrayRef ar) { - return caseArray(caseLocal((Local) ar.getBase())); + private FieldRefNode caseArrayRef(JArrayRef ar) { + return caseArray(caseLocal(ar.getBase())); } - private VarNode caseParameterRef(ParameterRef pr) { + private VarNode caseParameterRef(JParameterRef pr) { return caseParm(pr.getIndex()); } - private VarNode caseStaticFieldRef(StaticFieldRef sfr) { + private VarNode caseStaticFieldRef(JStaticFieldRef sfr) { return pag.makeGlobalVarNode(sfr.getField(), sfr.getField().getType()); } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index 3389a17f598..e6e26b18736 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -24,12 +24,11 @@ import qilin.util.PTAUtils; import soot.jimple.Jimple; -import soot.jimple.StaticFieldRef; import soot.jimple.ThrowStmt; -import soot.util.Chain; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Trap; +import sootup.core.jimple.common.ref.JStaticFieldRef; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootMethod; @@ -168,7 +167,7 @@ private void addStmtTrap(Node src, Stmt stmt, Trap trap) { protected void addMiscEdges() { if (method.getSignature().equals("(java.lang.Object,java.lang.ref.ReferenceQueue)>")) { // Implements the special status of java.lang.ref.Reference just as in Doop (library/reference.logic). - StaticFieldRef sfr = Jimple.v().newStaticFieldRef(RefType.v("java.lang.ref.Reference").getSootClass().getFieldByName("pending").makeRef()); + JStaticFieldRef sfr = Jimple.v().newStaticFieldRef(RefType.v("java.lang.ref.Reference").getSootClass().getFieldByName("pending").makeRef()); addInternalEdge(nodeFactory.caseThis(), nodeFactory.getNode(sfr)); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 2bb4afd242e..89a8bb2982d 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -31,8 +31,6 @@ import qilin.util.PTAUtils; import soot.Context; import soot.MethodOrMethodContext; -import soot.jimple.*; -import soot.jimple.internal.JArrayRef; import soot.jimple.internal.JAssignStmt; import soot.jimple.internal.JimpleLocal; import soot.util.ArrayNumberer; @@ -42,6 +40,9 @@ import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootField; @@ -556,10 +557,10 @@ private void handleArrayCopy(SootMethod method) { Body body = PTAUtils.getMethodBody(method); for (Stmt s : body.getStmts()) { if (s.containsInvokeExpr()) { - InvokeExpr invokeExpr = s.getInvokeExpr(); - if (invokeExpr instanceof StaticInvokeExpr sie) { + AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); + if (invokeExpr instanceof JStaticInvokeExpr sie) { SootMethod sm = sie.getMethod(); - String sig = sm.getSignature(); + String sig = sm.getSignature().toString(); if (sig.equals("")) { Value srcArr = sie.getArg(0); if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java index f4515be4a2f..125007e442f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java @@ -20,8 +20,8 @@ import soot.Kind; import soot.MethodOrMethodContext; -import soot.jimple.InstanceInvokeExpr; import soot.util.NumberedString; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import java.util.Objects; @@ -34,11 +34,11 @@ public class VirtualCallSite extends CallSite { private final VarNode recNode; private final MethodOrMethodContext container; - private final InstanceInvokeExpr iie; + private final AbstractInstanceInvokeExpr iie; private final NumberedString subSig; private final Kind kind; - public VirtualCallSite(VarNode recNode, Stmt stmt, MethodOrMethodContext container, InstanceInvokeExpr iie, + public VirtualCallSite(VarNode recNode, Stmt stmt, MethodOrMethodContext container, AbstractInstanceInvokeExpr iie, NumberedString subSig, Kind kind) { super(stmt); this.recNode = recNode; @@ -56,7 +56,7 @@ public MethodOrMethodContext container() { return container; } - public InstanceInvokeExpr iie() { + public AbstractInstanceInvokeExpr iie() { return iie; } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index b026bfdbfbd..cb3c352337b 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -21,7 +21,7 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.jimple.InvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -51,7 +51,7 @@ public abstract class ReflectionModel { protected final String sigReifiedDeclaredMethodArray = ""; private Collection transform(Stmt s) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); return switch (ie.getMethodRef().getSignature()) { case sigForName, sigForName2 -> transformClassForName(s); case sigClassNewInstance -> transformClassNewInstance(s); diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index 503d3f0d0f2..c2dddef906a 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -22,13 +22,21 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.jimple.*; import soot.jimple.internal.*; import soot.tagkit.LineNumberTag; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JFieldRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; @@ -111,9 +119,9 @@ protected Collection transformContructorNewInstance(Stmt s) { Map> constructorNewInstances = reflectionMap.getOrDefault(ReflectionKind.ConstructorNewInstance, Collections.emptyMap()); if (constructorNewInstances.containsKey(s)) { Collection constructorSignatures = constructorNewInstances.get(s); - InvokeExpr iie = s.getInvokeExpr(); + AbstractInvokeExpr iie = s.getInvokeExpr(); Value args = iie.getArg(0); - ArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); + JArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); Value arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); ret.add(new JAssignStmt(arg, arrayRef)); for (String constructorSignature : constructorSignatures) { @@ -139,12 +147,12 @@ protected Collection transformMethodInvoke(Stmt s) { Map> methodInvokes = reflectionMap.getOrDefault(ReflectionKind.MethodInvoke, Collections.emptyMap()); if (methodInvokes.containsKey(s)) { Collection methodSignatures = methodInvokes.get(s); - InvokeExpr iie = s.getInvokeExpr(); + AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); Value args = iie.getArg(1); Value arg = null; if (args.getType() instanceof ArrayType) { - ArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); + JArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); ret.add(new JAssignStmt(arg, arrayRef)); } @@ -156,7 +164,7 @@ protected Collection transformMethodInvoke(Stmt s) { for (int i = 0; i < argCount; i++) { mArgs.add(arg); } - InvokeExpr ie; + AbstractInvokeExpr ie; if (method.isStatic()) { assert base instanceof NullConstant; ie = new JStaticInvokeExpr(method.makeRef(), mArgs); @@ -182,12 +190,12 @@ protected Collection transformFieldSet(Stmt s) { Map> fieldSets = reflectionMap.getOrDefault(ReflectionKind.FieldSet, Collections.emptyMap()); if (fieldSets.containsKey(s)) { Collection fieldSignatures = fieldSets.get(s); - InvokeExpr iie = s.getInvokeExpr(); + AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); Value rValue = iie.getArg(1); for (String fieldSignature : fieldSignatures) { SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); - FieldRef fieldRef; + JFieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; fieldRef = Jimple.v().newStaticFieldRef(field.makeRef()); @@ -210,11 +218,11 @@ protected Collection transformFieldGet(Stmt s) { if (fieldGets.containsKey(s) && s instanceof AssignStmt) { Collection fieldSignatures = fieldGets.get(s); Value lvalue = ((AssignStmt) s).getLeftOp(); - InvokeExpr iie = s.getInvokeExpr(); + AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); for (String fieldSignature : fieldSignatures) { SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); - FieldRef fieldRef; + JFieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; fieldRef = Jimple.v().newStaticFieldRef(field.makeRef()); @@ -251,7 +259,7 @@ protected Collection transformArrayNewInstance(Stmt s) { @Override Collection transformArrayGet(Stmt s) { Collection ret = DataFactory.createSet(); - InvokeExpr iie = s.getInvokeExpr(); + AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); if (s instanceof AssignStmt) { Value lvalue = ((AssignStmt) s).getLeftOp(); @@ -273,7 +281,7 @@ Collection transformArrayGet(Stmt s) { @Override Collection transformArraySet(Stmt s) { Collection ret = DataFactory.createSet(); - InvokeExpr iie = s.getInvokeExpr(); + AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); if (base.getType() instanceof ArrayType) { Value from = iie.getArg(2); diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 5bcf1998c6d..5f48a85a5a5 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -26,20 +26,21 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.core.sets.DoublePointsToSet; -import qilin.core.sets.HybridPointsToSet; import qilin.core.sets.P2SetVisitor; import qilin.core.sets.PointsToSetInternal; import qilin.util.PTAUtils; import soot.Context; import soot.Kind; import soot.MethodOrMethodContext; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.Edge; import soot.options.Options; import soot.util.NumberedString; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JDynamicInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -130,9 +131,9 @@ public void processStmts(Iterator newRMs) { private void recordCallStmts(MethodOrMethodContext m, Collection units) { for (final Stmt s : units) { if (s.containsInvokeExpr()) { - InvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof InstanceInvokeExpr iie) { - Local receiver = (Local) iie.getBase(); + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof AbstractInstanceInvokeExpr iie) { + Local receiver = iie.getBase(); VarNode recNode = cgb.getReceiverVarNode(receiver, m); NumberedString subSig = iie.getMethodRef().getSubSignature(); VirtualCallSite virtualCallSite = new VirtualCallSite(recNode, s, m, iie, subSig, Edge.ieToKind(iie)); @@ -144,7 +145,7 @@ private void recordCallStmts(MethodOrMethodContext m, Collection units) { if (tgt != null) { // static invoke or dynamic invoke VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); recNode = (VarNode) pta.parameterize(recNode, m.context()); - if (ie instanceof DynamicInvokeExpr) { + if (ie instanceof JDynamicInvokeExpr) { // !TODO dynamicInvoke is provided in JDK after Java 7. // currently, PTA does not handle dynamicInvokeExpr. } else { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index 5431744b590..f0ddec59eca 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -24,10 +24,11 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.jimple.InvokeExpr; import soot.jimple.InvokeStmt; -import soot.jimple.SpecialInvokeExpr; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -90,8 +91,8 @@ private SootMethod findInvokedConstructorOf(SootMethod outerInit) { VarNode thisNode = nodeFactory.caseThis(); for (Stmt unit : cmpag.getInvokeStmts()) { if (unit instanceof InvokeStmt invokeStmt) { - InvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof SpecialInvokeExpr iie) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); SootMethod target = iie.getMethod(); @@ -123,7 +124,7 @@ private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMeth MethodPAG cmpag = pag.getMethodPAG(caller); Set ret = new HashSet<>(); for (Stmt stmt : cmpag.getInvokeStmts()) { - if (!(stmt.getInvokeExpr() instanceof SpecialInvokeExpr)) { + if (!(stmt.getInvokeExpr() instanceof JSpecialInvokeExpr)) { continue; } SootMethod target = stmt.getInvokeExpr().getMethod(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index 92eba5d716d..a8187125b24 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -21,6 +21,15 @@ import qilin.util.PTAUtils; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JNewMultiArrayExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; @@ -60,25 +69,25 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm) { Value right = assignStmt.getRightOp(); if (right instanceof Local) { this.f[14] = true; - } else if (right instanceof NewExpr || right instanceof NewArrayExpr || right instanceof NewMultiArrayExpr) { + } else if (right instanceof JNewExpr || right instanceof JNewArrayExpr || right instanceof JNewMultiArrayExpr) { heapAllocCnt++; - } else if (right instanceof InvokeExpr) { - if (right instanceof StaticInvokeExpr) { + } else if (right instanceof AbstractInvokeExpr) { + if (right instanceof JStaticInvokeExpr) { this.f[17] = true; - } else if (right instanceof VirtualInvokeExpr || right instanceof InterfaceInvokeExpr) { + } else if (right instanceof JVirtualInvokeExpr || right instanceof JInterfaceInvokeExpr) { this.f[18] = true; } - } else if (right instanceof ArrayRef) { + } else if (right instanceof JArrayRef) { this.f[13] = true; } - } else if (left instanceof InstanceFieldRef) { + } else if (left instanceof JInstanceFieldRef) { this.f[16] = true; } } else if (unit instanceof InvokeStmt invokeStmt) { - InvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof StaticInvokeExpr) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JStaticInvokeExpr) { this.f[17] = true; - } else if (expr instanceof VirtualInvokeExpr || expr instanceof InterfaceInvokeExpr) { + } else if (expr instanceof JVirtualInvokeExpr || expr instanceof JInterfaceInvokeExpr) { this.f[18] = true; } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java index 1d41b8ada6b..1d9ca2b1f33 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java @@ -5,15 +5,17 @@ import qilin.util.PTAUtils; import qilin.util.Pair; import qilin.util.queue.UniqueQueue; -import soot.jimple.InstanceInvokeExpr; -import soot.jimple.InvokeExpr; -import soot.jimple.NullConstant; import soot.util.NumberedString; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; +import sootup.core.types.ReferenceType; import sootup.core.types.Type; import java.util.HashSet; @@ -44,7 +46,7 @@ protected void collectParams() { VarNode thisNode = srcnf.caseThis(); // handle parameters for (int i = 0; i < method.getParameterCount(); ++i) { - if (method.getParameterType(i) instanceof RefLikeType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + if (method.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); this.params.add(param); } @@ -94,7 +96,7 @@ public boolean isDirectlyReturnedHeap(AllocNode heap) { public boolean isContentFromParam(AllocNode heap) { Type heapType = heap.getType(); - if (heapType instanceof RefType) { + if (heapType instanceof ClassType) { return isInstanceObjectContentFromParam(heap); } else { return isArrayContentFromParam(heap); @@ -130,16 +132,15 @@ private boolean isInstanceObjectContentFromParam(AllocNode heap) { } private Set collectParamInArguments(AllocNode heap) { - RefType type = (RefType) heap.getType(); + ClassType type = (ClassType) heap.getType(); Set x = epsilon(heap); Set ret = new HashSet<>(); HeapContainerQuery hcq = this.utility.getHCQ(heap); Set inParams = hcq.getInParamsToCSFields(); MethodPAG srcmpag = pag.getMethodPAG(method); - for (final Unit u : srcmpag.getInvokeStmts()) { - final Stmt s = (Stmt) u; - InvokeExpr ie = s.getInvokeExpr(); - if (!(ie instanceof InstanceInvokeExpr iie)) { + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (!(ie instanceof AbstractInstanceInvokeExpr iie)) { continue; } LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); @@ -150,7 +151,7 @@ private Set collectParamInArguments(AllocNode heap) { Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); - if (!(arg.getType() instanceof RefLikeType) || arg instanceof NullConstant) { + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { continue; } args[i] = arg; @@ -167,7 +168,7 @@ private Set collectParamInArguments(AllocNode heap) { System.out.println(target); } for (int i = 0; i < numParms; i++) { - if (target.getParameterType(i) instanceof RefLikeType) { + if (target.getParameterType(i) instanceof ReferenceType) { if (args[i] != null) { ValNode argNode = pag.findValNode(args[i]); if (argNode instanceof LocalVarNode lvn) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index 937c816011c..be174f4d17d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -7,6 +7,10 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -69,7 +73,7 @@ protected void buildInternalWithInline(SootMethod method) { } // handle call statements. for (final Stmt s : srcmpag.getInvokeStmts()) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { @@ -85,16 +89,16 @@ protected void buildInternalWithInline(SootMethod method) { retDest = pag.findLocalVarNode(dest); } } - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); - if (iie instanceof SpecialInvokeExpr sie) { + if (iie instanceof JSpecialInvokeExpr sie) { inline(s, sie.getMethod()); } else { /* instance call with non-this base variable are modeled as in Eagle/Turner. */ modelVirtualCall(numArgs, args, receiver, retDest); } } else { - if (ie instanceof StaticInvokeExpr sie) { + if (ie instanceof JStaticInvokeExpr sie) { SootMethod target = sie.getMethod(); inline(s, target); } @@ -134,7 +138,7 @@ private void modelVirtualCall(int numArgs, Value[] args, LocalVarNode receiver, } private void inline(Stmt invokeStmt, SootMethod method) { - InvokeExpr ie = invokeStmt.getInvokeExpr(); + AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { @@ -151,7 +155,7 @@ private void inline(Stmt invokeStmt, SootMethod method) { } } LocalVarNode receiver = null; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = pag.findLocalVarNode(iie.getBase()); } MethodPAG mpag = pag.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index 37fe6cd0616..3d417beafee 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -6,12 +6,12 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.jimple.InstanceInvokeExpr; -import soot.jimple.InvokeExpr; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.NumberedString; import soot.util.queue.QueueReader; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootClass; import sootup.core.model.SootField; @@ -209,8 +209,8 @@ private void buildHeapMethodsMapping() { continue; } final Stmt s = edge.srcStmt(); - InvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof InstanceInvokeExpr iie) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof AbstractInstanceInvokeExpr iie) { LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); NumberedString subSig = iie.getMethodRef().getSubSignature(); VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, edge.src(), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); @@ -221,7 +221,7 @@ private void buildHeapMethodsMapping() { } // foreach virtualcallsite, we build mapping from their receiver objects. for (VirtualCallSite vcallsite : vcallsites) { - InstanceInvokeExpr iie = vcallsite.iie(); + AbstractInstanceInvokeExpr iie = vcallsite.iie(); LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); for (AllocNode heap : pta.reachingObjects(receiver).toCIPointsToSet().toCollection()) { QueueReader reader = PTAUtils.dispatch(heap.getType(), vcallsite); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index d944ecad303..933c647601e 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -31,6 +31,8 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -320,7 +322,7 @@ else if (to instanceof FieldRefNode fr) { // add invoke edges for (final Stmt s : srcmpag.getInvokeStmts()) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { @@ -337,7 +339,7 @@ else if (to instanceof FieldRefNode fr) { } } LocalVarNode receiver; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } else { // static call diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index 90262126233..7f3e4936484 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -30,6 +30,8 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -268,7 +270,7 @@ private void buildGraph() { MethodNodeFactory srcnf = srcmpag.nodeFactory(); for (final Stmt s : srcmpag.getInvokeStmts()) { CallSite callSite = new CallSite(s); - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { @@ -286,7 +288,7 @@ private void buildGraph() { } } LocalVarNode receiver = null; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = prePAG.findLocalVarNode(iie.getBase()); } for (Iterator it = prePTA.getCallGraph().edgesOutOf(s); it.hasNext(); ) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 4b3b29e5edd..2f17a255cce 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -24,12 +24,13 @@ import qilin.core.pag.*; import qilin.util.Pair; import qilin.util.queue.UniqueQueue; -import soot.jimple.*; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -152,7 +153,7 @@ else if (to instanceof FieldRefNode fr) { // add invoke edges for (final Stmt s : srcmpag.getInvokeStmts()) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); Value[] args = new Value[numArgs]; for (int i = 0; i < numArgs; i++) { @@ -169,7 +170,7 @@ else if (to instanceof FieldRefNode fr) { } } LocalVarNode receiver; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = pag.findLocalVarNode(iie.getBase()); } else { // static call diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java index 7448dbd9eb5..b47db829431 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -9,9 +9,9 @@ import qilin.util.graph.ConcurrentDirectedGraphImpl; import qilin.util.graph.Reachability; import soot.jimple.AssignStmt; -import soot.jimple.InstanceInvokeExpr; -import soot.jimple.InvokeExpr; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -145,9 +145,9 @@ private void dfs(Node node) { pta.getCgb().getReceiverToSitesMap() .getOrDefault(var, Collections.emptySet()) .forEach(vcs -> { - Stmt callsiteStmt = (Stmt) vcs.getUnit(); - InvokeExpr invo = callsiteStmt.getInvokeExpr(); - if (!(invo instanceof InstanceInvokeExpr)) { + Stmt callsiteStmt = vcs.getUnit(); + AbstractInvokeExpr invo = callsiteStmt.getInvokeExpr(); + if (!(invo instanceof AbstractInstanceInvokeExpr)) { return; } if (callsiteStmt instanceof AssignStmt assignStmt) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java index 890f94a3d4a..3d9a2b47d30 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java @@ -4,8 +4,9 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.pta.toolkits.zipper.Global; -import soot.jimple.*; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -107,9 +108,9 @@ private void init() { if (!callee.isStatic()) { MethodNodeFactory calleeNF = pta.getPag().getMethodPAG(callee).nodeFactory(); LocalVarNode thisVar = (LocalVarNode) calleeNF.caseThis(); - InvokeExpr ie = callsite.getInvokeExpr(); + AbstractInvokeExpr ie = callsite.getInvokeExpr(); Value base = null; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { base = iie.getBase(); } if (base != null) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java index 61acc05840e..69006afea65 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java @@ -24,9 +24,9 @@ import qilin.pta.toolkits.eagle.Eagle; import qilin.util.Pair; import qilin.util.Stopwatch; -import soot.jimple.Expr; -import soot.jimple.NewArrayExpr; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.common.expr.Expr; +import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.stmt.Stmt; import java.io.FileNotFoundException; @@ -81,8 +81,8 @@ protected void writeToFile(Map partialResults) throws FileNotFo return; } String newExpr = heap.getNewExpr().toString(); - if (heap.getNewExpr() instanceof NewArrayExpr nae) { - newExpr = "new " + nae.getBaseType().toString() + "[]"; + if (heap.getNewExpr() instanceof JNewArrayExpr nae) { + newExpr = "new " + nae.getBaseType() + "[]"; } String heapSig = heap.getMethod().toString() + "/" + newExpr; heapWriter.write(heapSig); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index bbfbd88fe56..93e150d64d7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -32,6 +32,8 @@ import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -145,7 +147,7 @@ protected void extraStats() { } } for (final Stmt s : srcmpag.getInvokeStmts()) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); @@ -161,7 +163,7 @@ protected void extraStats() { nodes.add(dest); } } - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { Value base = iie.getBase(); if (base instanceof Local) { nodes.add(base); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 1dcc1c95abd..f4220ef1811 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -34,6 +34,8 @@ import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -146,7 +148,7 @@ protected void extraStats() { } } for (final Stmt s : srcmpag.getInvokeStmts()) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); @@ -162,7 +164,7 @@ protected void extraStats() { nodes.add(dest); } } - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { Value base = iie.getBase(); if (base instanceof Local) { nodes.add(base); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index 118c2f7e14f..b991eebad05 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -34,6 +34,8 @@ import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -116,7 +118,7 @@ protected void extraStats() { } } for (final Stmt s : srcmpag.getInvokeStmts()) { - InvokeExpr ie = s.getInvokeExpr(); + AbstractInvokeExpr ie = s.getInvokeExpr(); int numArgs = ie.getArgCount(); for (int i = 0; i < numArgs; i++) { Value arg = ie.getArg(i); @@ -132,7 +134,7 @@ protected void extraStats() { nodes.add(dest); } } - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { Value base = iie.getBase(); if (base instanceof Local) { nodes.add(base); diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index c2b7fd63d5b..12f88b1f9a7 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -30,6 +30,9 @@ import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -76,8 +79,8 @@ public void end() { for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { // virtual calls if (st.containsInvokeExpr()) { - InvokeExpr ie = st.getInvokeExpr(); - if (!(ie instanceof StaticInvokeExpr)) { + AbstractInvokeExpr ie = st.getInvokeExpr(); + if (!(ie instanceof JStaticInvokeExpr)) { // Virtual, Special or Instance // have to check target soot method, cannot just // count edges @@ -91,9 +94,9 @@ public void end() { } else if (st instanceof AssignStmt) { Value rhs = ((AssignStmt) st).getRightOp(); Value lhs = ((AssignStmt) st).getLeftOp(); - if (rhs instanceof CastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = ((CastExpr) rhs).getCastType(); - Value v = ((CastExpr) rhs).getOp(); + if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { + final Type targetType = ((JCastExpr) rhs).getCastType(); + Value v = ((JCastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; } diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index f78cb9a04df..5660f2fae2d 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -28,6 +28,9 @@ import soot.jimple.toolkits.callgraph.Edge; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -49,7 +52,7 @@ public class TypeClientStat implements AbstractStat { private int totalStaticCalls = 0; private int totalPolyCallTargets = 0; private int unreachable = 0; - private final Map polyCalls = new HashMap<>(); + private final Map polyCalls = new HashMap<>(); private final Map> mayFailCasts = new HashMap<>(); public TypeClientStat(PTA pta) { @@ -75,8 +78,8 @@ private void init() { for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { // virtual calls if (st.containsInvokeExpr()) { - InvokeExpr ie = st.getInvokeExpr(); - if (ie instanceof StaticInvokeExpr) { + AbstractInvokeExpr ie = st.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { totalStaticCalls++; } else {// Virtual, Special or Instance totalVirtualCalls++; @@ -104,9 +107,9 @@ private void init() { } else if (st instanceof AssignStmt) { Value rhs = ((AssignStmt) st).getRightOp(); Value lhs = ((AssignStmt) st).getLeftOp(); - if (rhs instanceof CastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = ((CastExpr) rhs).getCastType(); - Value v = ((CastExpr) rhs).getOp(); + if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { + final Type targetType = ((JCastExpr) rhs).getCastType(); + Value v = ((JCastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; } diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index b0f2ee765fc..597cb845502 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -44,7 +44,11 @@ import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; @@ -85,7 +89,7 @@ public static Map> calcStaticThisPTS(PTA pta) { for (final Stmt s : srcmpag.getInvokeStmts()) { AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof StaticInvokeExpr) { + if (ie instanceof JStaticInvokeExpr) { for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); @@ -118,7 +122,7 @@ public static Map> calcStaticThisPTS(PTA pta) { for (final Stmt s : srcmpag.getInvokeStmts()) { AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof StaticInvokeExpr) { + if (ie instanceof JStaticInvokeExpr) { for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { Edge e = it.next(); SootMethod tgtmtd = e.tgt(); @@ -294,8 +298,8 @@ public static QueueReader dispatch(Type type, VirtualCallSite site) return targets; } MethodOrMethodContext container = site.container(); - if (site.iie() instanceof SpecialInvokeExpr && site.kind() != Kind.THREAD) { - SootMethod target = VirtualCalls.v().resolveSpecial((SpecialInvokeExpr) site.iie(), site.subSig(), container.method()); + if (site.iie() instanceof JSpecialInvokeExpr && site.kind() != Kind.THREAD) { + SootMethod target = VirtualCalls.v().resolveSpecial((JSpecialInvokeExpr) site.iie(), site.subSig(), container.method()); // if the call target resides in a phantom class then // "target" will be null, simply do not add the target in that case if (target != null) { @@ -797,7 +801,7 @@ public static Body getMethodBody(SootMethod m) { public static boolean isEmptyArray(AllocNode heap) { Object var = heap.getNewExpr(); - if (var instanceof NewArrayExpr nae) { + if (var instanceof JNewArrayExpr nae) { Value sizeVal = nae.getSize(); if (sizeVal instanceof IntConstant size) { return size.getValue() == 0; @@ -808,11 +812,11 @@ public static boolean isEmptyArray(AllocNode heap) { public static LocalVarNode paramToArg(PAG pag, Stmt invokeStmt, MethodPAG srcmpag, VarNode pi) { MethodNodeFactory srcnf = srcmpag.nodeFactory(); - InvokeExpr ie = invokeStmt.getInvokeExpr(); + AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); Parm mPi = (Parm) pi.getVariable(); LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); LocalVarNode receiver; - if (ie instanceof InstanceInvokeExpr iie) { + if (ie instanceof AbstractInstanceInvokeExpr iie) { receiver = pag.findLocalVarNode(iie.getBase()); } else { // static call diff --git a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java index 89bdc379335..972b95737a9 100644 --- a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java +++ b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java @@ -25,12 +25,12 @@ import soot.Context; import soot.Kind; import soot.MethodOrMethodContext; -import soot.jimple.InterfaceInvokeExpr; -import soot.jimple.InvokeExpr; -import soot.jimple.SpecialInvokeExpr; -import soot.jimple.StaticInvokeExpr; -import soot.jimple.VirtualInvokeExpr; import soot.util.Invalidable; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -116,14 +116,14 @@ public Kind kind() { return kind; } - public static Kind ieToKind(InvokeExpr ie) { - if (ie instanceof VirtualInvokeExpr) { + public static Kind ieToKind(AbstractInvokeExpr ie) { + if (ie instanceof JVirtualInvokeExpr) { return Kind.VIRTUAL; - } else if (ie instanceof SpecialInvokeExpr) { + } else if (ie instanceof JSpecialInvokeExpr) { return Kind.SPECIAL; - } else if (ie instanceof InterfaceInvokeExpr) { + } else if (ie instanceof JInterfaceInvokeExpr) { return Kind.INTERFACE; - } else if (ie instanceof StaticInvokeExpr) { + } else if (ie instanceof JStaticInvokeExpr) { return Kind.STATIC; } else { throw new RuntimeException(); From eaa966fcabc18be70af43ffe54317118d3e576bd Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 17 Sep 2023 13:19:31 +1000 Subject: [PATCH 015/145] replace isPhantom with not isConcrete --- sootup.qilin/src/main/java/qilin/core/solver/Solver.java | 2 +- sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java | 2 +- .../src/main/java/qilin/pta/toolkits/conch/AbstractConch.java | 2 +- .../src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java | 2 +- .../src/main/java/qilin/pta/toolkits/conch/Conch.java | 4 ++-- .../src/main/java/qilin/pta/toolkits/eagle/Eagle.java | 2 +- .../src/main/java/qilin/pta/toolkits/selectx/Selectx.java | 2 +- .../src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java | 4 ++-- .../src/main/java/qilin/pta/toolkits/turner/Turner.java | 4 ++-- .../src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java | 2 +- .../src/main/java/qilin/pta/tools/PartialObjSensPTA.java | 2 +- sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java | 2 +- sootup.qilin/src/main/java/qilin/stat/YummyStat.java | 2 +- sootup.qilin/src/main/java/qilin/util/PTAUtils.java | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 5f48a85a5a5..01719db4b9e 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -109,7 +109,7 @@ public void processStmts(Iterator newRMs) { while (newRMs.hasNext()) { MethodOrMethodContext momc = newRMs.next(); SootMethod method = momc.method(); - if (method.isPhantom()) { + if (!method.isConcrete()) { continue; } MethodPAG mpag = pag.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java index 09229b65257..d0c550388b5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java @@ -108,7 +108,7 @@ public boolean reaches(AllocNode source, AllocNode dest) { protected void buildOAG() { Map> pts = PTAUtils.calcStaticThisPTS(this.pta); for (SootMethod method : this.pta.getNakedReachableMethods()) { - if (method.isPhantom()) { + if (!method.isConcrete()) { continue; } MethodPAG srcmpag = pta.getPag().getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java index ef18a73d290..a2abca8bf06 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java @@ -55,7 +55,7 @@ private void init() { * The following line computes the receiver objects for the this_ptr of static methods. * */ Map> pts = PTAUtils.calcStaticThisPTS(pta); - pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(method -> { + pta.getNakedReachableMethods().stream().filter(SootMethod::isConcrete).forEach(method -> { collectStoresIn(method); collectLoadsIn(method); buildInvokedOnFor(method, pts); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java index d83e0aba27a..2227bf8c703 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -68,7 +68,7 @@ protected AbstractPAG(PTA prePTA) { protected void build() { prePTA.getNakedReachableMethods() - .parallelStream().filter(m -> !m.isPhantom()) + .parallelStream().filter(SootMethod::isConcrete) .forEach(this::buildFG); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index f0ddec59eca..521e083dfc2 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -70,8 +70,8 @@ private SootMethod findInvokedConstructorOf(AllocNode heap) { MethodNodeFactory nodeFactory = cmpag.nodeFactory(); for (Stmt unit : cmpag.getInvokeStmts()) { if (unit instanceof InvokeStmt invokeStmt) { - InvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof SpecialInvokeExpr iie) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); PointsToSet v1pts = pta.reachingObjects(baseNode); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index 933c647601e..95b8e355687 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -263,7 +263,7 @@ public void buildGraph(PTA prePTA) { CallGraph callGraph = prePTA.getCallGraph(); for (SootMethod method : prePTA.getNakedReachableMethods()) { - if (method.isPhantom()) { + if (!method.isConcrete()) { continue; } MethodPAG srcmpag = prePAG.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index 7f3e4936484..a0982d587b0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -228,7 +228,7 @@ int getCallSiteNumber(CallSite callsite) { private void buildGraph() { for (SootMethod method : prePTA.getNakedReachableMethods()) { - if (method.isPhantom()) { + if (!method.isConcrete()) { continue; } MethodPAG srcmpag = prePAG.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java index 18ed2b167f8..7f2750fe093 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -47,7 +47,7 @@ public ModularMVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode protected boolean statisfyAddingLoadCondition(Set targets) { for (SootMethod tgtmtd : targets) { // the target method is in the same scc with current method. - if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { + if (!tgtmtd.isConcrete() || sccNode.getContent().contains(tgtmtd)) { return true; } if (!(tgtmtd.getReturnType() instanceof ReferenceType)) { @@ -69,7 +69,7 @@ protected boolean statisfyAddingLoadCondition(Set targets) { protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { for (SootMethod tgtmtd : targets) { // the target method is in the same scc with current method. - if (tgtmtd.isPhantom() || sccNode.getContent().contains(tgtmtd)) { + if (!tgtmtd.isConcrete() || sccNode.getContent().contains(tgtmtd)) { return true; } MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java index 3f45885e976..856d2c1a927 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java @@ -167,7 +167,7 @@ private void statObjInOCG(Map ret) { } private Collection computeCtxLevelForVariables(SootMethod method) { - if (method.isPhantom()) { + if (!method.isConcrete()) { return Collections.emptySet(); } else { AbstractMVFG mvfg = MethodVFG.findOrCreateMethodVFG(prePTA, method, ocg); @@ -178,7 +178,7 @@ private Collection computeCtxLevelForVariables(SootMethod method) { } private Collection computeCtxLevelForVariables(SootMethod method, MergedNode sccNode) { - if (method.isPhantom()) { + if (!method.isConcrete()) { return Collections.emptySet(); } else { AbstractMVFG mvfg = ModularMVFG.findOrCreateMethodVFG(prePTA, method, ocg, sccNode); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index 93e150d64d7..b472fbd5a30 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -119,7 +119,7 @@ protected void extraStats() { for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); - if (method.isPhantom()) { + if (!method.isConcrete()) { return; } MethodPAG srcmpag = pag.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index f4220ef1811..15393f3d620 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -120,7 +120,7 @@ protected void extraStats() { for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); - if (method.isPhantom()) { + if (!method.isConcrete()) { return; } MethodPAG srcmpag = pag.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index b991eebad05..1f91b40cc52 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -90,7 +90,7 @@ protected void extraStats() { SootMethod method = momc.method(); Set nodes = new HashSet<>(); - if (method.isPhantom()) { + if (!method.isConcrete()) { return; } MethodPAG srcmpag = pag.getMethodPAG(method); diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java index 9fea2dc0db7..21d304c6402 100644 --- a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -69,7 +69,7 @@ private void init() { Set instanceReachables = new HashSet<>(); for (final MethodOrMethodContext momc : pta.getReachableMethods()) { SootMethod method = momc.method(); - if (!method.isPhantom() && !method.isStatic()) { + if (method.isConcrete() && !method.isStatic()) { instanceReachables.add(method); } } diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 597cb845502..2bd22e2c706 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -82,7 +82,7 @@ public static Map> calcStaticThisPTS(PTA pta) { PAG pag = pta.getPag(); // add all instance methods which potentially contain static call for (SootMethod method : pta.getNakedReachableMethods()) { - if (PTAUtils.isFakeMainMethod(method) || !method.isPhantom() && !method.isStatic()) { + if (PTAUtils.isFakeMainMethod(method) || method.isConcrete() && !method.isStatic()) { MethodPAG srcmpag = pag.getMethodPAG(method); LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); final PointsToSet other = pta.reachingObjects(thisRef).toCIPointsToSet(); From 3daad2fd57aac08a22d9ae50880cba5f862bf43d Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 17 Sep 2023 19:41:30 +1000 Subject: [PATCH 016/145] replace stmts with their counterparts in sootup --- .../java/qilin/core/ArtificialMethod.java | 56 +++++++++++-------- .../qilin/core/builder/CallGraphBuilder.java | 5 +- .../qilin/core/builder/ExceptionHandler.java | 6 +- .../qilin/core/builder/MethodNodeFactory.java | 16 ++++-- .../main/java/qilin/core/pag/MethodPAG.java | 13 ++--- .../src/main/java/qilin/core/pag/PAG.java | 11 ++-- .../qilin/core/reflection/TamiflexModel.java | 54 +++++++++--------- .../main/java/qilin/core/solver/Solver.java | 5 +- .../java/qilin/pta/toolkits/conch/Conch.java | 6 +- .../toolkits/conch/DepOnParamAnalysis.java | 4 +- .../pta/toolkits/conch/LeakAnalysis.java | 2 +- .../dd/CtxTunnelingFeaturesTrueTable.java | 6 +- .../pta/toolkits/dd/FeaturesTrueTable.java | 44 ++++++++++----- .../qilin/pta/toolkits/debloaterx/XPAG.java | 9 +-- .../pta/toolkits/debloaterx/XUtility.java | 4 +- .../java/qilin/pta/toolkits/eagle/Eagle.java | 5 +- .../qilin/pta/toolkits/selectx/Selectx.java | 5 +- .../pta/toolkits/turner/AbstractMVFG.java | 5 +- .../zipper/flowgraph/FlowAnalysis.java | 4 +- .../pta/tools/PartialCallSiteSensPTA.java | 11 ++-- .../qilin/pta/tools/PartialObjSensPTA.java | 11 ++-- .../main/java/qilin/pta/tools/ZipperPTA.java | 11 ++-- .../java/qilin/stat/SimplifiedEvaluator.java | 7 ++- .../main/java/qilin/stat/TypeClientStat.java | 7 ++- 24 files changed, 172 insertions(+), 135 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index 84208f0b058..bb7e7aadf7a 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -18,12 +18,22 @@ package qilin.core; -import soot.jimple.Jimple; -import soot.jimple.ParameterRef; -import soot.jimple.ThisRef; -import soot.jimple.internal.*; +import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; +import sootup.core.jimple.common.ref.IdentityRef; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JIdentityStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; +import sootup.core.jimple.common.stmt.JReturnStmt; import sootup.core.model.Body; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; @@ -71,13 +81,13 @@ protected Value getPara(int index, Type type) { return paraLocal; } - private void addIdentity(Value lValue, Value rValue) { - body.getUnits().add(new JIdentityStmt(lValue, rValue)); + private void addIdentity(Local lValue, IdentityRef rValue) { + body.getUnits().add(new JIdentityStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); } - protected Value getNew(ClassType type) { + protected Local getNew(ClassType type) { Value newExpr = new JNewExpr(type); - Value local = getNextLocal(type); + Local local = getNextLocal(type); addAssign(local, newExpr); return local; } @@ -89,18 +99,18 @@ protected Value getNewArray(ClassType type) { return local; } - protected Value getNextLocal(Type type) { + protected Local getNextLocal(Type type) { return getLocal(type, localStart++); } - private Value getLocal(Type type, int index) { + private Local getLocal(Type type, int index) { Local local = new JimpleLocal("r" + index, type); body.getLocals().add(local); return local; } - protected void addReturn(Value ret) { - body.getUnits().add(new JReturnStmt(ret)); + protected void addReturn(Immediate ret) { + body.getUnits().add(new JReturnStmt(ret, StmtPositionInfo.createNoStmtPositionInfo())); } protected Value getStaticFieldRef(String className, String name) { @@ -114,12 +124,12 @@ protected Value getArrayRef(Value base) { /** * add an instance invocation receiver.sig(args) */ - protected void addInvoke(Value receiver, String sig, Value... args) { + protected void addInvoke(Local receiver, String sig, Immediate ... args) { SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); - List argsL = Arrays.asList(args); - Value invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) + List argsL = Arrays.asList(args); + AbstractInvokeExpr invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) : new JVirtualInvokeExpr(receiver, methodRef, argsL); - body.getUnits().add(new JInvokeStmt(invoke)); + body.getUnits().add(new JInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo())); } /** @@ -127,9 +137,9 @@ protected void addInvoke(Value receiver, String sig, Value... args) { * * @return rx */ - protected Value getInvoke(Value receiver, String sig, Value... args) { + protected Value getInvoke(Local receiver, String sig, Immediate... args) { SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); - List argsL = Arrays.asList(args); + List argsL = Arrays.asList(args); Value invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) : new JVirtualInvokeExpr(receiver, methodRef, argsL); Value rx = getNextLocal(methodRef.getReturnType()); @@ -140,9 +150,9 @@ protected Value getInvoke(Value receiver, String sig, Value... args) { /** * add a static invocation sig(args) */ - protected void addInvoke(String sig, Value... args) { + protected void addInvoke(String sig, Immediate... args) { SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); - List argsL = Arrays.asList(args); + List argsL = Arrays.asList(args); body.getUnits().add(new JInvokeStmt(new JStaticInvokeExpr(methodRef, argsL))); } @@ -151,15 +161,15 @@ protected void addInvoke(String sig, Value... args) { * * @return rx */ - protected Value getInvoke(String sig, Value... args) { + protected Value getInvoke(String sig, Immediate... args) { SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); - List argsL = Arrays.asList(args); + List argsL = Arrays.asList(args); Value rx = getNextLocal(methodRef.getReturnType()); addAssign(rx, new JStaticInvokeExpr(methodRef, argsL)); return rx; } protected void addAssign(Value lValue, Value rValue) { - body.getUnits().add(new JAssignStmt(lValue, rValue)); + body.getUnits().add(new JAssignStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 67c19ee0a67..44f1e5adfb6 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -39,6 +39,7 @@ import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -232,8 +233,8 @@ private void processCallAssign(Edge e) { pag.addEdge(argNode, parm); } // add normal return edge - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { Node destNode = srcnf.getNode(dest); diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index 5def737b49a..f08c197128f 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -26,8 +26,8 @@ import qilin.util.DataFactory; import soot.Context; import soot.MethodOrMethodContext; -import soot.jimple.IdentityStmt; import sootup.core.jimple.basic.Trap; +import sootup.core.jimple.common.stmt.JIdentityStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.Type; @@ -76,8 +76,8 @@ public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { for (Trap trap : trapList) { if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, trap.getException().getType())) { Stmt handler = trap.getHandlerUnit(); - assert handler instanceof IdentityStmt; - IdentityStmt handlerStmt = (IdentityStmt) handler; + assert handler instanceof JIdentityStmt; + JIdentityStmt handlerStmt = (JIdentityStmt) handler; Node caughtParam = nodeFactory.getNode(handlerStmt.getRightOp()); Node dst = pta.parameterize(caughtParam, context); pag.addEdge(throwObj, dst); diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index e694d345364..6e6433c9275 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -41,6 +41,10 @@ import sootup.core.jimple.common.ref.JParameterRef; import sootup.core.jimple.common.ref.JStaticFieldRef; import sootup.core.jimple.common.ref.JThisRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JIdentityStmt; +import sootup.core.jimple.common.stmt.JReturnStmt; +import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Modifier; import sootup.core.model.SootClass; @@ -124,8 +128,8 @@ protected void handleInvokeStmt(Stmt s) { } getNode(arg); } - if (s instanceof AssignStmt) { - Value l = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value l = ((JAssignStmt) s).getLeftOp(); if ((l.getType() instanceof ReferenceType)) { getNode(l); } @@ -144,7 +148,7 @@ private void resolveClinit(JStaticFieldRef staticFieldRef) { */ private void handleIntraStmt(Stmt s) { s.apply(new AbstractStmtSwitch<>() { - public void caseAssignStmt(AssignStmt as) { + public void caseAssignStmt(JAssignStmt as) { Value l = as.getLeftOp(); Value r = as.getRightOp(); if (l instanceof JStaticFieldRef) { @@ -169,14 +173,14 @@ public void caseAssignStmt(AssignStmt as) { mpag.addInternalEdge(src, dest); } - public void caseReturnStmt(ReturnStmt rs) { + public void caseReturnStmt(JReturnStmt rs) { if (!(rs.getOp().getType() instanceof ReferenceType)) return; Node retNode = getNode(rs.getOp()); mpag.addInternalEdge(retNode, caseRet()); } - public void caseIdentityStmt(IdentityStmt is) { + public void caseIdentityStmt(JIdentityStmt is) { if (!(is.getLeftOp().getType() instanceof ReferenceType)) { return; } @@ -185,7 +189,7 @@ public void caseIdentityStmt(IdentityStmt is) { mpag.addInternalEdge(src, dest); } - public void caseThrowStmt(ThrowStmt ts) { + public void caseThrowStmt(JThrowStmt ts) { if (!CoreConfig.v().getPtaConfig().preciseExceptions) { mpag.addInternalEdge(getNode(ts.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index e6e26b18736..6d93e6acc8c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -24,11 +24,11 @@ import qilin.util.PTAUtils; import soot.jimple.Jimple; -import soot.jimple.ThrowStmt; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Trap; import sootup.core.jimple.common.ref.JStaticFieldRef; +import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootMethod; @@ -125,12 +125,12 @@ protected void buildException() { return; } inTraps.add(unit); - Stmt stmt = (Stmt) unit; + Stmt stmt = unit; Node src = null; if (stmt.containsInvokeExpr()) { // note, method.getExceptions() does not return implicit exceptions. src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); - } else if (stmt instanceof ThrowStmt ts) { + } else if (stmt instanceof JThrowStmt ts) { src = nodeFactory.getNode(ts.getOp()); } if (src != null) { @@ -139,15 +139,14 @@ protected void buildException() { }); }); - for (Stmt unit : body.getStmts()) { - if (inTraps.contains(unit)) { + for (Stmt stmt : body.getStmts()) { + if (inTraps.contains(stmt)) { continue; } - Stmt stmt = unit; Node src = null; if (stmt.containsInvokeExpr()) { src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); - } else if (stmt instanceof ThrowStmt ts) { + } else if (stmt instanceof JThrowStmt ts) { src = nodeFactory.getNode(ts.getOp()); } if (src != null) { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 89a8bb2982d..7d25996e705 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -31,18 +31,19 @@ import qilin.util.PTAUtils; import soot.Context; import soot.MethodOrMethodContext; -import soot.jimple.internal.JAssignStmt; import soot.jimple.internal.JimpleLocal; import soot.util.ArrayNumberer; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootField; @@ -570,7 +571,7 @@ private void handleArrayCopy(SootMethod method) { if (srcArr.getType() == objType) { Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); body.getLocals().add(localSrc); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr)); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); srcArr = localSrc; } Value dstArr = sie.getArg(2); @@ -580,15 +581,15 @@ private void handleArrayCopy(SootMethod method) { if (dstArr.getType() == objType) { Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); body.getLocals().add(localDst); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr)); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr,StmtPositionInfo.createNoStmtPositionInfo())); dstArr = localDst; } Value src = new JArrayRef(srcArr, IntConstant.v(0)); Value dst = new JArrayRef(dstArr, IntConstant.v(0)); Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), PTAUtils.getClassType("java.lang.Object")); body.getLocals().add(local); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(local, src)); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(dst, local)); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(local, src, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); } } } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index c2dddef906a..c6e755fb667 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -22,9 +22,9 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.jimple.internal.*; import soot.tagkit.LineNumberTag; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; import sootup.core.jimple.common.constant.NullConstant; @@ -37,6 +37,8 @@ import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JFieldRef; import sootup.core.jimple.common.ref.JInstanceFieldRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; @@ -75,9 +77,9 @@ Collection transformClassForName(Stmt s) { for (String clazz : fornames) { Type refType = PTAUtils.getClassType(clazz); ClassConstant cc = ClassConstant.fromType(refType); - if (s instanceof AssignStmt) { - Value lvalue = ((AssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt(lvalue, cc)); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); } } } @@ -87,10 +89,10 @@ Collection transformClassForName(Stmt s) { @Override protected Collection transformClassNewInstance(Stmt s) { // - if (!(s instanceof AssignStmt)) { + if (!(s instanceof JAssignStmt)) { return Collections.emptySet(); } - Value lvalue = ((AssignStmt) s).getLeftOp(); + Value lvalue = ((JAssignStmt) s).getLeftOp(); Collection ret = DataFactory.createSet(); Map> classNewInstances = reflectionMap.getOrDefault(ReflectionKind.ClassNewInstance, Collections.emptyMap()); if (classNewInstances.containsKey(s)) { @@ -99,7 +101,7 @@ protected Collection transformClassNewInstance(Stmt s) { SootClass cls = PTAScene.v().getSootClass(clsName); if (cls.declaresMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()"))) { JNewExpr newExpr = new JNewExpr(cls.getType()); - ret.add(new JAssignStmt(lvalue, newExpr)); + ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); SootMethod constructor = cls.getMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()")); ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.makeRef(), Collections.emptyList()))); } @@ -111,10 +113,10 @@ protected Collection transformClassNewInstance(Stmt s) { @Override protected Collection transformContructorNewInstance(Stmt s) { // - if (!(s instanceof AssignStmt)) { + if (!(s instanceof JAssignStmt)) { return Collections.emptySet(); } - Value lvalue = ((AssignStmt) s).getLeftOp(); + Value lvalue = ((JAssignStmt) s).getLeftOp(); Collection ret = DataFactory.createSet(); Map> constructorNewInstances = reflectionMap.getOrDefault(ReflectionKind.ConstructorNewInstance, Collections.emptyMap()); if (constructorNewInstances.containsKey(s)) { @@ -123,12 +125,12 @@ protected Collection transformContructorNewInstance(Stmt s) { Value args = iie.getArg(0); JArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); Value arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); - ret.add(new JAssignStmt(arg, arrayRef)); + ret.add(new JAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); for (String constructorSignature : constructorSignatures) { SootMethod constructor = PTAScene.v().getMethod(constructorSignature); SootClass cls = constructor.getDeclaringClass(); JNewExpr newExpr = new JNewExpr(cls.getType()); - ret.add(new JAssignStmt(lvalue, newExpr)); + ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); int argCount = constructor.getParameterCount(); List mArgs = new ArrayList<>(argCount); for (int i = 0; i < argCount; i++) { @@ -172,11 +174,11 @@ protected Collection transformMethodInvoke(Stmt s) { assert !(base instanceof NullConstant); ie = new JVirtualInvokeExpr(base, method.makeRef(), mArgs); } - if (s instanceof AssignStmt) { - Value lvalue = ((AssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt(lvalue, ie)); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt(lvalue, ie, StmtPositionInfo.createNoStmtPositionInfo())); } else { - ret.add(new JInvokeStmt(ie)); + ret.add(new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo())); } } } @@ -203,7 +205,7 @@ protected Collection transformFieldSet(Stmt s) { assert !(base instanceof NullConstant); fieldRef = new JInstanceFieldRef(base, field.makeRef()); } - Stmt stmt = new JAssignStmt(fieldRef, rValue); + Stmt stmt = new JAssignStmt(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); ret.add(stmt); } } @@ -215,9 +217,9 @@ protected Collection transformFieldGet(Stmt s) { // Collection ret = DataFactory.createSet(); Map> fieldGets = reflectionMap.getOrDefault(ReflectionKind.FieldGet, Collections.emptyMap()); - if (fieldGets.containsKey(s) && s instanceof AssignStmt) { + if (fieldGets.containsKey(s) && s instanceof JAssignStmt) { Collection fieldSignatures = fieldGets.get(s); - Value lvalue = ((AssignStmt) s).getLeftOp(); + Value lvalue = ((JAssignStmt) s).getLeftOp(); AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); for (String fieldSignature : fieldSignatures) { @@ -231,7 +233,7 @@ protected Collection transformFieldGet(Stmt s) { fieldRef = new JInstanceFieldRef(base, field.makeRef()); } if (fieldRef.getType() instanceof ReferenceType) { - Stmt stmt = new JAssignStmt(lvalue, fieldRef); + Stmt stmt = new JAssignStmt(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); ret.add(stmt); } } @@ -248,9 +250,9 @@ protected Collection transformArrayNewInstance(Stmt s) { for (String arrayType : arrayTypes) { ArrayType at = (ArrayType) PTAScene.v().getTypeUnsafe(arrayType, true); JNewArrayExpr newExpr = new JNewArrayExpr(at.getElementType(), IntConstant.v(1)); - if (s instanceof AssignStmt) { - Value lvalue = ((AssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt(lvalue, newExpr)); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); } } return ret; @@ -261,8 +263,8 @@ Collection transformArrayGet(Stmt s) { Collection ret = DataFactory.createSet(); AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); - if (s instanceof AssignStmt) { - Value lvalue = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); Value arrayRef = null; if (base.getType() instanceof ArrayType) { arrayRef = new JArrayRef(base, IntConstant.v(0)); @@ -272,7 +274,7 @@ Collection transformArrayGet(Stmt s) { arrayRef = new JArrayRef(local, IntConstant.v(0)); } if (arrayRef != null) { - ret.add(new JAssignStmt(lvalue, arrayRef)); + ret.add(new JAssignStmt(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); } } return ret; @@ -286,7 +288,7 @@ Collection transformArraySet(Stmt s) { if (base.getType() instanceof ArrayType) { Value from = iie.getArg(2); Value arrayRef = new JArrayRef(base, IntConstant.v(0)); - ret.add(new JAssignStmt(arrayRef, from)); + ret.add(new JAssignStmt(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); } return ret; } diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 01719db4b9e..5ef2af8531b 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -41,6 +41,7 @@ import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JDynamicInvokeExpr; +import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -169,8 +170,8 @@ private void recordThrowStmts(MethodOrMethodContext m, Collection stmts) { if (stmt.containsInvokeExpr()) { src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, sm); } else { - assert stmt instanceof ThrowStmt; - ThrowStmt ts = (ThrowStmt) stmt; + assert stmt instanceof JThrowStmt; + JThrowStmt ts = (JThrowStmt) stmt; src = nodeFactory.getNode(ts.getOp()); } VarNode throwNode = (VarNode) pta.parameterize(src, m.context()); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index 521e083dfc2..e915edcc361 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -24,11 +24,11 @@ import qilin.core.sets.PointsToSet; import qilin.util.PTAUtils; import qilin.util.Pair; -import soot.jimple.InvokeStmt; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -69,7 +69,7 @@ private SootMethod findInvokedConstructorOf(AllocNode heap) { MethodPAG cmpag = pag.getMethodPAG(containingMethod); MethodNodeFactory nodeFactory = cmpag.nodeFactory(); for (Stmt unit : cmpag.getInvokeStmts()) { - if (unit instanceof InvokeStmt invokeStmt) { + if (unit instanceof JInvokeStmt invokeStmt) { AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); @@ -90,7 +90,7 @@ private SootMethod findInvokedConstructorOf(SootMethod outerInit) { MethodNodeFactory nodeFactory = cmpag.nodeFactory(); VarNode thisNode = nodeFactory.caseThis(); for (Stmt unit : cmpag.getInvokeStmts()) { - if (unit instanceof InvokeStmt invokeStmt) { + if (unit instanceof JInvokeStmt invokeStmt) { AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index cca8dce7565..dc50b08911a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -22,8 +22,8 @@ import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; -import soot.jimple.AssignStmt; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; @@ -119,7 +119,7 @@ public void run() { MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); MethodNodeFactory srcnf = srcmpag.nodeFactory(); Stmt invokeStmt = edge.srcUnit(); - if (invokeStmt instanceof AssignStmt assignStmt) { + if (invokeStmt instanceof JAssignStmt assignStmt) { VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); if (sourceParam instanceof LocalVarNode pj) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java index 3d1b300cea0..dbac0893565 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -183,7 +183,7 @@ public void run() { Edge edge = it.next(); SootMethod srcMethod = edge.src(); MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); - Stmt invokeStmt = (Stmt) edge.srcUnit(); + Stmt invokeStmt = edge.srcUnit(); VarNode ai = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pi); VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, retOrThrow); if (r != null && ai != null) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index a8187125b24..ce703ac5dde 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -30,6 +30,8 @@ import sootup.core.jimple.common.expr.JVirtualInvokeExpr; import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JInstanceFieldRef; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; @@ -63,7 +65,7 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm) { this.f[15] = body.getLocalCount() > 0; int heapAllocCnt = 0; for (Stmt unit : body.getStmts()) { - if (unit instanceof AssignStmt assignStmt) { + if (unit instanceof JAssignStmt assignStmt) { Value left = assignStmt.getLeftOp(); if (left instanceof Local) { Value right = assignStmt.getRightOp(); @@ -83,7 +85,7 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm) { } else if (left instanceof JInstanceFieldRef) { this.f[16] = true; } - } else if (unit instanceof InvokeStmt invokeStmt) { + } else if (unit instanceof JInvokeStmt invokeStmt) { AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); if (expr instanceof JStaticInvokeExpr) { this.f[17] = true; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java index e7bd80278df..973bc19838c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -19,7 +19,21 @@ package qilin.pta.toolkits.dd; import qilin.util.PTAUtils; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.JGotoStmt; +import sootup.core.jimple.common.stmt.JIdentityStmt; +import sootup.core.jimple.common.stmt.JIfStmt; +import sootup.core.jimple.common.stmt.JInvokeStmt; +import sootup.core.jimple.common.stmt.JNopStmt; +import sootup.core.jimple.common.stmt.JReturnStmt; +import sootup.core.jimple.common.stmt.JReturnVoidStmt; +import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.jimple.javabytecode.stmt.JBreakpointStmt; +import sootup.core.jimple.javabytecode.stmt.JEnterMonitorStmt; +import sootup.core.jimple.javabytecode.stmt.JExitMonitorStmt; +import sootup.core.jimple.javabytecode.stmt.JRetStmt; +import sootup.core.jimple.javabytecode.stmt.JSwitchStmt; import sootup.core.model.Body; import sootup.core.model.SootMethod; @@ -43,35 +57,35 @@ public FeaturesTrueTable(SootMethod sm) { this.features[10] = sig.contains("init"); Body body = PTAUtils.getMethodBody(sm); for (Stmt unit : body.getStmts()) { - if (unit instanceof AssignStmt) { + if (unit instanceof JAssignStmt) { this.features[11] = true; - } else if (unit instanceof IdentityStmt) { + } else if (unit instanceof JIdentityStmt) { this.features[12] = true; - } else if (unit instanceof InvokeStmt) { + } else if (unit instanceof JInvokeStmt) { this.features[13] = true; - } else if (unit instanceof ReturnStmt) { + } else if (unit instanceof JReturnStmt) { this.features[14] = true; - } else if (unit instanceof ThrowStmt) { + } else if (unit instanceof JThrowStmt) { this.features[15] = true; - } else if (unit instanceof BreakpointStmt) { + } else if (unit instanceof JBreakpointStmt) { this.features[16] = true; - } else if (unit instanceof EnterMonitorStmt) { + } else if (unit instanceof JEnterMonitorStmt) { this.features[17] = true; - } else if (unit instanceof ExitMonitorStmt) { + } else if (unit instanceof JExitMonitorStmt) { this.features[18] = true; - } else if (unit instanceof GotoStmt) { + } else if (unit instanceof JGotoStmt) { this.features[19] = true; - } else if (unit instanceof IfStmt) { + } else if (unit instanceof JIfStmt) { this.features[20] = true; - } else if (unit instanceof LookupSwitchStmt) { + } else if (unit instanceof JSwitchStmt) { this.features[21] = true; - } else if (unit instanceof NopStmt) { + } else if (unit instanceof JNopStmt) { this.features[22] = true; - } else if (unit instanceof RetStmt) { + } else if (unit instanceof JRetStmt) { this.features[23] = true; - } else if (unit instanceof ReturnVoidStmt) { + } else if (unit instanceof JReturnVoidStmt) { this.features[24] = true; - } else if (unit instanceof TableSwitchStmt) { + } else if (unit instanceof JSwitchStmt) { this.features[25] = true; } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index be174f4d17d..7aa01dbe20b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -11,6 +11,7 @@ import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -83,8 +84,8 @@ protected void buildInternalWithInline(SootMethod method) { args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { retDest = pag.findLocalVarNode(dest); } @@ -148,8 +149,8 @@ private void inline(Stmt invokeStmt, SootMethod method) { args[i] = arg; } LocalVarNode retDest = null; - if (invokeStmt instanceof AssignStmt) { - Value dest = ((AssignStmt) invokeStmt).getLeftOp(); + if (invokeStmt instanceof JAssignStmt) { + Value dest = ((JAssignStmt) invokeStmt).getLeftOp(); if (dest.getType() instanceof ReferenceType) { retDest = pag.findLocalVarNode(dest); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index 3d417beafee..4644994d787 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -195,7 +195,7 @@ private void buildHeapFieldsMappingIn(SootMethod method) { } private void buildHeapFieldsMapping() { - pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(this::buildHeapFieldsMappingIn); + pta.getNakedReachableMethods().stream().filter(SootMethod::isConcrete).forEach(this::buildHeapFieldsMappingIn); } /* records objects (together with their types) and their invoked methods */ @@ -205,7 +205,7 @@ private void buildHeapMethodsMapping() { Set vcallsites = new HashSet<>(); for (Edge edge : callgraph) { SootMethod tgtM = edge.tgt(); - if (tgtM.isStatic() || tgtM.isPhantom()) { + if (tgtM.isStatic() || !tgtM.isConcrete()) { continue; } final Stmt s = edge.srcStmt(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index 95b8e355687..efb8fdef9c2 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -33,6 +33,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -332,8 +333,8 @@ else if (to instanceof FieldRefNode fr) { args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { retDest = prePAG.findLocalVarNode(dest); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index a0982d587b0..0f3fa83dc3f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -32,6 +32,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -281,8 +282,8 @@ private void buildGraph() { args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { retDest = prePAG.findLocalVarNode(dest); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 2f17a255cce..1bd305e8e7c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -31,6 +31,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -163,8 +164,8 @@ else if (to instanceof FieldRefNode fr) { args[i] = arg; } LocalVarNode retDest = null; - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { retDest = pag.findLocalVarNode(dest); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java index b47db829431..39b29874e4a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -8,10 +8,10 @@ import qilin.util.ANSIColor; import qilin.util.graph.ConcurrentDirectedGraphImpl; import qilin.util.graph.Reachability; -import soot.jimple.AssignStmt; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -150,7 +150,7 @@ private void dfs(Node node) { if (!(invo instanceof AbstractInstanceInvokeExpr)) { return; } - if (callsiteStmt instanceof AssignStmt assignStmt) { + if (callsiteStmt instanceof JAssignStmt assignStmt) { Value lv = assignStmt.getLeftOp(); if (!(lv.getType() instanceof ReferenceType)) { return; diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index b472fbd5a30..2721a6ff7ed 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -34,6 +34,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -157,17 +158,15 @@ protected void extraStats() { nodes.add(arg); } - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } if (ie instanceof AbstractInstanceInvokeExpr iie) { - Value base = iie.getBase(); - if (base instanceof Local) { - nodes.add(base); - } + Local base = iie.getBase(); + nodes.add(base); } } for (Object o : nodes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 15393f3d620..87282a87ae5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -36,6 +36,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -158,17 +159,15 @@ protected void extraStats() { nodes.add(arg); } - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } if (ie instanceof AbstractInstanceInvokeExpr iie) { - Value base = iie.getBase(); - if (base instanceof Local) { - nodes.add(base); - } + Local base = iie.getBase(); + nodes.add(base); } } for (Object o : nodes) { diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index 1f91b40cc52..883eccca646 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -36,6 +36,7 @@ import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -128,17 +129,15 @@ protected void extraStats() { nodes.add(arg); } - if (s instanceof AssignStmt) { - Value dest = ((AssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); if (dest.getType() instanceof ReferenceType) { nodes.add(dest); } } if (ie instanceof AbstractInstanceInvokeExpr iie) { - Value base = iie.getBase(); - if (base instanceof Local) { - nodes.add(base); - } + Local base = iie.getBase(); + nodes.add(base); } } diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index 12f88b1f9a7..f1e1a27ddd1 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -33,6 +33,7 @@ import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JCastExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -91,9 +92,9 @@ public void end() { totalPolyCalls++; } } - } else if (st instanceof AssignStmt) { - Value rhs = ((AssignStmt) st).getRightOp(); - Value lhs = ((AssignStmt) st).getLeftOp(); + } else if (st instanceof JAssignStmt assignStmt) { + Value rhs = assignStmt.getRightOp(); + Value lhs = assignStmt.getLeftOp(); if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { final Type targetType = ((JCastExpr) rhs).getCastType(); Value v = ((JCastExpr) rhs).getOp(); diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index 5660f2fae2d..f294d3db84e 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -31,6 +31,7 @@ import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JCastExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; @@ -104,9 +105,9 @@ private void init() { } } } - } else if (st instanceof AssignStmt) { - Value rhs = ((AssignStmt) st).getRightOp(); - Value lhs = ((AssignStmt) st).getLeftOp(); + } else if (st instanceof JAssignStmt assignStmt) { + Value rhs = assignStmt.getRightOp(); + Value lhs = assignStmt.getLeftOp(); if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { final Type targetType = ((JCastExpr) rhs).getCastType(); Value v = ((JCastExpr) rhs).getOp(); From d59ca77a37831945565df65f8f060cf3c517b10e Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 17 Sep 2023 21:37:25 +1000 Subject: [PATCH 017/145] replace refs to their counterparts in sootup --- .../java/qilin/core/ArtificialMethod.java | 16 ++++---- .../qilin/core/builder/CallGraphBuilder.java | 3 +- .../qilin/core/builder/FakeMainFactory.java | 38 ++++++++++--------- .../src/main/java/qilin/stat/Exporter.java | 18 ++++----- .../java/qilin/stat/SimplifiedEvaluator.java | 2 +- .../main/java/qilin/stat/TypeClientStat.java | 2 +- 6 files changed, 42 insertions(+), 37 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index bb7e7aadf7a..c2184b0fb89 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -30,6 +30,8 @@ import sootup.core.jimple.common.expr.JVirtualInvokeExpr; import sootup.core.jimple.common.ref.IdentityRef; import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JParameterRef; +import sootup.core.jimple.common.ref.JThisRef; import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.JIdentityStmt; import sootup.core.jimple.common.stmt.JInvokeStmt; @@ -46,15 +48,15 @@ public abstract class ArtificialMethod { protected SootMethod method; protected Body body; - protected Value thisLocal; - protected Value[] paraLocals; + protected Local thisLocal; + protected Local[] paraLocals; protected int paraStart; protected int localStart; protected Value getThis() { if (thisLocal == null) { ClassType type = method.getDeclaringClassType(); - Value thisRef = new ThisRef(type); + IdentityRef thisRef = new JThisRef(type); thisLocal = getLocal(type, 0); addIdentity(thisLocal, thisRef); } @@ -71,9 +73,9 @@ protected Value getPara(int index) { } protected Value getPara(int index, Type type) { - Value paraLocal = paraLocals[index]; + Local paraLocal = paraLocals[index]; if (paraLocal == null) { - Value paraRef = new ParameterRef(type, index); + IdentityRef paraRef = new JParameterRef(type, index); paraLocal = getLocal(type, paraStart + index); addIdentity(paraLocal, paraRef); paraLocals[index] = paraLocal; @@ -92,9 +94,9 @@ protected Local getNew(ClassType type) { return local; } - protected Value getNewArray(ClassType type) { + protected Immediate getNewArray(ClassType type) { Value newExpr = new JNewArrayExpr(type, IntConstant.v(1)); - Value local = getNextLocal(new ArrayType(type, 1)); + Local local = getNextLocal(new ArrayType(type, 1)); addAssign(local, newExpr); return local; } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 44f1e5adfb6..6f0862a1c06 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -34,6 +34,7 @@ import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; @@ -165,7 +166,7 @@ public void injectCallEdge(Object heapOrType, MethodOrMethodContext callee, Kind Map stmtMap = methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap()); if (!stmtMap.containsKey(heapOrType)) { AbstractInvokeExpr ie = new JStaticInvokeExpr(callee.method().makeRef(), Collections.emptyList()); - JInvokeStmt stmt = new JInvokeStmt(ie); + JInvokeStmt stmt = new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo()); stmtMap.put(heapOrType, stmt); handleCallEdge(new Edge(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext()), stmtMap.get(heapOrType), callee, kind)); } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index ec3c26c6644..ecd710124d6 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -22,6 +22,8 @@ import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; import soot.jimple.JimpleBody; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.Modifier; import sootup.core.model.SootClass; @@ -105,13 +107,13 @@ private void makeFakeMain() { if (entry.isStatic()) { if (entry.getSubSignature().equals("void main(java.lang.String[])")) { Value mockStr = getNew(PTAUtils.getClassType("java.lang.String")); - Value strArray = getNewArray(PTAUtils.getClassType("java.lang.String")); + Immediate strArray = getNewArray(PTAUtils.getClassType("java.lang.String")); addAssign(getArrayRef(strArray), mockStr); - addInvoke(entry.getSignature(), strArray); + addInvoke(entry.getSignature().toString(), strArray); implicitCallEdges++; } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !entry.isStaticInitializer()) { // in the on fly mode, we won't add a call directly for methods. - addInvoke(entry.getSignature()); + addInvoke(entry.getSignature().toString()); implicitCallEdges++; } } @@ -119,42 +121,42 @@ private void makeFakeMain() { if (CoreConfig.v().getPtaConfig().singleentry) { return; } - Value sv = getNextLocal(PTAUtils.getClassType("java.lang.String")); - Value mainThread = getNew(PTAUtils.getClassType("java.lang.Thread")); - Value mainThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); - Value systemThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); + Local sv = getNextLocal(PTAUtils.getClassType("java.lang.String")); + Local mainThread = getNew(PTAUtils.getClassType("java.lang.Thread")); + Local mainThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); + Local systemThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); Value gCurrentThread = getFieldCurrentThread(); addAssign(gCurrentThread, mainThread); // Store - Value vRunnable = getNextLocal(PTAUtils.getClassType("java.lang.Runnable")); + Local vRunnable = getNextLocal(PTAUtils.getClassType("java.lang.Runnable")); - Value lThreadGroup = getNextLocal(PTAUtils.getClassType("java.lang.ThreadGroup")); + Local lThreadGroup = getNextLocal(PTAUtils.getClassType("java.lang.ThreadGroup")); addInvoke(mainThread, "(java.lang.ThreadGroup,java.lang.String)>", mainThreadGroup, sv); - Value tmpThread = getNew(PTAUtils.getClassType("java.lang.Thread")); + Local tmpThread = getNew(PTAUtils.getClassType("java.lang.Thread")); addInvoke(tmpThread, "(java.lang.ThreadGroup,java.lang.Runnable)>", lThreadGroup, vRunnable); addInvoke(tmpThread, ""); addInvoke(systemThreadGroup, "()>"); addInvoke(mainThreadGroup, "(java.lang.ThreadGroup,java.lang.String)>", systemThreadGroup, sv); - Value lThread = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); - Value lThrowable = getNextLocal(PTAUtils.getClassType("java.lang.Throwable")); - Value tmpThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); + Local lThread = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); + Local lThrowable = getNextLocal(PTAUtils.getClassType("java.lang.Throwable")); + Local tmpThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); addInvoke(tmpThreadGroup, "", lThread, lThrowable); // TODO. // ClassLoader - Value defaultClassLoader = getNew(PTAUtils.getClassType("sun.misc.Launcher$AppClassLoader")); + Local defaultClassLoader = getNew(PTAUtils.getClassType("sun.misc.Launcher$AppClassLoader")); addInvoke(defaultClassLoader, "()>"); - Value vClass = getNextLocal(PTAUtils.getClassType("java.lang.Class")); - Value vDomain = getNextLocal(PTAUtils.getClassType("java.security.ProtectionDomain")); + Local vClass = getNextLocal(PTAUtils.getClassType("java.lang.Class")); + Local vDomain = getNextLocal(PTAUtils.getClassType("java.security.ProtectionDomain")); addInvoke(defaultClassLoader, "", sv); addInvoke(defaultClassLoader, "", vClass, vDomain); addInvoke(defaultClassLoader, "", vClass); // PrivilegedActionException - Value privilegedActionException = getNew(PTAUtils.getClassType("java.security.PrivilegedActionException")); - Value gLthrow = getNextLocal(PTAUtils.getClassType("java.lang.Exception")); + Local privilegedActionException = getNew(PTAUtils.getClassType("java.security.PrivilegedActionException")); + Local gLthrow = getNextLocal(PTAUtils.getClassType("java.lang.Exception")); addInvoke(privilegedActionException, "(java.lang.Exception)>", gLthrow); } } diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index 5458c72d9f1..aa7653efe8d 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -25,11 +25,11 @@ import qilin.core.pag.Parm; import qilin.core.sets.PointsToSet; import qilin.util.Util; -import soot.jimple.AssignStmt; -import soot.jimple.CastExpr; -import soot.jimple.InvokeExpr; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; @@ -81,7 +81,7 @@ private String getFilePath(String fileName) { private void dumpMethods(Collection methods, String fileName) { StringBuilder builder = new StringBuilder(); for (SootMethod sm : methods) { - String sig = sm.getSignature(); + String sig = sm.getSignature().toString(); sig = Util.stripQuotes(sig); builder.append(sig); builder.append("\n"); @@ -126,9 +126,9 @@ public void dumpClassTypes(Collection classes) { Util.writeToFile(finalPath, builder.toString()); } - public void dumpPolyCalls(Map polys) { + public void dumpPolyCalls(Map polys) { StringBuilder builder = new StringBuilder(); - for (InvokeExpr ie : polys.keySet()) { + for (AbstractInvokeExpr ie : polys.keySet()) { SootMethod tgt = ie.getMethod(); String polySig = polys.get(ie).getSignature() + "/" + tgt.getDeclaringClass() + "." + tgt.getName() + "\n"; builder.append(polySig); @@ -142,9 +142,9 @@ public void dumpMayFailCasts(Map> casts) { StringBuilder builder = new StringBuilder(); for (SootMethod sm : casts.keySet()) { for (Stmt stmt : casts.get(sm)) { - AssignStmt as = (AssignStmt) stmt; - CastExpr ce = (CastExpr) as.getRightOp(); - final Type targetType = ce.getCastType(); + JAssignStmt as = (JAssignStmt) stmt; + JCastExpr ce = (JCastExpr) as.getRightOp(); + final Type targetType = ce.getType(); builder.append(sm.toString()); builder.append("\t"); builder.append(targetType.toString()); diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index f1e1a27ddd1..3f67dc561f1 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -96,7 +96,7 @@ public void end() { Value rhs = assignStmt.getRightOp(); Value lhs = assignStmt.getLeftOp(); if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = ((JCastExpr) rhs).getCastType(); + final Type targetType = rhs.getType(); Value v = ((JCastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index f294d3db84e..3cebb984b39 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -109,7 +109,7 @@ private void init() { Value rhs = assignStmt.getRightOp(); Value lhs = assignStmt.getLeftOp(); if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = ((JCastExpr) rhs).getCastType(); + final Type targetType = rhs.getType(); Value v = ((JCastExpr) rhs).getOp(); if (!(v instanceof Local)) { continue; From e2b6f4b569e027661863294f8cfac7056d9e1370 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Mon, 18 Sep 2023 10:28:44 +1000 Subject: [PATCH 018/145] updat --- .../main/java/qilin/core/VirtualCalls.java | 22 +++---- .../qilin/core/builder/CallGraphBuilder.java | 2 +- .../qilin/core/builder/MethodNodeFactory.java | 18 ++++-- .../src/main/java/qilin/core/pag/PAG.java | 13 +++-- .../java/qilin/core/pag/VirtualCallSite.java | 7 ++- .../core/reflection/ReflectionModel.java | 2 +- .../qilin/core/reflection/TamiflexModel.java | 58 +++++++++---------- .../main/java/qilin/core/solver/Solver.java | 18 +++--- .../java/qilin/pta/toolkits/conch/Conch.java | 8 ++- .../main/java/qilin/stat/TypeClientStat.java | 7 ++- 10 files changed, 88 insertions(+), 67 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index 85440402d99..49591245291 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -20,11 +20,11 @@ import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.util.*; import soot.util.queue.ChunkedQueue; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.NullType; @@ -42,7 +42,7 @@ */ public class VirtualCalls { private static volatile VirtualCalls instance = null; - private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); + private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); protected Map> baseToSubTypes = DataFactory.createMap(); private VirtualCalls() { @@ -63,11 +63,11 @@ public static void reset() { instance = null; } - public SootMethod resolveSpecial(JSpecialInvokeExpr iie, NumberedString subSig, SootMethod container) { + public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container) { return resolveSpecial(iie, subSig, container, false); } - public SootMethod resolveSpecial(JSpecialInvokeExpr iie, NumberedString subSig, SootMethod container, boolean appOnly) { + public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container, boolean appOnly) { SootMethod target = iie.getMethod(); /* cf. JVM spec, invokespecial instruction */ if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClassType(), @@ -82,12 +82,12 @@ public SootMethod resolveSpecial(JSpecialInvokeExpr iie, NumberedString subSig, } } - public SootMethod resolveNonSpecial(ClassType t, NumberedString subSig) { + public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig) { return resolveNonSpecial(t, subSig, false); } - public SootMethod resolveNonSpecial(ClassType t, NumberedString subSig, boolean appOnly) { - Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); + public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, boolean appOnly) { + Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); SootMethod ret = vtbl.get(subSig); if (ret != null) { return ret; @@ -115,17 +115,17 @@ public SootMethod resolveNonSpecial(ClassType t, NumberedString subSig, boolean return ret; } - public void resolve(Type t, Type declaredType, NumberedString subSig, SootMethod container, + public void resolve(Type t, Type declaredType, MethodSubSignature subSig, SootMethod container, ChunkedQueue targets) { resolve(t, declaredType, null, subSig, container, targets); } - public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, ChunkedQueue targets) { resolve(t, declaredType, sigType, subSig, container, targets, false); } - public void resolve(Type t, Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, ChunkedQueue targets, boolean appOnly) { if (declaredType instanceof ArrayType) { declaredType = PTAUtils.getClassType("java.lang.Object"); @@ -169,7 +169,7 @@ public void resolve(Type t, Type declaredType, Type sigType, NumberedString subS } } - protected void resolveAnySubType(Type declaredType, Type sigType, NumberedString subSig, SootMethod container, + protected void resolveAnySubType(Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, ChunkedQueue targets, boolean appOnly, ClassType base) { { Set subTypes = baseToSubTypes.get(base); diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 6f0862a1c06..b1728034552 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -165,7 +165,7 @@ private void addVirtualEdge(MethodOrMethodContext caller, Stmt callStmt, SootMet public void injectCallEdge(Object heapOrType, MethodOrMethodContext callee, Kind kind) { Map stmtMap = methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap()); if (!stmtMap.containsKey(heapOrType)) { - AbstractInvokeExpr ie = new JStaticInvokeExpr(callee.method().makeRef(), Collections.emptyList()); + AbstractInvokeExpr ie = new JStaticInvokeExpr(callee.method().getSignature(), Collections.emptyList()); JInvokeStmt stmt = new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo()); stmtMap.put(heapOrType, stmt); handleCallEdge(new Edge(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext()), stmtMap.get(heapOrType), callee, kind)); diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index 6e6433c9275..e810f4da504 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -24,9 +24,12 @@ import qilin.core.pag.*; import qilin.util.PTAUtils; import qilin.util.Pair; +import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.NoPositionInformation; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; @@ -47,13 +50,17 @@ import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Modifier; +import sootup.core.model.Position; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.signatures.FieldSignature; import sootup.core.types.ArrayType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; +import java.util.Collections; + /** * @author Ondrej Lhotak */ @@ -213,8 +220,9 @@ private AllocNode caseNewExpr(JNewExpr ne) { private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { SootField sf = ifr.getField(); + FieldSignature fieldSig = ifr.getFieldSignature(); if (sf == null) { - sf = new SootField(ifr.getFieldRef().name(), ifr.getType(), Modifier.PUBLIC); + sf = new SootField(fieldSig, Collections.singleton(Modifier.PUBLIC), NoPositionInformation.getInstance()); sf.setNumber(Scene.v().getFieldNumberer().size()); Scene.v().getFieldNumberer().add(sf); System.out.println("Warnning:" + ifr + " is resolved to be a null field in Scene."); @@ -230,17 +238,17 @@ private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { mpag.addInternalEdge(prevAn, prevVn); // new VarNode ret = prevVn; while (true) { - Type t = type.getElementType(); + Type t = type.getArrayElementType(); if (!(t instanceof ArrayType)) { break; } type = (ArrayType) t; ++pos; - Value sizeVal; + Immediate sizeVal; if (pos < nmae.getSizeCount()) { sizeVal = nmae.getSize(pos); } else { - sizeVal = IntConstant.v(1); + sizeVal = IntConstant.getInstance(1); } AllocNode an = pag.makeAllocNode(new JNewArrayExpr(type, sizeVal), type, method); VarNode vn = pag.makeLocalVarNode(an.getNewExpr(), an.getType(), method); @@ -253,7 +261,7 @@ private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { private VarNode caseCastExpr(JCastExpr ce) { Node opNode = getNode(ce.getOp()); - VarNode castNode = pag.makeLocalVarNode(ce, ce.getCastType(), method); + VarNode castNode = pag.makeLocalVarNode(ce, ce.getType(), method); mpag.addInternalEdge(opNode, castNode); return castNode; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 7d25996e705..388fa811605 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -31,14 +31,15 @@ import qilin.util.PTAUtils; import soot.Context; import soot.MethodOrMethodContext; -import soot.jimple.internal.JimpleLocal; import soot.util.ArrayNumberer; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; +import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; @@ -50,6 +51,7 @@ import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; import sootup.core.types.Type; +import sootup.java.core.language.JavaJimple; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -317,7 +319,7 @@ public AllocNode makeAllocNode(Object newExpr, Type type, SootMethod m) { public AllocNode makeStringConstantNode(StringConstant sc) { StringConstant stringConstant = sc; if (!CoreConfig.v().getPtaConfig().stringConstants) { - stringConstant = StringConstant.v(PointsToAnalysis.STRING_NODE); + stringConstant = JavaJimple.getInstance().newStringConstant(PointsToAnalysis.STRING_NODE); } AllocNode ret = valToAllocNode.get(stringConstant); if (ret == null) { @@ -560,8 +562,7 @@ private void handleArrayCopy(SootMethod method) { if (s.containsInvokeExpr()) { AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); if (invokeExpr instanceof JStaticInvokeExpr sie) { - SootMethod sm = sie.getMethod(); - String sig = sm.getSignature().toString(); + String sig = sie.getMethodSignature().toString(); if (sig.equals("")) { Value srcArr = sie.getArg(0); if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { @@ -584,8 +585,8 @@ private void handleArrayCopy(SootMethod method) { newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr,StmtPositionInfo.createNoStmtPositionInfo())); dstArr = localDst; } - Value src = new JArrayRef(srcArr, IntConstant.v(0)); - Value dst = new JArrayRef(dstArr, IntConstant.v(0)); + Value src = new JArrayRef((Local) srcArr, IntConstant.getInstance(0)); + Value dst = new JArrayRef((Local) dstArr, IntConstant.getInstance(0)); Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), PTAUtils.getClassType("java.lang.Object")); body.getLocals().add(local); newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(local, src, StmtPositionInfo.createNoStmtPositionInfo())); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java index 125007e442f..bcb4361ef47 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java @@ -23,6 +23,7 @@ import soot.util.NumberedString; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.signatures.MethodSubSignature; import java.util.Objects; @@ -35,11 +36,11 @@ public class VirtualCallSite extends CallSite { private final VarNode recNode; private final MethodOrMethodContext container; private final AbstractInstanceInvokeExpr iie; - private final NumberedString subSig; + private final MethodSubSignature subSig; private final Kind kind; public VirtualCallSite(VarNode recNode, Stmt stmt, MethodOrMethodContext container, AbstractInstanceInvokeExpr iie, - NumberedString subSig, Kind kind) { + MethodSubSignature subSig, Kind kind) { super(stmt); this.recNode = recNode; this.container = container; @@ -60,7 +61,7 @@ public AbstractInstanceInvokeExpr iie() { return iie; } - public NumberedString subSig() { + public MethodSubSignature subSig() { return subSig; } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index cb3c352337b..7f2993c860b 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -52,7 +52,7 @@ public abstract class ReflectionModel { private Collection transform(Stmt s) { AbstractInvokeExpr ie = s.getInvokeExpr(); - return switch (ie.getMethodRef().getSignature()) { + return switch (ie.getMethodSignature().toString()) { case sigForName, sigForName2 -> transformClassForName(s); case sigClassNewInstance -> transformClassNewInstance(s); case sigConstructorNewInstance -> transformContructorNewInstance(s); diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index c6e755fb667..5539b4f623c 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -22,11 +22,12 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; -import soot.tagkit.LineNumberTag; +import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JNewExpr; @@ -79,7 +80,7 @@ Collection transformClassForName(Stmt s) { ClassConstant cc = ClassConstant.fromType(refType); if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JAssignStmt<>(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); } } } @@ -101,9 +102,9 @@ protected Collection transformClassNewInstance(Stmt s) { SootClass cls = PTAScene.v().getSootClass(clsName); if (cls.declaresMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()"))) { JNewExpr newExpr = new JNewExpr(cls.getType()); - ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); SootMethod constructor = cls.getMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()")); - ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.makeRef(), Collections.emptyList()))); + ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), Collections.emptyList()), StmtPositionInfo.createNoStmtPositionInfo())); } } } @@ -123,20 +124,19 @@ protected Collection transformContructorNewInstance(Stmt s) { Collection constructorSignatures = constructorNewInstances.get(s); AbstractInvokeExpr iie = s.getInvokeExpr(); Value args = iie.getArg(0); - JArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); - Value arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); - ret.add(new JAssignStmt(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0)); + Immediate arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); + ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); for (String constructorSignature : constructorSignatures) { SootMethod constructor = PTAScene.v().getMethod(constructorSignature); - SootClass cls = constructor.getDeclaringClass(); - JNewExpr newExpr = new JNewExpr(cls.getType()); - ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + JNewExpr newExpr = new JNewExpr(constructor.getDeclaringClassType()); + ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); int argCount = constructor.getParameterCount(); - List mArgs = new ArrayList<>(argCount); + List mArgs = new ArrayList<>(argCount); for (int i = 0; i < argCount; i++) { mArgs.add(arg); } - ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.makeRef(), mArgs))); + ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), mArgs), StmtPositionInfo.createNoStmtPositionInfo())); } } return ret; @@ -152,31 +152,31 @@ protected Collection transformMethodInvoke(Stmt s) { AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); Value args = iie.getArg(1); - Value arg = null; + Immediate arg = null; if (args.getType() instanceof ArrayType) { - JArrayRef arrayRef = new JArrayRef(args, IntConstant.v(0)); + JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0)); arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); - ret.add(new JAssignStmt(arg, arrayRef)); + ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); } for (String methodSignature : methodSignatures) { SootMethod method = PTAScene.v().getMethod(methodSignature); int argCount = method.getParameterCount(); - List mArgs = new ArrayList<>(argCount); + List mArgs = new ArrayList<>(argCount); for (int i = 0; i < argCount; i++) { mArgs.add(arg); } AbstractInvokeExpr ie; if (method.isStatic()) { assert base instanceof NullConstant; - ie = new JStaticInvokeExpr(method.makeRef(), mArgs); + ie = new JStaticInvokeExpr(method.getSignature(), mArgs); } else { assert !(base instanceof NullConstant); - ie = new JVirtualInvokeExpr(base, method.makeRef(), mArgs); + ie = new JVirtualInvokeExpr((Local) base, method.getSignature(), mArgs); } if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt(lvalue, ie, StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JAssignStmt<>(lvalue, ie, StmtPositionInfo.createNoStmtPositionInfo())); } else { ret.add(new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo())); } @@ -205,7 +205,7 @@ protected Collection transformFieldSet(Stmt s) { assert !(base instanceof NullConstant); fieldRef = new JInstanceFieldRef(base, field.makeRef()); } - Stmt stmt = new JAssignStmt(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + Stmt stmt = new JAssignStmt<>(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); ret.add(stmt); } } @@ -249,10 +249,10 @@ protected Collection transformArrayNewInstance(Stmt s) { Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); for (String arrayType : arrayTypes) { ArrayType at = (ArrayType) PTAScene.v().getTypeUnsafe(arrayType, true); - JNewArrayExpr newExpr = new JNewArrayExpr(at.getElementType(), IntConstant.v(1)); + JNewArrayExpr newExpr = new JNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1)); if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); } } return ret; @@ -267,14 +267,14 @@ Collection transformArrayGet(Stmt s) { Value lvalue = ((JAssignStmt) s).getLeftOp(); Value arrayRef = null; if (base.getType() instanceof ArrayType) { - arrayRef = new JArrayRef(base, IntConstant.v(0)); + arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0)); } else if (base.getType() == PTAUtils.getClassType("java.lang.Object")) { Local local = new JimpleLocal("intermediate/" + base, new ArrayType(PTAUtils.getClassType("java.lang.Object"), 1)); - ret.add(new JAssignStmt(local, base)); - arrayRef = new JArrayRef(local, IntConstant.v(0)); + ret.add(new JAssignStmt<>(local, base, StmtPositionInfo.createNoStmtPositionInfo())); + arrayRef = new JArrayRef(local, IntConstant.getInstance(0)); } if (arrayRef != null) { - ret.add(new JAssignStmt(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + ret.add(new JAssignStmt<>(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); } } return ret; @@ -287,8 +287,8 @@ Collection transformArraySet(Stmt s) { Value base = iie.getArg(0); if (base.getType() instanceof ArrayType) { Value from = iie.getArg(2); - Value arrayRef = new JArrayRef(base, IntConstant.v(0)); - ret.add(new JAssignStmt(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); + Value arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0)); + ret.add(new JAssignStmt<>(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); } return ret; } @@ -393,7 +393,7 @@ private Collection inferSourceStmt(String inClzDotMthd, ReflectionKind kin Body body = PTAUtils.getMethodBody(sm); for (Stmt stmt : body.getStmts()) { if (stmt.containsInvokeExpr()) { - String methodSig = stmt.getInvokeExpr().getMethodRef().getSignature(); + String methodSig = stmt.getInvokeExpr().getMethodSignature().toString(); if (matchReflectionKind(kind, methodSig)) { potential.add(stmt); } diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 5ef2af8531b..7422b3c5d92 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -33,7 +33,6 @@ import soot.Kind; import soot.MethodOrMethodContext; import soot.jimple.toolkits.callgraph.Edge; -import soot.options.Options; import soot.util.NumberedString; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; @@ -44,6 +43,8 @@ import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.MethodSubSignature; import java.util.*; @@ -136,25 +137,26 @@ private void recordCallStmts(MethodOrMethodContext m, Collection units) { if (ie instanceof AbstractInstanceInvokeExpr iie) { Local receiver = iie.getBase(); VarNode recNode = cgb.getReceiverVarNode(receiver, m); - NumberedString subSig = iie.getMethodRef().getSubSignature(); + MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); VirtualCallSite virtualCallSite = new VirtualCallSite(recNode, s, m, iie, subSig, Edge.ieToKind(iie)); if (cgb.recordVirtualCallSite(recNode, virtualCallSite)) { virtualCallSiteQueue.add(virtualCallSite); } } else { - SootMethod tgt = ie.getMethod(); - if (tgt != null) { // static invoke or dynamic invoke + MethodSignature tgtSig = ie.getMethodSignature(); + Optional otgt = PTAScene.v().getView().getMethod(tgtSig); + if (otgt.isPresent()) { + // static invoke or dynamic invoke VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); recNode = (VarNode) pta.parameterize(recNode, m.context()); if (ie instanceof JDynamicInvokeExpr) { // !TODO dynamicInvoke is provided in JDK after Java 7. // currently, PTA does not handle dynamicInvokeExpr. } else { - cgb.addStaticEdge(m, s, tgt, Edge.ieToKind(ie)); + cgb.addStaticEdge(m, s, otgt.get(), Edge.ieToKind(ie)); } - } else if (!Options.v().ignore_resolution_errors()) { - throw new InternalError("Unresolved target " + ie.getMethod() - + ". Resolution error should have occured earlier."); + } else { + // } } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index e915edcc361..375db386f09 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -19,6 +19,7 @@ package qilin.pta.toolkits.conch; import qilin.core.PTA; +import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; @@ -31,6 +32,8 @@ import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.MethodSubSignature; import java.util.*; import java.util.stream.Collectors; @@ -95,8 +98,9 @@ private SootMethod findInvokedConstructorOf(SootMethod outerInit) { if (expr instanceof JSpecialInvokeExpr iie) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); - SootMethod target = iie.getMethod(); - if (PTAUtils.mustAlias(pta, thisNode, baseNode) && target.isConstructor()) { + MethodSignature targetSig = iie.getMethodSignature(); + SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(targetSig).get(); + if (PTAUtils.mustAlias(pta, thisNode, baseNode) && targetSig.getSubSignature().getName().equals("")) { return target; } } diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index 3cebb984b39..9d80c04e753 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -20,6 +20,7 @@ import qilin.CoreConfig; import qilin.core.PTA; +import qilin.core.PTAScene; import qilin.core.builder.FakeMainFactory; import qilin.core.pag.AllocNode; import qilin.util.PTAUtils; @@ -33,9 +34,11 @@ import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; import sootup.core.types.Type; +import sootup.core.views.View; import java.util.*; @@ -73,7 +76,9 @@ private void init() { } for (SootMethod sm : reachableMethods) { - boolean app = sm.getDeclaringClass().isApplicationClass(); + View view = PTAScene.v().getView(); + SootClass sc = (SootClass) view.getClass(sm.getDeclaringClassType()).get(); + boolean app = sc.isApplicationClass(); // All the statements in the method for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { From 2c9086eedb30a1ddc7c00b51b4c5481887cd3e54 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Mon, 18 Sep 2023 11:55:17 +1000 Subject: [PATCH 019/145] update --- .../java/qilin/core/ArtificialMethod.java | 25 +++++++---- .../qilin/core/builder/MethodNodeFactory.java | 5 ++- .../src/main/java/qilin/core/pag/PAG.java | 20 ++++----- .../qilin/core/reflection/TamiflexModel.java | 44 ++++++++++--------- .../debloaterx/IntraFlowAnalysis.java | 3 +- .../pta/toolkits/debloaterx/XUtility.java | 10 ++--- .../src/main/java/qilin/stat/AliasStat.java | 5 ++- .../src/main/java/qilin/util/PTAUtils.java | 6 +++ 8 files changed, 70 insertions(+), 48 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index c2184b0fb89..e2025113d30 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -18,18 +18,19 @@ package qilin.core; +import qilin.util.PTAUtils; +import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; -import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.expr.JNewExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.expr.JVirtualInvokeExpr; import sootup.core.jimple.common.ref.IdentityRef; -import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JParameterRef; import sootup.core.jimple.common.ref.JThisRef; import sootup.core.jimple.common.stmt.JAssignStmt; @@ -37,10 +38,15 @@ import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.JReturnStmt; import sootup.core.model.Body; +import sootup.core.model.SootClass; +import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.signatures.FieldSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.language.JavaJimple; import java.util.Arrays; import java.util.List; @@ -84,7 +90,7 @@ protected Value getPara(int index, Type type) { } private void addIdentity(Local lValue, IdentityRef rValue) { - body.getUnits().add(new JIdentityStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); + body.getUnits().add(new JIdentityStmt<>(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); } protected Local getNew(ClassType type) { @@ -95,7 +101,7 @@ protected Local getNew(ClassType type) { } protected Immediate getNewArray(ClassType type) { - Value newExpr = new JNewArrayExpr(type, IntConstant.v(1)); + Value newExpr = JavaJimple.getInstance().newNewArrayExpr(type, IntConstant.getInstance(1)); Local local = getNextLocal(new ArrayType(type, 1)); addAssign(local, newExpr); return local; @@ -106,7 +112,7 @@ protected Local getNextLocal(Type type) { } private Local getLocal(Type type, int index) { - Local local = new JimpleLocal("r" + index, type); + Local local = Jimple.newLocal("r" + index, type); body.getLocals().add(local); return local; } @@ -116,11 +122,14 @@ protected void addReturn(Immediate ret) { } protected Value getStaticFieldRef(String className, String name) { - return Jimple.v().newStaticFieldRef(RefType.v(className).getSootClass().getFieldByName(name).makeRef()); + ClassType classType = PTAUtils.getClassType(className); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(classType).get(); + SootField field = (SootField) sc.getField(name).get(); + return Jimple.newStaticFieldRef(field.getSignature()); } protected Value getArrayRef(Value base) { - return new JArrayRef(base, IntConstant.v(0)); + return JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); } /** @@ -172,6 +181,6 @@ protected Value getInvoke(String sig, Immediate... args) { } protected void addAssign(Value lValue, Value rValue) { - body.getUnits().add(new JAssignStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); + body.getUnits().add(new JAssignStmt<>(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index e810f4da504..a66edfd68d2 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -58,6 +58,7 @@ import sootup.core.types.ArrayType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; +import sootup.java.core.language.JavaJimple; import java.util.Collections; @@ -233,7 +234,7 @@ private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { ArrayType type = (ArrayType) nmae.getType(); int pos = 0; - AllocNode prevAn = pag.makeAllocNode(new JNewArrayExpr(type, nmae.getSize(pos)), type, method); + AllocNode prevAn = pag.makeAllocNode(JavaJimple.getInstance().newNewArrayExpr(type, nmae.getSize(pos)), type, method); VarNode prevVn = pag.makeLocalVarNode(prevAn.getNewExpr(), prevAn.getType(), method); mpag.addInternalEdge(prevAn, prevVn); // new VarNode ret = prevVn; @@ -250,7 +251,7 @@ private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { } else { sizeVal = IntConstant.getInstance(1); } - AllocNode an = pag.makeAllocNode(new JNewArrayExpr(type, sizeVal), type, method); + AllocNode an = pag.makeAllocNode(JavaJimple.getInstance().newNewArrayExpr(type, sizeVal), type, method); VarNode vn = pag.makeLocalVarNode(an.getNewExpr(), an.getType(), method); mpag.addInternalEdge(an, vn); // new mpag.addInternalEdge(vn, pag.makeFieldRefNode(prevVn, ArrayElement.v())); // store diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 388fa811605..71234c484f2 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -34,7 +34,7 @@ import soot.util.ArrayNumberer; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; -import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; @@ -570,9 +570,9 @@ private void handleArrayCopy(SootMethod method) { } Type objType = PTAUtils.getClassType("java.lang.Object"); if (srcArr.getType() == objType) { - Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); + Local localSrc = Jimple.newLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); body.getLocals().add(localSrc); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt<>(localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); srcArr = localSrc; } Value dstArr = sie.getArg(2); @@ -580,17 +580,17 @@ private void handleArrayCopy(SootMethod method) { continue; } if (dstArr.getType() == objType) { - Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); + Local localDst = Jimple.newLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); body.getLocals().add(localDst); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr,StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt<>(localDst, dstArr,StmtPositionInfo.createNoStmtPositionInfo())); dstArr = localDst; } - Value src = new JArrayRef((Local) srcArr, IntConstant.getInstance(0)); - Value dst = new JArrayRef((Local) dstArr, IntConstant.getInstance(0)); - Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), PTAUtils.getClassType("java.lang.Object")); + Value src = JavaJimple.getInstance().newArrayRef((Local) srcArr, IntConstant.getInstance(0)); + Value dst = JavaJimple.getInstance().newArrayRef((Local) dstArr, IntConstant.getInstance(0)); + Local local = Jimple.newLocal("nativeArrayCopy" + body.getLocalCount(), PTAUtils.getClassType("java.lang.Object")); body.getLocals().add(local); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(local, src, StmtPositionInfo.createNoStmtPositionInfo())); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt<>(local, src, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt<>(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); } } } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index 5539b4f623c..02b5f298964 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -22,6 +22,7 @@ import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; +import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.StmtPositionInfo; @@ -37,7 +38,6 @@ import sootup.core.jimple.common.expr.JVirtualInvokeExpr; import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JFieldRef; -import sootup.core.jimple.common.ref.JInstanceFieldRef; import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; @@ -45,9 +45,11 @@ import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.signatures.FieldSignature; import sootup.core.types.ArrayType; import sootup.core.types.ReferenceType; -import sootup.core.types.Type; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.language.JavaJimple; import java.io.BufferedReader; import java.io.FileInputStream; @@ -76,8 +78,8 @@ Collection transformClassForName(Stmt s) { if (classForNames.containsKey(s)) { Collection fornames = classForNames.get(s); for (String clazz : fornames) { - Type refType = PTAUtils.getClassType(clazz); - ClassConstant cc = ClassConstant.fromType(refType); + //!TODO potential bug + ClassConstant cc = JavaJimple.getInstance().newClassConstant(clazz); if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); ret.add(new JAssignStmt<>(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); @@ -124,8 +126,8 @@ protected Collection transformContructorNewInstance(Stmt s) { Collection constructorSignatures = constructorNewInstances.get(s); AbstractInvokeExpr iie = s.getInvokeExpr(); Value args = iie.getArg(0); - JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0)); - Immediate arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); + JArrayRef arrayRef = JavaJimple.getInstance().newArrayRef((Local) args, IntConstant.getInstance(0)); + Immediate arg = Jimple.newLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); for (String constructorSignature : constructorSignatures) { SootMethod constructor = PTAScene.v().getMethod(constructorSignature); @@ -154,8 +156,8 @@ protected Collection transformMethodInvoke(Stmt s) { Value args = iie.getArg(1); Immediate arg = null; if (args.getType() instanceof ArrayType) { - JArrayRef arrayRef = new JArrayRef((Local) args, IntConstant.getInstance(0)); - arg = new JimpleLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); + JArrayRef arrayRef = JavaJimple.getInstance().newArrayRef((Local) args, IntConstant.getInstance(0)); + arg = Jimple.newLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); } @@ -196,14 +198,15 @@ protected Collection transformFieldSet(Stmt s) { Value base = iie.getArg(0); Value rValue = iie.getArg(1); for (String fieldSignature : fieldSignatures) { - SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); JFieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; - fieldRef = Jimple.v().newStaticFieldRef(field.makeRef()); + fieldRef = Jimple.newStaticFieldRef(field.getSignature()); } else { assert !(base instanceof NullConstant); - fieldRef = new JInstanceFieldRef(base, field.makeRef()); + fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); } Stmt stmt = new JAssignStmt<>(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); ret.add(stmt); @@ -223,17 +226,18 @@ protected Collection transformFieldGet(Stmt s) { AbstractInvokeExpr iie = s.getInvokeExpr(); Value base = iie.getArg(0); for (String fieldSignature : fieldSignatures) { - SootField field = PTAScene.v().getField(fieldSignature).makeRef().resolve(); + FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); JFieldRef fieldRef; if (field.isStatic()) { assert base instanceof NullConstant; - fieldRef = Jimple.v().newStaticFieldRef(field.makeRef()); + fieldRef = Jimple.newStaticFieldRef(field.getSignature()); } else { assert !(base instanceof NullConstant); - fieldRef = new JInstanceFieldRef(base, field.makeRef()); + fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); } if (fieldRef.getType() instanceof ReferenceType) { - Stmt stmt = new JAssignStmt(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); + Stmt stmt = new JAssignStmt<>(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); ret.add(stmt); } } @@ -249,7 +253,7 @@ protected Collection transformArrayNewInstance(Stmt s) { Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); for (String arrayType : arrayTypes) { ArrayType at = (ArrayType) PTAScene.v().getTypeUnsafe(arrayType, true); - JNewArrayExpr newExpr = new JNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1)); + JNewArrayExpr newExpr = JavaJimple.getInstance().newNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1)); if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); @@ -267,11 +271,11 @@ Collection transformArrayGet(Stmt s) { Value lvalue = ((JAssignStmt) s).getLeftOp(); Value arrayRef = null; if (base.getType() instanceof ArrayType) { - arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0)); + arrayRef = JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); } else if (base.getType() == PTAUtils.getClassType("java.lang.Object")) { - Local local = new JimpleLocal("intermediate/" + base, new ArrayType(PTAUtils.getClassType("java.lang.Object"), 1)); + Local local = Jimple.newLocal("intermediate/" + base, new ArrayType(PTAUtils.getClassType("java.lang.Object"), 1)); ret.add(new JAssignStmt<>(local, base, StmtPositionInfo.createNoStmtPositionInfo())); - arrayRef = new JArrayRef(local, IntConstant.getInstance(0)); + arrayRef = JavaJimple.getInstance().newArrayRef(local, IntConstant.getInstance(0)); } if (arrayRef != null) { ret.add(new JAssignStmt<>(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); @@ -287,7 +291,7 @@ Collection transformArraySet(Stmt s) { Value base = iie.getArg(0); if (base.getType() instanceof ArrayType) { Value from = iie.getArg(2); - Value arrayRef = new JArrayRef((Local) base, IntConstant.getInstance(0)); + Value arrayRef = JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); ret.add(new JAssignStmt<>(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); } return ret; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java index 1d9ca2b1f33..34adc458dbb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java @@ -13,6 +13,7 @@ import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; @@ -156,7 +157,7 @@ private Set collectParamInArguments(AllocNode heap) { } args[i] = arg; } - NumberedString subSig = iie.getMethodRef().getSubSignature(); + MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, method, iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); QueueReader targets = PTAUtils.dispatch(type, virtualCallSite); while (targets.hasNext()) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index 4644994d787..b373b515b1b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -8,7 +8,6 @@ import qilin.util.Stopwatch; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; -import soot.util.NumberedString; import soot.util.queue.QueueReader; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; @@ -16,6 +15,7 @@ import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.Type; @@ -85,7 +85,7 @@ private boolean isImpreciseType(Type type) { /* Implemnting the rules for defining coarse types (Figure 6 in the paper) */ public boolean isCoarseType(Type type) { if (type instanceof ArrayType at) { - type = at.getElementType(); + type = at.getArrayElementType(); } return isImpreciseType(type) || rawOrPolyTypes().contains(type); } @@ -95,7 +95,7 @@ private void computeRawOrPolyTypes() { for (AllocNode heap : pag.getAllocNodes()) { Type type = heap.getType(); if (type instanceof ArrayType at) { - Type et = at.getElementType(); + Type et = at.getArrayElementType(); if (isImpreciseType(et)) { rawOrPolyTypes.add(et); } else { @@ -105,7 +105,7 @@ private void computeRawOrPolyTypes() { for (SparkField field : getFields(heap)) { Type ft = field.getType(); if (ft instanceof ArrayType fat) { - ft = fat.getElementType(); + ft = fat.getArrayElementType(); } if (isImpreciseType(ft)) { rawOrPolyTypes.add(ft); @@ -212,7 +212,7 @@ private void buildHeapMethodsMapping() { AbstractInvokeExpr ie = s.getInvokeExpr(); if (ie instanceof AbstractInstanceInvokeExpr iie) { LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); - NumberedString subSig = iie.getMethodRef().getSubSignature(); + MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, edge.src(), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); vcallsites.add(virtualCallSite); } else { diff --git a/sootup.qilin/src/main/java/qilin/stat/AliasStat.java b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java index 60f265cc1a3..430385299f9 100644 --- a/sootup.qilin/src/main/java/qilin/stat/AliasStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java @@ -26,6 +26,7 @@ import qilin.core.pag.SparkField; import qilin.core.pag.VarNode; import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; import qilin.util.Pair; import qilin.util.Util; import soot.util.queue.QueueReader; @@ -144,13 +145,13 @@ public static boolean addToMap(Map>> m, K key1, T key public void aliasesProcessing() { Collection reachableMethods = pta.getNakedReachableMethods(); - Pair r1 = recordAndComputeIntraAliases(reachableMethods.stream().filter(m -> m.getDeclaringClass().isApplicationClass()).collect(Collectors.toSet())); + Pair r1 = recordAndComputeIntraAliases(reachableMethods.stream().filter(PTAUtils::isApplicationMethod).collect(Collectors.toSet())); this.intraAlias_app = r1.getFirst(); this.intraAlias_incstst_app = r1.getSecond(); Pair r2 = computeInterAliases(); this.globalAlias_app = r2.getFirst(); this.globalAlias_incstst_app = r2.getSecond(); - Pair r3 = recordAndComputeIntraAliases(reachableMethods.stream().filter(m -> !m.getDeclaringClass().isApplicationClass()).collect(Collectors.toSet())); + Pair r3 = recordAndComputeIntraAliases(reachableMethods.stream().filter(m -> !PTAUtils.isApplicationMethod(m)).collect(Collectors.toSet())); this.intraAlias = this.intraAlias_app + r3.getFirst(); this.intraAlias_incstst = this.intraAlias_incstst_app + r3.getSecond(); Pair r4 = computeInterAliases(); diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 2bd22e2c706..4f1eb2f41be 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -76,6 +76,12 @@ public static ClassType getClassType(String fullyQualifiedClassName) { return JavaIdentifierFactory.getInstance().getClassType(fullyQualifiedClassName); } + public static boolean isApplicationMethod(SootMethod sm) { + ClassType classType = sm.getDeclaringClassType(); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(classType).get(); + return sc.isApplicationClass(); + } + public static Map> calcStaticThisPTS(PTA pta) { Map> pts = new HashMap<>(); Set workList = new HashSet<>(); From c2220c3bfdea772496f0f34fada3009cb61eb3ab Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Mon, 18 Sep 2023 15:28:40 +1000 Subject: [PATCH 020/145] update --- .../java/qilin/core/ArtificialMethod.java | 33 ++++++------ .../qilin/core/builder/MethodNodeFactory.java | 53 +++++++++++-------- .../java/qilin/pta/toolkits/conch/Conch.java | 15 +++--- .../dd/CtxTunnelingFeaturesTrueTable.java | 6 ++- .../pta/toolkits/debloaterx/DebloaterX.java | 3 +- .../debloaterx/IntraFlowAnalysis.java | 1 - .../pta/toolkits/debloaterx/XUtility.java | 4 +- .../main/java/qilin/stat/BenchmarkStat.java | 8 +-- .../main/java/qilin/stat/CallGraphStat.java | 9 ++-- .../main/java/qilin/stat/PointsToStat.java | 2 +- .../src/main/java/qilin/util/PTAUtils.java | 8 +++ 11 files changed, 83 insertions(+), 59 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index e2025113d30..326dbe9ec6a 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -26,10 +26,7 @@ import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; import sootup.core.jimple.common.expr.JNewExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.expr.JVirtualInvokeExpr; import sootup.core.jimple.common.ref.IdentityRef; import sootup.core.jimple.common.ref.JParameterRef; import sootup.core.jimple.common.ref.JThisRef; @@ -41,7 +38,7 @@ import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; -import sootup.core.signatures.FieldSignature; +import sootup.core.signatures.MethodSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.Type; @@ -136,10 +133,12 @@ protected Value getArrayRef(Value base) { * add an instance invocation receiver.sig(args) */ protected void addInvoke(Local receiver, String sig, Immediate ... args) { - SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); + SootMethod method = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); + SootClass clazz = (SootClass) PTAScene.v().getView().getClass(method.getDeclaringClassType()).get(); List argsL = Arrays.asList(args); - AbstractInvokeExpr invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) - : new JVirtualInvokeExpr(receiver, methodRef, argsL); + AbstractInvokeExpr invoke = clazz.isInterface() ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) + : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); body.getUnits().add(new JInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo())); } @@ -149,11 +148,13 @@ protected void addInvoke(Local receiver, String sig, Immediate ... args) { * @return rx */ protected Value getInvoke(Local receiver, String sig, Immediate... args) { - SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); + SootMethod method = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); + SootClass clazz = (SootClass) PTAScene.v().getView().getClass(method.getDeclaringClassType()).get(); List argsL = Arrays.asList(args); - Value invoke = methodRef.getDeclaringClass().isInterface() ? new JInterfaceInvokeExpr(receiver, methodRef, argsL) - : new JVirtualInvokeExpr(receiver, methodRef, argsL); - Value rx = getNextLocal(methodRef.getReturnType()); + Value invoke = clazz.isInterface() ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) + : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); + Value rx = getNextLocal(method.getReturnType()); addAssign(rx, invoke); return rx; } @@ -162,9 +163,9 @@ protected Value getInvoke(Local receiver, String sig, Immediate... args) { * add a static invocation sig(args) */ protected void addInvoke(String sig, Immediate... args) { - SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); List argsL = Arrays.asList(args); - body.getUnits().add(new JInvokeStmt(new JStaticInvokeExpr(methodRef, argsL))); + body.getUnits().add(new JInvokeStmt(Jimple.newStaticInvokeExpr(methodSig, argsL), StmtPositionInfo.createNoStmtPositionInfo())); } /** @@ -173,10 +174,10 @@ protected void addInvoke(String sig, Immediate... args) { * @return rx */ protected Value getInvoke(String sig, Immediate... args) { - SootMethodRef methodRef = PTAScene.v().getMethod(sig).makeRef(); + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); List argsL = Arrays.asList(args); - Value rx = getNextLocal(methodRef.getReturnType()); - addAssign(rx, new JStaticInvokeExpr(methodRef, argsL)); + Value rx = getNextLocal(methodSig.getType()); + addAssign(rx, Jimple.newStaticInvokeExpr(methodSig, argsL)); return rx; } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index a66edfd68d2..77911e66fd9 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -49,8 +49,9 @@ import sootup.core.jimple.common.stmt.JReturnStmt; import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.jimple.javabytecode.stmt.JExitMonitorStmt; +import sootup.core.jimple.visitor.AbstractStmtVisitor; import sootup.core.model.Modifier; -import sootup.core.model.Position; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; @@ -60,6 +61,7 @@ import sootup.core.types.Type; import sootup.java.core.language.JavaJimple; +import javax.annotation.Nonnull; import java.util.Collections; /** @@ -136,8 +138,8 @@ protected void handleInvokeStmt(Stmt s) { } getNode(arg); } - if (s instanceof JAssignStmt) { - Value l = ((JAssignStmt) s).getLeftOp(); + if (s instanceof JAssignStmt assignStmt) { + Value l = assignStmt.getLeftOp(); if ((l.getType() instanceof ReferenceType)) { getNode(l); } @@ -155,10 +157,11 @@ private void resolveClinit(JStaticFieldRef staticFieldRef) { * Adds the edges required for this statement to the graph. */ private void handleIntraStmt(Stmt s) { - s.apply(new AbstractStmtSwitch<>() { - public void caseAssignStmt(JAssignStmt as) { - Value l = as.getLeftOp(); - Value r = as.getRightOp(); + s.accept(new AbstractStmtVisitor<>() { + @Override + public void caseAssignStmt(@Nonnull JAssignStmt stmt) { + Value l = stmt.getLeftOp(); + Value r = stmt.getRightOp(); if (l instanceof JStaticFieldRef) { resolveClinit((JStaticFieldRef) l); } else if (r instanceof JStaticFieldRef) { @@ -174,32 +177,40 @@ public void caseAssignStmt(JAssignStmt as) { } if (!(r.getType() instanceof ReferenceType)) - throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + as + throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + stmt + " in method " + method.getSignature()); Node dest = getNode(l); Node src = getNode(r); mpag.addInternalEdge(src, dest); } - public void caseReturnStmt(JReturnStmt rs) { - if (!(rs.getOp().getType() instanceof ReferenceType)) + @Override + public void caseIdentityStmt(@Nonnull JIdentityStmt stmt) { + if (!(stmt.getLeftOp().getType() instanceof ReferenceType)) { return; - Node retNode = getNode(rs.getOp()); - mpag.addInternalEdge(retNode, caseRet()); + } + Node dest = getNode(stmt.getLeftOp()); + Node src = getNode(stmt.getRightOp()); + mpag.addInternalEdge(src, dest); + } + + @Override + public void caseExitMonitorStmt(@Nonnull JExitMonitorStmt stmt) { + defaultCaseStmt(stmt); } - public void caseIdentityStmt(JIdentityStmt is) { - if (!(is.getLeftOp().getType() instanceof ReferenceType)) { + @Override + public void caseReturnStmt(@Nonnull JReturnStmt stmt) { + if (!(stmt.getOp().getType() instanceof ReferenceType)) return; - } - Node dest = getNode(is.getLeftOp()); - Node src = getNode(is.getRightOp()); - mpag.addInternalEdge(src, dest); + Node retNode = getNode(stmt.getOp()); + mpag.addInternalEdge(retNode, caseRet()); } - public void caseThrowStmt(JThrowStmt ts) { + @Override + public void caseThrowStmt(@Nonnull JThrowStmt stmt) { if (!CoreConfig.v().getPtaConfig().preciseExceptions) { - mpag.addInternalEdge(getNode(ts.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); + mpag.addInternalEdge(getNode(stmt.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); } } }); @@ -314,7 +325,7 @@ private VarNode caseParameterRef(JParameterRef pr) { } private VarNode caseStaticFieldRef(JStaticFieldRef sfr) { - return pag.makeGlobalVarNode(sfr.getField(), sfr.getField().getType()); + return pag.makeGlobalVarNode(sfr.getFieldSignature(), sfr.getType()); } private Node caseNullConstant(NullConstant nr) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index 375db386f09..ffdf4f6f40f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -27,13 +27,11 @@ import qilin.util.Pair; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; -import sootup.core.signatures.MethodSubSignature; import java.util.*; import java.util.stream.Collectors; @@ -78,8 +76,8 @@ private SootMethod findInvokedConstructorOf(AllocNode heap) { Value base = iie.getBase(); VarNode baseNode = (VarNode) nodeFactory.getNode(base); PointsToSet v1pts = pta.reachingObjects(baseNode); - SootMethod target = iie.getMethod(); - if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && target.isConstructor()) { + SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(iie.getMethodSignature()).get(); + if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && PTAUtils.isConstructor(target)) { return target; } } @@ -131,8 +129,9 @@ private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMeth if (!(stmt.getInvokeExpr() instanceof JSpecialInvokeExpr)) { continue; } - SootMethod target = stmt.getInvokeExpr().getMethod(); - if (target != null && target.equals(curr)) { + MethodSignature methodSig = stmt.getInvokeExpr().getMethodSignature(); + Optional otarget = (Optional) PTAScene.v().getView().getMethod(methodSig); + if (otarget.isPresent() && otarget.get().equals(curr)) { for (Node n : params) { if (n instanceof VarNode paramNode) { LocalVarNode argNode = PTAUtils.paramToArg(pag, stmt, cmpag, paramNode); @@ -208,7 +207,7 @@ private Trilean checkResult(Set res) { private Trilean isCommingFromParams(LocalVarNode from, SootMethod method, AllocNode heap) { Set ret = this.pfg.fetchReachableParamsOf(from); - if (method.isConstructor()) { + if (PTAUtils.isConstructor(method)) { return handleTransitiveConstructors(method, heap, ret); } else { return checkResult(ret); @@ -299,7 +298,7 @@ public void runClassifier() { ciHeaps.add(heap); } else { SootMethod mthd = heap.getMethod(); - if (mthd.isStaticInitializer()) { + if (PTAUtils.isStaticInitializer(mthd)) { ciHeaps.add(heap); } else { remainToSolve.add(heap); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index ce703ac5dde..b16b870e453 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -18,6 +18,7 @@ package qilin.pta.toolkits.dd; +import qilin.core.PTAScene; import qilin.util.PTAUtils; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; @@ -99,11 +100,12 @@ public CtxTunnelingFeaturesTrueTable(SootMethod sm) { this.f[20] = heapAllocCnt == 1; this.f[21] = sig.contains("Object"); this.f[22] = heapAllocCnt >= 1; // note, the original implementation is >=1 not > 1 which is conflict with the paper. - this.f[23] = sm.getDeclaringClass().getMethods().size() > 20; // their artifact uses 20 as the threshold. + SootClass sc = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); + this.f[23] = sc.getMethods().size() > 20; // their artifact uses 20 as the threshold. } public boolean containedInNestedClass(SootMethod sm) { - SootClass sc = sm.getDeclaringClass(); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); return sc.toString().contains("$"); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java index 92e37fc7dea..b8197867da5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java @@ -4,6 +4,7 @@ import qilin.core.PTA; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; +import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; @@ -111,7 +112,7 @@ public void run() { Map> m2o = new HashMap<>(); for (AllocNode heap : pag.getAllocNodes()) { SootMethod method = heap.getMethod(); - if (method == null || method.isStaticInitializer()) { + if (method == null || PTAUtils.isStaticInitializer(method)) { continue; } m2o.computeIfAbsent(method, k -> new HashSet<>()).add(heap); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java index 34adc458dbb..193d4d51f75 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java @@ -5,7 +5,6 @@ import qilin.util.PTAUtils; import qilin.util.Pair; import qilin.util.queue.UniqueQueue; -import soot.util.NumberedString; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.NullConstant; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index b373b515b1b..6267cf112a5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -76,8 +76,8 @@ private boolean isImpreciseType(Type type) { return true; } if (type instanceof ClassType refType) { - SootClass sc = refType.getSootClass(); - return sc.isAbstract() || sc.isInterface() || sc.getShortName().startsWith("Abstract"); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(refType).get(); + return sc.isAbstract() || sc.isInterface() || refType.getClassName().startsWith("Abstract"); } return false; } diff --git a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java index c4073bf5843..b53dc025961 100644 --- a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java @@ -22,7 +22,7 @@ import qilin.core.PTA; import qilin.core.PTAScene; import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; +import sootup.core.types.ClassType; import java.util.Set; import java.util.stream.Collectors; @@ -44,8 +44,10 @@ public BenchmarkStat(PTA pta) { } private void init() { - reachableClasses = pta.getNakedReachableMethods().stream().map(SootMethod::getDeclaringClass) - .collect(Collectors.toSet()); + reachableClasses = pta.getNakedReachableMethods().stream().map(m -> { + ClassType classType = m.getDeclaringClassType(); + return (SootClass) PTAScene.v().getView().getClass(classType).get(); + }).collect(Collectors.toSet()); reachableAppClasses = reachableClasses.stream().filter(SootClass::isApplicationClass) .collect(Collectors.toSet()); diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index ec9ff2ccfda..9a5e4b0b746 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -24,6 +24,7 @@ import qilin.core.builder.FakeMainFactory; import qilin.core.pag.ContextVarNode; import qilin.core.pag.LocalVarNode; +import qilin.util.PTAUtils; import soot.MethodOrMethodContext; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; @@ -71,7 +72,7 @@ private void init() { CSCallEdges = csCallGraph.size(); for (final MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { final SootMethod m = momc.method(); - boolean toApp = m.getDeclaringClass().isApplicationClass(); + boolean toApp = PTAUtils.isApplicationMethod(m); reachableParameterizedMethods.add(momc); reachableMethods.add(m); // if (m.toString().equals("")) { @@ -86,7 +87,7 @@ private void init() { for (Iterator iterator = csCallGraph.edgesInto(momc); iterator.hasNext(); ) { Edge e = iterator.next(); final SootMethod srcm = e.getSrc().method(); - boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); + boolean fromApp = PTAUtils.isApplicationMethod(srcm); if (fromApp && toApp) { CSApp2app++; } else if (fromApp) { @@ -112,7 +113,7 @@ private void init() { CallGraph ciCallGraph = pta.getCallGraph(); CICallEdges = ciCallGraph.size(); for (SootMethod sm : reachableMethods) { - boolean toApp = sm.getDeclaringClass().isApplicationClass(); + boolean toApp = PTAUtils.isApplicationMethod(sm); if (sm.isStatic()) { reachableStatic++; if (toApp) { @@ -125,7 +126,7 @@ private void init() { // if (sm.toString().equals("")) { // System.out.println("from:" + srcm); // } - boolean fromApp = srcm.getDeclaringClass().isApplicationClass(); + boolean fromApp = PTAUtils.isApplicationMethod(srcm); if (fromApp && toApp) { CIApp2app++; } else if (fromApp) { diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java index d95921dddcb..07638617561 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -144,7 +144,7 @@ private void init() { if (!handledNatives.contains(lvn.getMethod().toString())) { mLocalVarNodesNoNative.add(lvn); } - boolean app = lvn.getMethod().getDeclaringClass().isApplicationClass(); + boolean app = PTAUtils.isApplicationMethod(lvn.getMethod()); totalLocalPointersCi++; if (app) { appLocalPointersCi++; diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 4f1eb2f41be..2f33acdc2c9 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -82,6 +82,14 @@ public static boolean isApplicationMethod(SootMethod sm) { return sc.isApplicationClass(); } + public static boolean isStaticInitializer(SootMethod method) { + return method.getName().equals(""); + } + + public static boolean isConstructor(SootMethod method) { + return method.getName().equals(""); + } + public static Map> calcStaticThisPTS(PTA pta) { Map> pts = new HashMap<>(); Set workList = new HashSet<>(); From 37b8b868addf13676221103816e2bc7160dae159 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Mon, 18 Sep 2023 16:06:37 +1000 Subject: [PATCH 021/145] update --- .../java/qilin/core/ArtificialMethod.java | 29 ++++++++++++------- .../qilin/core/builder/FakeMainFactory.java | 14 ++++----- .../qilin/core/reflection/TamiflexModel.java | 1 + 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index 326dbe9ec6a..5bc38413872 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -30,10 +30,7 @@ import sootup.core.jimple.common.ref.IdentityRef; import sootup.core.jimple.common.ref.JParameterRef; import sootup.core.jimple.common.ref.JThisRef; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JIdentityStmt; -import sootup.core.jimple.common.stmt.JInvokeStmt; -import sootup.core.jimple.common.stmt.JReturnStmt; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; import sootup.core.model.SootField; @@ -50,7 +47,7 @@ public abstract class ArtificialMethod { protected SootMethod method; - protected Body body; + protected Body.BodyBuilder bodyBuilder; protected Local thisLocal; protected Local[] paraLocals; protected int paraStart; @@ -87,7 +84,9 @@ protected Value getPara(int index, Type type) { } private void addIdentity(Local lValue, IdentityRef rValue) { - body.getUnits().add(new JIdentityStmt<>(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); + Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); + Stmt identityStmt = Jimple.newIdentityStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + bodyBuilder.addFlow(startingStmt, identityStmt); } protected Local getNew(ClassType type) { @@ -110,12 +109,14 @@ protected Local getNextLocal(Type type) { private Local getLocal(Type type, int index) { Local local = Jimple.newLocal("r" + index, type); - body.getLocals().add(local); + bodyBuilder.addLocal(local); return local; } protected void addReturn(Immediate ret) { - body.getUnits().add(new JReturnStmt(ret, StmtPositionInfo.createNoStmtPositionInfo())); + Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); + Stmt stmt = Jimple.newReturnStmt(ret, StmtPositionInfo.createNoStmtPositionInfo()); + bodyBuilder.addFlow(startingStmt, stmt); } protected Value getStaticFieldRef(String className, String name) { @@ -139,7 +140,9 @@ protected void addInvoke(Local receiver, String sig, Immediate ... args) { List argsL = Arrays.asList(args); AbstractInvokeExpr invoke = clazz.isInterface() ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); - body.getUnits().add(new JInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo())); + Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); + Stmt stmt = Jimple.newInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo()); + bodyBuilder.addFlow(startingStmt, stmt); } /** @@ -165,7 +168,9 @@ protected Value getInvoke(Local receiver, String sig, Immediate... args) { protected void addInvoke(String sig, Immediate... args) { MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); List argsL = Arrays.asList(args); - body.getUnits().add(new JInvokeStmt(Jimple.newStaticInvokeExpr(methodSig, argsL), StmtPositionInfo.createNoStmtPositionInfo())); + Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); + Stmt stmt = Jimple.newInvokeStmt(Jimple.newStaticInvokeExpr(methodSig, argsL), StmtPositionInfo.createNoStmtPositionInfo()); + bodyBuilder.addFlow(startingStmt, stmt); } /** @@ -182,6 +187,8 @@ protected Value getInvoke(String sig, Immediate... args) { } protected void addAssign(Value lValue, Value rValue) { - body.getUnits().add(new JAssignStmt<>(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo())); + Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); + Stmt stmt = Jimple.newAssignStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + bodyBuilder.addFlow(startingStmt, stmt); } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index ecd710124d6..da33a28e2cd 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -34,8 +34,6 @@ import java.util.Collections; import java.util.List; -import static com.ibm.wala.cast.java.types.JavaPrimitiveTypeMap.VoidType; - public class FakeMainFactory extends ArtificialMethod { public static FakeMainFactory instance; @@ -46,7 +44,7 @@ public FakeMainFactory() { this.localStart = 0; this.fakeClass = new SootClass("FakeMain"); this.fakeClass.setResolvingLevel(SootClass.BODIES); - this.method = new SootMethod("fakeMain", null, VoidType.v()); + this.method = new SootMethod("fakeMain", null, VoidType); this.method.setModifiers(Modifier.STATIC); SootField currentThread = new SootField("currentThread", RefType.v("java.lang.Thread"), Modifier.STATIC); SootField globalThrow = new SootField("globalThrow", RefType.v("java.lang.Exception"), Modifier.STATIC); @@ -81,12 +79,12 @@ private List getEntryPoints() { } public SootMethod getFakeMain() { - if (body == null) { + if (bodyBuilder == null) { synchronized (this) { - if (body == null) { + if (bodyBuilder == null) { this.method.setSource((m, phaseName) -> new JimpleBody(this.method)); - this.body = PTAUtils.getMethodBody(method); makeFakeMain(); + this.body = PTAUtils.getMethodBody(method); } } } @@ -105,13 +103,13 @@ private void makeFakeMain() { implicitCallEdges = 0; for (SootMethod entry : getEntryPoints()) { if (entry.isStatic()) { - if (entry.getSubSignature().equals("void main(java.lang.String[])")) { + if (entry.getSignature().getSubSignature().toString().equals("void main(java.lang.String[])")) { Value mockStr = getNew(PTAUtils.getClassType("java.lang.String")); Immediate strArray = getNewArray(PTAUtils.getClassType("java.lang.String")); addAssign(getArrayRef(strArray), mockStr); addInvoke(entry.getSignature().toString(), strArray); implicitCallEdges++; - } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !entry.isStaticInitializer()) { + } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !PTAUtils.isStaticInitializer(entry)) { // in the on fly mode, we won't add a call directly for methods. addInvoke(entry.getSignature().toString()); implicitCallEdges++; diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index 02b5f298964..df56aa873f2 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -102,6 +102,7 @@ protected Collection transformClassNewInstance(Stmt s) { Collection classNames = classNewInstances.get(s); for (String clsName : classNames) { SootClass cls = PTAScene.v().getSootClass(clsName); + if (cls.declaresMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()"))) { JNewExpr newExpr = new JNewExpr(cls.getType()); ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); From 2ba64f4e2442a0669316d75397310b17a964e77c Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Mon, 18 Sep 2023 19:12:49 +1000 Subject: [PATCH 022/145] update --- .../main/java/qilin/core/VirtualCalls.java | 86 ++++++++++--------- .../qilin/core/builder/CallGraphBuilder.java | 2 +- .../qilin/core/builder/MethodNodeFactory.java | 9 +- .../src/main/java/qilin/core/pag/PAG.java | 1 - .../toolkits/conch/DepOnParamAnalysis.java | 2 +- .../src/main/java/qilin/util/PTAUtils.java | 2 +- 6 files changed, 55 insertions(+), 47 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index 49591245291..010c54672b6 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -24,6 +24,7 @@ import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; @@ -33,6 +34,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.Map; +import java.util.Optional; import java.util.Set; /** @@ -42,7 +44,7 @@ */ public class VirtualCalls { private static volatile VirtualCalls instance = null; - private final Map> typeToVtbl = DataFactory.createMap(Scene.v().getTypeNumberer().size()); + private final Map> typeToVtbl = DataFactory.createMap(PTAScene.v().getView().getClasses().size()); protected Map> baseToSubTypes = DataFactory.createMap(); private VirtualCalls() { @@ -68,15 +70,16 @@ public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subS } public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container, boolean appOnly) { - SootMethod target = iie.getMethod(); + MethodSignature methodSig = iie.getMethodSignature(); + SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); /* cf. JVM spec, invokespecial instruction */ - if (Scene.v().getFastHierarchy().canStoreType(container.getDeclaringClassType(), - target.getDeclaringClassType()) + if (PTAScene.v().getView().getTypeHierarchy().isSubtype(target.getDeclaringClassType(), container.getDeclaringClassType()) && container.getDeclaringClassType() != target.getDeclaringClassType() && !target.getName().equals("") - && subSig != Scene.v().getSubSigNumberer().findOrAdd("void ()")) { - - return resolveNonSpecial(container.getDeclaringClass().getSuperclass().getType(), subSig, appOnly); + && !subSig.toString().equals("void ()")) { + SootClass cls = (SootClass) PTAScene.v().getView().getClass(container.getDeclaringClassType()).get(); + SootClass superCls = (SootClass) cls.getSuperclass().get(); + return resolveNonSpecial(superCls.getType(), subSig, appOnly); } else { return target; } @@ -92,19 +95,20 @@ public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, bool if (ret != null) { return ret; } - SootClass cls = t.getSootClass(); + SootClass cls = (SootClass) PTAScene.v().getView().getClass(t).get(); if (appOnly && cls.isLibraryClass()) { return null; } - - SootMethod m = cls.getMethodUnsafe(subSig); - if (m != null) { + Optional om = cls.getMethod(subSig); + if (om.isPresent()) { + SootMethod m = om.get(); if (!m.isAbstract()) { ret = m; } } else { - SootClass c = cls.getSuperclassUnsafe(); - if (c != null) { + Optional oc = cls.getSuperclass(); + if (oc.isPresent()) { + SootClass c = oc.get(); ret = resolveNonSpecial(c.getType(), subSig); } } @@ -137,10 +141,10 @@ public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature t = PTAUtils.getClassType("java.lang.Object"); } - if (declaredType != null && !Scene.v().getFastHierarchy().canStoreType(t, declaredType)) { + if (declaredType != null && !PTAScene.v().getView().getTypeHierarchy().isSubtype(declaredType, t)) { return; } - if (sigType != null && !Scene.v().getFastHierarchy().canStoreType(t, sigType)) { + if (sigType != null && !PTAScene.v().getView().getTypeHierarchy().isSubtype(sigType, t)) { return; } if (t instanceof ClassType) { @@ -148,22 +152,24 @@ public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature if (target != null) { targets.add(target); } - } else if (t instanceof AnySubType) { - ClassType base = ((AnySubType) t).getBase(); - - /* - * Whenever any sub type of a specific type is considered as receiver for a method to call and the base type is an - * interface, calls to existing methods with matching signature (possible implementation of method to call) are also - * added. As Javas' subtyping allows contra-variance for return types and co-variance for parameters when overriding a - * method, these cases are also considered here. - * - * Example: Classes A, B (B sub type of A), interface I with method public A foo(B b); and a class C with method public - * B foo(A a) { ... }. The extended class hierarchy will contain C as possible implementation of I. - * - * Since Java has no multiple inheritance call by signature resolution is only activated if the base is an interface. - */ - resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); - } else if (t instanceof NullType) { + } +// else if (t instanceof AnySubType) { +// ClassType base = ((AnySubType) t).getBase(); +// +// /* +// * Whenever any sub type of a specific type is considered as receiver for a method to call and the base type is an +// * interface, calls to existing methods with matching signature (possible implementation of method to call) are also +// * added. As Javas' subtyping allows contra-variance for return types and co-variance for parameters when overriding a +// * method, these cases are also considered here. +// * +// * Example: Classes A, B (B sub type of A), interface I with method public A foo(B b); and a class C with method public +// * B foo(A a) { ... }. The extended class hierarchy will contain C as possible implementation of I. +// * +// * Since Java has no multiple inheritance call by signature resolution is only activated if the base is an interface. +// */ +// resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); +// } + else if (t instanceof NullType) { } else { throw new RuntimeException("oops " + t); } @@ -184,17 +190,15 @@ protected void resolveAnySubType(Type declaredType, Type sigType, MethodSubSigna Set newSubTypes = new HashSet<>(); newSubTypes.add(base); - LinkedList worklist = new LinkedList<>(); - HashSet workset = new HashSet<>(); - SootClass cl = base.getSootClass(); - - if (workset.add(cl)) { - worklist.add(cl); - } + LinkedList worklist = new LinkedList<>(); + HashSet workset = new HashSet<>(); + workset.add(base); + worklist.add(base); while (!worklist.isEmpty()) { - cl = worklist.removeFirst(); + ClassType classType = worklist.removeFirst(); + SootClass cl = (SootClass) PTAScene.v().getView().getClass(classType).get(); if (cl.isInterface()) { - for (final SootClass c : Scene.v().getFastHierarchy().getAllImplementersOfInterface(cl)) { + for (final ClassType c : PTAScene.v().getView().getTypeHierarchy().implementersOf(cl.getType())) { if (workset.add(c)) { worklist.add(c); } @@ -204,7 +208,7 @@ protected void resolveAnySubType(Type declaredType, Type sigType, MethodSubSigna resolve(cl.getType(), declaredType, sigType, subSig, container, targets, appOnly); newSubTypes.add(cl.getType()); } - for (final SootClass c : Scene.v().getFastHierarchy().getSubclassesOf(cl)) { + for (final ClassType c : PTAScene.v().getView().getTypeHierarchy().subclassesOf(classType)) { if (workset.add(c)) { worklist.add(c); } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index b1728034552..becf1618c0b 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -113,7 +113,7 @@ private void constructCallGraph() { Map> submap = map.computeIfAbsent(unit, k -> DataFactory.createMap()); Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); if (set.add(tgt)) { - cicg.addEdge(new Edge(src, e.srcUnit(), tgt, e.kind())); + cicg.addEdge(new Edge(new ContextMethod(src, pta.emptyContext()), e.srcUnit(), new ContextMethod(tgt, pta.emptyContext()), e.kind())); } }); } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index 77911e66fd9..e3999e0fd3a 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -57,6 +57,7 @@ import sootup.core.model.SootMethod; import sootup.core.signatures.FieldSignature; import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; import sootup.core.types.Type; import sootup.java.core.language.JavaJimple; @@ -150,7 +151,11 @@ protected void handleInvokeStmt(Stmt s) { } private void resolveClinit(JStaticFieldRef staticFieldRef) { - PTAUtils.clinitsOf(staticFieldRef.getField().getDeclaringClass()).forEach(mpag::addTriggeredClinit); + FieldSignature fieldSig = staticFieldRef.getFieldSignature(); + SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); + ClassType classType = field.getDeclaringClassType(); + SootClass sootClass = (SootClass) PTAScene.v().getView().getClass(classType).get(); + PTAUtils.clinitsOf(sootClass).forEach(mpag::addTriggeredClinit); } /** @@ -231,8 +236,8 @@ private AllocNode caseNewExpr(JNewExpr ne) { } private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { - SootField sf = ifr.getField(); FieldSignature fieldSig = ifr.getFieldSignature(); + SootField sf = (SootField) PTAScene.v().getView().getField(fieldSig).get(); if (sf == null) { sf = new SootField(fieldSig, Collections.singleton(Modifier.PUBLIC), NoPositionInformation.getInstance()); sf.setNumber(Scene.v().getFieldNumberer().size()); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 71234c484f2..138d8375995 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -43,7 +43,6 @@ import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; -import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index dc50b08911a..a814624fc87 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -112,7 +112,7 @@ public void run() { containingMethod = heap.getMethod(); } - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 2f33acdc2c9..8c4f400c7bf 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -193,7 +193,7 @@ public static void dumpCallGraph(Iterable callgraph, boolean appOnly) { for (Edge edge : callgraph) { MethodOrMethodContext srcmtd = edge.getSrc(); - if (appOnly && !srcmtd.method().getDeclaringClass().isApplicationClass()) + if (appOnly && !PTAUtils.isApplicationMethod(srcmtd.method())) continue; MethodOrMethodContext dstmtd = edge.getTgt(); String srcName = srcmtd.toString(); From 1f9fbc21a90c2d863a3c7f726ece08176a103230 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Wed, 20 Sep 2023 08:30:33 +1000 Subject: [PATCH 023/145] update --- .../src/main/java/qilin/core/PTAScene.java | 101 ++++----- .../qilin/core/builder/ExceptionHandler.java | 2 +- .../qilin/core/builder/FakeMainFactory.java | 106 +++++++-- .../qilin/core/reflection/TamiflexModel.java | 13 +- .../pta/toolkits/debloaterx/XUtility.java | 6 +- .../main/java/qilin/stat/CallGraphStat.java | 14 +- .../src/main/java/qilin/util/PTAUtils.java | 12 +- .../src/main/java/soot/EntryPoints.java | 207 ++++++++++++++++++ .../src/main/java/soot/JavaMethods.java | 57 +++++ 9 files changed, 426 insertions(+), 92 deletions(-) create mode 100644 sootup.qilin/src/main/java/soot/EntryPoints.java create mode 100644 sootup.qilin/src/main/java/soot/JavaMethods.java diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java index 84df8712081..0c9f8042c4e 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTAScene.java +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -20,26 +20,51 @@ import qilin.core.builder.FakeMainFactory; import qilin.util.DataFactory; +import qilin.util.PTAUtils; import soot.jimple.toolkits.callgraph.CallGraph; import soot.util.Chain; import soot.util.IterableNumberer; -import soot.util.StringNumberer; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.signatures.FieldSignature; +import sootup.core.signatures.MethodSignature; +import sootup.core.types.ClassType; import sootup.core.types.Type; import sootup.core.views.View; +import sootup.java.core.JavaIdentifierFactory; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; import java.util.Set; public class PTAScene { private static volatile PTAScene instance = null; - private final Scene sootScene; + private final View view; + private CallGraph callgraph; private final FakeMainFactory fakeMainFactory; + private SootClass mainClass = null; + + public void setMainClass(SootClass m) { + mainClass = m; + } + + public boolean hasMainClass() { + return mainClass != null; + } + + public SootClass getMainClass() { + if (!hasMainClass()) { + throw new RuntimeException("There is no main class set!"); + } + return mainClass; + } + public static PTAScene v() { if (instance == null) { synchronized (PTAScene.class) { @@ -57,13 +82,11 @@ public static void junitReset() { } public static void reset() { - G.reset(); VirtualCalls.reset(); instance = null; } private PTAScene() { - this.sootScene = Scene.v(); this.fakeMainFactory = new FakeMainFactory(); } @@ -86,16 +109,12 @@ public Value getFieldGlobalThrow() { return this.fakeMainFactory.getFieldGlobalThrow(); } - public void setMainClass(SootClass m) { - sootScene.setMainClass(m); - } - /* * wrapper methods of Soot Scene. Note, we do not allow you to use Soot Scene directly in qilin.qilin.pta subproject * to avoid confusing. * */ public void setCallGraph(CallGraph cg) { - sootScene.setCallGraph(cg); + this.callgraph = cg; } public View getView() { @@ -103,19 +122,15 @@ public View getView() { } public CallGraph getCallGraph() { - return sootScene.getCallGraph(); + return this.callgraph; } public IterableNumberer getLocalNumberer() { return sootScene.getLocalNumberer(); } - public IterableNumberer getTypeNumberer() { - return sootScene.getTypeNumberer(); - } - - public FastHierarchy getOrMakeFastHierarchy() { - return sootScene.getOrMakeFastHierarchy(); + public boolean canStoreType(final Type child, final Type parent) { + return view.getTypeHierarchy().isSubtype(parent, child); } public SootClass loadClassAndSupport(String className) { @@ -123,7 +138,8 @@ public SootClass loadClassAndSupport(String className) { } public SootMethod getMethod(String methodSignature) { - return sootScene.getMethod(methodSignature); + MethodSignature mthdSig = JavaIdentifierFactory.getInstance().parseMethodSignature(methodSignature); + return (SootMethod) view.getMethod(mthdSig).get(); } public Chain getApplicationClasses() { @@ -135,65 +151,44 @@ public Chain getLibraryClasses() { } public boolean containsMethod(String methodSignature) { - return sootScene.containsMethod(methodSignature); + MethodSignature mthdSig = JavaIdentifierFactory.getInstance().parseMethodSignature(methodSignature); + return view.getMethod(mthdSig).isPresent(); } public boolean containsField(String fieldSignature) { - return sootScene.containsField(fieldSignature); - } - - public void loadBasicClasses() { - sootScene.loadBasicClasses(); + FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + return view.getField(fieldSig).isPresent(); } - public void addBasicClass(String name, int level) { - sootScene.addBasicClass(name, level); + public Collection getClasses() { + return view.getClasses(); } - public Chain getClasses() { - return sootScene.getClasses(); - } - - public Chain getPhantomClasses() { - return sootScene.getPhantomClasses(); + public Collection getPhantomClasses() { + return Collections.emptySet(); } public SootClass getSootClass(String className) { - return sootScene.getSootClass(className); + ClassType classType = PTAUtils.getClassType(className); + return (SootClass) view.getClass(classType).get(); } public boolean containsClass(String className) { - return sootScene.containsClass(className); + ClassType classType = PTAUtils.getClassType(className); + Optional oclazz = view.getClass(classType); + return oclazz.isPresent(); } public SootField getField(String fieldSignature) { - return sootScene.getField(fieldSignature); - } - - public Type getTypeUnsafe(String arg, boolean phantomNonExist) { - return sootScene.getTypeUnsafe(arg, phantomNonExist); + FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + return (SootField) view.getField(fieldSig).get(); } - public StringNumberer getSubSigNumberer() { - return sootScene.getSubSigNumberer(); - } - - public IterableNumberer getMethodNumberer() { - return sootScene.getMethodNumberer(); - } public void loadNecessaryClasses() { sootScene.loadNecessaryClasses(); } - public boolean containsType(String className) { - return sootScene.containsType(className); - } - - public RefType getRefType(String className) { - return sootScene.getRefType(className); - } - /* * copy from doop's soot-fact-generator * */ diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index f08c197128f..ddb3bc0367b 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -74,7 +74,7 @@ public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { VarNode throwNode = site.getThrowNode(); List trapList = mpag.stmt2wrapperedTraps.getOrDefault(site.getUnit(), Collections.emptyList()); for (Trap trap : trapList) { - if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, trap.getException().getType())) { + if (PTAScene.v().canStoreType(type, trap.getException().getType())) { Stmt handler = trap.getHandlerUnit(); assert handler instanceof JIdentityStmt; JIdentityStmt handlerStmt = (JIdentityStmt) handler; diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index da33a28e2cd..d3290e5171f 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -20,18 +20,36 @@ import qilin.CoreConfig; import qilin.core.ArtificialMethod; +import qilin.core.PTAScene; import qilin.util.PTAUtils; -import soot.jimple.JimpleBody; +import soot.EntryPoints; +import sootup.core.IdentifierFactory; +import sootup.core.frontend.OverridingBodySource; +import sootup.core.frontend.OverridingClassSource; +import sootup.core.inputlocation.EagerInputLocation; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.NoPositionInformation; +import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.JNopStmt; +import sootup.core.jimple.common.stmt.JReturnVoidStmt; +import sootup.core.model.Body; import sootup.core.model.Modifier; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; +import sootup.core.model.SourceType; +import sootup.core.signatures.FieldSignature; +import sootup.core.signatures.MethodSignature; +import sootup.core.types.ClassType; +import sootup.java.core.JavaIdentifierFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashSet; import java.util.List; public class FakeMainFactory extends ArtificialMethod { @@ -42,15 +60,70 @@ public class FakeMainFactory extends ArtificialMethod { public FakeMainFactory() { this.localStart = 0; - this.fakeClass = new SootClass("FakeMain"); - this.fakeClass.setResolvingLevel(SootClass.BODIES); - this.method = new SootMethod("fakeMain", null, VoidType); - this.method.setModifiers(Modifier.STATIC); - SootField currentThread = new SootField("currentThread", RefType.v("java.lang.Thread"), Modifier.STATIC); - SootField globalThrow = new SootField("globalThrow", RefType.v("java.lang.Exception"), Modifier.STATIC); - fakeClass.addMethod(this.method); - fakeClass.addField(currentThread); - fakeClass.addField(globalThrow); + // this.fakeClass = new SootClass("FakeMain"); +// this.fakeClass.setResolvingLevel(SootClass.BODIES); +// this.method = new SootMethod("fakeMain", null, VoidType); +// this.method.setModifiers(Modifier.STATIC); + String className = "qilin.pta.FakeMain"; + IdentifierFactory fact = PTAScene.v().getView().getIdentifierFactory(); + ClassType declaringClassSignature = JavaIdentifierFactory.getInstance().getClassType(className); + FieldSignature ctSig = fact.getFieldSignature("currentThread", declaringClassSignature, "java.lang.Thread"); + SootField currentThread = new SootField(ctSig, EnumSet.of(Modifier.STATIC), NoPositionInformation.getInstance()); + FieldSignature gtSig = fact.getFieldSignature("globalThrow", declaringClassSignature, "java.lang.Exception"); + SootField globalThrow = new SootField(gtSig, EnumSet.of(Modifier.STATIC), NoPositionInformation.getInstance()); +// fakeClass.addMethod(this.method); +// fakeClass.addField(currentThread); +// fakeClass.addField(globalThrow); + + + MethodSignature methodSignatureOne = PTAScene.v().getView().getIdentifierFactory() + .getMethodSignature("main", className, "void", Collections.emptyList()); + + StmtPositionInfo noPosInfo = StmtPositionInfo.createNoStmtPositionInfo(); + final JReturnVoidStmt returnVoidStmt = new JReturnVoidStmt(noPosInfo); + final JNopStmt jNop = new JNopStmt(noPosInfo); + this.bodyBuilder = Body.builder(); + bodyBuilder + .setStartingStmt(jNop) + .addFlow(jNop, returnVoidStmt) + .setMethodSignature(methodSignatureOne) + .setPosition(NoPositionInformation.getInstance()); + makeFakeMain(); + Body bodyOne = bodyBuilder.build(); + SootMethod dummyMainMethod = + new SootMethod( + new OverridingBodySource(methodSignatureOne, bodyOne), + methodSignatureOne, + EnumSet.of(Modifier.PUBLIC, Modifier.STATIC), + Collections.emptyList(), + NoPositionInformation.getInstance()); + this.method = dummyMainMethod; + this.fakeClass = new SootClass( + new OverridingClassSource( + Collections.singleton(dummyMainMethod), + new LinkedHashSet<>(Arrays.asList(currentThread, globalThrow)), + EnumSet.of(Modifier.PUBLIC), + null, + JavaIdentifierFactory.getInstance().getClassType("java.lang.Object"), + null, + NoPositionInformation.getInstance(), + null, + PTAScene.v().getView().getIdentifierFactory().getClassType(className), + new EagerInputLocation()), + SourceType.Application); + } + + public SootMethod getFakeMain() { +// if (bodyBuilder == null) { +// synchronized (this) { +// if (bodyBuilder == null) { +// this.method.setSource((m, phaseName) -> new JimpleBody(this.method)); +// makeFakeMain(); +// this.body = PTAUtils.getMethodBody(method); +// } +// } +// } + return this.method; } private List getEntryPoints() { @@ -78,19 +151,6 @@ private List getEntryPoints() { return ret; } - public SootMethod getFakeMain() { - if (bodyBuilder == null) { - synchronized (this) { - if (bodyBuilder == null) { - this.method.setSource((m, phaseName) -> new JimpleBody(this.method)); - makeFakeMain(); - this.body = PTAUtils.getMethodBody(method); - } - } - } - return this.method; - } - public Value getFieldCurrentThread() { return getStaticFieldRef("FakeMain", "currentThread"); } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index df56aa873f2..f58cb2f9833 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -46,6 +46,7 @@ import sootup.core.model.SootField; import sootup.core.model.SootMethod; import sootup.core.signatures.FieldSignature; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ReferenceType; import sootup.java.core.JavaIdentifierFactory; @@ -102,11 +103,12 @@ protected Collection transformClassNewInstance(Stmt s) { Collection classNames = classNewInstances.get(s); for (String clsName : classNames) { SootClass cls = PTAScene.v().getSootClass(clsName); - - if (cls.declaresMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()"))) { + MethodSubSignature initSubSig = JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); + Optional omthd = cls.getMethod(initSubSig); + if (omthd.isPresent()) { JNewExpr newExpr = new JNewExpr(cls.getType()); ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); - SootMethod constructor = cls.getMethod(PTAScene.v().getSubSigNumberer().findOrAdd("void ()")); + SootMethod constructor = omthd.get(); ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), Collections.emptyList()), StmtPositionInfo.createNoStmtPositionInfo())); } } @@ -253,7 +255,7 @@ protected Collection transformArrayNewInstance(Stmt s) { Map> mappedToArrayTypes = reflectionMap.getOrDefault(ReflectionKind.ArrayNewInstance, Collections.emptyMap()); Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); for (String arrayType : arrayTypes) { - ArrayType at = (ArrayType) PTAScene.v().getTypeUnsafe(arrayType, true); + ArrayType at = (ArrayType) JavaIdentifierFactory.getInstance().getType(arrayType); JNewArrayExpr newExpr = JavaJimple.getInstance().newNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1)); if (s instanceof JAssignStmt) { Value lvalue = ((JAssignStmt) s).getLeftOp(); @@ -382,7 +384,8 @@ private Collection inferSourceMethod(String inClzDotMthd) { } SootClass sootClass = PTAScene.v().getSootClass(inClassStr); Set ret = DataFactory.createSet(); - for (SootMethod m : sootClass.getMethods()) { + Set declMethods = sootClass.getMethods(); + for (SootMethod m : declMethods) { if (m.isConcrete() && m.getName().equals(inMethodStr)) { ret.add(m); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index 6267cf112a5..604fcaef8c4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -213,7 +213,7 @@ private void buildHeapMethodsMapping() { if (ie instanceof AbstractInstanceInvokeExpr iie) { LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); - VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, edge.src(), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); + VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, new ContextMethod(edge.src(), pta.emptyContext()), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); vcallsites.add(virtualCallSite); } else { throw new RuntimeException("ie could not be of " + ie.getClass()); @@ -279,12 +279,12 @@ public Set getFields(Type type) { } else { ret = this.t2Fields.computeIfAbsent(refType, k -> new HashSet<>()); for (AllocNode heap : this.o2Fields.keySet()) { - if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(heap.getType(), refType)) { + if (PTAScene.v().canStoreType(heap.getType(), refType)) { for (SparkField sparkField : this.o2Fields.get(heap)) { if (sparkField instanceof Field f) { SootField sf = f.getField(); Type declType = sf.getDeclaringClassType(); - if (PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, declType)) { + if (PTAScene.v().canStoreType(type, declType)) { ret.add(sparkField); } } else { diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index 9a5e4b0b746..97faaca4f14 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -22,14 +22,17 @@ import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.FakeMainFactory; +import qilin.core.pag.ContextMethod; import qilin.core.pag.ContextVarNode; import qilin.core.pag.LocalVarNode; import qilin.util.PTAUtils; import soot.MethodOrMethodContext; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -61,6 +64,7 @@ public class CallGraphStat implements AbstractStat { private int CIStaticToInstance = 0; private int CIInstanceToStatic = 0; private int CIInstancetoInstance = 0; + private int allMethods = 0; public CallGraphStat(PTA pta) { this.pta = pta; @@ -68,6 +72,12 @@ public CallGraphStat(PTA pta) { } private void init() { + // stat method numbers + Collection clazzs = PTAScene.v().getView().getClasses(); + for (SootClass clazz : clazzs) { + allMethods += clazz.getMethods().size(); + } + // CallGraph csCallGraph = pta.getCgb().getCallGraph(); CSCallEdges = csCallGraph.size(); for (final MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { @@ -120,7 +130,7 @@ private void init() { reachableAppStatic++; } } - for (Iterator iterator = ciCallGraph.edgesInto(sm); iterator.hasNext(); ) { + for (Iterator iterator = ciCallGraph.edgesInto(new ContextMethod(sm, pta.emptyContext())); iterator.hasNext(); ) { Edge e = iterator.next(); final SootMethod srcm = e.getSrc().method(); // if (sm.toString().equals("")) { @@ -161,7 +171,7 @@ private long thisReceiverCount() { @Override public void export(Exporter exporter) { - exporter.collectMetric("#Method (Static):", String.valueOf(PTAScene.v().getMethodNumberer().size() - 1));// -fakeMain + exporter.collectMetric("#Method (Static):", String.valueOf( allMethods - 1));// -fakeMain exporter.collectMetric("#Reachable Method (CI):", String.valueOf(reachableMethods.size() - 1));// -fakeMain exporter.collectMetric("\t#Reachable-Static Method (CI):", String.valueOf(reachableStatic - 1));// -fakeMain exporter.collectMetric("#Reachable Method (CS):", String.valueOf(reachableParameterizedMethods.size() - 1));// -fakeMain diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 8c4f400c7bf..c96206e40de 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -49,10 +49,12 @@ import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.NullType; @@ -302,13 +304,13 @@ public static boolean castNeverFails(Type src, Type dst) { return false; if (dst instanceof AnySubType) throw new RuntimeException("oops src=" + src + " dst=" + dst); - return PTAScene.v().getOrMakeFastHierarchy().canStoreType(src, dst); + return PTAScene.v().canStoreType(src, dst); } public static QueueReader dispatch(Type type, VirtualCallSite site) { final ChunkedQueue targetsQueue = new ChunkedQueue<>(); final QueueReader targets = targetsQueue.reader(); - if (site.kind() == Kind.THREAD && !PTAScene.v().getOrMakeFastHierarchy().canStoreType(type, clRunnable)) { + if (site.kind() == Kind.THREAD && !PTAScene.v().canStoreType(type, clRunnable)) { return targets; } MethodOrMethodContext container = site.container(); @@ -566,7 +568,7 @@ private static void drawInvPAGMap(DotGraph canvas, Map. + * #L% + */ + +import qilin.core.PTAScene; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.MethodSubSignature; +import sootup.java.core.JavaIdentifierFactory; + +/** + * Returns the various potential entry points of a Java program. + * + * @author Ondrej Lhotak + */ +public class EntryPoints { + + final MethodSubSignature sigMain; + final MethodSubSignature sigFinalize; + final MethodSubSignature sigExit; + final MethodSubSignature sigClinit; + final MethodSubSignature sigInit; + final MethodSubSignature sigStart; + final MethodSubSignature sigRun; + final MethodSubSignature sigObjRun; + final MethodSubSignature sigForName; + + private static EntryPoints instance = new EntryPoints(); + private EntryPoints() { + sigMain = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_MAIN); + sigFinalize = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_FINALIZE); + + sigExit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_EXIT); + sigClinit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_CLINIT); + sigInit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_INIT); + sigStart = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_START); + sigRun = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_RUN); + sigObjRun = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_OBJ_RUN); + sigForName = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_FOR_NAME); + } + + public static EntryPoints v() { + return instance; + } + + protected void addMethod(List set, SootClass cls, MethodSubSignature methodSubSig) { + Optional osm = cls.getMethod(methodSubSig); + osm.ifPresent(set::add); + } + + protected void addMethod(List set, String methodSig) { + MethodSignature ms = JavaIdentifierFactory.getInstance().parseMethodSignature(methodSig); + Optional osm = PTAScene.v().getView().getMethod(ms); + osm.ifPresent(set::add); + } + + /** + * Returns only the application entry points, not including entry points invoked implicitly by the VM. + */ + public List application() { + List ret = new ArrayList(); + if (PTAScene.v().hasMainClass()) { + SootClass mainClass = PTAScene.v().getMainClass(); + addMethod(ret, mainClass, sigMain); + for (SootMethod clinit : clinitsOf(mainClass)) { + ret.add(clinit); + } + } + return ret; + } + + /** Returns only the entry points invoked implicitly by the VM. */ + public List implicit() { + List ret = new ArrayList(); + +// if (Options.v().src_prec() == Options.src_prec_dotnet) { +// return ret; +// } + + addMethod(ret, JavaMethods.INITIALIZE_SYSTEM_CLASS); + addMethod(ret, JavaMethods.THREAD_GROUP_INIT); + // addMethod( ret, ""); + addMethod(ret, JavaMethods.THREAD_EXIT); + addMethod(ret, JavaMethods.THREADGROUP_UNCAUGHT_EXCEPTION); + // addMethod( ret, ""); + addMethod(ret, JavaMethods.CLASSLOADER_INIT); + addMethod(ret, JavaMethods.CLASSLOADER_LOAD_CLASS_INTERNAL); + addMethod(ret, JavaMethods.CLASSLOADER_CHECK_PACKAGE_ACC); + addMethod(ret, JavaMethods.CLASSLOADER_ADD_CLASS); + addMethod(ret, JavaMethods.CLASSLOADER_FIND_NATIVE); + addMethod(ret, JavaMethods.PRIV_ACTION_EXC_INIT); + // addMethod( ret, ""); + addMethod(ret, JavaMethods.RUN_FINALIZE); + addMethod(ret, JavaMethods.THREAD_INIT_RUNNABLE); + addMethod(ret, JavaMethods.THREAD_INIT_STRING); + return ret; + } + + /** Returns all the entry points. */ + public List all() { + List ret = new ArrayList(); + ret.addAll(application()); + ret.addAll(implicit()); + return ret; + } + + /** Returns a list of all static initializers. */ + public List clinits() { + List ret = new ArrayList(); + Collection classes = PTAScene.v().getView().getClasses(); + for (SootClass cl : classes) { + addMethod(ret, cl, sigClinit); + } + return ret; + } + + /** Returns a list of all clinits of class cl and its superclasses. */ + public Iterable clinitsOf(SootClass cl) { + // Do not create an actual list, since this method gets called quite often + // Instead, callers usually just want to iterate over the result. + Optional oinit = cl.getMethod(sigClinit); + Optional osuperClass = cl.getSuperclass(); + // check super classes until finds a constructor or no super class there anymore. + while (oinit.isPresent() && osuperClass.isPresent()) { + oinit = osuperClass.get().getMethod(sigClinit); + osuperClass = osuperClass.get().getSuperclass(); + } + if (!oinit.isPresent()) { + return Collections.emptyList(); + } + SootMethod initStart = oinit.get(); + return new Iterable() { + + @Override + public Iterator iterator() { + return new Iterator() { + SootMethod current = initStart; + + @Override + public SootMethod next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + SootMethod n = current; + + // Pre-fetch the next element + current = null; + SootClass currentClass = (SootClass) PTAScene.v().getView().getClass(n.getDeclaringClassType()).get(); + while (true) { + Optional osuperClass = currentClass.getSuperclass(); + if (!osuperClass.isPresent()) { + break; + } + + Optional om = osuperClass.get().getMethod(sigClinit); + if (om.isPresent()) { + current = om.get(); + break; + } + + currentClass = osuperClass.get(); + } + + return n; + } + + @Override + public boolean hasNext() { + return current != null; + } + }; + } + }; + } +} diff --git a/sootup.qilin/src/main/java/soot/JavaMethods.java b/sootup.qilin/src/main/java/soot/JavaMethods.java new file mode 100644 index 00000000000..40f9b4f5742 --- /dev/null +++ b/sootup.qilin/src/main/java/soot/JavaMethods.java @@ -0,0 +1,57 @@ +package soot; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2022 Fraunhofer SIT + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +public class JavaMethods { + + public static final String SIG_MAIN = "void main(java.lang.String[])"; + public static final String SIG_FINALIZE = "void finalize()"; + public static final String SIG_EXIT = "void exit()"; + public static final String SIG_CLINIT = "void ()"; + public static final String SIG_INIT = "void ()"; + public static final String SIG_START = "void start()"; + public static final String SIG_RUN = "void run()"; + public static final String SIG_OBJ_RUN = "java.lang.Object run()"; + public static final String SIG_FOR_NAME = "java.lang.Class forName(java.lang.String)"; + + public static final String INITIALIZE_SYSTEM_CLASS = ""; + public static final String THREAD_GROUP_INIT = "()>"; + public static final String THREAD_EXIT = ""; + public static final String THREADGROUP_UNCAUGHT_EXCEPTION + = ""; + public static final String CLASSLOADER_INIT = "()>"; + public static final String CLASSLOADER_LOAD_CLASS_INTERNAL + = ""; + public static final String CLASSLOADER_CHECK_PACKAGE_ACC + = ""; + public static final String CLASSLOADER_ADD_CLASS = ""; + public static final String CLASSLOADER_FIND_NATIVE + = ""; + public static final String PRIV_ACTION_EXC_INIT + = "(java.lang.Exception)>"; + public static final String RUN_FINALIZE = ""; + public static final String THREAD_INIT_RUNNABLE + = "(java.lang.ThreadGroup,java.lang.Runnable)>"; + public static final String THREAD_INIT_STRING = "(java.lang.ThreadGroup,java.lang.String)>"; +} + From 98f2a25d4a460e85ee93ac371b589da86abe2e59 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Wed, 20 Sep 2023 08:51:58 +1000 Subject: [PATCH 024/145] update --- sootup.qilin/src/main/java/qilin/core/PTAScene.java | 6 ------ .../src/main/java/qilin/core/builder/CallGraphBuilder.java | 4 ++-- .../src/main/java/qilin/core/builder/ExceptionHandler.java | 6 +++--- sootup.qilin/src/main/java/qilin/core/pag/PAG.java | 6 +++--- .../src/main/java/qilin/core/reflection/TamiflexModel.java | 6 ++++-- sootup.qilin/src/main/java/soot/util/Numberer.java | 2 +- 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java index 0c9f8042c4e..a77883d11e3 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTAScene.java +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -23,8 +23,6 @@ import qilin.util.PTAUtils; import soot.jimple.toolkits.callgraph.CallGraph; import soot.util.Chain; -import soot.util.IterableNumberer; -import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.SootClass; import sootup.core.model.SootField; @@ -125,10 +123,6 @@ public CallGraph getCallGraph() { return this.callgraph; } - public IterableNumberer getLocalNumberer() { - return sootScene.getLocalNumberer(); - } - public boolean canStoreType(final Type child, final Type parent) { return view.getTypeHierarchy().isSubtype(parent, child); } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index becf1618c0b..ff8ef420a15 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -64,7 +64,7 @@ public CallGraphBuilder(PTA pta) { this.pta = pta; this.pag = pta.getPag(); PTAScene.v().setCallGraph(new CallGraph()); - receiverToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); + receiverToSites = DataFactory.createMap(PTAScene.v().getView().getClasses().size()); methodToInvokeStmt = DataFactory.createMap(); reachMethods = DataFactory.createSet(); calledges = DataFactory.createSet(); @@ -145,7 +145,7 @@ protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { SootMethod target = targets.next(); if (site.iie() instanceof JSpecialInvokeExpr) { Type calleeDeclType = target.getDeclaringClassType(); - if (!Scene.v().getFastHierarchy().canStoreType(type, calleeDeclType)) { + if (!PTAScene.v().canStoreType(type, calleeDeclType)) { continue; } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index ddb3bc0367b..9fd72867524 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -35,7 +35,7 @@ import java.util.*; public class ExceptionHandler { - protected final Map> throwNodeToSites = DataFactory.createMap(PTAScene.v().getLocalNumberer().size()); + protected final Map> throwNodeToSites = DataFactory.createMap(PTAScene.v().getView().getClasses().size()); protected PTA pta; protected PAG pag; @@ -74,8 +74,8 @@ public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { VarNode throwNode = site.getThrowNode(); List trapList = mpag.stmt2wrapperedTraps.getOrDefault(site.getUnit(), Collections.emptyList()); for (Trap trap : trapList) { - if (PTAScene.v().canStoreType(type, trap.getException().getType())) { - Stmt handler = trap.getHandlerUnit(); + if (PTAScene.v().canStoreType(type, trap.getExceptionType())) { + Stmt handler = trap.getHandlerStmt(); assert handler instanceof JIdentityStmt; JIdentityStmt handlerStmt = (JIdentityStmt) handler; Node caughtParam = nodeFactory.getNode(handlerStmt.getRightOp()); diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 138d8375995..cf758c4a50a 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -363,9 +363,9 @@ public LocalVarNode makeLocalVarNode(Object value, Type type, SootMethod method) valToValNode.put(value, ret = new LocalVarNode(value, type, method)); valNodeNumberer.add(ret); if (value instanceof Local local) { - if (local.getNumber() == 0) { - PTAScene.v().getLocalNumberer().add(local); - } +// if (local.getNumber() == 0) { +// PTAScene.v().getLocalNumberer().add(local); +// } locals.add(local); } } else if (!(ret.getType().equals(type))) { diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index f58cb2f9833..f96d2e7f2cc 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -409,8 +409,10 @@ private Collection inferSourceStmt(String inClzDotMthd, ReflectionKind kin } } for (Stmt stmt : potential) { - LineNumberTag tag = (LineNumberTag) stmt.getTag("LineNumberTag"); - if (lineNumber < 0 || tag != null && tag.getLineNumber() == lineNumber) { + int firstLine = stmt.getPositionInfo().getStmtPosition().getFirstLine(); + int lastLine = stmt.getPositionInfo().getStmtPosition().getLastLine(); + // !TODO potential bug here + if (lineNumber < 0 || firstLine <= lineNumber && lineNumber <= lastLine) { ret.add(stmt); } } diff --git a/sootup.qilin/src/main/java/soot/util/Numberer.java b/sootup.qilin/src/main/java/soot/util/Numberer.java index 51ba04cafc9..9efe5ea5a2a 100644 --- a/sootup.qilin/src/main/java/soot/util/Numberer.java +++ b/sootup.qilin/src/main/java/soot/util/Numberer.java @@ -45,7 +45,7 @@ public interface Numberer { */ public long get(E o); - /** Should return the object that was assigned the number number. */ + /** Should return the object that was assigned the number. */ public E get(long number); /** Should return the number of objects that have been assigned numbers. */ From 4025b5c06c110b7e1ca287103f7a1b5ae48888d1 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Wed, 20 Sep 2023 10:41:14 +1000 Subject: [PATCH 025/145] update --- .../java/qilin/core/pag/GlobalVarNode.java | 3 +- .../src/main/java/qilin/util/PTAUtils.java | 94 ++++--------------- .../java/qilin/test/util/AliasAssertion.java | 22 ++--- .../qilin/test/util/AssertionsParser.java | 21 ++--- .../test/java/qilin/test/util/JunitTests.java | 2 - 5 files changed, 42 insertions(+), 100 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java index 9582d78217f..9fc0396bdf1 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java @@ -19,6 +19,7 @@ package qilin.core.pag; +import qilin.core.PTAScene; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.types.Type; @@ -45,7 +46,7 @@ public String toString() { public SootClass getDeclaringClass() { if (variable instanceof SootField sf) { - return sf.getDeclaringClass(); + return (SootClass) PTAScene.v().getView().getClass(sf.getDeclaringClassType()).get(); } return null; diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index c96206e40de..1ca2bdd8fba 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -36,7 +36,6 @@ import soot.MethodOrMethodContext; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; -import soot.util.NumberedString; import soot.util.dot.DotGraph; import soot.util.dot.DotGraphConstants; import soot.util.dot.DotGraphNode; @@ -55,11 +54,13 @@ import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSubSignature; +import sootup.core.signatures.PackageName; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.NullType; import sootup.core.types.PrimitiveType; import sootup.core.types.Type; +import sootup.core.util.printer.JimplePrinter; import sootup.java.core.JavaIdentifierFactory; import java.io.*; @@ -276,15 +277,17 @@ public static void dumpSlicedCallGraph2(CallGraph callgraph, MethodOrMethodConte public static boolean isUnresolved(Type type) { if (type instanceof ArrayType at) { - type = at.getArrayElementType(); + type = at.getBaseType(); } if (!(type instanceof ClassType rt)) return false; // if (!rt.hasSootClass()) { // return true; // } - SootClass cl = rt.getSootClass(); - return cl.resolvingLevel() < SootClass.HIERARCHY; + Optional ocl = PTAScene.v().getView().getClass(rt); + return ocl.isEmpty(); +// SootClass cl = rt.getSootClass(); +// return cl.resolvingLevel() < SootClass.HIERARCHY; } public static boolean castNeverFails(Type src, Type dst) { @@ -298,12 +301,12 @@ public static boolean castNeverFails(Type src, Type dst) { return true; if (src instanceof NullType) return true; - if (src instanceof AnySubType) - return true; +// if (src instanceof AnySubType) +// return true; if (dst instanceof NullType) return false; - if (dst instanceof AnySubType) - throw new RuntimeException("oops src=" + src + " dst=" + dst); +// if (dst instanceof AnySubType) +// throw new RuntimeException("oops src=" + src + " dst=" + dst); return PTAScene.v().canStoreType(src, dst); } @@ -350,14 +353,14 @@ public static void dumpPts(PTA pta, boolean appOnly) { if (vn instanceof LocalVarNode) { SootMethod sm = ((LocalVarNode) vn).getMethod(); if (sm != null) { - clz = sm.getDeclaringClass(); + clz = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); } } else if (vn instanceof GlobalVarNode gvn) { clz = gvn.getDeclaringClass(); } else if (vn instanceof ContextVarNode cv) { VarNode varNode = cv.base(); if (varNode instanceof LocalVarNode cvbase) { - clz = cvbase.getMethod().getDeclaringClass(); + clz = (SootClass) PTAScene.v().getView().getClass(cvbase.getMethod().getDeclaringClassType()).get(); } else if (varNode instanceof GlobalVarNode gvn) { clz = gvn.getDeclaringClass(); } @@ -614,7 +617,7 @@ public static Context plusplusOp(AllocNode heap) { } public static boolean isFakeMainMethod(SootMethod method) { - String sig = ""; + String sig = ""; return method.getSignature().equals(sig); } @@ -626,32 +629,6 @@ public static boolean isFakeMainMethod(SootMethod method) { private static final String[] NO_CONTEXT = {"java.lang.Throwable", "java.lang.StringBuffer", "java.lang.StringBuilder"}; private static Set ignoreList = null; - /** - * Install no context list for classes given plus all subclasses. - */ - private static void initEmptyHeapContextTypes() { - if (ignoreList == null) { - ignoreList = new HashSet<>(); - Hierarchy hierarchy = new Hierarchy(); - for (String str : NO_CONTEXT) { - SootClass clz = PTAScene.v().getSootClass(str); - if (clz.isInterface()) { - for (SootClass child : hierarchy.getSubinterfacesOfIncluding(clz)) { - if (child != null) { - ignoreList.add(child); - } - } - } else { - for (SootClass child : hierarchy.getSubclassesOfIncluding(clz)) { - if (child != null) { - ignoreList.add(child); - } - } - } - } - } - } - public static boolean isOfPrimitiveBaseType(AllocNode heap) { if (heap.getType() instanceof ArrayType arrayType) { return arrayType.getBaseType() instanceof PrimitiveType; @@ -666,45 +643,22 @@ public static boolean isPrimitiveArrayType(Type type) { return false; } - /** - * Limit heap context to 0 for these AllocNodes of types in ignoreList. - * We set heaps of StringBuilder/StringBuffer/Throwable types to be context-insensitive just like that in Doop. - * refers to library/string-constants.logic in doop. - */ - public static boolean enforceEmptyContext(AllocNode probe) { - // primitive array objects should be context-insenstive. - if (probe.getType() instanceof ArrayType arrayType) { - if (arrayType.getArrayElementType() instanceof PrimitiveType) { - return true; - } - } - // shortcircuit below computation - initEmptyHeapContextTypes(); - if (!ignoreList.isEmpty()) { - // check if the type that is allocated should never has context - // because it is on the ignore List - SootClass allocated = getSootClass(probe.getType()); - // first check if on the no context list, that trumps all - return ignoreList.contains(allocated); - } - return false; - } - /** * Write the jimple file for clz. ParentDir is the absolute path of parent * directory. */ public static void writeJimple(String parentDir, SootClass clz) { - + PackageName pkgName = clz.getType().getPackageName(); + String clzName = clz.getType().getClassName(); File packageDirectory = new File( - parentDir + File.separator + clz.getPackageName().replace(".", File.separator)); + parentDir + File.separator + pkgName.getPackageName().replace(".", File.separator)); try { packageDirectory.mkdirs(); OutputStream streamOut = new FileOutputStream( - packageDirectory + File.separator + clz.getShortName() + ".jimple"); + packageDirectory + File.separator + clzName + ".jimple"); PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut)); - Printer.v().printTo(clz, writerOut); + new JimplePrinter().printTo(clz, writerOut); writerOut.flush(); writerOut.close(); streamOut.close(); @@ -786,16 +740,6 @@ public static String findMainFromMetaInfo(String appPath) { return mainClass; } - public static SootClass getSootClass(Type type) { - SootClass allocated = null; - if (type instanceof ClassType) { - allocated = ((ClassType) type).getSootClass(); - } else if (type instanceof ArrayType && ((ArrayType) type).getArrayElementType() instanceof ClassType) { - allocated = ((ClassType) ((ArrayType) type).getArrayElementType()).getSootClass(); - } - return allocated; - } - private static final Map methodToBody = DataFactory.createMap(); public static Body getMethodBody(SootMethod m) { diff --git a/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java b/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java index a6ff745166a..a0320acbb98 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java +++ b/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java @@ -22,13 +22,13 @@ import qilin.core.sets.PointsToSet; import qilin.pta.PTAConfig; import qilin.util.PTAUtils; -import soot.Local; -import soot.SootMethod; -import soot.Value; -import soot.jimple.ClassConstant; -import soot.jimple.NullConstant; -import soot.jimple.Stmt; -import soot.jimple.StringConstant; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.NullConstant; +import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; import java.util.Objects; @@ -82,15 +82,15 @@ protected boolean isMayAlias(PTA pta, Value va, Value vb) { } if (va instanceof StringConstant && vb instanceof StringConstant) { return va.equals(vb); - } else if (va instanceof StringConstant) { - String s = ((StringConstant) va).value; + } else if (va instanceof StringConstant strConst) { + String s = strConst.getValue(); if (!PTAConfig.v().getPtaConfig().stringConstants) { s = "STRING_NODE"; } PointsToSet pts = pta.reachingObjects((Local) vb).toCIPointsToSet(); return pts.possibleStringConstants().contains(s); - } else if (vb instanceof StringConstant) { - String s = ((StringConstant) vb).value; + } else if (vb instanceof StringConstant strConst) { + String s = strConst.getValue(); if (!PTAConfig.v().getPtaConfig().stringConstants) { s = "STRING_NODE"; } diff --git a/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java b/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java index 60da49f282e..0e476eaa116 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java +++ b/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java @@ -20,11 +20,11 @@ import qilin.core.PTA; import qilin.util.PTAUtils; -import soot.SootMethod; -import soot.Unit; -import soot.jimple.InvokeExpr; -import soot.jimple.StaticInvokeExpr; -import soot.jimple.Stmt; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; import java.util.HashSet; import java.util.Set; @@ -36,7 +36,7 @@ public class AssertionsParser { public static Set retrieveQueryInfo(PTA pta) { Set aliasAssertionSet = new HashSet<>(); for (SootMethod sm : pta.getNakedReachableMethods()) { - if (sm.isNative() || sm.isPhantom()) { + if (sm.isNative()) { continue; } @@ -46,12 +46,11 @@ public static Set retrieveQueryInfo(PTA pta) { // PTAUtils.dumpMPAG(pta, sm); // System.out.println("================================================================="); // } - for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) { - final Stmt stmt = (Stmt) unit; + for (final Stmt stmt : PTAUtils.getMethodBody(sm).getStmts()) { if (stmt.containsInvokeExpr()) { - InvokeExpr ie = stmt.getInvokeExpr(); - if (ie instanceof StaticInvokeExpr) { - final String calleeSig = ie.getMethodRef().getSignature(); + AbstractInvokeExpr ie = stmt.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { + final MethodSignature calleeSig = ie.getMethodSignature(); if (calleeSig.equals(mayAliasSig)) { aliasAssertionSet.add(new AliasAssertion(pta, sm, stmt, ie.getArg(0), ie.getArg(1), true)); } else if (calleeSig.equals(notAliasSig)) { diff --git a/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java index fb341a6a02c..c62197a8de4 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java +++ b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java @@ -27,7 +27,6 @@ import qilin.core.PTA; import qilin.core.PTAScene; import qilin.pta.PTAConfig; -import soot.options.Options; import java.io.File; import java.io.IOException; @@ -70,7 +69,6 @@ public PTA run(String mainClass) { public PTA run(String mainClass, String ptaPattern) { PTAConfig.v().getAppConfig().MAIN_CLASS = mainClass; - Options.v().set_main_class(mainClass); PTAScene.v().setMainClass(PTAScene.v().getSootClass(mainClass)); PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPattern); PTAConfig.v().getPtaConfig().ptaName = PTAConfig.v().getPtaConfig().ptaPattern.toString(); From 5abd2611aa18d56436aabfd72e5ab757fbc6ece5 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Wed, 20 Sep 2023 14:23:01 +1000 Subject: [PATCH 026/145] update --- .../java/qilin/core/ArtificialMethod.java | 12 ++++----- .../JavaIoFileSystemGetFileSystemNative.java | 4 +-- .../natives/JavaIoFileSystemListNative.java | 3 ++- .../natives/JavaLangObjectCloneNative.java | 4 +-- ...efFinalizerInvokeFinalizeMethodNative.java | 3 ++- .../core/natives/JavaLangReflectArrayGet.java | 3 ++- .../natives/JavaLangThreadCurrentThread.java | 3 ++- .../natives/JavaLangThreadStart0Native.java | 3 ++- ...ityAccessControllerDoPrivilegedNative.java | 6 ++--- ...ontrollerDoPrivileged_ExceptionNative.java | 5 ++-- .../java/qilin/core/natives/NativeMethod.java | 4 +-- .../src/main/java/qilin/core/pag/Field.java | 20 +++++++-------- .../main/java/qilin/core/pag/SparkField.java | 3 ++- .../src/main/java/qilin/core/pag/VarNode.java | 4 +-- .../qilin/pta/toolkits/common/ToolUtil.java | 5 ++-- .../pta/toolkits/conch/LeakAnalysis.java | 6 ++--- .../debloaterx/CollectionHeuristic.java | 25 +++++++++++-------- .../toolkits/debloaterx/ContainerFinder.java | 2 +- .../debloaterx/IntraFlowAnalysis.java | 2 +- .../qilin/pta/toolkits/debloaterx/XPAG.java | 6 +++-- .../analysis/PotentialContextElement.java | 3 ++- .../src/main/java/qilin/stat/Exporter.java | 5 ++-- .../src/main/java/qilin/util/PTAUtils.java | 24 ++++++++++++------ 23 files changed, 89 insertions(+), 66 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index 5bc38413872..a77a97bd731 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -53,7 +53,7 @@ public abstract class ArtificialMethod { protected int paraStart; protected int localStart; - protected Value getThis() { + protected Local getThis() { if (thisLocal == null) { ClassType type = method.getDeclaringClassType(); IdentityRef thisRef = new JThisRef(type); @@ -63,8 +63,8 @@ protected Value getThis() { return thisLocal; } - protected Value getPara(int index) { - Value paraLocal = paraLocals[index]; + protected Local getPara(int index) { + Local paraLocal = paraLocals[index]; if (paraLocal == null) { Type type = method.getParameterType(index); return getPara(index, type); @@ -72,7 +72,7 @@ protected Value getPara(int index) { return paraLocal; } - protected Value getPara(int index, Type type) { + protected Local getPara(int index, Type type) { Local paraLocal = paraLocals[index]; if (paraLocal == null) { IdentityRef paraRef = new JParameterRef(type, index); @@ -150,14 +150,14 @@ protected void addInvoke(Local receiver, String sig, Immediate ... args) { * * @return rx */ - protected Value getInvoke(Local receiver, String sig, Immediate... args) { + protected Local getInvoke(Local receiver, String sig, Immediate... args) { MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); SootMethod method = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); SootClass clazz = (SootClass) PTAScene.v().getView().getClass(method.getDeclaringClassType()).get(); List argsL = Arrays.asList(args); Value invoke = clazz.isInterface() ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); - Value rx = getNextLocal(method.getReturnType()); + Local rx = getNextLocal(method.getReturnType()); addAssign(rx, invoke); return rx; } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index 0e165bb7b05..ed340c393b9 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -19,7 +19,7 @@ package qilin.core.natives; import qilin.util.PTAUtils; -import sootup.core.jimple.basic.Value; +import sootup.core.jimple.basic.Local; import sootup.core.model.SootMethod; public class JavaIoFileSystemGetFileSystemNative extends NativeMethod { @@ -35,7 +35,7 @@ public JavaIoFileSystemGetFileSystemNative(SootMethod method) { * only exists in old version of JDK(e.g., JDK6). */ public void simulate() { - Value newLocal0 = getNew(PTAUtils.getClassType("java.io.UnixFileSystem")); + Local newLocal0 = getNew(PTAUtils.getClassType("java.io.UnixFileSystem")); addInvoke(newLocal0, "()>"); addReturn(newLocal0); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java index b8a27c97419..c6a00a6c1e7 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -19,6 +19,7 @@ package qilin.core.natives; import qilin.util.PTAUtils; +import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -33,7 +34,7 @@ public JavaIoFileSystemListNative(SootMethod method) { * only exists in old JDK(e.g., JDK6). */ public void simulate() { - Value arrLocal = getNewArray(PTAUtils.getClassType("java.lang.String")); + Immediate arrLocal = getNewArray(PTAUtils.getClassType("java.lang.String")); Value elem = getNew(PTAUtils.getClassType("java.lang.String")); // addInvoke(elem, "()>"); addAssign(getArrayRef(arrLocal), elem); diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java index 996a49745e9..fb61e9e7069 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java @@ -19,7 +19,7 @@ package qilin.core.natives; -import sootup.core.jimple.basic.Value; +import sootup.core.jimple.basic.Local; import sootup.core.model.SootMethod; public class JavaLangObjectCloneNative extends NativeMethod { @@ -33,7 +33,7 @@ public JavaLangObjectCloneNative(SootMethod method) { * the corresponding methods by signatures. */ public void simulate() { - Value r0 = getThis(); + Local r0 = getThis(); addReturn(r0); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java index 833399c4dd7..99b4bbea9aa 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java @@ -18,6 +18,7 @@ package qilin.core.natives; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -30,7 +31,7 @@ public JavaLangRefFinalizerInvokeFinalizeMethodNative(SootMethod method) { * "" */ public void simulate() { - Value r0 = getPara(0); + Local r0 = getPara(0); addInvoke(r0, ""); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index 77a6fb8025d..4badd6e426e 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -19,6 +19,7 @@ package qilin.core.natives; import qilin.util.PTAUtils; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; import sootup.core.types.ArrayType; @@ -38,7 +39,7 @@ void simulate() { ClassType objType = PTAUtils.getClassType("java.lang.Object"); Value arrayBase = getPara(0, new ArrayType(objType, 1)); Value arrayRef = getArrayRef(arrayBase); - Value ret = getNextLocal(objType); + Local ret = getNextLocal(objType); addAssign(ret, arrayRef); addReturn(ret); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java index 9d521d5dc8e..3aa180e08b4 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -20,6 +20,7 @@ import qilin.core.PTAScene; import qilin.util.PTAUtils; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -30,7 +31,7 @@ public class JavaLangThreadCurrentThread extends NativeMethod { @Override void simulate() { - Value lv = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); + Local lv = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); Value rv = PTAScene.v().getFieldCurrentThread(); addAssign(lv, rv); addReturn(lv); diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java index be330b7d483..c87cf33991f 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java @@ -19,6 +19,7 @@ package qilin.core.natives; import qilin.core.PTAScene; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -37,7 +38,7 @@ public JavaLangThreadStart0Native(SootMethod method) { @Override void simulate() { - Value mThis = getThis(); + Local mThis = getThis(); addInvoke(mThis, ""); Value lv = PTAScene.v().getFieldCurrentThread(); addAssign(lv, mThis); // store. diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java index f9c6b6f5d08..a6ad1e4bd3f 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java @@ -17,7 +17,7 @@ */ package qilin.core.natives; -import sootup.core.jimple.basic.Value; +import sootup.core.jimple.basic.Local; import sootup.core.model.SootMethod; public class JavaSecurityAccessControllerDoPrivilegedNative extends NativeMethod { @@ -32,8 +32,8 @@ public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { * doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext) */ public void simulate() { - Value r0 = getPara(0); - Value r1 = getInvoke(r0, ""); + Local r0 = getPara(0); + Local r1 = getInvoke(r0, ""); addReturn(r1); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java index 088995fddc1..8f803712a84 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java @@ -18,6 +18,7 @@ package qilin.core.natives; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; @@ -33,8 +34,8 @@ public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod metho * doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext) */ public void simulate() { - Value r0 = getPara(0); - Value r1 = getInvoke(r0, ""); + Local r0 = getPara(0); + Local r1 = getInvoke(r0, ""); addReturn(r1); } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java index 5d95b132cfe..b94cbcb1b02 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java @@ -20,7 +20,7 @@ import qilin.core.ArtificialMethod; import qilin.util.PTAUtils; -import sootup.core.jimple.basic.Value; +import sootup.core.jimple.basic.Local; import sootup.core.model.SootMethod; public abstract class NativeMethod extends ArtificialMethod { @@ -29,7 +29,7 @@ public abstract class NativeMethod extends ArtificialMethod { this.method = method; this.body = PTAUtils.getMethodBody(method); int paraCount = method.getParameterCount(); - paraLocals = new Value[paraCount]; + paraLocals = new Local[paraCount]; this.paraStart = method.isStatic() ? 0 : 1; this.localStart = this.paraStart + paraCount; } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Field.java b/sootup.qilin/src/main/java/qilin/core/pag/Field.java index 683a27cce65..a3e93438628 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Field.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Field.java @@ -33,15 +33,15 @@ public Field(SootField sf) { this.field = sf; } - @Override - public int getNumber() { - return field.getNumber(); - } - - @Override - public void setNumber(int number) { - throw new UnsupportedOperationException(); - } +// @Override +// public int getNumber() { +// return field.getNumber(); +// } +// +// @Override +// public void setNumber(int number) { +// throw new UnsupportedOperationException(); +// } @Override public Type getType() { @@ -54,7 +54,7 @@ public SootField getField() { @Override public String toString() { - return "FieldNode " + getNumber() + " " + field; + return "FieldNode " + field; } @Override diff --git a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java index 6427e6efce2..726a3b536e5 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java @@ -30,7 +30,8 @@ * * @author Ondrej Lhotak */ -public interface SparkField extends Numberable { +//public interface SparkField extends Numberable { +public interface SparkField { public Type getType(); } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java index 1a9cb55091b..8484650efdc 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java @@ -19,7 +19,7 @@ package qilin.core.pag; import qilin.util.DataFactory; -import soot.AnySubType; +//import soot.AnySubType; import soot.Context; import sootup.core.types.ReferenceType; import sootup.core.types.Type; @@ -42,7 +42,7 @@ public abstract class VarNode extends ValNode { protected VarNode(Object variable, Type t) { super(t); - if (!(t instanceof ReferenceType) || t instanceof AnySubType) { + if (!(t instanceof ReferenceType) /*|| t instanceof AnySubType*/ ) { throw new RuntimeException("Attempt to create VarNode of type " + t); } this.variable = variable; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index a2d3c0d287e..9e404d0e604 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -71,9 +71,10 @@ public static int pointsToSetSizeOf(final PTA pta, VarNode var) { public static boolean isInnerType(final ClassType pInner, ClassType pOuter) { final String pInnerStr = pInner.toString(); while (!pInnerStr.startsWith(pOuter.toString() + "$")) { - SootClass sc = pOuter.getSootClass(); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(pOuter).get(); if (sc.hasSuperclass()) { - pOuter = sc.getSuperclass().getType(); + SootClass otsuper = (SootClass) sc.getSuperclass().get(); + pOuter = otsuper.getType(); } else { return false; } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java index dbac0893565..83ef03944e9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -128,7 +128,7 @@ public void run() { AllocNode sourceHeap = (AllocNode) sourceNode; result.add(sourceHeap); SootMethod containingMethod = sourceHeap.getMethod(); - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); @@ -148,7 +148,7 @@ public void run() { } else if (initState == DFA.State.F) { LocalVarNode pj = (LocalVarNode) sourceNode; SootMethod containingMethod = pj.getMethod(); - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); while (it.hasNext()) { Edge edge = it.next(); SootMethod srcMethod = edge.src(); @@ -176,7 +176,7 @@ public void run() { // ret = pi.f* LocalVarNode retOrThrow = (LocalVarNode) sourceNode; SootMethod containingMethod = retOrThrow.getMethod(); - Iterator it = callGraph.edgesInto(containingMethod); + Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); VarNode pi = (VarNode) pe.getTgtNode(); // add r --> ai summary edge inverse_inter_load. while (it.hasNext()) { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java index a4162e89643..7a475c040cb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java @@ -1,6 +1,7 @@ package qilin.pta.toolkits.debloaterx; import qilin.core.PTA; +import qilin.core.PTAScene; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldRefNode; import qilin.core.pag.LocalVarNode; @@ -84,26 +85,28 @@ private void buildHeapFieldsMappingIn(SootMethod method) { } private void buildHeapFieldsMapping() { - pta.getNakedReachableMethods().stream().filter(m -> !m.isPhantom()).forEach(this::buildHeapFieldsMappingIn); + pta.getNakedReachableMethods().stream().filter(SootMethod::isConcrete).forEach(this::buildHeapFieldsMappingIn); } private boolean isImplementingCollection(SootClass sc) { - Set allInterfaces = new HashSet<>(sc.getInterfaces()); + Set allInterfaces = new HashSet<>(sc.getInterfaces()); while (sc.hasSuperclass()) { - sc = sc.getSuperclass(); + sc = (SootClass) sc.getSuperclass().get(); allInterfaces.addAll(sc.getInterfaces()); } // interface may also have super class Set worklist = new HashSet<>(); - for (SootClass tmp : allInterfaces) { - while (tmp.hasSuperclass() && tmp.getSuperclass().isInterface()) { - worklist.add(tmp.getSuperclass()); - tmp = tmp.getSuperclass(); + for (ClassType tmp : allInterfaces) { + SootClass msc = (SootClass) PTAScene.v().getView().getClass(tmp).get(); + worklist.add(msc); + while (msc.hasSuperclass() && ((SootClass) msc.getSuperclass().get()).isInterface()) { + SootClass superClazz = (SootClass) msc.getSuperclass().get(); + worklist.add(superClazz); + msc = superClazz; } } - allInterfaces.addAll(worklist); boolean flag = false; - for (SootClass interf : allInterfaces) { + for (SootClass interf : worklist) { if (interf.getType() == PTAUtils.getClassType("java.util.Collection") // || interf.getType() == RefType.v("java.util.Map") ) { @@ -117,7 +120,7 @@ private boolean isNestedInClassImplementCollection(SootClass sc) { if (!sc.isInnerClass()) { return false; } - SootClass outer = sc.getOuterClass(); + SootClass outer = (SootClass) sc.getOuterClass().get(); if (isImplementingCollection(outer)) { return true; } @@ -127,7 +130,7 @@ private boolean isNestedInClassImplementCollection(SootClass sc) { private void computeContainerTypes() { for (Type type : t2Fields.keySet()) { if (type instanceof ClassType refType) { - SootClass sc = refType.getSootClass(); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(refType).get(); if (isImplementingCollection(sc) || isNestedInClassImplementCollection(sc)) { containerType.add(type); } else { diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java index 3d094076901..6518bf69169 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java @@ -6,9 +6,9 @@ import qilin.core.pag.PAG; import qilin.core.pag.SparkField; import qilin.util.Stopwatch; -import soot.jimple.internal.JNewArrayExpr; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.Type; diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java index 193d4d51f75..9c8105252fa 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java @@ -157,7 +157,7 @@ private Set collectParamInArguments(AllocNode heap) { args[i] = arg; } MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); - VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, method, iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); + VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, new ContextMethod(method, utility.getPta().emptyContext()), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); QueueReader targets = PTAUtils.dispatch(type, virtualCallSite); while (targets.hasNext()) { SootMethod target = targets.next(); diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index 7aa01dbe20b..3a6624a6b57 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -1,6 +1,7 @@ package qilin.pta.toolkits.debloaterx; import qilin.core.PTA; +import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; @@ -93,14 +94,15 @@ protected void buildInternalWithInline(SootMethod method) { if (ie instanceof AbstractInstanceInvokeExpr iie) { LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); if (iie instanceof JSpecialInvokeExpr sie) { - inline(s, sie.getMethod()); + SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(sie.getMethodSignature()).get(); + inline(s, target); } else { /* instance call with non-this base variable are modeled as in Eagle/Turner. */ modelVirtualCall(numArgs, args, receiver, retDest); } } else { if (ie instanceof JStaticInvokeExpr sie) { - SootMethod target = sie.getMethod(); + SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(sie.getMethodSignature()).get(); inline(s, target); } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java index ebc86bc094d..c8936ade446 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java @@ -3,6 +3,7 @@ import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.AllocNode; +import qilin.core.pag.ContextMethod; import qilin.core.pag.VarNode; import qilin.core.sets.PointsToSet; import qilin.pta.toolkits.common.OAG; @@ -160,7 +161,7 @@ private Set invokedMethodsOf(final AllocNode obj) { while (!queue.isEmpty()) { final SootMethod method = queue.poll(); methods.add(method); - pta.getCallGraph().edgesOutOf(method).forEachRemaining(edge -> { + pta.getCallGraph().edgesOutOf(new ContextMethod(method, pta.emptyContext())).forEachRemaining(edge -> { SootMethod callee = edge.getTgt().method(); if (callee.isStatic() && !methods.contains(callee)) { queue.offer(callee); diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index aa7653efe8d..ee5788315a1 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -20,6 +20,7 @@ import qilin.CoreConfig; import qilin.core.PTA; +import qilin.core.PTAScene; import qilin.core.pag.AllocNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.Parm; @@ -129,8 +130,8 @@ public void dumpClassTypes(Collection classes) { public void dumpPolyCalls(Map polys) { StringBuilder builder = new StringBuilder(); for (AbstractInvokeExpr ie : polys.keySet()) { - SootMethod tgt = ie.getMethod(); - String polySig = polys.get(ie).getSignature() + "/" + tgt.getDeclaringClass() + "." + tgt.getName() + "\n"; + SootMethod tgt = (SootMethod) PTAScene.v().getView().getMethod(ie.getMethodSignature()).get(); + String polySig = polys.get(ie).getSignature() + "/" + tgt.getDeclaringClassType() + "." + tgt.getName() + "\n"; builder.append(polySig); } String polyCalls = "PolyCalls.csv"; diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 1ca2bdd8fba..6e180cc5835 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -810,21 +810,29 @@ public static Set clinitsOf(SootClass cl) { Set ret = new HashSet<>(); Set visit = new HashSet<>(); Queue worklist = new UniqueQueue<>(); - SootClass curr = cl; - while (curr != null) { - worklist.add(curr); - curr = curr.getSuperclassUnsafe(); + Optional curr = Optional.of(cl); + while (curr.isPresent()) { + SootClass sc = curr.get(); + worklist.add(sc); + curr = sc.getSuperclass(); } while (!worklist.isEmpty()) { SootClass sc = worklist.poll(); if (visit.add(sc)) { - worklist.addAll(sc.getInterfaces()); + Set itfs = sc.getInterfaces(); + for (ClassType itf : itfs) { + Optional xsc = PTAScene.v().getView().getClass(itf); + if (xsc.isPresent()) { + worklist.add(xsc.get()); + } + } } } for (SootClass sc : visit) { - final SootMethod initStart = sc.getMethodUnsafe(Scene.v().getSubSigNumberer().findOrAdd("void ()")); - if (initStart != null) { - ret.add(initStart); + MethodSubSignature subclinit = JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); + final Optional initStart = sc.getMethod(subclinit); + if (initStart.isPresent()) { + ret.add(initStart.get()); } } return ret; From 90856a9094f5ab46a88e3edb732444adfe2c0dba Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Wed, 20 Sep 2023 16:18:46 +1000 Subject: [PATCH 027/145] update --- .../java/qilin/core/builder/MethodNodeFactory.java | 10 ++++++---- .../natives/JavaIoFileSystemGetFileSystemNative.java | 1 + .../main/java/qilin/core/natives/NativeMethod.java | 12 +++++++++--- .../src/main/java/qilin/core/pag/MethodPAG.java | 7 +++++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index e3999e0fd3a..b0b95a947f9 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -64,6 +64,7 @@ import javax.annotation.Nonnull; import java.util.Collections; +import java.util.Optional; /** * @author Ondrej Lhotak @@ -237,12 +238,13 @@ private AllocNode caseNewExpr(JNewExpr ne) { private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { FieldSignature fieldSig = ifr.getFieldSignature(); - SootField sf = (SootField) PTAScene.v().getView().getField(fieldSig).get(); - if (sf == null) { + Optional osf = PTAScene.v().getView().getField(fieldSig); + SootField sf; + if (osf.isEmpty()) { sf = new SootField(fieldSig, Collections.singleton(Modifier.PUBLIC), NoPositionInformation.getInstance()); - sf.setNumber(Scene.v().getFieldNumberer().size()); - Scene.v().getFieldNumberer().add(sf); System.out.println("Warnning:" + ifr + " is resolved to be a null field in Scene."); + } else { + sf = osf.get(); } return pag.makeFieldRefNode(pag.makeLocalVarNode(ifr.getBase(), ifr.getBase().getType(), method), new Field(sf)); } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index ed340c393b9..508b7f6e11a 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -38,5 +38,6 @@ public void simulate() { Local newLocal0 = getNew(PTAUtils.getClassType("java.io.UnixFileSystem")); addInvoke(newLocal0, "()>"); addReturn(newLocal0); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java index b94cbcb1b02..18c54813023 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java @@ -19,15 +19,21 @@ package qilin.core.natives; import qilin.core.ArtificialMethod; -import qilin.util.PTAUtils; import sootup.core.jimple.basic.Local; +import sootup.core.model.Body; import sootup.core.model.SootMethod; -public abstract class NativeMethod extends ArtificialMethod { +import java.util.Collections; +public abstract class NativeMethod extends ArtificialMethod { NativeMethod(SootMethod method) { this.method = method; - this.body = PTAUtils.getMethodBody(method); + if (method.isConcrete()) { + Body body = method.getBody(); + this.bodyBuilder = Body.builder(body, Collections.emptySet()); + } else { + this.bodyBuilder = Body.builder(); + } int paraCount = method.getParameterCount(); paraLocals = new Local[paraCount]; this.paraStart = method.isStatic() ? 0 : 1; diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index 6d93e6acc8c..0b76b0916a2 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -19,6 +19,7 @@ package qilin.core.pag; import qilin.CoreConfig; +import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.core.builder.MethodNodeFactory; import qilin.util.PTAUtils; @@ -31,6 +32,7 @@ import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; +import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import java.util.*; @@ -97,7 +99,8 @@ protected void build() { protected void buildNormal() { if (method.isStatic()) { - PTAUtils.clinitsOf(method.getDeclaringClass()).forEach(this::addTriggeredClinit); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(method.getDeclaringClassType()).get(); + PTAUtils.clinitsOf(sc).forEach(this::addTriggeredClinit); } for (Stmt unit : body.getStmts()) { try { @@ -120,7 +123,7 @@ protected void buildException() { * The traps is already visited in order. , ; implies is a previous Trap of . * */ traps.forEach(trap -> { - units.iterator(trap.getBeginUnit(), trap.getEndUnit()).forEachRemaining(unit -> { + units.iterator(trap.getBeginStmt(), trap.getEndStmt()).forEachRemaining(unit -> { if (unit == trap.getEndUnit()) { return; } From e7cb02ea37c32fab93078a5c8ad82aa66d9bcb59 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 24 Sep 2023 07:59:40 +1000 Subject: [PATCH 028/145] update --- .../src/main/java/qilin/core/PTAScene.java | 16 +++-- .../main/java/qilin/core/pag/MethodPAG.java | 62 ++++++++++++++----- .../src/main/java/qilin/core/pag/PAG.java | 56 ++++++++--------- .../core/reflection/ReflectionModel.java | 10 ++- .../src/main/java/qilin/util/PTAUtils.java | 18 +++--- 5 files changed, 103 insertions(+), 59 deletions(-) diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java index a77883d11e3..94f074ba475 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTAScene.java +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -38,6 +38,7 @@ import java.util.Collections; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; public class PTAScene { private static volatile PTAScene instance = null; @@ -136,12 +137,19 @@ public SootMethod getMethod(String methodSignature) { return (SootMethod) view.getMethod(mthdSig).get(); } - public Chain getApplicationClasses() { - return sootScene.getApplicationClasses(); + public Collection getApplicationClasses() { + Collection classes = view.getClasses(); + return classes.stream().filter(SootClass::isApplicationClass).collect(Collectors.toSet()); +// for (SootClass sc : classes) { +// sc.isApplicationClass() +// } +// return sootScene.getApplicationClasses(); } - public Chain getLibraryClasses() { - return sootScene.getLibraryClasses(); + public Collection getLibraryClasses() { + Collection classes = view.getClasses(); + return classes.stream().filter(SootClass::isLibraryClass).collect(Collectors.toSet()); +// return sootScene.getLibraryClasses(); } public boolean containsMethod(String methodSignature) { diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index 0b76b0916a2..5645aa2a5f7 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -24,15 +24,17 @@ import qilin.core.builder.MethodNodeFactory; import qilin.util.PTAUtils; -import soot.jimple.Jimple; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; +import sootup.core.graph.StmtGraph; +import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Trap; import sootup.core.jimple.common.ref.JStaticFieldRef; import sootup.core.jimple.common.stmt.JThrowStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; import sootup.core.model.SootClass; +import sootup.core.model.SootField; import sootup.core.model.SootMethod; import java.util.*; @@ -123,23 +125,49 @@ protected void buildException() { * The traps is already visited in order. , ; implies is a previous Trap of . * */ traps.forEach(trap -> { - units.iterator(trap.getBeginStmt(), trap.getEndStmt()).forEachRemaining(unit -> { - if (unit == trap.getEndUnit()) { - return; + StmtGraph stmtGraph = body.getStmtGraph(); + List succs = stmtGraph.getAllSuccessors(trap.getBeginStmt()); + while(true) { + if (succs.contains(trap.getEndStmt())) { + break; } - inTraps.add(unit); - Stmt stmt = unit; - Node src = null; - if (stmt.containsInvokeExpr()) { - // note, method.getExceptions() does not return implicit exceptions. - src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); - } else if (stmt instanceof JThrowStmt ts) { - src = nodeFactory.getNode(ts.getOp()); + if (succs.size() == 0) { + break; } - if (src != null) { - addStmtTrap(src, stmt, trap); + List tmp = new ArrayList<>(); + for (Stmt stmt : succs) { + inTraps.add(stmt); + Node src = null; + if (stmt.containsInvokeExpr()) { + // note, method.getExceptions() does not return implicit exceptions. + src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); + } else if (stmt instanceof JThrowStmt ts) { + src = nodeFactory.getNode(ts.getOp()); + } + if (src != null) { + addStmtTrap(src, stmt, trap); + } + tmp.addAll(stmtGraph.getAllSuccessors(stmt)); } - }); + succs = tmp; + } +// units.iterator(trap.getBeginStmt(), trap.getEndStmt()).forEachRemaining(unit -> { +// if (unit == trap.getEndUnit()) { +// return; +// } +// inTraps.add(unit); +// Stmt stmt = unit; +// Node src = null; +// if (stmt.containsInvokeExpr()) { +// // note, method.getExceptions() does not return implicit exceptions. +// src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); +// } else if (stmt instanceof JThrowStmt ts) { +// src = nodeFactory.getNode(ts.getOp()); +// } +// if (src != null) { +// addStmtTrap(src, stmt, trap); +// } +// }); }); for (Stmt stmt : body.getStmts()) { @@ -169,7 +197,9 @@ private void addStmtTrap(Node src, Stmt stmt, Trap trap) { protected void addMiscEdges() { if (method.getSignature().equals("(java.lang.Object,java.lang.ref.ReferenceQueue)>")) { // Implements the special status of java.lang.ref.Reference just as in Doop (library/reference.logic). - JStaticFieldRef sfr = Jimple.v().newStaticFieldRef(RefType.v("java.lang.ref.Reference").getSootClass().getFieldByName("pending").makeRef()); + SootClass sootClass = PTAScene.v().getSootClass("java.lang.ref.Reference"); + SootField sf = (SootField) sootClass.getField("pending").get(); + JStaticFieldRef sfr = Jimple.newStaticFieldRef(sf.getSignature()); addInternalEdge(nodeFactory.caseThis(), nodeFactory.getNode(sfr)); } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index cf758c4a50a..785e1c87a0b 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -528,35 +528,31 @@ public MethodPAG getMethodPAG(SootMethod m) { if (methodToPag.containsKey(m)) { return methodToPag.get(m); } - Body body = PTAUtils.getMethodBody(m); - synchronized (body) { - // Some other thread may have created the MethodPAG for this method. - if (methodToPag.containsKey(m)) { - return methodToPag.get(m); - } - if (m.isConcrete()) { - reflectionModel.buildReflection(m); - } - if (m.isNative()) { - nativeDriver.buildNative(m); - } else { - // we will revert these back in the future. - /* - * To keep same with Doop, we move the simulation of - * - * directly to its caller methods. - * */ - if (PTAScene.v().arraycopyBuilt.add(m)) { - handleArrayCopy(m); - } + if (m.isConcrete()) { + reflectionModel.buildReflection(m); + } + if (m.isNative()) { + nativeDriver.buildNative(m); + } else { + // we will revert these back in the future. + /* + * To keep same with Doop, we move the simulation of + * + * directly to its caller methods. + * */ + if (PTAScene.v().arraycopyBuilt.add(m)) { + handleArrayCopy(m); } } + Body body = PTAUtils.getMethodBody(m); return methodToPag.computeIfAbsent(m, k -> new MethodPAG(this, m, body)); } private void handleArrayCopy(SootMethod method) { Map> newUnits = DataFactory.createMap(); Body body = PTAUtils.getMethodBody(method); + Body.BodyBuilder builder = Body.builder(body, Collections.emptySet()); + int localCount = body.getLocalCount(); for (Stmt s : body.getStmts()) { if (s.containsInvokeExpr()) { AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); @@ -569,8 +565,8 @@ private void handleArrayCopy(SootMethod method) { } Type objType = PTAUtils.getClassType("java.lang.Object"); if (srcArr.getType() == objType) { - Local localSrc = Jimple.newLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); - body.getLocals().add(localSrc); + Local localSrc = Jimple.newLocal("intermediate/" + (localCount ++), new ArrayType(objType, 1)); + builder.addLocal(localSrc); newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt<>(localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); srcArr = localSrc; } @@ -579,24 +575,28 @@ private void handleArrayCopy(SootMethod method) { continue; } if (dstArr.getType() == objType) { - Local localDst = Jimple.newLocal("intermediate/" + body.getLocalCount(), new ArrayType(objType, 1)); - body.getLocals().add(localDst); + Local localDst = Jimple.newLocal("intermediate/" + (localCount ++), new ArrayType(objType, 1)); + builder.addLocal(localDst); newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt<>(localDst, dstArr,StmtPositionInfo.createNoStmtPositionInfo())); dstArr = localDst; } Value src = JavaJimple.getInstance().newArrayRef((Local) srcArr, IntConstant.getInstance(0)); Value dst = JavaJimple.getInstance().newArrayRef((Local) dstArr, IntConstant.getInstance(0)); - Local local = Jimple.newLocal("nativeArrayCopy" + body.getLocalCount(), PTAUtils.getClassType("java.lang.Object")); - body.getLocals().add(local); + Local local = Jimple.newLocal("nativeArrayCopy" + (localCount ++), PTAUtils.getClassType("java.lang.Object")); + builder.addLocal(local); newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt<>(local, src, StmtPositionInfo.createNoStmtPositionInfo())); newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt<>(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); } } } } + for (Stmt unit : newUnits.keySet()) { - body.getUnits().insertAfter(newUnits.get(unit), unit); + for (Stmt succ : newUnits.get(unit)) { + builder.addFlow(unit, succ); + } } + PTAUtils.updateMethodBody(method, builder.build()); } public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index 7f2993c860b..53973427dc0 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -23,6 +23,7 @@ import qilin.util.PTAUtils; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; import sootup.core.model.SootMethod; import java.util.Collection; @@ -74,15 +75,20 @@ public void buildReflection(SootMethod m) { return; } Map> newUnits = DataFactory.createMap(); - List units = PTAUtils.getMethodBody(m).getStmts(); + Body body = PTAUtils.getMethodBody(m); + List units = body.getStmts(); for (final Stmt u : units) { if (u.containsInvokeExpr()) { newUnits.put(u, transform(u)); } } + Body.BodyBuilder builder = Body.builder(body, Collections.emptySet()); for (Stmt unit : newUnits.keySet()) { - units.insertAfter(newUnits.get(unit), unit); + for (Stmt succ : newUnits.get(unit)) { + builder.addFlow(unit, succ); + } } + PTAUtils.updateMethodBody(m, builder.build()); } abstract Collection transformClassForName(Stmt s); diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 6e180cc5835..b65d09a95d3 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -745,20 +745,20 @@ public static String findMainFromMetaInfo(String appPath) { public static Body getMethodBody(SootMethod m) { Body body = methodToBody.get(m); if (body == null) { - synchronized (PTAUtils.class) { - if (body == null) { - if (m.isConcrete()) { - body = m.retrieveActiveBody(); - } else { - body = new JimpleBody(m); - } - methodToBody.putIfAbsent(m, body); - } + if (m.isConcrete()) { + body = m.getBody(); + } else { + body = Body.builder().build(); } + methodToBody.putIfAbsent(m, body); } return body; } + public static void updateMethodBody(SootMethod m, Body body) { + methodToBody.put(m, body); + } + public static boolean isEmptyArray(AllocNode heap) { Object var = heap.getNewExpr(); if (var instanceof JNewArrayExpr nae) { From 0a8ff937a65f52ecc1ecf9533e719b1cf342628d Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Sun, 24 Sep 2023 21:33:43 +1000 Subject: [PATCH 029/145] update --- sootup.qilin/pom.xml | 172 +- .../src/main/java/driver/ContextKind.java | 70 +- sootup.qilin/src/main/java/driver/Main.java | 256 +-- .../src/main/java/driver/PTAComparator.java | 220 +-- .../src/main/java/driver/PTAFactory.java | 260 +-- .../src/main/java/driver/PTAOption.java | 385 +++-- .../src/main/java/driver/PTAPattern.java | 371 ++-- .../src/main/java/qilin/CoreConfig.java | 273 ++- .../java/qilin/core/ArtificialMethod.java | 303 ++-- .../src/main/java/qilin/core/CorePTA.java | 164 +- .../src/main/java/qilin/core/PTA.java | 384 +++-- .../src/main/java/qilin/core/PTAScene.java | 386 +++-- .../java/qilin/core/PointsToAnalysis.java | 70 +- .../main/java/qilin/core/VirtualCalls.java | 352 ++-- .../qilin/core/builder/CallGraphBuilder.java | 388 +++-- .../qilin/core/builder/ExceptionHandler.java | 117 +- .../qilin/core/builder/FakeMainFactory.java | 524 ++++-- .../qilin/core/builder/MethodNodeFactory.java | 582 ++++--- .../qilin/core/context/ContextElement.java | 8 +- .../qilin/core/context/ContextElements.java | 171 +- .../core/context/TypeContextElement.java | 85 +- .../JavaIoFileSystemGetFileSystemNative.java | 31 +- .../natives/JavaIoFileSystemListNative.java | 27 +- .../natives/JavaLangObjectCloneNative.java | 24 +- ...efFinalizerInvokeFinalizeMethodNative.java | 19 +- .../core/natives/JavaLangReflectArrayGet.java | 24 +- .../core/natives/JavaLangReflectArraySet.java | 22 +- .../JavaLangSystemArraycopyNative.java | 37 +- .../natives/JavaLangSystemSetErr0Native.java | 28 +- .../natives/JavaLangSystemSetIn0Native.java | 28 +- .../natives/JavaLangSystemSetOut0Native.java | 29 +- .../natives/JavaLangThreadCurrentThread.java | 20 +- .../natives/JavaLangThreadStart0Native.java | 32 +- ...ityAccessControllerDoPrivilegedNative.java | 27 +- ...ontrollerDoPrivileged_ExceptionNative.java | 28 +- .../java/qilin/core/natives/NativeMethod.java | 37 +- .../core/natives/NativeMethodDriver.java | 116 +- .../java/qilin/core/natives/package-info.java | 2 +- .../main/java/qilin/core/pag/AllocNode.java | 67 +- .../java/qilin/core/pag/ArrayElement.java | 36 +- .../main/java/qilin/core/pag/CallSite.java | 75 +- .../qilin/core/pag/ClassConstantNode.java | 18 +- .../java/qilin/core/pag/ConstantNode.java | 6 +- .../java/qilin/core/pag/ContextAllocNode.java | 43 +- .../java/qilin/core/pag/ContextField.java | 90 +- .../java/qilin/core/pag/ContextMethod.java | 58 +- .../java/qilin/core/pag/ContextVarNode.java | 65 +- .../qilin/core/pag/ExceptionThrowSite.java | 73 +- .../src/main/java/qilin/core/pag/Field.java | 77 +- .../java/qilin/core/pag/FieldRefNode.java | 42 +- .../java/qilin/core/pag/FieldValNode.java | 20 +- .../java/qilin/core/pag/GlobalVarNode.java | 41 +- .../java/qilin/core/pag/LocalVarNode.java | 55 +- .../java/qilin/core/pag/MergedNewExpr.java | 20 +- .../main/java/qilin/core/pag/MethodPAG.java | 376 ++-- .../src/main/java/qilin/core/pag/Node.java | 56 +- .../src/main/java/qilin/core/pag/PAG.java | 1115 ++++++------ .../src/main/java/qilin/core/pag/Parm.java | 102 +- .../main/java/qilin/core/pag/SparkField.java | 6 +- .../qilin/core/pag/StringConstantNode.java | 18 +- .../src/main/java/qilin/core/pag/ValNode.java | 51 +- .../src/main/java/qilin/core/pag/VarNode.java | 164 +- .../java/qilin/core/pag/VirtualCallSite.java | 95 +- .../java/qilin/core/pag/package-info.java | 2 +- .../core/reflection/NopReflectionModel.java | 75 +- .../qilin/core/reflection/ReflectionKind.java | 43 +- .../core/reflection/ReflectionModel.java | 152 +- .../qilin/core/reflection/TamiflexModel.java | 722 ++++---- .../qilin/core/sets/DoublePointsToSet.java | 220 ++- .../qilin/core/sets/HybridPointsToSet.java | 287 ++- .../java/qilin/core/sets/P2SetVisitor.java | 27 +- .../java/qilin/core/sets/PointsToSet.java | 127 +- .../qilin/core/sets/PointsToSetInternal.java | 47 +- .../core/sets/UnmodifiablePointsToSet.java | 345 ++-- .../java/qilin/core/sets/package-info.java | 2 +- .../java/qilin/core/solver/Propagator.java | 10 +- .../main/java/qilin/core/solver/Solver.java | 502 +++--- .../parm/ctxcons/CallsiteCtxConstructor.java | 30 +- .../qilin/parm/ctxcons/CtxConstructor.java | 10 +- .../parm/ctxcons/HybObjCtxConstructor.java | 76 +- .../parm/ctxcons/HybTypeCtxConstructor.java | 56 +- .../parm/ctxcons/InsensCtxConstructor.java | 12 +- .../qilin/parm/ctxcons/ObjCtxConstructor.java | 34 +- .../parm/ctxcons/TypeCtxConstructor.java | 36 +- .../parm/heapabst/AllocSiteAbstractor.java | 8 +- .../qilin/parm/heapabst/HeapAbstractor.java | 2 +- .../parm/heapabst/HeuristicAbstractor.java | 35 +- .../parm/heapabst/MahjongAbstractor.java | 51 +- .../java/qilin/parm/select/BeanSelector.java | 95 +- .../java/qilin/parm/select/CtxSelector.java | 32 +- .../qilin/parm/select/DebloatingSelector.java | 61 +- .../parm/select/FullMethodLvSelector.java | 67 +- .../qilin/parm/select/HeuristicSelector.java | 37 +- .../java/qilin/parm/select/InsenSelector.java | 32 +- .../parm/select/PartialMethodLvSelector.java | 75 +- .../qilin/parm/select/PartialVarSelector.java | 87 +- .../qilin/parm/select/PipelineSelector.java | 54 +- .../qilin/parm/select/UniformSelector.java | 54 +- .../java/qilin/parm/select/VarLvSelector.java | 66 +- .../src/main/java/qilin/pta/PTAConfig.java | 86 +- .../java/qilin/pta/toolkits/bean/Bean.java | 91 +- .../pta/toolkits/bean/ContextSelector.java | 60 +- .../bean/RepresentativeContextSelector.java | 173 +- .../pta/toolkits/common/DebloatedOAG.java | 35 +- .../toolkits/common/FieldPointstoGraph.java | 149 +- .../java/qilin/pta/toolkits/common/OAG.java | 245 ++- .../qilin/pta/toolkits/common/ToolUtil.java | 89 +- .../pta/toolkits/conch/AbstractConch.java | 370 ++-- .../qilin/pta/toolkits/conch/AbstractPAG.java | 372 ++-- .../java/qilin/pta/toolkits/conch/CSDG.java | 51 +- .../java/qilin/pta/toolkits/conch/Conch.java | 633 +++---- .../java/qilin/pta/toolkits/conch/DFA.java | 109 +- .../toolkits/conch/DepOnParamAnalysis.java | 208 +-- .../pta/toolkits/conch/LeakAnalysis.java | 350 ++-- .../qilin/pta/toolkits/conch/PathEdge.java | 123 +- .../java/qilin/pta/toolkits/conch/SMPAG.java | 126 +- .../qilin/pta/toolkits/conch/TranEdge.java | 73 +- .../qilin/pta/toolkits/conch/Trilean.java | 20 +- .../dd/CtxTunnelingFeaturesTrueTable.java | 339 ++-- .../pta/toolkits/dd/DataDrivenSelector.java | 109 +- .../pta/toolkits/dd/FeaturesTrueTable.java | 363 ++-- .../pta/toolkits/dd/TunnelingConstructor.java | 74 +- .../debloaterx/CollectionHeuristic.java | 331 ++-- .../toolkits/debloaterx/ContainerFinder.java | 181 +- .../pta/toolkits/debloaterx/DebloaterX.java | 303 ++-- .../qilin/pta/toolkits/debloaterx/Edge.java | 22 +- .../pta/toolkits/debloaterx/EdgeKind.java | 40 +- .../debloaterx/HeapContainerQuery.java | 117 +- .../debloaterx/InterFlowAnalysis.java | 398 ++--- .../debloaterx/IntraFlowAnalysis.java | 497 +++--- .../qilin/pta/toolkits/debloaterx/State.java | 9 +- .../qilin/pta/toolkits/debloaterx/XPAG.java | 447 ++--- .../pta/toolkits/debloaterx/XUtility.java | 514 +++--- .../java/qilin/pta/toolkits/eagle/BNode.java | 73 +- .../java/qilin/pta/toolkits/eagle/Eagle.java | 651 +++---- .../pta/toolkits/mahjong/HeapAbstraction.java | 202 +-- .../qilin/pta/toolkits/mahjong/Mahjong.java | 102 +- .../pta/toolkits/mahjong/automata/DFA.java | 91 +- .../automata/DFAEquivalenceChecker.java | 142 +- .../toolkits/mahjong/automata/DFAFactory.java | 146 +- .../toolkits/mahjong/automata/DFAState.java | 144 +- .../pta/toolkits/mahjong/automata/NFA.java | 120 +- .../qilin/pta/toolkits/selectx/BNode.java | 70 +- .../java/qilin/pta/toolkits/selectx/G.java | 53 +- .../java/qilin/pta/toolkits/selectx/I.java | 72 +- .../java/qilin/pta/toolkits/selectx/L.java | 155 +- .../java/qilin/pta/toolkits/selectx/O.java | 17 +- .../qilin/pta/toolkits/selectx/Selectx.java | 525 +++--- .../pta/toolkits/turner/AbstractMVFG.java | 448 +++-- .../java/qilin/pta/toolkits/turner/DFA.java | 82 +- .../toolkits/turner/MethodLevelCallGraph.java | 66 +- .../qilin/pta/toolkits/turner/MethodVFG.java | 35 +- .../pta/toolkits/turner/ModularMVFG.java | 112 +- .../java/qilin/pta/toolkits/turner/OCG.java | 375 ++-- .../qilin/pta/toolkits/turner/TranEdge.java | 74 +- .../qilin/pta/toolkits/turner/Turner.java | 362 ++-- .../qilin/pta/toolkits/zipper/Global.java | 166 +- .../java/qilin/pta/toolkits/zipper/Main.java | 62 +- .../analysis/PotentialContextElement.java | 333 ++-- .../pta/toolkits/zipper/analysis/Zipper.java | 532 +++--- .../pta/toolkits/zipper/cases/CaseA.java | 24 +- .../pta/toolkits/zipper/cases/CaseB.java | 30 +- .../pta/toolkits/zipper/cases/CaseC.java | 52 +- .../pta/toolkits/zipper/cases/CaseD.java | 30 +- .../pta/toolkits/zipper/flowgraph/Edge.java | 107 +- .../zipper/flowgraph/FlowAnalysis.java | 448 ++--- .../zipper/flowgraph/IObjectFlowGraph.java | 7 +- .../pta/toolkits/zipper/flowgraph/Kind.java | 12 +- .../zipper/flowgraph/ObjectFlowGraph.java | 180 +- .../main/java/qilin/pta/tools/BasePTA.java | 86 +- .../main/java/qilin/pta/tools/BeanPTA.java | 63 +- .../java/qilin/pta/tools/CallSiteSensPTA.java | 28 +- .../java/qilin/pta/tools/DataDrivenPTA.java | 29 +- .../java/qilin/pta/tools/DebloatedPTA.java | 323 ++-- .../main/java/qilin/pta/tools/EaglePTA.java | 157 +- .../qilin/pta/tools/HybridObjectSensPTA.java | 33 +- .../qilin/pta/tools/HybridTypeSensPTA.java | 33 +- .../main/java/qilin/pta/tools/MahjongPTA.java | 74 +- .../java/qilin/pta/tools/ObjectSensPTA.java | 30 +- .../pta/tools/PartialCallSiteSensPTA.java | 276 +-- .../qilin/pta/tools/PartialObjSensPTA.java | 276 +-- .../main/java/qilin/pta/tools/SelectxPTA.java | 34 +- .../src/main/java/qilin/pta/tools/Spark.java | 18 +- .../main/java/qilin/pta/tools/StagedPTA.java | 32 +- .../java/qilin/pta/tools/TunnelingPTA.java | 28 +- .../main/java/qilin/pta/tools/TurnerPTA.java | 27 +- .../java/qilin/pta/tools/TypeSensPTA.java | 28 +- .../main/java/qilin/pta/tools/ZipperPTA.java | 205 ++- .../main/java/qilin/stat/AbstractStat.java | 2 +- .../src/main/java/qilin/stat/AliasStat.java | 263 +-- .../main/java/qilin/stat/BenchmarkStat.java | 83 +- .../main/java/qilin/stat/CallGraphStat.java | 346 ++-- .../src/main/java/qilin/stat/Exporter.java | 448 ++--- .../src/main/java/qilin/stat/IEvaluator.java | 6 +- .../src/main/java/qilin/stat/PAGStat.java | 98 +- .../main/java/qilin/stat/PTAEvaluator.java | 160 +- .../main/java/qilin/stat/PointsToStat.java | 496 +++--- .../src/main/java/qilin/stat/RuntimeStat.java | 26 +- .../java/qilin/stat/SimplifiedEvaluator.java | 316 ++-- .../main/java/qilin/stat/TypeClientStat.java | 221 +-- .../src/main/java/qilin/stat/YummyStat.java | 123 +- .../src/main/java/qilin/util/ANSIColor.java | 28 +- .../src/main/java/qilin/util/DataFactory.java | 40 +- .../main/java/qilin/util/MemoryWatcher.java | 86 +- .../src/main/java/qilin/util/PTAUtils.java | 1534 +++++++++-------- .../src/main/java/qilin/util/Pair.java | 63 +- .../src/main/java/qilin/util/Stopwatch.java | 78 +- .../src/main/java/qilin/util/Triple.java | 66 +- .../main/java/qilin/util/UnionFindSet.java | 107 +- .../src/main/java/qilin/util/Util.java | 97 +- .../java/qilin/util/collect/SetFactory.java | 18 +- .../graph/ConcurrentDirectedGraphImpl.java | 70 +- .../java/qilin/util/graph/DirectedGraph.java | 56 +- .../qilin/util/graph/DirectedGraphImpl.java | 70 +- .../java/qilin/util/graph/MergedNode.java | 58 +- .../java/qilin/util/graph/Reachability.java | 82 +- .../java/qilin/util/graph/SCCMergedGraph.java | 77 +- .../graph/StronglyConnectedComponents.java | 132 +- .../qilin/util/graph/TopologicalSorter.java | 70 +- .../src/main/java/qilin/util/graph/Tree.java | 14 +- .../main/java/qilin/util/graph/TreeImpl.java | 104 +- .../main/java/qilin/util/graph/TreeNode.java | 72 +- .../java/qilin/util/queue/UniqueQueue.java | 225 ++- sootup.qilin/src/main/java/soot/Context.java | 7 +- .../src/main/java/soot/EntryPoints.java | 207 --- .../src/main/java/soot/JavaMethods.java | 60 +- sootup.qilin/src/main/java/soot/Kind.java | 474 +++-- .../main/java/soot/MethodOrMethodContext.java | 5 +- .../jimple/toolkits/callgraph/CallGraph.java | 655 ++++--- .../soot/jimple/toolkits/callgraph/Edge.java | 507 +++--- .../main/java/soot/util/ArrayNumberer.java | 206 +-- .../main/java/soot/util/BitSetIterator.java | 102 +- .../src/main/java/soot/util/BitVector.java | 791 ++++----- .../src/main/java/soot/util/Chain.java | 147 +- .../src/main/java/soot/util/Invalidable.java | 21 +- .../main/java/soot/util/IterableNumberer.java | 6 +- .../src/main/java/soot/util/Numberable.java | 6 +- .../main/java/soot/util/NumberedString.java | 94 +- .../src/main/java/soot/util/Numberer.java | 36 +- .../main/java/soot/util/StringNumberer.java | 27 +- .../util/dot/AbstractDotGraphElement.java | 181 +- .../src/main/java/soot/util/dot/DotGraph.java | 520 +++--- .../java/soot/util/dot/DotGraphAttribute.java | 41 +- .../java/soot/util/dot/DotGraphCommand.java | 42 +- .../java/soot/util/dot/DotGraphConstants.java | 43 +- .../main/java/soot/util/dot/DotGraphEdge.java | 111 +- .../main/java/soot/util/dot/DotGraphNode.java | 80 +- .../java/soot/util/dot/DotGraphUtility.java | 165 +- .../main/java/soot/util/dot/Renderable.java | 2 +- .../java/soot/util/queue/ChunkedQueue.java | 114 +- .../java/soot/util/queue/QueueReader.java | 316 ++-- .../test/java/qilin/test/FlowSensTests.java | 58 +- .../java/qilin/test/context/CFATests.java | 34 +- .../qilin/test/context/CollectionsTests.java | 82 +- .../java/qilin/test/context/HybTests.java | 24 +- .../java/qilin/test/context/OBJTests.java | 75 +- .../java/qilin/test/context/TypeTests.java | 16 +- .../test/java/qilin/test/core/ArrayTests.java | 40 +- .../java/qilin/test/core/AssignTests.java | 104 +- .../test/java/qilin/test/core/CallTests.java | 25 +- .../java/qilin/test/core/ClinitTests.java | 32 +- .../java/qilin/test/core/ExceptionTests.java | 26 +- .../test/java/qilin/test/core/FieldTests.java | 32 +- .../java/qilin/test/core/GlobalTests.java | 24 +- .../java/qilin/test/core/NativeTests.java | 106 +- .../java/qilin/test/core/ReflogTests.java | 104 +- .../java/qilin/test/util/AliasAssertion.java | 160 +- .../qilin/test/util/AssertionsParser.java | 68 +- .../test/java/qilin/test/util/IAssertion.java | 2 +- .../test/java/qilin/test/util/JunitTests.java | 171 +- 270 files changed, 19887 insertions(+), 19396 deletions(-) delete mode 100644 sootup.qilin/src/main/java/soot/EntryPoints.java diff --git a/sootup.qilin/pom.xml b/sootup.qilin/pom.xml index b1d8eb584f0..dae85287afc 100644 --- a/sootup.qilin/pom.xml +++ b/sootup.qilin/pom.xml @@ -1,95 +1,95 @@ - 4.0.0 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - SootUp Qilin - sootup.qilin + SootUp Qilin + sootup.qilin - - org.soot-oss - sootup - 1.0.0-SNAPSHOT - + + org.soot-oss + sootup + 1.0.0-SNAPSHOT + - - - org.soot-oss - sootup.core - 1.0.0-SNAPSHOT - - - org.soot-oss - sootup.java.core - 1.0.0-SNAPSHOT - - - org.soot-oss - sootup.java.bytecode - 1.0.0-SNAPSHOT - - - org.soot-oss - sootup.java.sourcecode - 1.0.0-SNAPSHOT - - - org.soot-oss - sootup.callgraph - 1.0.0-SNAPSHOT - - - - commons-cli - commons-cli - 1.5.0 - - - - com.github.oshi - oshi-core - 6.4.0 - - - - de.upb.cs.swt - heros - 1.2.3 - - + + + org.soot-oss + sootup.core + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.java.core + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.java.bytecode + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.java.sourcecode + 1.0.0-SNAPSHOT + + + org.soot-oss + sootup.callgraph + 1.0.0-SNAPSHOT + + + + commons-cli + commons-cli + 1.5.0 + + + + com.github.oshi + oshi-core + 6.4.0 + + + + de.upb.cs.swt + heros + 1.2.3 + + - - - - org.soot-oss - sootup.java.sourcecode - 1.0.0-SNAPSHOT - pom - import - - - + + + + org.soot-oss + sootup.java.sourcecode + 1.0.0-SNAPSHOT + pom + import + + + - - - - org.sonatype.plugins - nexus-staging-maven-plugin - ${nexus-staging-maven-plugin.version} - - true - - - - org.apache.maven.plugins - maven-compiler-plugin - - 16 - 16 - - - - + + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + + true + + + + org.apache.maven.plugins + maven-compiler-plugin + + 16 + 16 + + + + \ No newline at end of file diff --git a/sootup.qilin/src/main/java/driver/ContextKind.java b/sootup.qilin/src/main/java/driver/ContextKind.java index cfbf74c8475..980239b4980 100644 --- a/sootup.qilin/src/main/java/driver/ContextKind.java +++ b/sootup.qilin/src/main/java/driver/ContextKind.java @@ -18,42 +18,46 @@ package driver; -import qilin.util.Util; - import java.util.Collection; import java.util.HashMap; import java.util.Map; +import qilin.util.Util; public enum ContextKind { - INSENS, CALLSITE, OBJECT, TYPE, HYBOBJ, HYBTYPE; - static final Map contextKinds = new HashMap<>(); - - static { - Util.add(contextKinds, INSENS, "insensitive", "insens", "ci"); - Util.add(contextKinds, CALLSITE, "callsite", "call", "c"); - Util.add(contextKinds, OBJECT, "object", "obj", "o"); - Util.add(contextKinds, HYBOBJ, "hybobj", "ho", "h"); - Util.add(contextKinds, HYBTYPE, "hybtype", "ht"); - Util.add(contextKinds, TYPE, "type", "t"); - } - - public static Collection contextAliases() { - return contextKinds.keySet(); - } - - public static ContextKind toCtxKind(String name) { - return contextKinds.getOrDefault(name, INSENS); - } - - @Override - public String toString() { - return switch (this) { - case CALLSITE -> "callsite"; - case OBJECT -> "object"; - case HYBOBJ -> "hybobj"; - case HYBTYPE -> "hybtype"; - case TYPE -> "type"; - default -> "insensitive"; - }; - } + INSENS, + CALLSITE, + OBJECT, + TYPE, + HYBOBJ, + HYBTYPE; + static final Map contextKinds = new HashMap<>(); + + static { + Util.add(contextKinds, INSENS, "insensitive", "insens", "ci"); + Util.add(contextKinds, CALLSITE, "callsite", "call", "c"); + Util.add(contextKinds, OBJECT, "object", "obj", "o"); + Util.add(contextKinds, HYBOBJ, "hybobj", "ho", "h"); + Util.add(contextKinds, HYBTYPE, "hybtype", "ht"); + Util.add(contextKinds, TYPE, "type", "t"); + } + + public static Collection contextAliases() { + return contextKinds.keySet(); + } + + public static ContextKind toCtxKind(String name) { + return contextKinds.getOrDefault(name, INSENS); + } + + @Override + public String toString() { + return switch (this) { + case CALLSITE -> "callsite"; + case OBJECT -> "object"; + case HYBOBJ -> "hybobj"; + case HYBTYPE -> "hybtype"; + case TYPE -> "type"; + default -> "insensitive"; + }; + } } diff --git a/sootup.qilin/src/main/java/driver/Main.java b/sootup.qilin/src/main/java/driver/Main.java index 73f0282fd25..e2e4ddf9741 100644 --- a/sootup.qilin/src/main/java/driver/Main.java +++ b/sootup.qilin/src/main/java/driver/Main.java @@ -18,240 +18,40 @@ package driver; -import org.apache.commons.io.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import qilin.core.PTA; -import qilin.core.PTAScene; import qilin.pta.PTAConfig; import qilin.util.MemoryWatcher; import qilin.util.PTAUtils; import qilin.util.Stopwatch; -import soot.PackManager; -import soot.jimple.toolkits.callgraph.CallGraph; -import soot.options.Options; - -import java.io.*; -import java.util.*; -import java.util.stream.Collectors; public class Main { - private static final Logger logger = LoggerFactory.getLogger(Main.class); - - public static PTA run(String[] args) { - PTA pta; - new PTAOption().parseCommandLine(args); - setupSoot(); - if (PTAConfig.v().getOutConfig().dumpJimple) { - String jimplePath = PTAConfig.v().getAppConfig().APP_PATH.replace(".jar", ""); - PTAUtils.dumpJimple(jimplePath); - System.out.println("Jimple files have been dumped to: " + jimplePath); - } - logger.info("Constructing the callgraph..."); - PackManager.v().getPack("cg").apply(); - CallGraph cg = PTAScene.v().getCallGraph(); - System.out.println("#CALLGRAPH:" + cg.size()); - pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); - pta.run(); - return pta; - } - - public static void mainRun(String[] args) { - Stopwatch ptaTimer = Stopwatch.newAndStart("Main PTA (including pre-analysis)"); - long pid = ProcessHandle.current().pid(); - MemoryWatcher memoryWatcher = new MemoryWatcher(pid, "Main PTA"); - memoryWatcher.start(); - run(args); - ptaTimer.stop(); - System.out.println(ptaTimer); - memoryWatcher.stop(); - System.out.println(memoryWatcher); - } - - public static void setupSoot() { - setSootOptions(PTAConfig.v()); - setSootClassPath(PTAConfig.v()); - PTAScene.v().addBasicClasses(); - PTAScene.v().loadNecessaryClasses(); - } - - /** - * Set command line options for soot. - */ - private static void setSootOptions(PTAConfig config) { - List dirs = new ArrayList<>(); - PTAConfig.ApplicationConfiguration appConfig = config.getAppConfig(); - dirs.add(appConfig.APP_PATH); - Options.v().set_process_dir(dirs); - - if (appConfig.MAIN_CLASS == null) { - appConfig.MAIN_CLASS = PTAUtils.findMainFromMetaInfo(appConfig.APP_PATH); - } - - if (appConfig.MAIN_CLASS != null) { - Options.v().set_main_class(appConfig.MAIN_CLASS); - } - - if (appConfig.INCLUDE_ALL) { - Options.v().set_include_all(true); - } - - if (appConfig.INCLUDE != null) { - Options.v().set_include(appConfig.INCLUDE); - } - - if (appConfig.EXCLUDE != null) { - Options.v().set_no_bodies_for_excluded(true); - Options.v().set_exclude(appConfig.EXCLUDE); - } - - // configure callgraph construction algorithm - configureCallgraphAlg(config.callgraphAlg); - - Options.v().setPhaseOption("jb", "use-original-names:true"); - Options.v().setPhaseOption("jb", "model-lambdametafactory:false"); - Options.v().set_output_format(Options.output_format_jimple); - - if (appConfig.REFLECTION_LOG != null) { - Options.v().setPhaseOption("cg", "reflection-log:" + appConfig.REFLECTION_LOG); - } - - Options.v().set_keep_line_number(true); - Options.v().set_full_resolver(true); - // Options.v().set_src_prec(Options.src_prec_class); - Options.v().set_src_prec(Options.src_prec_only_class); - Options.v().set_allow_phantom_refs(true); - - } - - /** - * Set the soot class path to point to the default class path appended with the - * app path (the classes dir or the application jar) and jar files in the - * library dir of the application. - */ - private static void setSootClassPath(PTAConfig config) { - List cps = new ArrayList<>(); - PTAConfig.ApplicationConfiguration appConfig = config.getAppConfig(); - // note that the order is important! - cps.add(appConfig.APP_PATH); - cps.addAll(getLibJars(appConfig.LIB_PATH)); - cps.addAll(getJreJars(appConfig.JRE)); - final String classpath = String.join(File.pathSeparator, cps); - logger.info("Setting Soot ClassPath: {}", classpath); - System.setProperty("soot.class.path", classpath); - } - - private static Collection getJreJars(String JRE) { - if (JRE == null) { - return Collections.emptySet(); - } - final String jreLibDir = JRE + File.separator + "lib"; - return FileUtils.listFiles(new File(jreLibDir), new String[]{"jar"}, false).stream().map(File::toString) - .collect(Collectors.toList()); - } - - /** - * Returns a collection of files, one for each of the jar files in the app's lib - * folder - */ - private static Collection getLibJars(String LIB_PATH) { - if (LIB_PATH == null) { - return Collections.emptySet(); - } - File libFile = new File(LIB_PATH); - if (libFile.exists()) { - if (libFile.isDirectory()) { - return FileUtils.listFiles(libFile, new String[]{"jar"}, true).stream().map(File::toString) - .collect(Collectors.toList()); - } else if (libFile.isFile()) { - if (libFile.getName().endsWith(".jar")) { - return Collections.singletonList(LIB_PATH); - } - logger.error("Project not configured properly. Application library path {} is not a jar file.", - libFile); - System.exit(1); - } - } - logger.error("Project not configured properly. Application library path {} is not correct.", libFile); - System.exit(1); - return null; - } - - // callgraph relevant APIs - // refer to https://github.com/secure-software-engineering/FlowDroid/blob/develop/soot-infoflow-android/src/soot/jimple/infoflow/android/SetupApplication.java - private static void configureCallgraphAlg(PTAConfig.CallgraphAlgorithm cgAlg) { - switch (cgAlg) { - case CHA -> { - Options.v().setPhaseOption("cg.cha", "on"); - break; - } - case VTA -> { - Options.v().setPhaseOption("cg.spark", "on"); - Options.v().setPhaseOption("cg.spark", "vta:true"); - break; - } - case RTA -> { - Options.v().setPhaseOption("cg.spark", "on"); - Options.v().setPhaseOption("cg.spark", "rta:true"); - Options.v().setPhaseOption("cg.spark", "on-fly-cg:false"); - break; - } - case GEOM -> { - Options.v().setPhaseOption("cg.spark", "on"); - Options.v().setPhaseOption("cg.spark", "geom-pta:true"); - // Those are default options, not sure whether removing them works. - Options.v().setPhaseOption("cg.spark", "geom-encoding:Geom"); - Options.v().setPhaseOption("cg.spark", "geom-worklist:PQ"); - break; - } - case SPARK -> { - Options.v().setPhaseOption("cg.spark", "on"); - break; - } - case QILIN -> { - } - default -> { - break; - } - } - } - - public static CallGraph runCallgraphAlg(String[] args) { - CallGraph cg; - new PTAOption().parseCommandLine(args); - setupSoot(); - if (PTAConfig.v().getOutConfig().dumpJimple) { - String jimplePath = PTAConfig.v().getAppConfig().APP_PATH.replace(".jar", ""); - PTAUtils.dumpJimple(jimplePath); - System.out.println("Jimple files have been dumped to: " + jimplePath); - } - logger.info("Constructing the callgraph using " + PTAConfig.v().callgraphAlg + "..."); - if (PTAConfig.v().callgraphAlg == PTAConfig.CallgraphAlgorithm.QILIN) { - PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); - pta.run(); - } else { - PackManager.v().getPack("cg").apply(); - } - cg = PTAScene.v().getCallGraph(); - System.out.println("#CALLGRAPH:" + cg.size()); - return cg; - } - - public static void mainCG(String[] args) { - Stopwatch cgTimer = Stopwatch.newAndStart("Main CG"); - long pid = ProcessHandle.current().pid(); - MemoryWatcher memoryWatcher = new MemoryWatcher(pid, "Main CG"); - memoryWatcher.start(); - runCallgraphAlg(args); - cgTimer.stop(); - System.out.println(cgTimer); - memoryWatcher.stop(); - System.out.println(memoryWatcher); - } - - public static void main(String[] args) { - mainRun(args); - // mainCG(args); - } + public static PTA run(String[] args) { + PTA pta; + new PTAOption().parseCommandLine(args); + if (PTAConfig.v().getOutConfig().dumpJimple) { + String jimplePath = PTAConfig.v().getAppConfig().APP_PATH.replace(".jar", ""); + PTAUtils.dumpJimple(jimplePath); + System.out.println("Jimple files have been dumped to: " + jimplePath); + } + pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + pta.run(); + return pta; + } + + public static void mainRun(String[] args) { + Stopwatch ptaTimer = Stopwatch.newAndStart("Main PTA (including pre-analysis)"); + long pid = ProcessHandle.current().pid(); + MemoryWatcher memoryWatcher = new MemoryWatcher(pid, "Main PTA"); + memoryWatcher.start(); + run(args); + ptaTimer.stop(); + System.out.println(ptaTimer); + memoryWatcher.stop(); + System.out.println(memoryWatcher); + } + + public static void main(String[] args) { + mainRun(args); + } } diff --git a/sootup.qilin/src/main/java/driver/PTAComparator.java b/sootup.qilin/src/main/java/driver/PTAComparator.java index 91a29ccb0ab..15c6b9200de 100644 --- a/sootup.qilin/src/main/java/driver/PTAComparator.java +++ b/sootup.qilin/src/main/java/driver/PTAComparator.java @@ -18,6 +18,8 @@ package driver; +import java.io.PrintStream; +import java.util.*; import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; @@ -27,130 +29,132 @@ import qilin.util.Util; import sootup.core.jimple.basic.Local; -import java.io.PrintStream; -import java.util.*; - public class PTAComparator { - static final boolean verbose = true; - public static int count, count2; - - public static void main(String[] args) { - List list = new ArrayList<>(); - for (String arg : args) { - if (!arg.startsWith("-pta=")) { - list.add(arg); - } - } - runCompare(list.toArray(new String[0]), "2o", "E-2o"); + static final boolean verbose = true; + public static int count, count2; + + public static void main(String[] args) { + List list = new ArrayList<>(); + for (String arg : args) { + if (!arg.startsWith("-pta=")) { + list.add(arg); + } } - - public static void runCompare(String[] args, String ptaPtn1, String ptaPtn2) { - Comparator comparator = new PTSComparator(); - String[] ptaArg1 = Util.concat(args, new String[]{"-pta=" + ptaPtn1}); - comparator.record(Main.run(ptaArg1)); - PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPtn2); - PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); - pta.pureRun(); - comparator.compare(pta); - comparator.out.close(); - count = comparator.count; - count2 = comparator.count2; + runCompare(list.toArray(new String[0]), "2o", "E-2o"); + } + + public static void runCompare(String[] args, String ptaPtn1, String ptaPtn2) { + Comparator comparator = new PTSComparator(); + String[] ptaArg1 = Util.concat(args, new String[] {"-pta=" + ptaPtn1}); + comparator.record(Main.run(ptaArg1)); + PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPtn2); + PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + pta.pureRun(); + comparator.compare(pta); + comparator.out.close(); + count = comparator.count; + count2 = comparator.count2; + } + + abstract static class Comparator { + protected int count, count2; + PrintStream out; + + public Comparator() { + out = System.out; } - abstract static class Comparator { - protected int count, count2; - PrintStream out; + abstract void record(PTA pta); - public Comparator() { - out = System.out; - } + abstract void compare(PTA pta); + } - abstract void record(PTA pta); + static class PTSComparator extends Comparator { + private final Map> valToOldAllocs = new HashMap<>(); + private final Map> valToNewAllocs = new HashMap<>(); - abstract void compare(PTA pta); + private Set getOldAllocs(Object val) { + return valToOldAllocs.computeIfAbsent(val, k -> new HashSet<>()); } - static class PTSComparator extends Comparator { - private final Map> valToOldAllocs = new HashMap<>(); - private final Map> valToNewAllocs = new HashMap<>(); - - private Set getOldAllocs(Object val) { - return valToOldAllocs.computeIfAbsent(val, k -> new HashSet<>()); - } - - private Set getNewAllocs(Object val) { - return valToNewAllocs.computeIfAbsent(val, k -> new HashSet<>()); - } + private Set getNewAllocs(Object val) { + return valToNewAllocs.computeIfAbsent(val, k -> new HashSet<>()); + } - @Override - void record(PTA pta) { - pta.getPag().getValNodes().forEach(valNode -> { + @Override + void record(PTA pta) { + pta.getPag() + .getValNodes() + .forEach( + valNode -> { if (valNode instanceof VarNode varNode) { - final Set allocSites = getOldAllocs(varNode.getVariable()); - PointsToSet pts = pta.reachingObjects(varNode).toCIPointsToSet(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - allocSites.add(n.getNewExpr()); - } + final Set allocSites = getOldAllocs(varNode.getVariable()); + PointsToSet pts = pta.reachingObjects(varNode).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + allocSites.add(n.getNewExpr()); + } } - }); - } - - @Override - void compare(PTA pta) { - count = 0; - PAG pag = pta.getPag(); - pag.getValNodes().forEach(valNode -> { + }); + } + + @Override + void compare(PTA pta) { + count = 0; + PAG pag = pta.getPag(); + pag.getValNodes() + .forEach( + valNode -> { if (valNode instanceof VarNode varNode) { - final Set allocSites = getNewAllocs(varNode.getVariable()); + final Set allocSites = getNewAllocs(varNode.getVariable()); - PointsToSet pts1 = pta.reachingObjects(varNode).toCIPointsToSet(); - for (Iterator it = pts1.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - allocSites.add(n.getNewExpr()); - } + PointsToSet pts1 = pta.reachingObjects(varNode).toCIPointsToSet(); + for (Iterator it = pts1.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + allocSites.add(n.getNewExpr()); + } } - }); - valToNewAllocs.forEach((val, allocSites) -> { - if (val.toString().contains("Parm THIS_NODE")) { - return; + }); + valToNewAllocs.forEach( + (val, allocSites) -> { + if (val.toString().contains("Parm THIS_NODE")) { + return; + } + Set oldAllocSites = getOldAllocs(val); + if (oldAllocSites == null) oldAllocSites = Collections.emptySet(); + if (!oldAllocSites.equals(allocSites)) { + if (verbose) { + out.println("\nPoint-to sets not equal!"); + if (val instanceof Local) { + out.println("local: " + pag.findLocalVarNode(val).getMethod() + ": " + val); + } else { + out.println("not local: " + pag.findValNode(val) + ": " + val); } - Set oldAllocSites = getOldAllocs(val); - if (oldAllocSites == null) - oldAllocSites = Collections.emptySet(); - if (!oldAllocSites.equals(allocSites)) { - if (verbose) { - out.println("\nPoint-to sets not equal!"); - if (val instanceof Local) { - out.println("local: " + pag.findLocalVarNode(val).getMethod() + ": " + val); - } else { - out.println("not local: " + pag.findValNode(val) + ": " + val); - } - - out.println("Old Points-to set:" + oldAllocSites.size()); -// oldAllocSites.forEach(a -> System.out.println(qilin.pta.getPag().valToAllocNode.get(a))); - out.println("New Points-to set:" + allocSites.size()); -// allocSites.forEach(a -> System.out.println(qilin.pta.getPag().valToAllocNode.get(a))); - } - int diff = allocSites.size() - oldAllocSites.size(); - if (diff > 0) - count += diff; - else if (diff < 0) - count2 -= diff; - if (verbose) { - out.println("difference:" + diff); - if (diff > 0) { - allocSites.removeAll(oldAllocSites); - allocSites.forEach(a -> out.println(pag.findAllocNode(a))); - } else if (diff < 0) { - oldAllocSites.removeAll(allocSites); - oldAllocSites.forEach(a -> out.println(pag.findAllocNode(a))); - } - } + + out.println("Old Points-to set:" + oldAllocSites.size()); + // oldAllocSites.forEach(a -> + // System.out.println(qilin.pta.getPag().valToAllocNode.get(a))); + out.println("New Points-to set:" + allocSites.size()); + // allocSites.forEach(a -> + // System.out.println(qilin.pta.getPag().valToAllocNode.get(a))); + } + int diff = allocSites.size() - oldAllocSites.size(); + if (diff > 0) count += diff; + else if (diff < 0) count2 -= diff; + if (verbose) { + out.println("difference:" + diff); + if (diff > 0) { + allocSites.removeAll(oldAllocSites); + allocSites.forEach(a -> out.println(pag.findAllocNode(a))); + } else if (diff < 0) { + oldAllocSites.removeAll(allocSites); + oldAllocSites.forEach(a -> out.println(pag.findAllocNode(a))); } - }); - out.println("\nTotal pts over:" + count); - out.println("\nTotal pts lose:" + count2); - } + } + } + }); + out.println("\nTotal pts over:" + count); + out.println("\nTotal pts lose:" + count2); } + } } diff --git a/sootup.qilin/src/main/java/driver/PTAFactory.java b/sootup.qilin/src/main/java/driver/PTAFactory.java index 41fe63373b4..07fcd0905ec 100644 --- a/sootup.qilin/src/main/java/driver/PTAFactory.java +++ b/sootup.qilin/src/main/java/driver/PTAFactory.java @@ -24,128 +24,146 @@ import qilin.pta.tools.*; public class PTAFactory { - public static PTA createPTA(PTAPattern ptaPattern) { - switch (ptaPattern.getContextKind()) { - case HYBOBJ: { - switch (ptaPattern.getApproach()) { - case DATADRIVEN -> { - // data-driven hybrid-2obj, Sehun Jeong oopsla'17 - CtxConstructor ctxCons = new HybObjCtxConstructor(); - return new DataDrivenPTA(ctxCons); - } - case TUNNELING -> { - CtxConstructor ctxCons = new HybObjCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - } - default -> { - // static method using callsite as context, Yannis pldi'13 - return new HybridObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - } - } - } - case OBJECT: { - switch (ptaPattern.getApproach()) { - case EAGLE -> { - // k-obj pointer analysis with Eagle pre-analysis, Jingbo OOPSLA'19 - assert ptaPattern.getContextDepth() == ptaPattern.getHeapContextDepth() + 1; - BasePTA eagle = new EaglePTA(ptaPattern.getContextDepth()); - if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(eagle, PTAConfig.v().getPtaConfig().debloatApproach); - } else { - return eagle; - } - } - case BEAN -> { - CtxConstructor ctxCons = new ObjCtxConstructor(); - return new BeanPTA(ctxCons); - } - case TURNER -> { - return new TurnerPTA(ptaPattern.getContextDepth()); - } - case ZIPPER -> { - CtxConstructor ctxCons = new ObjCtxConstructor(); - BasePTA zipperPTA = new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); - if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(zipperPTA, PTAConfig.v().getPtaConfig().debloatApproach); - } else { - return zipperPTA; - } - } - case MAHJONG -> { - CtxConstructor ctxCons = new ObjCtxConstructor(); - BasePTA mahjongPTA = new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); - if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(mahjongPTA, PTAConfig.v().getPtaConfig().debloatApproach); - } else { - return mahjongPTA; - } - } - case DATADRIVEN -> { - CtxConstructor ctxCons = new ObjCtxConstructor(); - return new DataDrivenPTA(ctxCons); - } - case TUNNELING -> { - CtxConstructor ctxCons = new ObjCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - } - default -> { - BasePTA kobj = new ObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + public static PTA createPTA(PTAPattern ptaPattern) { + switch (ptaPattern.getContextKind()) { + case HYBOBJ: + { + switch (ptaPattern.getApproach()) { + case DATADRIVEN -> { + // data-driven hybrid-2obj, Sehun Jeong oopsla'17 + CtxConstructor ctxCons = new HybObjCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new HybObjCtxConstructor(); + return new TunnelingPTA( + ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + default -> { + // static method using callsite as context, Yannis pldi'13 + return new HybridObjectSensPTA( + ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + } + } + case OBJECT: + { + switch (ptaPattern.getApproach()) { + case EAGLE -> { + // k-obj pointer analysis with Eagle pre-analysis, Jingbo OOPSLA'19 + assert ptaPattern.getContextDepth() == ptaPattern.getHeapContextDepth() + 1; + BasePTA eagle = new EaglePTA(ptaPattern.getContextDepth()); + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(eagle, PTAConfig.v().getPtaConfig().debloatApproach); + } else { + return eagle; + } + } + case BEAN -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + return new BeanPTA(ctxCons); + } + case TURNER -> { + return new TurnerPTA(ptaPattern.getContextDepth()); + } + case ZIPPER -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + BasePTA zipperPTA = + new ZipperPTA( + ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(zipperPTA, PTAConfig.v().getPtaConfig().debloatApproach); + } else { + return zipperPTA; + } + } + case MAHJONG -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + BasePTA mahjongPTA = + new MahjongPTA( + ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(mahjongPTA, PTAConfig.v().getPtaConfig().debloatApproach); + } else { + return mahjongPTA; + } + } + case DATADRIVEN -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new ObjCtxConstructor(); + return new TunnelingPTA( + ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + default -> { + BasePTA kobj = + new ObjectSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - if (PTAConfig.v().getPtaConfig().ctxDebloating) { - return new DebloatedPTA(kobj, PTAConfig.v().getPtaConfig().debloatApproach); - } else { - // normal object-sensitive pointer analysis, Milanova TOSEM'05 - return kobj; - } - } - } - } - case TYPE: { - switch (ptaPattern.getApproach()) { - case DATADRIVEN -> { - CtxConstructor ctxCons = new TypeCtxConstructor(); - return new DataDrivenPTA(ctxCons); - } - case TUNNELING -> { - CtxConstructor ctxCons = new TypeCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - } - default -> { - // normal type-sensitive pointer analysis, Yannis popl'11 - return new TypeSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - } - } - } - case CALLSITE: { - switch (ptaPattern.getApproach()) { - case ZIPPER -> { - CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new ZipperPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); - } - case MAHJONG -> { - CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new MahjongPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); - } - case DATADRIVEN -> { - CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new DataDrivenPTA(ctxCons); - } - case TUNNELING -> { - CtxConstructor ctxCons = new CallsiteCtxConstructor(); - return new TunnelingPTA(ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - } - case SELECTX -> { - return new SelectxPTA(ptaPattern.getContextDepth()); - } - default -> { - // CallSite Sensitive - return new CallSiteSensPTA(ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); - } - } - } - case INSENS: - default: - return new Spark(); + if (PTAConfig.v().getPtaConfig().ctxDebloating) { + return new DebloatedPTA(kobj, PTAConfig.v().getPtaConfig().debloatApproach); + } else { + // normal object-sensitive pointer analysis, Milanova TOSEM'05 + return kobj; + } + } + } + } + case TYPE: + { + switch (ptaPattern.getApproach()) { + case DATADRIVEN -> { + CtxConstructor ctxCons = new TypeCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new TypeCtxConstructor(); + return new TunnelingPTA( + ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + default -> { + // normal type-sensitive pointer analysis, Yannis popl'11 + return new TypeSensPTA( + ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + } + } + case CALLSITE: + { + switch (ptaPattern.getApproach()) { + case ZIPPER -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new ZipperPTA( + ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + } + case MAHJONG -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new MahjongPTA( + ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth(), ctxCons); + } + case DATADRIVEN -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new DataDrivenPTA(ctxCons); + } + case TUNNELING -> { + CtxConstructor ctxCons = new CallsiteCtxConstructor(); + return new TunnelingPTA( + ctxCons, ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + case SELECTX -> { + return new SelectxPTA(ptaPattern.getContextDepth()); + } + default -> { + // CallSite Sensitive + return new CallSiteSensPTA( + ptaPattern.getContextDepth(), ptaPattern.getHeapContextDepth()); + } + } } + case INSENS: + default: + return new Spark(); } + } } diff --git a/sootup.qilin/src/main/java/driver/PTAOption.java b/sootup.qilin/src/main/java/driver/PTAOption.java index f61035c8398..b20d7601957 100644 --- a/sootup.qilin/src/main/java/driver/PTAOption.java +++ b/sootup.qilin/src/main/java/driver/PTAOption.java @@ -18,6 +18,7 @@ package driver; +import java.util.*; import org.apache.commons.cli.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,188 +26,234 @@ import qilin.pta.toolkits.turner.Turner; import qilin.pta.tools.DebloatedPTA; -import java.util.*; - public class PTAOption extends Options { - private static final Logger logger = LoggerFactory.getLogger(PTAOption.class); + private static final Logger logger = LoggerFactory.getLogger(PTAOption.class); - /** - * add option "-brief -option" with description - */ - protected void addOption(String brief, String option, String description) { - addOption(new Option(brief, option, false, description)); - } + /** add option "-brief -option" with description */ + protected void addOption(String brief, String option, String description) { + addOption(new Option(brief, option, false, description)); + } - /** - * add option "-brief -option " with description - */ - protected void addOption(String brief, String option, String arg, String description) { - addOption(OptionBuilder.withLongOpt(option).withArgName(arg).hasArg().withDescription(description).create(brief)); - } + /** add option "-brief -option " with description */ + protected void addOption(String brief, String option, String arg, String description) { + addOption( + OptionBuilder.withLongOpt(option) + .withArgName(arg) + .hasArg() + .withDescription(description) + .create(brief)); + } - public PTAOption() { - // input configurations - addOption("app", "apppath", "dir or jar", - "The directory containing the classes for the application or the application jar file (default: .)"); - addOption("lib", "libpath", "dir or jar", - "The directory containing the library jar files for the application or the library jar file"); - addOption(null, "includeall", "Include packages which are not analyzed by default. (default value: false)"); - addOption(null, "exclude", "packages", "Exclude selected packages. (delimiting symbol: semicolon ';')"); - addOption(null, "jre", "dir", - "The directory containing the version of JRE to be used for whole program analysis"); - addOption("reflog", "reflectionlog", "file", - "The reflection log file for the application for resolving reflective call sites"); - addOption("main", "mainclass", "class name", - "Name of the main class for the application (must be specified when appmode)"); + public PTAOption() { + // input configurations + addOption( + "app", + "apppath", + "dir or jar", + "The directory containing the classes for the application or the application jar file (default: .)"); + addOption( + "lib", + "libpath", + "dir or jar", + "The directory containing the library jar files for the application or the library jar file"); + addOption( + null, + "includeall", + "Include packages which are not analyzed by default. (default value: false)"); + addOption( + null, + "exclude", + "packages", + "Exclude selected packages. (delimiting symbol: semicolon ';')"); + addOption( + null, + "jre", + "dir", + "The directory containing the version of JRE to be used for whole program analysis"); + addOption( + "reflog", + "reflectionlog", + "file", + "The reflection log file for the application for resolving reflective call sites"); + addOption( + "main", + "mainclass", + "class name", + "Name of the main class for the application (must be specified when appmode)"); - // output configurations. - addOption("cg", "dumpcallgraph", "Output .dot callgraph file (default value: false)"); - addOption("jimple", "dumpjimple", "Dump appclasses to jimple. (default value: false)"); - addOption("stats", "dumpstats", "Dump statistics into files. (default value: false)"); - addOption("ptsall", "dumpallpts", - "Dump points-to of lib vars results to output/pts.txt (default value: false)"); - addOption("pag", "dumppag", "Print PAG to terminal. (default value: false)"); - addOption("pts", "dumppts", "Dump points-to results to output/pts.txt (default value: false)"); + // output configurations. + addOption("cg", "dumpcallgraph", "Output .dot callgraph file (default value: false)"); + addOption("jimple", "dumpjimple", "Dump appclasses to jimple. (default value: false)"); + addOption("stats", "dumpstats", "Dump statistics into files. (default value: false)"); + addOption( + "ptsall", + "dumpallpts", + "Dump points-to of lib vars results to output/pts.txt (default value: false)"); + addOption("pag", "dumppag", "Print PAG to terminal. (default value: false)"); + addOption("pts", "dumppts", "Dump points-to results to output/pts.txt (default value: false)"); - // general PTA configurations - addOption("clinit", "clinitmode", "APP|FULL|ONFLY", "clinit methods loading mode, default: ONFLY"); - addOption("mh", "mergeheap", - "merge heaps of StringBuilder/StringBuffer/Throwable (default value: false)"); - addOption("lcs", "emptycontextforignoretypes", "Limit heap context to 0 for Strings/Exceptions in PTA (default value: false)"); - addOption("pta", "pointstoanalysis", "(c|o)+?(h)?|insens", - "Specify Pointer Analysis e.g. 2o1h or 2o -> 2obj+1heap (default value: insens; default h: k-1.)"); - addOption("se", "singleentry", "A lightweight mode with only one main method entry. (default value: false)"); - addOption("sc", "stringconstants", "Propagate all string constants (default value: false)"); - addOption("pae", "precisearray", "Enable precise Array Element type (default value: false)"); - addOption("pe", "preciseexceptions", "Enable precisely handling exceptions (default value: false)"); + // general PTA configurations + addOption( + "clinit", "clinitmode", "APP|FULL|ONFLY", "clinit methods loading mode, default: ONFLY"); + addOption( + "mh", + "mergeheap", + "merge heaps of StringBuilder/StringBuffer/Throwable (default value: false)"); + addOption( + "lcs", + "emptycontextforignoretypes", + "Limit heap context to 0 for Strings/Exceptions in PTA (default value: false)"); + addOption( + "pta", + "pointstoanalysis", + "(c|o)+?(h)?|insens", + "Specify Pointer Analysis e.g. 2o1h or 2o -> 2obj+1heap (default value: insens; default h: k-1.)"); + addOption( + "se", + "singleentry", + "A lightweight mode with only one main method entry. (default value: false)"); + addOption("sc", "stringconstants", "Propagate all string constants (default value: false)"); + addOption("pae", "precisearray", "Enable precise Array Element type (default value: false)"); + addOption( + "pe", "preciseexceptions", "Enable precisely handling exceptions (default value: false)"); - // a specific PTA's configuration - addOption("tc", "turnerconfig", "[DEFAULT, PHASE_ONE, PHASE_TWO]", "Run Turner in the given setting (default value: DEFAULT)"); - addOption("cd", "ctxdebloat", "Enable context debloating optimization (default value: false)"); - addOption("cda", "debloatapproach", "[CONCH, DEBLOATERX]", "Specify debloating approach (default value: CONCH)"); - addOption("tmd", "modular", "Enable Turner to run modularly (default value: false)"); + // a specific PTA's configuration + addOption( + "tc", + "turnerconfig", + "[DEFAULT, PHASE_ONE, PHASE_TWO]", + "Run Turner in the given setting (default value: DEFAULT)"); + addOption("cd", "ctxdebloat", "Enable context debloating optimization (default value: false)"); + addOption( + "cda", + "debloatapproach", + "[CONCH, DEBLOATERX]", + "Specify debloating approach (default value: CONCH)"); + addOption("tmd", "modular", "Enable Turner to run modularly (default value: false)"); - // callgraph algorithm configurations - addOption("cga", "callgraphalg", "[CHA, VTA, RTA, SPARK, GEOM, QILIN]", "Specify callgraph construction algorithm (default value: QILIN)"); + // callgraph algorithm configurations + addOption( + "cga", + "callgraphalg", + "[CHA, VTA, RTA, SPARK, GEOM, QILIN]", + "Specify callgraph construction algorithm (default value: QILIN)"); - // others - addOption("h", "help", "print this message"); - addOption("pre", "preonly", "Run only pre-analysis (default value: false)"); + // others + addOption("h", "help", "print this message"); + addOption("pre", "preonly", "Run only pre-analysis (default value: false)"); + } + public void parseCommandLine(String[] args) { + try { + CommandLine cmd = new GnuParser().parse(this, args); + if (cmd.hasOption("help")) { + new HelpFormatter().printHelp("qilin", this); + System.exit(0); + } + parseCommandLineOptions(cmd); + } catch (Exception e) { + logger.error("Error parsing command line options", e); + System.exit(1); } + } - public void parseCommandLine(String[] args) { - try { - CommandLine cmd = new GnuParser().parse(this, args); - if (cmd.hasOption("help")) { - new HelpFormatter().printHelp("qilin", this); - System.exit(0); - } - parseCommandLineOptions(cmd); - } catch (Exception e) { - logger.error("Error parsing command line options", e); - System.exit(1); - } + /** + * Set all variables from the command line arguments. + * + * @param cmd + */ + protected void parseCommandLineOptions(CommandLine cmd) { + // pointer analysis configuration + if (cmd.hasOption("apppath")) { + PTAConfig.v().getAppConfig().APP_PATH = cmd.getOptionValue("apppath"); } - - /** - * Set all variables from the command line arguments. - * - * @param cmd - */ - protected void parseCommandLineOptions(CommandLine cmd) { - // pointer analysis configuration - if (cmd.hasOption("apppath")) { - PTAConfig.v().getAppConfig().APP_PATH = cmd.getOptionValue("apppath"); - } - String ptacmd = cmd.hasOption("pta") ? cmd.getOptionValue("pta") : "insens"; - PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptacmd); - PTAConfig.v().getPtaConfig().ptaName = PTAConfig.v().getPtaConfig().ptaPattern.toString(); - if (cmd.hasOption("singleentry")) { - PTAConfig.v().getPtaConfig().singleentry = true; - } - if (cmd.hasOption("mergeheap")) { - PTAConfig.v().getPtaConfig().mergeHeap = true; - } - if (cmd.hasOption("stringconstants")) { - PTAConfig.v().getPtaConfig().stringConstants = true; - } - if (cmd.hasOption("emptycontextforignoretypes")) { - PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes = true; - } - if (cmd.hasOption("clinitmode")) { - PTAConfig.v().getPtaConfig().clinitMode = PTAConfig.ClinitMode.valueOf(cmd.getOptionValue("clinitmode")); - } - if (cmd.hasOption("preonly")) { - PTAConfig.v().getPtaConfig().preAnalysisOnly = true; - } - if (cmd.hasOption("ctxdebloat")) { - PTAConfig.v().getPtaConfig().ctxDebloating = true; - if (cmd.hasOption("debloatapproach")) { - PTAConfig.v().getPtaConfig().debloatApproach = DebloatedPTA.DebloatApproach.valueOf(cmd.getOptionValue("debloatapproach")); - } - } - if (cmd.hasOption("preciseexceptions")) { - PTAConfig.v().getPtaConfig().preciseExceptions = true; - } - if (cmd.hasOption("modular")) { - Turner.isModular = true; - } - if (cmd.hasOption("precisearray")) { - PTAConfig.v().getPtaConfig().preciseArrayElement = true; - } - // application configuration - if (cmd.hasOption("mainclass")) { - PTAConfig.v().getAppConfig().MAIN_CLASS = cmd.getOptionValue("mainclass"); - } - if (cmd.hasOption("jre")) { - PTAConfig.v().getAppConfig().JRE = cmd.getOptionValue("jre"); - } - if (cmd.hasOption("libpath")) { - PTAConfig.v().getAppConfig().LIB_PATH = cmd.getOptionValue("libpath"); - } - if (cmd.hasOption("exclude")) { - PTAConfig.v().getAppConfig().EXCLUDE = parsePackages(cmd.getOptionValue("exclude")); - } - if (cmd.hasOption("reflectionlog")) { - PTAConfig.v().getAppConfig().REFLECTION_LOG = cmd.getOptionValue("reflectionlog"); - } - if (cmd.hasOption("inlcudeall")) { - PTAConfig.v().getAppConfig().INCLUDE_ALL = true; - } - if (cmd.hasOption("turnerconfig")) { - PTAConfig.v().turnerConfig = PTAConfig.TurnerConfig.valueOf(cmd.getOptionValue("turnerconfig")); - } - // callgraph - if (cmd.hasOption("callgraphalg")) { - PTAConfig.v().callgraphAlg = PTAConfig.CallgraphAlgorithm.valueOf(cmd.getOptionValue("callgraphalg")); - } - // output - if (cmd.hasOption("dumpjimple")) { - PTAConfig.v().getOutConfig().dumpJimple = true; - } - if (cmd.hasOption("dumppts")) { - PTAConfig.v().getOutConfig().dumppts = true; - } - if (cmd.hasOption("dumpallpts")) { - PTAConfig.v().getOutConfig().dumppts = true; - PTAConfig.v().getOutConfig().dumplibpts = true; - } - if (cmd.hasOption("dumpcallgraph")) { - PTAConfig.v().getOutConfig().dumpCallGraph = true; - } - if (cmd.hasOption("dumppag")) { - PTAConfig.v().getOutConfig().dumppag = true; - } - if (cmd.hasOption("dumpstats")) { - PTAConfig.v().getOutConfig().dumpStats = true; - } + String ptacmd = cmd.hasOption("pta") ? cmd.getOptionValue("pta") : "insens"; + PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptacmd); + PTAConfig.v().getPtaConfig().ptaName = PTAConfig.v().getPtaConfig().ptaPattern.toString(); + if (cmd.hasOption("singleentry")) { + PTAConfig.v().getPtaConfig().singleentry = true; } - - static List parsePackages(String packagesString) { - ArrayList pkgList = new ArrayList<>(); - String[] pkgs = packagesString.split(";"); - Collections.addAll(pkgList, pkgs); - return pkgList; + if (cmd.hasOption("mergeheap")) { + PTAConfig.v().getPtaConfig().mergeHeap = true; + } + if (cmd.hasOption("stringconstants")) { + PTAConfig.v().getPtaConfig().stringConstants = true; + } + if (cmd.hasOption("emptycontextforignoretypes")) { + PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes = true; + } + if (cmd.hasOption("clinitmode")) { + PTAConfig.v().getPtaConfig().clinitMode = + PTAConfig.ClinitMode.valueOf(cmd.getOptionValue("clinitmode")); + } + if (cmd.hasOption("preonly")) { + PTAConfig.v().getPtaConfig().preAnalysisOnly = true; + } + if (cmd.hasOption("ctxdebloat")) { + PTAConfig.v().getPtaConfig().ctxDebloating = true; + if (cmd.hasOption("debloatapproach")) { + PTAConfig.v().getPtaConfig().debloatApproach = + DebloatedPTA.DebloatApproach.valueOf(cmd.getOptionValue("debloatapproach")); + } + } + if (cmd.hasOption("preciseexceptions")) { + PTAConfig.v().getPtaConfig().preciseExceptions = true; + } + if (cmd.hasOption("modular")) { + Turner.isModular = true; + } + if (cmd.hasOption("precisearray")) { + PTAConfig.v().getPtaConfig().preciseArrayElement = true; } + // application configuration + if (cmd.hasOption("mainclass")) { + PTAConfig.v().getAppConfig().MAIN_CLASS = cmd.getOptionValue("mainclass"); + } + if (cmd.hasOption("jre")) { + PTAConfig.v().getAppConfig().JRE = cmd.getOptionValue("jre"); + } + if (cmd.hasOption("libpath")) { + PTAConfig.v().getAppConfig().LIB_PATH = cmd.getOptionValue("libpath"); + } + if (cmd.hasOption("exclude")) { + PTAConfig.v().getAppConfig().EXCLUDE = parsePackages(cmd.getOptionValue("exclude")); + } + if (cmd.hasOption("reflectionlog")) { + PTAConfig.v().getAppConfig().REFLECTION_LOG = cmd.getOptionValue("reflectionlog"); + } + if (cmd.hasOption("inlcudeall")) { + PTAConfig.v().getAppConfig().INCLUDE_ALL = true; + } + if (cmd.hasOption("turnerconfig")) { + PTAConfig.v().turnerConfig = + PTAConfig.TurnerConfig.valueOf(cmd.getOptionValue("turnerconfig")); + } + // output + if (cmd.hasOption("dumpjimple")) { + PTAConfig.v().getOutConfig().dumpJimple = true; + } + if (cmd.hasOption("dumppts")) { + PTAConfig.v().getOutConfig().dumppts = true; + } + if (cmd.hasOption("dumpallpts")) { + PTAConfig.v().getOutConfig().dumppts = true; + PTAConfig.v().getOutConfig().dumplibpts = true; + } + if (cmd.hasOption("dumpcallgraph")) { + PTAConfig.v().getOutConfig().dumpCallGraph = true; + } + if (cmd.hasOption("dumppag")) { + PTAConfig.v().getOutConfig().dumppag = true; + } + if (cmd.hasOption("dumpstats")) { + PTAConfig.v().getOutConfig().dumpStats = true; + } + } + + static List parsePackages(String packagesString) { + ArrayList pkgList = new ArrayList<>(); + String[] pkgs = packagesString.split(";"); + Collections.addAll(pkgList, pkgs); + return pkgList; + } } diff --git a/sootup.qilin/src/main/java/driver/PTAPattern.java b/sootup.qilin/src/main/java/driver/PTAPattern.java index 9d901994a87..fb59acdcec7 100644 --- a/sootup.qilin/src/main/java/driver/PTAPattern.java +++ b/sootup.qilin/src/main/java/driver/PTAPattern.java @@ -18,204 +18,235 @@ package driver; -import qilin.util.Util; - import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import qilin.util.Util; public class PTAPattern { - private ContextKind ctxKind; - private Approach approach; - private int k, hk; - - public PTAPattern(String ptacmd) { - parsePTACommand(ptacmd); + private ContextKind ctxKind; + private Approach approach; + private int k, hk; + + public PTAPattern(String ptacmd) { + parsePTACommand(ptacmd); + } + + private Pattern getSupportPTAPattern() { + String approachPtn = "(" + String.join("|", Approach.approachAliases()) + ")"; + String ctxLenPtn = "(\\d*)"; + String ctxKindPtn = "(" + String.join("|", ContextKind.contextAliases()) + ")"; + String heapLenPtn = "(\\+?(\\d*)h(eap)?)?"; + String regexPattern = "^(" + approachPtn + "-)?" + ctxLenPtn + ctxKindPtn + heapLenPtn + "$"; + return Pattern.compile(regexPattern); + } + + private void parsePTACommand(String ptacmd) { + Pattern pattern = getSupportPTAPattern(); + Matcher matcher = pattern.matcher(ptacmd); + if (!matcher.find()) { + throw new RuntimeException("Unsupported PTA: " + ptacmd + " !"); } - private Pattern getSupportPTAPattern() { - String approachPtn = "(" + String.join("|", Approach.approachAliases()) + ")"; - String ctxLenPtn = "(\\d*)"; - String ctxKindPtn = "(" + String.join("|", ContextKind.contextAliases()) + ")"; - String heapLenPtn = "(\\+?(\\d*)h(eap)?)?"; - String regexPattern = "^(" + approachPtn + "-)?" + ctxLenPtn + ctxKindPtn + heapLenPtn + "$"; - return Pattern.compile(regexPattern); - } + String approachString = matcher.group(2); + String kString = matcher.group(3); + String typeString = matcher.group(4); + String hkString = matcher.group(6); - private void parsePTACommand(String ptacmd) { - Pattern pattern = getSupportPTAPattern(); - Matcher matcher = pattern.matcher(ptacmd); - if (!matcher.find()) { - throw new RuntimeException("Unsupported PTA: " + ptacmd + " !"); - } - - String approachString = matcher.group(2); - String kString = matcher.group(3); - String typeString = matcher.group(4); - String hkString = matcher.group(6); + approach = Approach.toApproach(approachString); + k = kString.equals("") ? 1 : Integer.parseInt(kString); + ctxKind = ContextKind.toCtxKind(typeString); + hk = hkString == null ? -1 : hkString.equals("") ? 1 : Integer.parseInt(hkString); - approach = Approach.toApproach(approachString); - k = kString.equals("") ? 1 : Integer.parseInt(kString); - ctxKind = ContextKind.toCtxKind(typeString); - hk = hkString == null ? -1 : hkString.equals("") ? 1 : Integer.parseInt(hkString); - - if (k == 0) { - ctxKind = ContextKind.INSENS; + if (k == 0) { + ctxKind = ContextKind.INSENS; + } + if (hk == -1) { + hk = k - 1; + } + validateApproachCompatibility(); + validateContextLength(); + } + + private void validateApproachCompatibility() { + switch (ctxKind) { + case HYBOBJ: + if (approach != Approach.DATADRIVEN + && approach != Approach.NONE + && approach != Approach.TUNNELING) { + throw new RuntimeException( + "Approach <" + + approach.toString() + + " > is currently not designed for hybrid sensitivity"); } - if (hk == -1) { - hk = k - 1; + break; + case HYBTYPE: + if (approach != Approach.NONE) { + throw new RuntimeException( + "Approach <" + + approach.toString() + + " > is currently not designed for hybrid sensitivity"); } - validateApproachCompatibility(); - validateContextLength(); - } - - private void validateApproachCompatibility() { - switch (ctxKind) { - case HYBOBJ: - if (approach != Approach.DATADRIVEN && approach != Approach.NONE && approach != Approach.TUNNELING) { - throw new RuntimeException("Approach <" + approach.toString() + " > is currently not designed for hybrid sensitivity"); - } - break; - case HYBTYPE: - if (approach != Approach.NONE) { - throw new RuntimeException("Approach <" + approach.toString() + " > is currently not designed for hybrid sensitivity"); - } - break; - case TYPE: { - if (approach != Approach.NONE && approach != Approach.TUNNELING) { - throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for type sensitivity."); - } - } - break; - case CALLSITE: { - if (approach != Approach.NONE && approach != Approach.ZIPPER && approach != Approach.MAHJONG - && approach != Approach.DATADRIVEN && approach != Approach.TUNNELING - && approach != Approach.SELECTX - ) { - throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for call-site sensitivity."); - } - } - break; - case OBJECT: { - if (approach != Approach.EAGLE && approach != Approach.ZIPPER && approach != Approach.TURNER && - approach != Approach.DATADRIVEN && approach != Approach.TUNNELING - && approach != Approach.MERCURIAL && approach != Approach.MAHJONG && approach != Approach.BEAN - && approach != Approach.NONE) { - throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for object sensitivity."); - } - } - break; - case INSENS: { - if (approach != Approach.SPARK && approach != Approach.NONE) { - throw new RuntimeException("Approach <" + approach.toString() + "> is currently not designed for context insensitive pointer analysis."); - } - } - default: - break; + break; + case TYPE: + { + if (approach != Approach.NONE && approach != Approach.TUNNELING) { + throw new RuntimeException( + "Approach <" + + approach.toString() + + "> is currently not designed for type sensitivity."); + } } - } - - private void validateContextLength() { - if (ctxKind == ContextKind.INSENS) { - return; + break; + case CALLSITE: + { + if (approach != Approach.NONE + && approach != Approach.ZIPPER + && approach != Approach.MAHJONG + && approach != Approach.DATADRIVEN + && approach != Approach.TUNNELING + && approach != Approach.SELECTX) { + throw new RuntimeException( + "Approach <" + + approach.toString() + + "> is currently not designed for call-site sensitivity."); + } } - if (hk > k) { - throw new RuntimeException("Heap context depth cannot exceed method context depth!"); + break; + case OBJECT: + { + if (approach != Approach.EAGLE + && approach != Approach.ZIPPER + && approach != Approach.TURNER + && approach != Approach.DATADRIVEN + && approach != Approach.TUNNELING + && approach != Approach.MERCURIAL + && approach != Approach.MAHJONG + && approach != Approach.BEAN + && approach != Approach.NONE) { + throw new RuntimeException( + "Approach <" + + approach.toString() + + "> is currently not designed for object sensitivity."); + } } - if (hk < k - 1 && (ctxKind == ContextKind.OBJECT || ctxKind == ContextKind.TYPE)) { - throw new RuntimeException("Heap context depth can only be k or k-1 for object/type-sensitive analysis!"); + break; + case INSENS: + { + if (approach != Approach.SPARK && approach != Approach.NONE) { + throw new RuntimeException( + "Approach <" + + approach.toString() + + "> is currently not designed for context insensitive pointer analysis."); + } } + default: + break; } + } - public ContextKind getContextKind() { - return ctxKind; + private void validateContextLength() { + if (ctxKind == ContextKind.INSENS) { + return; + } + if (hk > k) { + throw new RuntimeException("Heap context depth cannot exceed method context depth!"); } + if (hk < k - 1 && (ctxKind == ContextKind.OBJECT || ctxKind == ContextKind.TYPE)) { + throw new RuntimeException( + "Heap context depth can only be k or k-1 for object/type-sensitive analysis!"); + } + } + + public ContextKind getContextKind() { + return ctxKind; + } - public Approach getApproach() { - return approach; + public Approach getApproach() { + return approach; + } + + public int getContextDepth() { + return k; + } + + public int getHeapContextDepth() { + return hk; + } + + @Override + public String toString() { + if (ctxKind == ContextKind.INSENS) { + return "insensitive"; + } + StringBuilder builder = new StringBuilder(); + if (!approach.toString().isEmpty()) { + builder.append(approach); + builder.append('-'); + } + builder.append(k); + builder.append(ctxKind.toString()); + builder.append('+'); + builder.append(hk); + builder.append("heap"); + return builder.toString(); + } + + public enum Approach { + // for insens + NONE, + SPARK, + // + BEAN, + ZIPPER, + EAGLE, + TURNER, + DATADRIVEN, + TUNNELING, + MERCURIAL, + MAHJONG, + SELECTX; + + static final Map approaches = new HashMap<>(); + + static { + Util.add(approaches, BEAN, "bean", "B"); + Util.add(approaches, ZIPPER, "zipper", "Z"); + Util.add(approaches, EAGLE, "eagle", "E"); + Util.add(approaches, TURNER, "turner", "T"); + Util.add(approaches, MERCURIAL, "mercurial", "hg"); + Util.add(approaches, MAHJONG, "mahjong", "M"); + Util.add(approaches, DATADRIVEN, "datadriven", "D"); + Util.add(approaches, TUNNELING, "tunneling", "t"); + Util.add(approaches, SELECTX, "selectx", "s"); + Util.add(approaches, SPARK, "insens", "ci"); } - public int getContextDepth() { - return k; + public static Collection approachAliases() { + return approaches.keySet(); } - public int getHeapContextDepth() { - return hk; + public static Approach toApproach(String name) { + return approaches.getOrDefault(name, NONE); } @Override public String toString() { - if (ctxKind == ContextKind.INSENS) { - return "insensitive"; - } - StringBuilder builder = new StringBuilder(); - if (!approach.toString().isEmpty()) { - builder.append(approach); - builder.append('-'); - } - builder.append(k); - builder.append(ctxKind.toString()); - builder.append('+'); - builder.append(hk); - builder.append("heap"); - return builder.toString(); - } - - public enum Approach { - // for insens - NONE, - SPARK, - // - BEAN, - ZIPPER, - EAGLE, - TURNER, - DATADRIVEN, - TUNNELING, - MERCURIAL, - MAHJONG, - SELECTX; - - static final Map approaches = new HashMap<>(); - - static { - Util.add(approaches, BEAN, "bean", "B"); - Util.add(approaches, ZIPPER, "zipper", "Z"); - Util.add(approaches, EAGLE, "eagle", "E"); - Util.add(approaches, TURNER, "turner", "T"); - Util.add(approaches, MERCURIAL, "mercurial", "hg"); - Util.add(approaches, MAHJONG, "mahjong", "M"); - Util.add(approaches, DATADRIVEN, "datadriven", "D"); - Util.add(approaches, TUNNELING, "tunneling", "t"); - Util.add(approaches, SELECTX, "selectx", "s"); - Util.add(approaches, SPARK, "insens", "ci"); - } - - public static Collection approachAliases() { - return approaches.keySet(); - } - - public static Approach toApproach(String name) { - return approaches.getOrDefault(name, NONE); - } - - @Override - public String toString() { - return switch (this) { - case DATADRIVEN -> "data-driven"; - case TUNNELING -> "tunneling"; - case BEAN -> "bean"; - case ZIPPER -> "zipper"; - case EAGLE -> "eagle"; - case TURNER -> "turner"; - case MERCURIAL -> "mercurial"; - case MAHJONG -> "mahjong"; - case SELECTX -> "selectx"; - case SPARK -> "spark"; - default -> ""; - }; - } + return switch (this) { + case DATADRIVEN -> "data-driven"; + case TUNNELING -> "tunneling"; + case BEAN -> "bean"; + case ZIPPER -> "zipper"; + case EAGLE -> "eagle"; + case TURNER -> "turner"; + case MERCURIAL -> "mercurial"; + case MAHJONG -> "mahjong"; + case SELECTX -> "selectx"; + case SPARK -> "spark"; + default -> ""; + }; } + } } diff --git a/sootup.qilin/src/main/java/qilin/CoreConfig.java b/sootup.qilin/src/main/java/qilin/CoreConfig.java index 8ad7d08bd9e..131ba87741f 100644 --- a/sootup.qilin/src/main/java/qilin/CoreConfig.java +++ b/sootup.qilin/src/main/java/qilin/CoreConfig.java @@ -18,161 +18,134 @@ package qilin; -import soot.SourceLocator; - import java.util.List; public class CoreConfig { - protected static CoreConfig coreConfig = null; - - public static CoreConfig v() { - if (coreConfig == null) { - throw new RuntimeException("Core configuration is not initialized!"); - } - return coreConfig; - } - - public static void reset() { - coreConfig = null; - } - - public enum ClinitMode { - FULL, ONFLY, APP - } - - public static class CorePTAConfiguration { - public boolean singleentry = false; - /** - * Clinit loading mode: - * APP: A debug mode for testing which load only the minimum of classes needed. - * FULL: load all of classes that are currently loaded in the scene. - * ON_THE_FLY: we load on the fly, this mode is same as DOOP (default mode). - */ - public ClinitMode clinitMode = ClinitMode.ONFLY; - - /** - * enable to merge heaps like StringBuilder/StringBuffer, exceptions by types. - */ - public boolean mergeHeap = false; - - /** - * the type of array element is java.lang.Object by default. - * if set to be true, we will use more precise type for array elements. - */ - public boolean preciseArrayElement = false; - - /** - * in qilin.spark propagate all string constants false means merge all string - * constants, see the corresponding flag, DISTINGUISH_NO_STRING_CONSTANTS, in DOOP. - */ - public boolean stringConstants = false; - - /** - * The default setting (same as the imprecise version in Doop): - * there is a global variable for all thrown exceptions and - * any caught exception variable points to all those exceptions. - * Obviously, this is extremely imprecise. - *

- * This imprecision does not seem to matter too much for typical - * programs in the context-insensitive and 1-call-site-sensitive - * analyses, but is disastrous in the 1-object-sensitive analysis. - *

- * once this switch is open, it will model exception flow-sensitively - * (same as the precise version in Doop). - * Implicitly thrown exceptions are not included. - */ - public boolean preciseExceptions = false; - - /** - * in qilin.spark limit heap context for strings if we are object sensitive - */ - public boolean enforceEmptyCtxForIgnoreTypes = false; - - public String ptaName; - } + protected static CoreConfig coreConfig = null; - public static class ApplicationConfiguration { - /** - * Path for the root folder for the application classes or for the application - * jar file. - */ - public String APP_PATH = "."; - /** - * Path for the JRE to be used for whole program analysis. - */ - public String JRE = null; - /** - * Path for the root folder for the library jars. - */ - public String LIB_PATH = null; - - /** - * Path for the reflection log file for the application. - */ - public String REFLECTION_LOG = null; - - /** - * Main class for the application. - */ - public String MAIN_CLASS = null; - - /** - * include selected packages which are not analyzed by default - */ - public List INCLUDE = null; - /** - * exclude selected packages - */ - public List EXCLUDE = null; - /** - * include packages which are not analyzed by default - */ - public boolean INCLUDE_ALL = false; + public static CoreConfig v() { + if (coreConfig == null) { + throw new RuntimeException("Core configuration is not initialized!"); } + return coreConfig; + } - public static class OutputConfiguration { - public String outDir = SourceLocator.v().getOutputDir(); - /** - * dump appclasses to jimple - */ - public boolean dumpJimple = false; - /** - * if true, dump pts in app code to a file - */ - public boolean dumppts = false; - /** - * if true, dump pts of vars in library - */ - public boolean dumplibpts = false; - /** - * print a CG graph - */ - public boolean dumpCallGraph = false; - /** - * print a PAG graph - */ - public boolean dumppag = false; - - /** - * if true, dump stats into files. - */ - public boolean dumpStats = false; - } - - protected CorePTAConfiguration ptaConfig; - protected final ApplicationConfiguration appConfig = new ApplicationConfiguration(); - protected final OutputConfiguration outConfig = new OutputConfiguration(); - - public CorePTAConfiguration getPtaConfig() { - return ptaConfig; - } - - public ApplicationConfiguration getAppConfig() { - return appConfig; - } - - public OutputConfiguration getOutConfig() { - return outConfig; - } + public static void reset() { + coreConfig = null; + } + public enum ClinitMode { + FULL, + ONFLY, + APP + } + + public static class CorePTAConfiguration { + public boolean singleentry = false; + + /** + * Clinit loading mode: APP: A debug mode for testing which load only the minimum of + * classes needed. FULL: load all of classes that are currently loaded in the scene. + * ON_THE_FLY: we load on the fly, this mode is same as DOOP (default mode). + */ + public ClinitMode clinitMode = ClinitMode.ONFLY; + + /** enable to merge heaps like StringBuilder/StringBuffer, exceptions by types. */ + public boolean mergeHeap = false; + + /** + * the type of array element is java.lang.Object by default. if set to be true, we will use more + * precise type for array elements. + */ + public boolean preciseArrayElement = false; + + /** + * in qilin.spark propagate all string constants false means merge all string constants, see the + * corresponding flag, DISTINGUISH_NO_STRING_CONSTANTS, in DOOP. + */ + public boolean stringConstants = false; + + /** + * The default setting (same as the imprecise version in Doop): there is a global variable for + * all thrown exceptions and any caught exception variable points to all those exceptions. + * Obviously, this is extremely imprecise. + * + *

This imprecision does not seem to matter too much for typical programs in the + * context-insensitive and 1-call-site-sensitive analyses, but is disastrous in the + * 1-object-sensitive analysis. + * + *

once this switch is open, it will model exception flow-sensitively (same as the precise + * version in Doop). Implicitly thrown exceptions are not included. + */ + public boolean preciseExceptions = false; + + /** in qilin.spark limit heap context for strings if we are object sensitive */ + public boolean enforceEmptyCtxForIgnoreTypes = false; + + public String ptaName; + } + + public static class ApplicationConfiguration { + /** Path for the root folder for the application classes or for the application jar file. */ + public String APP_PATH = "."; + + /** Path for the JRE to be used for whole program analysis. */ + public String JRE = null; + + /** Path for the root folder for the library jars. */ + public String LIB_PATH = null; + + /** Path for the reflection log file for the application. */ + public String REFLECTION_LOG = null; + + /** Main class for the application. */ + public String MAIN_CLASS = null; + + /** include selected packages which are not analyzed by default */ + public List INCLUDE = null; + + /** exclude selected packages */ + public List EXCLUDE = null; + + /** include packages which are not analyzed by default */ + public boolean INCLUDE_ALL = false; + } + + public static class OutputConfiguration { + public String outDir = ""; + + /** dump appclasses to jimple */ + public boolean dumpJimple = false; + + /** if true, dump pts in app code to a file */ + public boolean dumppts = false; + + /** if true, dump pts of vars in library */ + public boolean dumplibpts = false; + + /** print a CG graph */ + public boolean dumpCallGraph = false; + + /** print a PAG graph */ + public boolean dumppag = false; + + /** if true, dump stats into files. */ + public boolean dumpStats = false; + } + + protected CorePTAConfiguration ptaConfig; + protected final ApplicationConfiguration appConfig = new ApplicationConfiguration(); + protected final OutputConfiguration outConfig = new OutputConfiguration(); + + public CorePTAConfiguration getPtaConfig() { + return ptaConfig; + } + + public ApplicationConfiguration getAppConfig() { + return appConfig; + } + + public OutputConfiguration getOutConfig() { + return outConfig; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java index a77a97bd731..cd0d2bf8eb4 100644 --- a/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/ArtificialMethod.java @@ -18,6 +18,9 @@ package qilin.core; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import qilin.util.PTAUtils; import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Immediate; @@ -39,156 +42,160 @@ import sootup.core.types.ArrayType; import sootup.core.types.ClassType; import sootup.core.types.Type; +import sootup.core.views.View; import sootup.java.core.JavaIdentifierFactory; import sootup.java.core.language.JavaJimple; -import java.util.Arrays; -import java.util.List; - public abstract class ArtificialMethod { - protected SootMethod method; - protected Body.BodyBuilder bodyBuilder; - protected Local thisLocal; - protected Local[] paraLocals; - protected int paraStart; - protected int localStart; - - protected Local getThis() { - if (thisLocal == null) { - ClassType type = method.getDeclaringClassType(); - IdentityRef thisRef = new JThisRef(type); - thisLocal = getLocal(type, 0); - addIdentity(thisLocal, thisRef); - } - return thisLocal; - } - - protected Local getPara(int index) { - Local paraLocal = paraLocals[index]; - if (paraLocal == null) { - Type type = method.getParameterType(index); - return getPara(index, type); - } - return paraLocal; - } - - protected Local getPara(int index, Type type) { - Local paraLocal = paraLocals[index]; - if (paraLocal == null) { - IdentityRef paraRef = new JParameterRef(type, index); - paraLocal = getLocal(type, paraStart + index); - addIdentity(paraLocal, paraRef); - paraLocals[index] = paraLocal; - } - return paraLocal; - } - - private void addIdentity(Local lValue, IdentityRef rValue) { - Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); - Stmt identityStmt = Jimple.newIdentityStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo()); - bodyBuilder.addFlow(startingStmt, identityStmt); - } - - protected Local getNew(ClassType type) { - Value newExpr = new JNewExpr(type); - Local local = getNextLocal(type); - addAssign(local, newExpr); - return local; - } - - protected Immediate getNewArray(ClassType type) { - Value newExpr = JavaJimple.getInstance().newNewArrayExpr(type, IntConstant.getInstance(1)); - Local local = getNextLocal(new ArrayType(type, 1)); - addAssign(local, newExpr); - return local; - } - - protected Local getNextLocal(Type type) { - return getLocal(type, localStart++); - } - - private Local getLocal(Type type, int index) { - Local local = Jimple.newLocal("r" + index, type); - bodyBuilder.addLocal(local); - return local; - } - - protected void addReturn(Immediate ret) { - Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); - Stmt stmt = Jimple.newReturnStmt(ret, StmtPositionInfo.createNoStmtPositionInfo()); - bodyBuilder.addFlow(startingStmt, stmt); - } - - protected Value getStaticFieldRef(String className, String name) { - ClassType classType = PTAUtils.getClassType(className); - SootClass sc = (SootClass) PTAScene.v().getView().getClass(classType).get(); - SootField field = (SootField) sc.getField(name).get(); - return Jimple.newStaticFieldRef(field.getSignature()); - } - - protected Value getArrayRef(Value base) { - return JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); - } - - /** - * add an instance invocation receiver.sig(args) - */ - protected void addInvoke(Local receiver, String sig, Immediate ... args) { - MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); - SootMethod method = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); - SootClass clazz = (SootClass) PTAScene.v().getView().getClass(method.getDeclaringClassType()).get(); - List argsL = Arrays.asList(args); - AbstractInvokeExpr invoke = clazz.isInterface() ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) - : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); - Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); - Stmt stmt = Jimple.newInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo()); - bodyBuilder.addFlow(startingStmt, stmt); - } - - /** - * add an instance invocation and get the return value rx = receiver.sig(args) - * - * @return rx - */ - protected Local getInvoke(Local receiver, String sig, Immediate... args) { - MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); - SootMethod method = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); - SootClass clazz = (SootClass) PTAScene.v().getView().getClass(method.getDeclaringClassType()).get(); - List argsL = Arrays.asList(args); - Value invoke = clazz.isInterface() ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) - : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); - Local rx = getNextLocal(method.getReturnType()); - addAssign(rx, invoke); - return rx; - } - - /** - * add a static invocation sig(args) - */ - protected void addInvoke(String sig, Immediate... args) { - MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); - List argsL = Arrays.asList(args); - Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); - Stmt stmt = Jimple.newInvokeStmt(Jimple.newStaticInvokeExpr(methodSig, argsL), StmtPositionInfo.createNoStmtPositionInfo()); - bodyBuilder.addFlow(startingStmt, stmt); - } - - /** - * add a static invocation and get the return value rx = sig(args) - * - * @return rx - */ - protected Value getInvoke(String sig, Immediate... args) { - MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); - List argsL = Arrays.asList(args); - Value rx = getNextLocal(methodSig.getType()); - addAssign(rx, Jimple.newStaticInvokeExpr(methodSig, argsL)); - return rx; - } - - protected void addAssign(Value lValue, Value rValue) { - Stmt startingStmt = bodyBuilder.getStmtGraph().getStartingStmt(); - Stmt stmt = Jimple.newAssignStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo()); - bodyBuilder.addFlow(startingStmt, stmt); - } + protected final View view; + protected SootMethod method; + protected Body.BodyBuilder bodyBuilder; + protected Local thisLocal; + protected Local[] paraLocals; + protected int paraStart; + protected int localStart; + protected final List stmtList; + + protected ArtificialMethod(View view) { + this.view = view; + this.stmtList = new ArrayList<>(); + } + + protected Local getThis() { + if (thisLocal == null) { + ClassType type = method.getDeclaringClassType(); + IdentityRef thisRef = new JThisRef(type); + thisLocal = getLocal(type, 0); + addIdentity(thisLocal, thisRef); + } + return thisLocal; + } + + protected Local getPara(int index) { + Local paraLocal = paraLocals[index]; + if (paraLocal == null) { + Type type = method.getParameterType(index); + return getPara(index, type); + } + return paraLocal; + } + + protected Local getPara(int index, Type type) { + Local paraLocal = paraLocals[index]; + if (paraLocal == null) { + IdentityRef paraRef = new JParameterRef(type, index); + paraLocal = getLocal(type, paraStart + index); + addIdentity(paraLocal, paraRef); + paraLocals[index] = paraLocal; + } + return paraLocal; + } + + private void addIdentity(Local lValue, IdentityRef rValue) { + Stmt identityStmt = + Jimple.newIdentityStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + stmtList.add(identityStmt); + } + + protected Local getNew(ClassType type) { + Value newExpr = new JNewExpr(type); + Local local = getNextLocal(type); + addAssign(local, newExpr); + return local; + } + + protected Immediate getNewArray(ClassType type) { + Value newExpr = JavaJimple.getInstance().newNewArrayExpr(type, IntConstant.getInstance(1)); + Local local = getNextLocal(new ArrayType(type, 1)); + addAssign(local, newExpr); + return local; + } + + protected Local getNextLocal(Type type) { + return getLocal(type, localStart++); + } + + private Local getLocal(Type type, int index) { + Local local = Jimple.newLocal("r" + index, type); + bodyBuilder.addLocal(local); + return local; + } + + protected void addReturn(Immediate ret) { + Stmt stmt = Jimple.newReturnStmt(ret, StmtPositionInfo.createNoStmtPositionInfo()); + stmtList.add(stmt); + } + + protected Value getStaticFieldRef(String className, String name) { + ClassType classType = PTAUtils.getClassType(className); + SootClass sc = (SootClass) view.getClass(classType).get(); + SootField field = (SootField) sc.getField(name).get(); + return Jimple.newStaticFieldRef(field.getSignature()); + } + + protected Value getArrayRef(Value base) { + return JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); + } + + /** add an instance invocation receiver.sig(args) */ + protected void addInvoke(Local receiver, String sig, Immediate... args) { + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); + SootMethod method = (SootMethod) view.getMethod(methodSig).get(); + SootClass clazz = (SootClass) view.getClass(method.getDeclaringClassType()).get(); + List argsL = Arrays.asList(args); + AbstractInvokeExpr invoke = + clazz.isInterface() + ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) + : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); + Stmt stmt = Jimple.newInvokeStmt(invoke, StmtPositionInfo.createNoStmtPositionInfo()); + stmtList.add(stmt); + } + + /** + * add an instance invocation and get the return value rx = receiver.sig(args) + * + * @return rx + */ + protected Local getInvoke(Local receiver, String sig, Immediate... args) { + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); + SootMethod method = (SootMethod) view.getMethod(methodSig).get(); + SootClass clazz = (SootClass) view.getClass(method.getDeclaringClassType()).get(); + List argsL = Arrays.asList(args); + Value invoke = + clazz.isInterface() + ? Jimple.newInterfaceInvokeExpr(receiver, methodSig, argsL) + : Jimple.newVirtualInvokeExpr(receiver, methodSig, argsL); + Local rx = getNextLocal(method.getReturnType()); + addAssign(rx, invoke); + return rx; + } + + /** add a static invocation sig(args) */ + protected void addInvoke(String sig, Immediate... args) { + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); + List argsL = Arrays.asList(args); + Stmt stmt = + Jimple.newInvokeStmt( + Jimple.newStaticInvokeExpr(methodSig, argsL), + StmtPositionInfo.createNoStmtPositionInfo()); + stmtList.add(stmt); + } + + /** + * add a static invocation and get the return value rx = sig(args) + * + * @return rx + */ + protected Value getInvoke(String sig, Immediate... args) { + MethodSignature methodSig = JavaIdentifierFactory.getInstance().parseMethodSignature(sig); + List argsL = Arrays.asList(args); + Value rx = getNextLocal(methodSig.getType()); + addAssign(rx, Jimple.newStaticInvokeExpr(methodSig, argsL)); + return rx; + } + + protected void addAssign(Value lValue, Value rValue) { + Stmt stmt = Jimple.newAssignStmt(lValue, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + stmtList.add(stmt); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/CorePTA.java b/sootup.qilin/src/main/java/qilin/core/CorePTA.java index 60cc698a46d..75131b5e2af 100644 --- a/sootup.qilin/src/main/java/qilin/core/CorePTA.java +++ b/sootup.qilin/src/main/java/qilin/core/CorePTA.java @@ -30,93 +30,91 @@ * This represents a parameterized PTA which could be concreted to many pointer analyses. * */ public abstract class CorePTA extends PTA { - /* - * The following three parameterized functions must be initialized before doing the pointer analysis. - * */ - protected CtxConstructor ctxCons; - protected CtxSelector ctxSel; - protected HeapAbstractor heapAbst; - - public CtxSelector ctxSelector() { - return ctxSel; + /* + * The following three parameterized functions must be initialized before doing the pointer analysis. + * */ + protected CtxConstructor ctxCons; + protected CtxSelector ctxSel; + protected HeapAbstractor heapAbst; + + public CtxSelector ctxSelector() { + return ctxSel; + } + + public void setContextSelector(CtxSelector ctxSelector) { + this.ctxSel = ctxSelector; + } + + public CtxConstructor ctxConstructor() { + return ctxCons; + } + + public HeapAbstractor heapAbstractor() { + return this.heapAbst; + } + + public abstract Propagator getPropagator(); + + @Override + public Context createCalleeCtx( + MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + return ctxCons.constructCtx(caller, (ContextAllocNode) receiverNode, callSite, target); + } + + public Context emptyContext() { + return CtxConstructor.emptyContext; + } + + @Override + public Node parameterize(Node n, Context context) { + if (context == null) { + throw new RuntimeException("null context!!!"); } - - public void setContextSelector(CtxSelector ctxSelector) { - this.ctxSel = ctxSelector; + if (n instanceof LocalVarNode lvn) { + return parameterize(lvn, context); } - - public CtxConstructor ctxConstructor() { - return ctxCons; + if (n instanceof FieldRefNode frn) { + return parameterize(frn, context); } - - public HeapAbstractor heapAbstractor() { - return this.heapAbst; + if (n instanceof AllocNode an) { + return parameterize(an, context); } - - public abstract Propagator getPropagator(); - - @Override - public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { - return ctxCons.constructCtx(caller, (ContextAllocNode) receiverNode, callSite, target); + if (n instanceof FieldValNode fvn) { + return parameterize(fvn, context); } - - public Context emptyContext() { - return CtxConstructor.emptyContext; - } - - @Override - public Node parameterize(Node n, Context context) { - if (context == null) { - throw new RuntimeException("null context!!!"); - } - if (n instanceof LocalVarNode lvn) { - return parameterize(lvn, context); - } - if (n instanceof FieldRefNode frn) { - return parameterize(frn, context); - } - if (n instanceof AllocNode an) { - return parameterize(an, context); - } - if (n instanceof FieldValNode fvn) { - return parameterize(fvn, context); - } - if (n instanceof GlobalVarNode gvn) { - return pag.makeContextVarNode(gvn, emptyContext()); - } - throw new RuntimeException("cannot parameterize this node: " + n); - - } - - public ContextField parameterize(FieldValNode fvn, Context context) { - Context ctx = ctxSel.select(fvn, context); - return pag.makeContextField(ctx, fvn); - } - - protected ContextVarNode parameterize(LocalVarNode vn, Context context) { - Context ctx = ctxSel.select(vn, context); - return pag.makeContextVarNode(vn, ctx); - } - - protected FieldRefNode parameterize(FieldRefNode frn, Context context) { - return pag.makeFieldRefNode((VarNode) parameterize(frn.getBase(), context), frn.getField()); - } - - protected ContextAllocNode parameterize(AllocNode node, Context context) { - Context ctx = ctxSel.select(node, context); - return pag.makeContextAllocNode(node, ctx); - } - - /** - * Finds or creates the ContextMethod for method and context. - */ - @Override - public MethodOrMethodContext parameterize(SootMethod method, Context context) { - Context ctx = ctxSel.select(method, context); - return pag.makeContextMethod(ctx, method); - } - - public AllocNode getRootNode() { - return rootNode; + if (n instanceof GlobalVarNode gvn) { + return pag.makeContextVarNode(gvn, emptyContext()); } + throw new RuntimeException("cannot parameterize this node: " + n); + } + + public ContextField parameterize(FieldValNode fvn, Context context) { + Context ctx = ctxSel.select(fvn, context); + return pag.makeContextField(ctx, fvn); + } + + protected ContextVarNode parameterize(LocalVarNode vn, Context context) { + Context ctx = ctxSel.select(vn, context); + return pag.makeContextVarNode(vn, ctx); + } + + protected FieldRefNode parameterize(FieldRefNode frn, Context context) { + return pag.makeFieldRefNode((VarNode) parameterize(frn.getBase(), context), frn.getField()); + } + + protected ContextAllocNode parameterize(AllocNode node, Context context) { + Context ctx = ctxSel.select(node, context); + return pag.makeContextAllocNode(node, ctx); + } + + /** Finds or creates the ContextMethod for method and context. */ + @Override + public MethodOrMethodContext parameterize(SootMethod method, Context context) { + Context ctx = ctxSel.select(method, context); + return pag.makeContextMethod(ctx, method); + } + + public AllocNode getRootNode() { + return rootNode; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/PTA.java b/sootup.qilin/src/main/java/qilin/core/PTA.java index 08cd5c6325a..5e96c36d064 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTA.java +++ b/sootup.qilin/src/main/java/qilin/core/PTA.java @@ -18,6 +18,9 @@ package qilin.core; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import qilin.core.builder.CallGraphBuilder; import qilin.core.builder.ExceptionHandler; import qilin.core.pag.*; @@ -35,228 +38,229 @@ import sootup.core.model.SootField; import sootup.core.model.SootMethod; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - public abstract class PTA implements PointsToAnalysis { - protected AllocNode rootNode; - protected PAG pag; - protected CallGraph callGraph; - protected CallGraphBuilder cgb; - protected ExceptionHandler eh; - - public PTA() { - this.pag = createPAG(); - this.cgb = createCallGraphBuilder(); - this.eh = new ExceptionHandler(this); - AllocNode rootBase = pag.makeAllocNode("ROOT", PTAUtils.getClassType("java.lang.Object"), null); - this.rootNode = new ContextAllocNode(rootBase, CtxConstructor.emptyContext); - } + protected AllocNode rootNode; + protected PAG pag; + protected CallGraph callGraph; + protected CallGraphBuilder cgb; + protected ExceptionHandler eh; - protected abstract PAG createPAG(); + public PTA() { + this.pag = createPAG(); + this.cgb = createCallGraphBuilder(); + this.eh = new ExceptionHandler(this); + AllocNode rootBase = pag.makeAllocNode("ROOT", PTAUtils.getClassType("java.lang.Object"), null); + this.rootNode = new ContextAllocNode(rootBase, CtxConstructor.emptyContext); + } - protected abstract CallGraphBuilder createCallGraphBuilder(); + protected abstract PAG createPAG(); - public void run() { - pureRun(); - } + protected abstract CallGraphBuilder createCallGraphBuilder(); - public void pureRun() { - getPropagator().propagate(); - } + public void run() { + pureRun(); + } - public PAG getPag() { - return pag; - } + public void pureRun() { + getPropagator().propagate(); + } - public CallGraphBuilder getCgb() { - return cgb; - } + public PAG getPag() { + return pag; + } - public ExceptionHandler getExceptionHandler() { - return eh; - } + public CallGraphBuilder getCgb() { + return cgb; + } - public CallGraph getCallGraph() { - if (callGraph == null) { - callGraph = cgb.getCICallGraph(); - } - return callGraph; - } + public ExceptionHandler getExceptionHandler() { + return eh; + } - public Collection getReachableMethods() { - return cgb.getReachableMethods(); + public CallGraph getCallGraph() { + if (callGraph == null) { + callGraph = cgb.getCICallGraph(); } + return callGraph; + } - private Set nakedReachables = null; + public Collection getReachableMethods() { + return cgb.getReachableMethods(); + } - public Collection getNakedReachableMethods() { - if (nakedReachables == null) { - nakedReachables = new HashSet<>(); - cgb.getReachableMethods().forEach(momc -> nakedReachables.add(momc.method())); - } - return nakedReachables; - } + private Set nakedReachables = null; - protected abstract Propagator getPropagator(); + public Collection getNakedReachableMethods() { + if (nakedReachables == null) { + nakedReachables = new HashSet<>(); + cgb.getReachableMethods().forEach(momc -> nakedReachables.add(momc.method())); + } + return nakedReachables; + } - public abstract Node parameterize(Node n, Context context); + protected abstract Propagator getPropagator(); - public abstract MethodOrMethodContext parameterize(SootMethod method, Context context); + public abstract Node parameterize(Node n, Context context); - public abstract AllocNode getRootNode(); + public abstract MethodOrMethodContext parameterize(SootMethod method, Context context); - public abstract Context emptyContext(); + public abstract AllocNode getRootNode(); - public abstract Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target); + public abstract Context emptyContext(); - public abstract HeapAbstractor heapAbstractor(); + public abstract Context createCalleeCtx( + MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target); - public abstract CtxConstructor ctxConstructor(); + public abstract HeapAbstractor heapAbstractor(); - public abstract CtxSelector ctxSelector(); + public abstract CtxConstructor ctxConstructor(); - /** - * Returns the set of objects pointed to by variable l. - */ - @Override - public PointsToSet reachingObjects(Local l) { - // find all context nodes, and collect their answers - final PointsToSetInternal ret = new HybridPointsToSet(); - pag.getVarNodes(l).forEach(vn -> { - ret.addAll(vn.getP2Set(), null); - }); - return new UnmodifiablePointsToSet(this, ret); - } + public abstract CtxSelector ctxSelector(); - /** - * Returns the set of objects pointed by n: - * case 1: n is an insensitive node, return objects pointed by n under every possible context. - * case 2: n is a context-sensitive node, return objects pointed by n under the given context. - */ - public PointsToSet reachingObjects(Node n) { - final PointsToSetInternal ret; - if (n instanceof ContextVarNode cvn) { - ret = cvn.getP2Set(); - } else if (n instanceof ContextField cf) { - ret = cf.getP2Set(); - } else { - VarNode varNode = (VarNode) n; - ret = new HybridPointsToSet(); - if (pag.getContextVarNodeMap().containsKey(varNode)) { - pag.getContextVarNodeMap().get(varNode).values().forEach(vn -> { - ret.addAll(vn.getP2Set(), null); + /** Returns the set of objects pointed to by variable l. */ + @Override + public PointsToSet reachingObjects(Local l) { + // find all context nodes, and collect their answers + final PointsToSetInternal ret = new HybridPointsToSet(); + pag.getVarNodes(l) + .forEach( + vn -> { + ret.addAll(vn.getP2Set(), null); + }); + return new UnmodifiablePointsToSet(this, ret); + } + + /** + * Returns the set of objects pointed by n: case 1: n is an insensitive node, return objects + * pointed by n under every possible context. case 2: n is a context-sensitive node, return + * objects pointed by n under the given context. + */ + public PointsToSet reachingObjects(Node n) { + final PointsToSetInternal ret; + if (n instanceof ContextVarNode cvn) { + ret = cvn.getP2Set(); + } else if (n instanceof ContextField cf) { + ret = cf.getP2Set(); + } else { + VarNode varNode = (VarNode) n; + ret = new HybridPointsToSet(); + if (pag.getContextVarNodeMap().containsKey(varNode)) { + pag.getContextVarNodeMap() + .get(varNode) + .values() + .forEach( + vn -> { + ret.addAll(vn.getP2Set(), null); }); - } - } - return new UnmodifiablePointsToSet(this, ret); + } } - - /** - * Returns the set of objects pointed to by elements of the arrays in the - * PointsToSet s. - */ - @Override - public PointsToSet reachingObjectsOfArrayElement(PointsToSet s) { - return reachingObjectsInternal(s, ArrayElement.v()); + return new UnmodifiablePointsToSet(this, ret); + } + + /** Returns the set of objects pointed to by elements of the arrays in the PointsToSet s. */ + @Override + public PointsToSet reachingObjectsOfArrayElement(PointsToSet s) { + return reachingObjectsInternal(s, ArrayElement.v()); + } + + /** Returns the set of objects pointed to by variable l in context c. */ + @Override + public PointsToSet reachingObjects(Context c, Local l) { + VarNode n = pag.findContextVarNode(l, c); + PointsToSetInternal pts; + if (n == null) { + pts = HybridPointsToSet.getEmptySet(); + } else { + pts = n.getP2Set(); } - - /** - * Returns the set of objects pointed to by variable l in context c. - */ - @Override - public PointsToSet reachingObjects(Context c, Local l) { - VarNode n = pag.findContextVarNode(l, c); - PointsToSetInternal pts; - if (n == null) { - pts = HybridPointsToSet.getEmptySet(); - } else { - pts = n.getP2Set(); - } - return new UnmodifiablePointsToSet(this, pts); + return new UnmodifiablePointsToSet(this, pts); + } + + /** Returns the set of objects pointed to by instance field f of the objects pointed to by l. */ + @Override + public PointsToSet reachingObjects(Local l, SootField f) { + return reachingObjects(reachingObjects(l), f); + } + + /** + * Returns the set of objects pointed to by instance field f of the objects in the PointsToSet s. + */ + @Override + public PointsToSet reachingObjects(PointsToSet s, final SootField f) { + if (f.isStatic()) { + throw new RuntimeException("The parameter f must be an *instance* field."); } - - /** - * Returns the set of objects pointed to by instance field f of the objects - * pointed to by l. - */ - @Override - public PointsToSet reachingObjects(Local l, SootField f) { - return reachingObjects(reachingObjects(l), f); - } - - /** - * Returns the set of objects pointed to by instance field f of the objects in - * the PointsToSet s. - */ - @Override - public PointsToSet reachingObjects(PointsToSet s, final SootField f) { - if (f.isStatic()) { - throw new RuntimeException("The parameter f must be an *instance* field."); - } - return reachingObjectsInternal(s, new Field(f)); - } - - /** - * Returns the set of objects pointed to by instance field f of the objects - * pointed to by l in context c. - */ - @Override - public PointsToSet reachingObjects(Context c, Local l, SootField f) { - return reachingObjects(reachingObjects(c, l), f); - } - - @Override - public PointsToSet reachingObjects(SootField f) { - PointsToSetInternal ret; - if (f.isStatic()) { - VarNode n = pag.findGlobalVarNode(f); - if (n == null) { - ret = HybridPointsToSet.getEmptySet(); - } else { - ret = n.getP2Set(); - } - } else { - ret = new HybridPointsToSet(); - SparkField sparkField = new Field(f); - pag.getContextFieldVarNodeMap().values().stream().filter(map -> map.containsKey(sparkField)).forEach(map -> { + return reachingObjectsInternal(s, new Field(f)); + } + + /** + * Returns the set of objects pointed to by instance field f of the objects pointed to by l in + * context c. + */ + @Override + public PointsToSet reachingObjects(Context c, Local l, SootField f) { + return reachingObjects(reachingObjects(c, l), f); + } + + @Override + public PointsToSet reachingObjects(SootField f) { + PointsToSetInternal ret; + if (f.isStatic()) { + VarNode n = pag.findGlobalVarNode(f); + if (n == null) { + ret = HybridPointsToSet.getEmptySet(); + } else { + ret = n.getP2Set(); + } + } else { + ret = new HybridPointsToSet(); + SparkField sparkField = new Field(f); + pag.getContextFieldVarNodeMap().values().stream() + .filter(map -> map.containsKey(sparkField)) + .forEach( + map -> { ContextField contextField = map.get(sparkField); ret.addAll(contextField.getP2Set(), null); - }); - } - return new UnmodifiablePointsToSet(this, ret); + }); } - - public PointsToSet reachingObjectsInternal(PointsToSet bases, final SparkField f) { - final PointsToSetInternal ret = new HybridPointsToSet(); - pag.getContextFieldVarNodeMap().values().stream().filter(map -> map.containsKey(f)).forEach(map -> { - ContextField contextField = map.get(f); - AllocNode base = contextField.getBase(); - if (bases.contains(base)) { + return new UnmodifiablePointsToSet(this, ret); + } + + public PointsToSet reachingObjectsInternal(PointsToSet bases, final SparkField f) { + final PointsToSetInternal ret = new HybridPointsToSet(); + pag.getContextFieldVarNodeMap().values().stream() + .filter(map -> map.containsKey(f)) + .forEach( + map -> { + ContextField contextField = map.get(f); + AllocNode base = contextField.getBase(); + if (bases.contains(base)) { ret.addAll(contextField.getP2Set(), null); - } - }); - return new UnmodifiablePointsToSet(this, ret); - } - - public PointsToSet reachingObjectsInternal(AllocNode heap, final SparkField f) { - final PointsToSetInternal ret = new HybridPointsToSet(); - pag.getContextFieldVarNodeMap().values().stream().filter(map -> map.containsKey(f)).forEach(map -> { - ContextField contextField = map.get(f); - AllocNode base = contextField.getBase(); - if (heap.equals(base)) { + } + }); + return new UnmodifiablePointsToSet(this, ret); + } + + public PointsToSet reachingObjectsInternal(AllocNode heap, final SparkField f) { + final PointsToSetInternal ret = new HybridPointsToSet(); + pag.getContextFieldVarNodeMap().values().stream() + .filter(map -> map.containsKey(f)) + .forEach( + map -> { + ContextField contextField = map.get(f); + AllocNode base = contextField.getBase(); + if (heap.equals(base)) { ret.addAll(contextField.getP2Set(), null); - } - }); - return new UnmodifiablePointsToSet(this, ret); - } - - @Override - public boolean mayAlias(Local l1, Local l2) { - PointsToSet pts1 = reachingObjects(l1).toCIPointsToSet(); - PointsToSet pts2 = reachingObjects(l2).toCIPointsToSet(); - return pts1.hasNonEmptyIntersection(pts2); - } + } + }); + return new UnmodifiablePointsToSet(this, ret); + } + + @Override + public boolean mayAlias(Local l1, Local l2) { + PointsToSet pts1 = reachingObjects(l1).toCIPointsToSet(); + PointsToSet pts2 = reachingObjects(l2).toCIPointsToSet(); + return pts1.hasNonEmptyIntersection(pts2); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/PTAScene.java b/sootup.qilin/src/main/java/qilin/core/PTAScene.java index 94f074ba475..095c8612fdc 100644 --- a/sootup.qilin/src/main/java/qilin/core/PTAScene.java +++ b/sootup.qilin/src/main/java/qilin/core/PTAScene.java @@ -18,11 +18,23 @@ package qilin.core; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import qilin.core.builder.FakeMainFactory; +import qilin.pta.PTAConfig; import qilin.util.DataFactory; import qilin.util.PTAUtils; import soot.jimple.toolkits.callgraph.CallGraph; -import soot.util.Chain; +import sootup.core.inputlocation.ClassLoadingOptions; import sootup.core.jimple.basic.Value; import sootup.core.model.SootClass; import sootup.core.model.SootField; @@ -32,198 +44,218 @@ import sootup.core.types.ClassType; import sootup.core.types.Type; import sootup.core.views.View; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.bytecode.interceptors.TypeAssigner; import sootup.java.core.JavaIdentifierFactory; - -import java.util.Collection; -import java.util.Collections; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; +import sootup.java.core.JavaProject; +import sootup.java.core.language.JavaLanguage; +import sootup.java.core.views.JavaView; public class PTAScene { - private static volatile PTAScene instance = null; - - private final View view; - private CallGraph callgraph; - private final FakeMainFactory fakeMainFactory; + private static final Logger logger = LoggerFactory.getLogger(PTAScene.class); + private static volatile PTAScene instance = null; - private SootClass mainClass = null; + private final View view; + private CallGraph callgraph; + private final FakeMainFactory fakeMainFactory; - public void setMainClass(SootClass m) { - mainClass = m; - } - - public boolean hasMainClass() { - return mainClass != null; - } + private SootClass mainClass = null; - public SootClass getMainClass() { - if (!hasMainClass()) { - throw new RuntimeException("There is no main class set!"); - } - return mainClass; - } + public void setMainClass(SootClass m) { + mainClass = m; + } - public static PTAScene v() { + public static PTAScene v() { + if (instance == null) { + synchronized (PTAScene.class) { if (instance == null) { - synchronized (PTAScene.class) { - if (instance == null) { - instance = new PTAScene(); - } - } + instance = new PTAScene(); } - return instance; - } - - public static void junitReset() { - VirtualCalls.reset(); - instance = null; - } - - public static void reset() { - VirtualCalls.reset(); - instance = null; - } - - private PTAScene() { - this.fakeMainFactory = new FakeMainFactory(); - } - - public final Set nativeBuilt = DataFactory.createSet(); - public final Set reflectionBuilt = DataFactory.createSet(); - public final Set arraycopyBuilt = DataFactory.createSet(); - - /* - * wrapper methods for FakeMain. - * */ - public SootMethod getFakeMainMethod() { - return this.fakeMainFactory.getFakeMain(); - } - - public Value getFieldCurrentThread() { - return this.fakeMainFactory.getFieldCurrentThread(); - } - - public Value getFieldGlobalThrow() { - return this.fakeMainFactory.getFieldGlobalThrow(); + } } - - /* - * wrapper methods of Soot Scene. Note, we do not allow you to use Soot Scene directly in qilin.qilin.pta subproject - * to avoid confusing. - * */ - public void setCallGraph(CallGraph cg) { - this.callgraph = cg; - } - - public View getView() { - return view; - } - - public CallGraph getCallGraph() { - return this.callgraph; - } - - public boolean canStoreType(final Type child, final Type parent) { - return view.getTypeHierarchy().isSubtype(parent, child); - } - - public SootClass loadClassAndSupport(String className) { - return sootScene.loadClassAndSupport(className); - } - - public SootMethod getMethod(String methodSignature) { - MethodSignature mthdSig = JavaIdentifierFactory.getInstance().parseMethodSignature(methodSignature); - return (SootMethod) view.getMethod(mthdSig).get(); - } - - public Collection getApplicationClasses() { - Collection classes = view.getClasses(); - return classes.stream().filter(SootClass::isApplicationClass).collect(Collectors.toSet()); -// for (SootClass sc : classes) { -// sc.isApplicationClass() -// } -// return sootScene.getApplicationClasses(); - } - - public Collection getLibraryClasses() { - Collection classes = view.getClasses(); - return classes.stream().filter(SootClass::isLibraryClass).collect(Collectors.toSet()); -// return sootScene.getLibraryClasses(); + return instance; + } + + public static void junitReset() { + VirtualCalls.reset(); + instance = null; + } + + public static void reset() { + VirtualCalls.reset(); + instance = null; + } + + private PTAScene() { + /** + * Set the soot class path to point to the default class path appended with the app path (the + * classes dir or the application jar) and jar files in the library dir of the application. + */ + List cps = new ArrayList<>(); + PTAConfig.ApplicationConfiguration appConfig = PTAConfig.v().getAppConfig(); + // note that the order is important! + cps.add(appConfig.APP_PATH); + cps.addAll(getLibJars(appConfig.LIB_PATH)); + cps.addAll(getJreJars(appConfig.JRE)); + final String classpath = String.join(File.pathSeparator, cps); + System.out.println(cps.size()); + for (String s : cps) { + System.out.println("\t cps:" + s); } - - public boolean containsMethod(String methodSignature) { - MethodSignature mthdSig = JavaIdentifierFactory.getInstance().parseMethodSignature(methodSignature); - return view.getMethod(mthdSig).isPresent(); - } - - public boolean containsField(String fieldSignature) { - FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); - return view.getField(fieldSig).isPresent(); - } - - public Collection getClasses() { - return view.getClasses(); + // System.out.println("xxx:" + classpath); + logger.info("Setting Soot ClassPath: {}", classpath); + // System.setProperty("soot.class.path", classpath); + this.view = createViewForClassPath(cps); + // setup mainclass + if (appConfig.MAIN_CLASS == null) { + appConfig.MAIN_CLASS = PTAUtils.findMainFromMetaInfo(appConfig.APP_PATH); } - - public Collection getPhantomClasses() { - return Collections.emptySet(); + this.mainClass = getSootClass(appConfig.MAIN_CLASS); + // setup fakemain + this.fakeMainFactory = new FakeMainFactory(view, mainClass); + } + + private static JavaView createViewForClassPath(List classPaths) { + ClassLoadingOptions clo = () -> Collections.singletonList(new TypeAssigner()); + JavaProject.JavaProjectBuilder builder = JavaProject.builder(new JavaLanguage(8)); + for (String clazzPath : classPaths) { + builder.addInputLocation(new JavaClassPathAnalysisInputLocation(clazzPath)); } + JavaProject javaProject = builder.build(); + return javaProject.createOnDemandView(analysisInputLocation -> clo); + } - public SootClass getSootClass(String className) { - ClassType classType = PTAUtils.getClassType(className); - return (SootClass) view.getClass(classType).get(); + private static Collection getJreJars(String JRE) { + if (JRE == null) { + return Collections.emptySet(); } - - public boolean containsClass(String className) { - ClassType classType = PTAUtils.getClassType(className); - Optional oclazz = view.getClass(classType); - return oclazz.isPresent(); + final String jreLibDir = JRE + File.separator + "lib"; + return FileUtils.listFiles(new File(jreLibDir), new String[] {"jar"}, false).stream() + .map(File::toString) + .collect(Collectors.toList()); + } + + /** Returns a collection of files, one for each of the jar files in the app's lib folder */ + private static Collection getLibJars(String LIB_PATH) { + if (LIB_PATH == null) { + return Collections.emptySet(); } - - public SootField getField(String fieldSignature) { - FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); - return (SootField) view.getField(fieldSig).get(); - } - - - public void loadNecessaryClasses() { - sootScene.loadNecessaryClasses(); - } - - /* - * copy from doop's soot-fact-generator - * */ - public void addBasicClasses() { - /* - * Set resolution level for sun.net.www.protocol.ftp.FtpURLConnection - * to 1 (HIERARCHY) before calling produceFacts(). The following line is necessary to avoid - * a runtime exception when running soot with java 1.8, however it leads to different - * input fact generation thus leading to different analysis results - */ - sootScene.addBasicClass("sun.net.www.protocol.ftp.FtpURLConnection", SootClass.HIERARCHY); - sootScene.addBasicClass("javax.crypto.extObjectInputStream"); - sootScene.addBasicClass("sun.misc.Launcher$AppClassLoader"); - /* - * For simulating the FileSystem class, we need the implementation - * of the FileSystem, but the classes are not loaded automatically - * due to the indirection via native code. - */ - addCommonDynamicClass("java.io.UnixFileSystem"); - addCommonDynamicClass("java.io.WinNTFileSystem"); - addCommonDynamicClass("java.io.Win32FileSystem"); - - /* java.net.URL loads handlers dynamically */ - addCommonDynamicClass("sun.net.www.protocol.file.Handler"); - addCommonDynamicClass("sun.net.www.protocol.ftp.Handler"); - addCommonDynamicClass("sun.net.www.protocol.http.Handler"); - addCommonDynamicClass("sun.net.www.protocol.https.Handler"); - addCommonDynamicClass("sun.net.www.protocol.jar.Handler"); - } - - private void addCommonDynamicClass(String className) { - if (SourceLocator.v().getClassSource(className) != null) { - sootScene.addBasicClass(className); + File libFile = new File(LIB_PATH); + if (libFile.exists()) { + if (libFile.isDirectory()) { + return FileUtils.listFiles(libFile, new String[] {"jar"}, true).stream() + .map(File::toString) + .collect(Collectors.toList()); + } else if (libFile.isFile()) { + if (libFile.getName().endsWith(".jar")) { + return Collections.singletonList(LIB_PATH); } + logger.error( + "Project not configured properly. Application library path {} is not a jar file.", + libFile); + System.exit(1); + } } + logger.error( + "Project not configured properly. Application library path {} is not correct.", libFile); + System.exit(1); + return null; + } + + public final Set nativeBuilt = DataFactory.createSet(); + public final Set reflectionBuilt = DataFactory.createSet(); + public final Set arraycopyBuilt = DataFactory.createSet(); + + /* + * wrapper methods for FakeMain. + * */ + public SootMethod getFakeMainMethod() { + return this.fakeMainFactory.getFakeMain(); + } + + public Value getFieldCurrentThread() { + return this.fakeMainFactory.getFieldCurrentThread(); + } + + public Value getFieldGlobalThrow() { + return this.fakeMainFactory.getFieldGlobalThrow(); + } + + /* + * wrapper methods of Soot Scene. Note, we do not allow you to use Soot Scene directly in qilin.qilin.pta subproject + * to avoid confusing. + * */ + public void setCallGraph(CallGraph cg) { + this.callgraph = cg; + } + + public View getView() { + return view; + } + + public CallGraph getCallGraph() { + return this.callgraph; + } + + public boolean canStoreType(final Type child, final Type parent) { + return view.getTypeHierarchy().isSubtype(parent, child); + } + + public SootMethod getMethod(String methodSignature) { + MethodSignature mthdSig = + JavaIdentifierFactory.getInstance().parseMethodSignature(methodSignature); + return (SootMethod) view.getMethod(mthdSig).get(); + } + + public Collection getApplicationClasses() { + Collection classes = view.getClasses(); + return classes.stream().filter(SootClass::isApplicationClass).collect(Collectors.toSet()); + // for (SootClass sc : classes) { + // sc.isApplicationClass() + // } + // return sootScene.getApplicationClasses(); + } + + public Collection getLibraryClasses() { + Collection classes = view.getClasses(); + return classes.stream().filter(SootClass::isLibraryClass).collect(Collectors.toSet()); + // return sootScene.getLibraryClasses(); + } + + public boolean containsMethod(String methodSignature) { + MethodSignature mthdSig = + JavaIdentifierFactory.getInstance().parseMethodSignature(methodSignature); + return view.getMethod(mthdSig).isPresent(); + } + + public boolean containsField(String fieldSignature) { + FieldSignature fieldSig = + JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + return view.getField(fieldSig).isPresent(); + } + + public Collection getClasses() { + return view.getClasses(); + } + + public Collection getPhantomClasses() { + return Collections.emptySet(); + } + + public SootClass getSootClass(String className) { + ClassType classType = PTAUtils.getClassType(className); + return (SootClass) view.getClass(classType).get(); + } + + public boolean containsClass(String className) { + ClassType classType = PTAUtils.getClassType(className); + Optional oclazz = view.getClass(classType); + return oclazz.isPresent(); + } + + public SootField getField(String fieldSignature) { + FieldSignature fieldSig = + JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + return (SootField) view.getField(fieldSig).get(); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java b/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java index 323be98d4c7..7b8e4e8099a 100644 --- a/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/core/PointsToAnalysis.java @@ -29,55 +29,45 @@ * * @author Ondrej Lhotak */ - public interface PointsToAnalysis { - int THIS_NODE = -1; - int RETURN_NODE = -2; - int THROW_NODE = -3; - String STRING_NODE = "STRING_NODE"; - String EXCEPTION_NODE = "EXCEPTION_NODE"; - String MAIN_THREAD_GROUP_NODE_LOCAL = "MAIN_THREAD_GROUP_NODE_LOCAL"; + int THIS_NODE = -1; + int RETURN_NODE = -2; + int THROW_NODE = -3; + String STRING_NODE = "STRING_NODE"; + String EXCEPTION_NODE = "EXCEPTION_NODE"; + String MAIN_THREAD_GROUP_NODE_LOCAL = "MAIN_THREAD_GROUP_NODE_LOCAL"; - /** - * Returns the set of objects pointed to by variable l. - */ - PointsToSet reachingObjects(Local l); + /** Returns the set of objects pointed to by variable l. */ + PointsToSet reachingObjects(Local l); - PointsToSet reachingObjects(Node n); + PointsToSet reachingObjects(Node n); - /** - * Returns the set of objects pointed to by variable l in context c. - */ - PointsToSet reachingObjects(Context c, Local l); + /** Returns the set of objects pointed to by variable l in context c. */ + PointsToSet reachingObjects(Context c, Local l); - /** - * Returns the set of objects pointed to by static field f. - */ - PointsToSet reachingObjects(SootField f); + /** Returns the set of objects pointed to by static field f. */ + PointsToSet reachingObjects(SootField f); - /** - * Returns the set of objects pointed to by instance field f of the objects in the PointsToSet s. - */ - PointsToSet reachingObjects(PointsToSet s, SootField f); + /** + * Returns the set of objects pointed to by instance field f of the objects in the PointsToSet s. + */ + PointsToSet reachingObjects(PointsToSet s, SootField f); - /** - * Returns the set of objects pointed to by instance field f of the objects pointed to by l. - */ - PointsToSet reachingObjects(Local l, SootField f); + /** Returns the set of objects pointed to by instance field f of the objects pointed to by l. */ + PointsToSet reachingObjects(Local l, SootField f); - /** - * Returns the set of objects pointed to by instance field f of the objects pointed to by l in context c. - */ - PointsToSet reachingObjects(Context c, Local l, SootField f); + /** + * Returns the set of objects pointed to by instance field f of the objects pointed to by l in + * context c. + */ + PointsToSet reachingObjects(Context c, Local l, SootField f); - /** - * Returns the set of objects pointed to by elements of the arrays in the PointsToSet s. - */ - PointsToSet reachingObjectsOfArrayElement(PointsToSet s); + /** Returns the set of objects pointed to by elements of the arrays in the PointsToSet s. */ + PointsToSet reachingObjectsOfArrayElement(PointsToSet s); - /* - * Return true if l1 and l2 are aliases. - * */ - boolean mayAlias(Local l1, Local l2); + /* + * Return true if l1 and l2 are aliases. + * */ + boolean mayAlias(Local l1, Local l2); } diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index 010c54672b6..af7b7e4377f 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -18,6 +18,11 @@ package qilin.core; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import qilin.util.DataFactory; import qilin.util.PTAUtils; import soot.util.queue.ChunkedQueue; @@ -31,192 +36,223 @@ import sootup.core.types.NullType; import sootup.core.types.Type; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - /** * Resolves virtual calls. * * @author Ondrej Lhotak */ public class VirtualCalls { - private static volatile VirtualCalls instance = null; - private final Map> typeToVtbl = DataFactory.createMap(PTAScene.v().getView().getClasses().size()); - protected Map> baseToSubTypes = DataFactory.createMap(); + private static volatile VirtualCalls instance = null; + private final Map> typeToVtbl = + DataFactory.createMap(PTAScene.v().getView().getClasses().size()); + protected Map> baseToSubTypes = DataFactory.createMap(); - private VirtualCalls() { - } + private VirtualCalls() {} - public static VirtualCalls v() { + public static VirtualCalls v() { + if (instance == null) { + synchronized (VirtualCalls.class) { if (instance == null) { - synchronized (VirtualCalls.class) { - if (instance == null) { - instance = new VirtualCalls(); - } - } + instance = new VirtualCalls(); } - return instance; + } } + return instance; + } - public static void reset() { - instance = null; - } + public static void reset() { + instance = null; + } - public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container) { - return resolveSpecial(iie, subSig, container, false); - } + public SootMethod resolveSpecial( + JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container) { + return resolveSpecial(iie, subSig, container, false); + } - public SootMethod resolveSpecial(JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container, boolean appOnly) { - MethodSignature methodSig = iie.getMethodSignature(); - SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); - /* cf. JVM spec, invokespecial instruction */ - if (PTAScene.v().getView().getTypeHierarchy().isSubtype(target.getDeclaringClassType(), container.getDeclaringClassType()) - && container.getDeclaringClassType() != target.getDeclaringClassType() - && !target.getName().equals("") - && !subSig.toString().equals("void ()")) { - SootClass cls = (SootClass) PTAScene.v().getView().getClass(container.getDeclaringClassType()).get(); - SootClass superCls = (SootClass) cls.getSuperclass().get(); - return resolveNonSpecial(superCls.getType(), subSig, appOnly); - } else { - return target; - } + public SootMethod resolveSpecial( + JSpecialInvokeExpr iie, MethodSubSignature subSig, SootMethod container, boolean appOnly) { + MethodSignature methodSig = iie.getMethodSignature(); + SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(methodSig).get(); + /* cf. JVM spec, invokespecial instruction */ + if (PTAScene.v() + .getView() + .getTypeHierarchy() + .isSubtype(target.getDeclaringClassType(), container.getDeclaringClassType()) + && container.getDeclaringClassType() != target.getDeclaringClassType() + && !target.getName().equals("") + && !subSig.toString().equals("void ()")) { + SootClass cls = + (SootClass) PTAScene.v().getView().getClass(container.getDeclaringClassType()).get(); + SootClass superCls = (SootClass) cls.getSuperclass().get(); + return resolveNonSpecial(superCls.getType(), subSig, appOnly); + } else { + return target; } + } - public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig) { - return resolveNonSpecial(t, subSig, false); - } + public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig) { + return resolveNonSpecial(t, subSig, false); + } - public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, boolean appOnly) { - Map vtbl = typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); - SootMethod ret = vtbl.get(subSig); - if (ret != null) { - return ret; - } - SootClass cls = (SootClass) PTAScene.v().getView().getClass(t).get(); - if (appOnly && cls.isLibraryClass()) { - return null; - } - Optional om = cls.getMethod(subSig); - if (om.isPresent()) { - SootMethod m = om.get(); - if (!m.isAbstract()) { - ret = m; - } - } else { - Optional oc = cls.getSuperclass(); - if (oc.isPresent()) { - SootClass c = oc.get(); - ret = resolveNonSpecial(c.getType(), subSig); - } - } - if (ret == null) { - return null; - } - vtbl.put(subSig, ret); - return ret; + public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, boolean appOnly) { + Map vtbl = + typeToVtbl.computeIfAbsent(t, k -> DataFactory.createMap(8)); + SootMethod ret = vtbl.get(subSig); + if (ret != null) { + return ret; } - - public void resolve(Type t, Type declaredType, MethodSubSignature subSig, SootMethod container, - ChunkedQueue targets) { - resolve(t, declaredType, null, subSig, container, targets); + SootClass cls = (SootClass) PTAScene.v().getView().getClass(t).get(); + if (appOnly && cls.isLibraryClass()) { + return null; } + Optional om = cls.getMethod(subSig); + if (om.isPresent()) { + SootMethod m = om.get(); + if (!m.isAbstract()) { + ret = m; + } + } else { + Optional oc = cls.getSuperclass(); + if (oc.isPresent()) { + SootClass c = oc.get(); + ret = resolveNonSpecial(c.getType(), subSig); + } + } + if (ret == null) { + return null; + } + vtbl.put(subSig, ret); + return ret; + } + + public void resolve( + Type t, + Type declaredType, + MethodSubSignature subSig, + SootMethod container, + ChunkedQueue targets) { + resolve(t, declaredType, null, subSig, container, targets); + } - public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, - ChunkedQueue targets) { - resolve(t, declaredType, sigType, subSig, container, targets, false); + public void resolve( + Type t, + Type declaredType, + Type sigType, + MethodSubSignature subSig, + SootMethod container, + ChunkedQueue targets) { + resolve(t, declaredType, sigType, subSig, container, targets, false); + } + + public void resolve( + Type t, + Type declaredType, + Type sigType, + MethodSubSignature subSig, + SootMethod container, + ChunkedQueue targets, + boolean appOnly) { + if (declaredType instanceof ArrayType) { + declaredType = PTAUtils.getClassType("java.lang.Object"); + } + if (sigType instanceof ArrayType) { + sigType = PTAUtils.getClassType("java.lang.Object"); + } + if (t instanceof ArrayType) { + t = PTAUtils.getClassType("java.lang.Object"); } - public void resolve(Type t, Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, - ChunkedQueue targets, boolean appOnly) { - if (declaredType instanceof ArrayType) { - declaredType = PTAUtils.getClassType("java.lang.Object"); - } - if (sigType instanceof ArrayType) { - sigType = PTAUtils.getClassType("java.lang.Object"); - } - if (t instanceof ArrayType) { - t = PTAUtils.getClassType("java.lang.Object"); - } + if (declaredType != null + && !PTAScene.v().getView().getTypeHierarchy().isSubtype(declaredType, t)) { + return; + } + if (sigType != null && !PTAScene.v().getView().getTypeHierarchy().isSubtype(sigType, t)) { + return; + } + if (t instanceof ClassType) { + SootMethod target = resolveNonSpecial((ClassType) t, subSig, appOnly); + if (target != null) { + targets.add(target); + } + } + // else if (t instanceof AnySubType) { + // ClassType base = ((AnySubType) t).getBase(); + // + // /* + // * Whenever any sub type of a specific type is considered as receiver for a method + // to call and the base type is an + // * interface, calls to existing methods with matching signature (possible + // implementation of method to call) are also + // * added. As Javas' subtyping allows contra-variance for return types and + // co-variance for parameters when overriding a + // * method, these cases are also considered here. + // * + // * Example: Classes A, B (B sub type of A), interface I with method public A foo(B + // b); and a class C with method public + // * B foo(A a) { ... }. The extended class hierarchy will contain C as possible + // implementation of I. + // * + // * Since Java has no multiple inheritance call by signature resolution is only + // activated if the base is an interface. + // */ + // resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, + // base); + // } + else if (t instanceof NullType) { + } else { + throw new RuntimeException("oops " + t); + } + } - if (declaredType != null && !PTAScene.v().getView().getTypeHierarchy().isSubtype(declaredType, t)) { - return; - } - if (sigType != null && !PTAScene.v().getView().getTypeHierarchy().isSubtype(sigType, t)) { - return; - } - if (t instanceof ClassType) { - SootMethod target = resolveNonSpecial((ClassType) t, subSig, appOnly); - if (target != null) { - targets.add(target); - } - } -// else if (t instanceof AnySubType) { -// ClassType base = ((AnySubType) t).getBase(); -// -// /* -// * Whenever any sub type of a specific type is considered as receiver for a method to call and the base type is an -// * interface, calls to existing methods with matching signature (possible implementation of method to call) are also -// * added. As Javas' subtyping allows contra-variance for return types and co-variance for parameters when overriding a -// * method, these cases are also considered here. -// * -// * Example: Classes A, B (B sub type of A), interface I with method public A foo(B b); and a class C with method public -// * B foo(A a) { ... }. The extended class hierarchy will contain C as possible implementation of I. -// * -// * Since Java has no multiple inheritance call by signature resolution is only activated if the base is an interface. -// */ -// resolveAnySubType(declaredType, sigType, subSig, container, targets, appOnly, base); -// } - else if (t instanceof NullType) { - } else { - throw new RuntimeException("oops " + t); + protected void resolveAnySubType( + Type declaredType, + Type sigType, + MethodSubSignature subSig, + SootMethod container, + ChunkedQueue targets, + boolean appOnly, + ClassType base) { + { + Set subTypes = baseToSubTypes.get(base); + if (subTypes != null && !subTypes.isEmpty()) { + for (final Type st : subTypes) { + resolve(st, declaredType, sigType, subSig, container, targets, appOnly); } + return; + } } - protected void resolveAnySubType(Type declaredType, Type sigType, MethodSubSignature subSig, SootMethod container, - ChunkedQueue targets, boolean appOnly, ClassType base) { - { - Set subTypes = baseToSubTypes.get(base); - if (subTypes != null && !subTypes.isEmpty()) { - for (final Type st : subTypes) { - resolve(st, declaredType, sigType, subSig, container, targets, appOnly); - } - return; - } - } + Set newSubTypes = new HashSet<>(); + newSubTypes.add(base); - Set newSubTypes = new HashSet<>(); - newSubTypes.add(base); - - LinkedList worklist = new LinkedList<>(); - HashSet workset = new HashSet<>(); - workset.add(base); - worklist.add(base); - while (!worklist.isEmpty()) { - ClassType classType = worklist.removeFirst(); - SootClass cl = (SootClass) PTAScene.v().getView().getClass(classType).get(); - if (cl.isInterface()) { - for (final ClassType c : PTAScene.v().getView().getTypeHierarchy().implementersOf(cl.getType())) { - if (workset.add(c)) { - worklist.add(c); - } - } - } else { - if (cl.isConcrete()) { - resolve(cl.getType(), declaredType, sigType, subSig, container, targets, appOnly); - newSubTypes.add(cl.getType()); - } - for (final ClassType c : PTAScene.v().getView().getTypeHierarchy().subclassesOf(classType)) { - if (workset.add(c)) { - worklist.add(c); - } - } - } + LinkedList worklist = new LinkedList<>(); + HashSet workset = new HashSet<>(); + workset.add(base); + worklist.add(base); + while (!worklist.isEmpty()) { + ClassType classType = worklist.removeFirst(); + SootClass cl = (SootClass) PTAScene.v().getView().getClass(classType).get(); + if (cl.isInterface()) { + for (final ClassType c : + PTAScene.v().getView().getTypeHierarchy().implementersOf(cl.getType())) { + if (workset.add(c)) { + worklist.add(c); + } } - - baseToSubTypes.computeIfAbsent(base, k -> DataFactory.createSet()).addAll(newSubTypes); + } else { + if (cl.isConcrete()) { + resolve(cl.getType(), declaredType, sigType, subSig, container, targets, appOnly); + newSubTypes.add(cl.getType()); + } + for (final ClassType c : + PTAScene.v().getView().getTypeHierarchy().subclassesOf(classType)) { + if (workset.add(c)) { + worklist.add(c); + } + } + } } + baseToSubTypes.computeIfAbsent(base, k -> DataFactory.createSet()).addAll(newSubTypes); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index ff8ef420a15..2237ee58401 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -18,6 +18,7 @@ package qilin.core.builder; +import java.util.*; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; @@ -47,221 +48,240 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.*; - public class CallGraphBuilder { - protected final Map> receiverToSites; - protected final Map> methodToInvokeStmt; - protected final Set reachMethods; - private ChunkedQueue rmQueue; + protected final Map> receiverToSites; + protected final Map> methodToInvokeStmt; + protected final Set reachMethods; + private ChunkedQueue rmQueue; - protected final Set calledges; - protected final PTA pta; - protected final PAG pag; - protected CallGraph cicg; + protected final Set calledges; + protected final PTA pta; + protected final PAG pag; + protected CallGraph cicg; - public CallGraphBuilder(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - PTAScene.v().setCallGraph(new CallGraph()); - receiverToSites = DataFactory.createMap(PTAScene.v().getView().getClasses().size()); - methodToInvokeStmt = DataFactory.createMap(); - reachMethods = DataFactory.createSet(); - calledges = DataFactory.createSet(); - } + public CallGraphBuilder(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + PTAScene.v().setCallGraph(new CallGraph()); + receiverToSites = DataFactory.createMap(PTAScene.v().getView().getClasses().size()); + methodToInvokeStmt = DataFactory.createMap(); + reachMethods = DataFactory.createSet(); + calledges = DataFactory.createSet(); + } - public void setRMQueue(ChunkedQueue rmQueue) { - this.rmQueue = rmQueue; - } + public void setRMQueue(ChunkedQueue rmQueue) { + this.rmQueue = rmQueue; + } - public Collection getReachableMethods() { - return reachMethods; - } + public Collection getReachableMethods() { + return reachMethods; + } - // initialize the receiver to sites map with the number of locals * an - // estimate for the number of contexts per methods - public Map> getReceiverToSitesMap() { - return receiverToSites; - } + // initialize the receiver to sites map with the number of locals * an + // estimate for the number of contexts per methods + public Map> getReceiverToSitesMap() { + return receiverToSites; + } - public Collection callSitesLookUp(VarNode receiver) { - return receiverToSites.getOrDefault(receiver, Collections.emptySet()); - } + public Collection callSitesLookUp(VarNode receiver) { + return receiverToSites.getOrDefault(receiver, Collections.emptySet()); + } - public CallGraph getCallGraph() { - if (cicg == null) { - constructCallGraph(); - } - return PTAScene.v().getCallGraph(); + public CallGraph getCallGraph() { + if (cicg == null) { + constructCallGraph(); } + return PTAScene.v().getCallGraph(); + } - public CallGraph getCICallGraph() { - if (cicg == null) { - constructCallGraph(); - } - return cicg; + public CallGraph getCICallGraph() { + if (cicg == null) { + constructCallGraph(); } + return cicg; + } - private void constructCallGraph() { - cicg = new CallGraph(); - Map>> map = DataFactory.createMap(); - calledges.forEach(e -> { - PTAScene.v().getCallGraph().addEdge(e); - SootMethod src = e.src(); - SootMethod tgt = e.tgt(); - Stmt unit = e.srcUnit(); - Map> submap = map.computeIfAbsent(unit, k -> DataFactory.createMap()); - Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); - if (set.add(tgt)) { - cicg.addEdge(new Edge(new ContextMethod(src, pta.emptyContext()), e.srcUnit(), new ContextMethod(tgt, pta.emptyContext()), e.kind())); - } + private void constructCallGraph() { + cicg = new CallGraph(); + Map>> map = DataFactory.createMap(); + calledges.forEach( + e -> { + PTAScene.v().getCallGraph().addEdge(e); + SootMethod src = e.src(); + SootMethod tgt = e.tgt(); + Stmt unit = e.srcUnit(); + Map> submap = + map.computeIfAbsent(unit, k -> DataFactory.createMap()); + Set set = submap.computeIfAbsent(src, k -> DataFactory.createSet()); + if (set.add(tgt)) { + cicg.addEdge( + new Edge( + new ContextMethod(src, pta.emptyContext()), + e.srcUnit(), + new ContextMethod(tgt, pta.emptyContext()), + e.kind())); + } }); - } + } - public List getEntryPoints() { - Node thisRef = pag.getMethodPAG(PTAScene.v().getFakeMainMethod()).nodeFactory().caseThis(); - thisRef = pta.parameterize(thisRef, pta.emptyContext()); - pag.addEdge(pta.getRootNode(), thisRef); - return Collections.singletonList(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext())); - } + public List getEntryPoints() { + Node thisRef = pag.getMethodPAG(PTAScene.v().getFakeMainMethod()).nodeFactory().caseThis(); + thisRef = pta.parameterize(thisRef, pta.emptyContext()); + pag.addEdge(pta.getRootNode(), thisRef); + return Collections.singletonList( + pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext())); + } - public void initReachableMethods() { - for (MethodOrMethodContext momc : getEntryPoints()) { - if (reachMethods.add(momc)) { - rmQueue.add(momc); - } - } + public void initReachableMethods() { + for (MethodOrMethodContext momc : getEntryPoints()) { + if (reachMethods.add(momc)) { + rmQueue.add(momc); + } } + } - public VarNode getReceiverVarNode(Local receiver, MethodOrMethodContext m) { - LocalVarNode base = pag.makeLocalVarNode(receiver, receiver.getType(), m.method()); - return (VarNode) pta.parameterize(base, m.context()); - } + public VarNode getReceiverVarNode(Local receiver, MethodOrMethodContext m) { + LocalVarNode base = pag.makeLocalVarNode(receiver, receiver.getType(), m.method()); + return (VarNode) pta.parameterize(base, m.context()); + } - protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { - Type type = receiverNode.getType(); - final QueueReader targets = PTAUtils.dispatch(type, site); - while (targets.hasNext()) { - SootMethod target = targets.next(); - if (site.iie() instanceof JSpecialInvokeExpr) { - Type calleeDeclType = target.getDeclaringClassType(); - if (!PTAScene.v().canStoreType(type, calleeDeclType)) { - continue; - } - } - addVirtualEdge(site.container(), site.getUnit(), target, site.kind(), receiverNode); + protected void dispatch(AllocNode receiverNode, VirtualCallSite site) { + Type type = receiverNode.getType(); + final QueueReader targets = PTAUtils.dispatch(type, site); + while (targets.hasNext()) { + SootMethod target = targets.next(); + if (site.iie() instanceof JSpecialInvokeExpr) { + Type calleeDeclType = target.getDeclaringClassType(); + if (!PTAScene.v().canStoreType(type, calleeDeclType)) { + continue; } + } + addVirtualEdge(site.container(), site.getUnit(), target, site.kind(), receiverNode); } + } - private void addVirtualEdge(MethodOrMethodContext caller, Stmt callStmt, SootMethod callee, Kind kind, AllocNode receiverNode) { - Context tgtContext = pta.createCalleeCtx(caller, receiverNode, new CallSite(callStmt), callee); - MethodOrMethodContext cstarget = pta.parameterize(callee, tgtContext); - handleCallEdge(new Edge(caller, callStmt, cstarget, kind)); - Node thisRef = pag.getMethodPAG(callee).nodeFactory().caseThis(); - thisRef = pta.parameterize(thisRef, cstarget.context()); - pag.addEdge(receiverNode, thisRef); - } + private void addVirtualEdge( + MethodOrMethodContext caller, + Stmt callStmt, + SootMethod callee, + Kind kind, + AllocNode receiverNode) { + Context tgtContext = pta.createCalleeCtx(caller, receiverNode, new CallSite(callStmt), callee); + MethodOrMethodContext cstarget = pta.parameterize(callee, tgtContext); + handleCallEdge(new Edge(caller, callStmt, cstarget, kind)); + Node thisRef = pag.getMethodPAG(callee).nodeFactory().caseThis(); + thisRef = pta.parameterize(thisRef, cstarget.context()); + pag.addEdge(receiverNode, thisRef); + } - public void injectCallEdge(Object heapOrType, MethodOrMethodContext callee, Kind kind) { - Map stmtMap = methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap()); - if (!stmtMap.containsKey(heapOrType)) { - AbstractInvokeExpr ie = new JStaticInvokeExpr(callee.method().getSignature(), Collections.emptyList()); - JInvokeStmt stmt = new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo()); - stmtMap.put(heapOrType, stmt); - handleCallEdge(new Edge(pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext()), stmtMap.get(heapOrType), callee, kind)); - } + public void injectCallEdge(Object heapOrType, MethodOrMethodContext callee, Kind kind) { + Map stmtMap = + methodToInvokeStmt.computeIfAbsent(callee.method(), k -> DataFactory.createMap()); + if (!stmtMap.containsKey(heapOrType)) { + AbstractInvokeExpr ie = + new JStaticInvokeExpr(callee.method().getSignature(), Collections.emptyList()); + JInvokeStmt stmt = new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo()); + stmtMap.put(heapOrType, stmt); + handleCallEdge( + new Edge( + pta.parameterize(PTAScene.v().getFakeMainMethod(), pta.emptyContext()), + stmtMap.get(heapOrType), + callee, + kind)); } + } - public void addStaticEdge(MethodOrMethodContext caller, Stmt callStmt, SootMethod calleem, Kind kind) { - Context typeContext = pta.createCalleeCtx(caller, null, new CallSite(callStmt), calleem); - MethodOrMethodContext callee = pta.parameterize(calleem, typeContext); - handleCallEdge(new Edge(caller, callStmt, callee, kind)); - } + public void addStaticEdge( + MethodOrMethodContext caller, Stmt callStmt, SootMethod calleem, Kind kind) { + Context typeContext = pta.createCalleeCtx(caller, null, new CallSite(callStmt), calleem); + MethodOrMethodContext callee = pta.parameterize(calleem, typeContext); + handleCallEdge(new Edge(caller, callStmt, callee, kind)); + } - protected void handleCallEdge(Edge edge) { - if (calledges.add(edge)) { - MethodOrMethodContext callee = edge.getTgt(); - if (reachMethods.add(callee)) { - rmQueue.add(callee); - } - processCallAssign(edge); - } + protected void handleCallEdge(Edge edge) { + if (calledges.add(edge)) { + MethodOrMethodContext callee = edge.getTgt(); + if (reachMethods.add(callee)) { + rmQueue.add(callee); + } + processCallAssign(edge); } + } - public boolean recordVirtualCallSite(VarNode receiver, VirtualCallSite site) { - Collection sites = receiverToSites.computeIfAbsent(receiver, k -> DataFactory.createSet()); - return sites.add(site); - } + public boolean recordVirtualCallSite(VarNode receiver, VirtualCallSite site) { + Collection sites = + receiverToSites.computeIfAbsent(receiver, k -> DataFactory.createSet()); + return sites.add(site); + } - public void virtualCallDispatch(PointsToSetInternal p2set, VirtualCallSite site) { - p2set.forall(new P2SetVisitor(pta) { - public void visit(Node n) { - dispatch((AllocNode) n, site); - } + public void virtualCallDispatch(PointsToSetInternal p2set, VirtualCallSite site) { + p2set.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { + dispatch((AllocNode) n, site); + } }); - } - - /** - * Adds method target as a possible target of the invoke expression in s. If - * target is null, only creates the nodes for the call site, without actually - * connecting them to any target method. - **/ - private void processCallAssign(Edge e) { - MethodPAG srcmpag = pag.getMethodPAG(e.src()); - MethodPAG tgtmpag = pag.getMethodPAG(e.tgt()); - Stmt s = (Stmt) e.srcUnit(); - Context srcContext = e.srcCtxt(); - Context tgtContext = e.tgtCtxt(); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - SootMethod tgtmtd = tgtmpag.getMethod(); - AbstractInvokeExpr ie = s.getInvokeExpr(); - // add arg --> param edges. - int numArgs = ie.getArgCount(); - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { - continue; - } - Type tgtType = tgtmtd.getParameterType(i); - if (!(tgtType instanceof ReferenceType)) { - continue; - } - Node argNode = srcnf.getNode(arg); - argNode = pta.parameterize(argNode, srcContext); - Node parm = tgtnf.caseParm(i); - parm = pta.parameterize(parm, tgtContext); - pag.addEdge(argNode, parm); - } - // add normal return edge - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); + } - if (dest.getType() instanceof ReferenceType) { - Node destNode = srcnf.getNode(dest); - destNode = pta.parameterize(destNode, srcContext); - if (tgtmtd.getReturnType() instanceof ReferenceType) { - Node retNode = tgtnf.caseRet(); - retNode = pta.parameterize(retNode, tgtContext); - pag.addEdge(retNode, destNode); - } - } + /** + * Adds method target as a possible target of the invoke expression in s. If target is null, only + * creates the nodes for the call site, without actually connecting them to any target method. + */ + private void processCallAssign(Edge e) { + MethodPAG srcmpag = pag.getMethodPAG(e.src()); + MethodPAG tgtmpag = pag.getMethodPAG(e.tgt()); + Stmt s = (Stmt) e.srcUnit(); + Context srcContext = e.srcCtxt(); + Context tgtContext = e.tgtCtxt(); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + SootMethod tgtmtd = tgtmpag.getMethod(); + AbstractInvokeExpr ie = s.getInvokeExpr(); + // add arg --> param edges. + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + Type tgtType = tgtmtd.getParameterType(i); + if (!(tgtType instanceof ReferenceType)) { + continue; + } + Node argNode = srcnf.getNode(arg); + argNode = pta.parameterize(argNode, srcContext); + Node parm = tgtnf.caseParm(i); + parm = pta.parameterize(parm, tgtContext); + pag.addEdge(argNode, parm); + } + // add normal return edge + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + Node destNode = srcnf.getNode(dest); + destNode = pta.parameterize(destNode, srcContext); + if (tgtmtd.getReturnType() instanceof ReferenceType) { + Node retNode = tgtnf.caseRet(); + retNode = pta.parameterize(retNode, tgtContext); + pag.addEdge(retNode, destNode); } - // add throw return edge - if (CoreConfig.v().getPtaConfig().preciseExceptions) { - Node throwNode = tgtnf.caseMethodThrow(); - /* - * If an invocation statement may throw exceptions, we create a special local variables - * to receive the exception objects. - * a_ret = x.foo(); here, a_ret is a variable to receive values from return variables of foo(); - * a_throw = x.foo(); here, a_throw is a variable to receive exception values thrown by foo(); - * */ - throwNode = pta.parameterize(throwNode, tgtContext); - MethodNodeFactory mnf = srcmpag.nodeFactory(); - Node dst = mnf.makeInvokeStmtThrowVarNode(s, srcmpag.getMethod()); - dst = pta.parameterize(dst, srcContext); - pag.addEdge(throwNode, dst); - } + } + } + // add throw return edge + if (CoreConfig.v().getPtaConfig().preciseExceptions) { + Node throwNode = tgtnf.caseMethodThrow(); + /* + * If an invocation statement may throw exceptions, we create a special local variables + * to receive the exception objects. + * a_ret = x.foo(); here, a_ret is a variable to receive values from return variables of foo(); + * a_throw = x.foo(); here, a_throw is a variable to receive exception values thrown by foo(); + * */ + throwNode = pta.parameterize(throwNode, tgtContext); + MethodNodeFactory mnf = srcmpag.nodeFactory(); + Node dst = mnf.makeInvokeStmtThrowVarNode(s, srcmpag.getMethod()); + dst = pta.parameterize(dst, srcContext); + pag.addEdge(throwNode, dst); } + } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java index 9fd72867524..8fca2a8a5f9 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/ExceptionHandler.java @@ -18,6 +18,7 @@ package qilin.core.builder; +import java.util.*; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.pag.*; @@ -32,72 +33,74 @@ import sootup.core.model.SootMethod; import sootup.core.types.Type; -import java.util.*; - public class ExceptionHandler { - protected final Map> throwNodeToSites = DataFactory.createMap(PTAScene.v().getView().getClasses().size()); - protected PTA pta; - protected PAG pag; + protected final Map> throwNodeToSites = + DataFactory.createMap(PTAScene.v().getView().getClasses().size()); + protected PTA pta; + protected PAG pag; - public ExceptionHandler(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - } + public ExceptionHandler(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + } - public Collection throwSitesLookUp(VarNode throwNode) { - return throwNodeToSites.getOrDefault(throwNode, Collections.emptySet()); - } + public Collection throwSitesLookUp(VarNode throwNode) { + return throwNodeToSites.getOrDefault(throwNode, Collections.emptySet()); + } - public boolean addThrowSite(Node throwNode, ExceptionThrowSite ets) { - Collection throwSites = throwNodeToSites.computeIfAbsent(throwNode, k -> DataFactory.createSet()); - return throwSites.add(ets); - } + public boolean addThrowSite(Node throwNode, ExceptionThrowSite ets) { + Collection throwSites = + throwNodeToSites.computeIfAbsent(throwNode, k -> DataFactory.createSet()); + return throwSites.add(ets); + } - public void exceptionDispatch(PointsToSetInternal p2set, ExceptionThrowSite site) { - p2set.forall(new P2SetVisitor(pta) { - public void visit(Node n) { - dispatch((AllocNode) n, site); - } + public void exceptionDispatch(PointsToSetInternal p2set, ExceptionThrowSite site) { + p2set.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { + dispatch((AllocNode) n, site); + } }); - } + } - /* - * dispatch the exception objects by following the exception-cath-links in Doop-ISSTA09. - * */ - public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { - Type type = throwObj.getType(); - MethodOrMethodContext momc = site.container(); - SootMethod sm = momc.method(); - Context context = momc.context(); - MethodPAG mpag = pag.getMethodPAG(sm); - MethodNodeFactory nodeFactory = mpag.nodeFactory(); - VarNode throwNode = site.getThrowNode(); - List trapList = mpag.stmt2wrapperedTraps.getOrDefault(site.getUnit(), Collections.emptyList()); - for (Trap trap : trapList) { - if (PTAScene.v().canStoreType(type, trap.getExceptionType())) { - Stmt handler = trap.getHandlerStmt(); - assert handler instanceof JIdentityStmt; - JIdentityStmt handlerStmt = (JIdentityStmt) handler; - Node caughtParam = nodeFactory.getNode(handlerStmt.getRightOp()); - Node dst = pta.parameterize(caughtParam, context); - pag.addEdge(throwObj, dst); - // record an edge from base --> caughtParam on the methodPag. - recordImplictEdge(throwNode, caughtParam, mpag); - return; - } - } - // No trap handle the throwable object in the method. - Node methodThrowNode = nodeFactory.caseMethodThrow(); - Node dst = pta.parameterize(methodThrowNode, context); + /* + * dispatch the exception objects by following the exception-cath-links in Doop-ISSTA09. + * */ + public void dispatch(AllocNode throwObj, ExceptionThrowSite site) { + Type type = throwObj.getType(); + MethodOrMethodContext momc = site.container(); + SootMethod sm = momc.method(); + Context context = momc.context(); + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory nodeFactory = mpag.nodeFactory(); + VarNode throwNode = site.getThrowNode(); + List trapList = + mpag.stmt2wrapperedTraps.getOrDefault(site.getUnit(), Collections.emptyList()); + for (Trap trap : trapList) { + if (PTAScene.v().canStoreType(type, trap.getExceptionType())) { + Stmt handler = trap.getHandlerStmt(); + assert handler instanceof JIdentityStmt; + JIdentityStmt handlerStmt = (JIdentityStmt) handler; + Node caughtParam = nodeFactory.getNode(handlerStmt.getRightOp()); + Node dst = pta.parameterize(caughtParam, context); pag.addEdge(throwObj, dst); - // record an edge from base --> methodThrowNode on the methodPag. - recordImplictEdge(throwNode, methodThrowNode, mpag); + // record an edge from base --> caughtParam on the methodPag. + recordImplictEdge(throwNode, caughtParam, mpag); + return; + } } + // No trap handle the throwable object in the method. + Node methodThrowNode = nodeFactory.caseMethodThrow(); + Node dst = pta.parameterize(methodThrowNode, context); + pag.addEdge(throwObj, dst); + // record an edge from base --> methodThrowNode on the methodPag. + recordImplictEdge(throwNode, methodThrowNode, mpag); + } - private void recordImplictEdge(Node src, Node dst, MethodPAG mpag) { - if (src instanceof ContextVarNode) { - src = ((ContextVarNode) src).base(); - } - mpag.addExceptionEdge(src, dst); + private void recordImplictEdge(Node src, Node dst, MethodPAG mpag) { + if (src instanceof ContextVarNode) { + src = ((ContextVarNode) src).base(); } + mpag.addExceptionEdge(src, dst); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java index d3290e5171f..c2dcea0b8f9 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/FakeMainFactory.java @@ -18,15 +18,25 @@ package qilin.core.builder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; import qilin.CoreConfig; import qilin.core.ArtificialMethod; -import qilin.core.PTAScene; import qilin.util.PTAUtils; -import soot.EntryPoints; +import soot.JavaMethods; import sootup.core.IdentifierFactory; import sootup.core.frontend.OverridingBodySource; import sootup.core.frontend.OverridingClassSource; import sootup.core.inputlocation.EagerInputLocation; +import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.NoPositionInformation; @@ -42,179 +52,381 @@ import sootup.core.model.SourceType; import sootup.core.signatures.FieldSignature; import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.MethodSubSignature; import sootup.core.types.ClassType; +import sootup.core.views.View; import sootup.java.core.JavaIdentifierFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.LinkedHashSet; -import java.util.List; - public class FakeMainFactory extends ArtificialMethod { - public static FakeMainFactory instance; - - public static int implicitCallEdges; - private final SootClass fakeClass; - - public FakeMainFactory() { - this.localStart = 0; - // this.fakeClass = new SootClass("FakeMain"); -// this.fakeClass.setResolvingLevel(SootClass.BODIES); -// this.method = new SootMethod("fakeMain", null, VoidType); -// this.method.setModifiers(Modifier.STATIC); - String className = "qilin.pta.FakeMain"; - IdentifierFactory fact = PTAScene.v().getView().getIdentifierFactory(); - ClassType declaringClassSignature = JavaIdentifierFactory.getInstance().getClassType(className); - FieldSignature ctSig = fact.getFieldSignature("currentThread", declaringClassSignature, "java.lang.Thread"); - SootField currentThread = new SootField(ctSig, EnumSet.of(Modifier.STATIC), NoPositionInformation.getInstance()); - FieldSignature gtSig = fact.getFieldSignature("globalThrow", declaringClassSignature, "java.lang.Exception"); - SootField globalThrow = new SootField(gtSig, EnumSet.of(Modifier.STATIC), NoPositionInformation.getInstance()); -// fakeClass.addMethod(this.method); -// fakeClass.addField(currentThread); -// fakeClass.addField(globalThrow); - - - MethodSignature methodSignatureOne = PTAScene.v().getView().getIdentifierFactory() - .getMethodSignature("main", className, "void", Collections.emptyList()); - - StmtPositionInfo noPosInfo = StmtPositionInfo.createNoStmtPositionInfo(); - final JReturnVoidStmt returnVoidStmt = new JReturnVoidStmt(noPosInfo); - final JNopStmt jNop = new JNopStmt(noPosInfo); - this.bodyBuilder = Body.builder(); - bodyBuilder - .setStartingStmt(jNop) - .addFlow(jNop, returnVoidStmt) - .setMethodSignature(methodSignatureOne) - .setPosition(NoPositionInformation.getInstance()); - makeFakeMain(); - Body bodyOne = bodyBuilder.build(); - SootMethod dummyMainMethod = - new SootMethod( - new OverridingBodySource(methodSignatureOne, bodyOne), - methodSignatureOne, - EnumSet.of(Modifier.PUBLIC, Modifier.STATIC), - Collections.emptyList(), - NoPositionInformation.getInstance()); - this.method = dummyMainMethod; - this.fakeClass = new SootClass( - new OverridingClassSource( - Collections.singleton(dummyMainMethod), - new LinkedHashSet<>(Arrays.asList(currentThread, globalThrow)), - EnumSet.of(Modifier.PUBLIC), - null, - JavaIdentifierFactory.getInstance().getClassType("java.lang.Object"), - null, - NoPositionInformation.getInstance(), - null, - PTAScene.v().getView().getIdentifierFactory().getClassType(className), - new EagerInputLocation()), - SourceType.Application); + public static FakeMainFactory instance; + + public static int implicitCallEdges; + private final SootClass fakeClass; + private final SootClass mainClass; + private final EntryPoints entryPoints; + + public FakeMainFactory(View view, SootClass mainClazz) { + super(view); + this.mainClass = mainClazz; + this.entryPoints = new EntryPoints(); + this.localStart = 0; + // this.fakeClass = new SootClass("FakeMain"); + // this.fakeClass.setResolvingLevel(SootClass.BODIES); + // this.method = new SootMethod("fakeMain", null, VoidType); + // this.method.setModifiers(Modifier.STATIC); + String className = "qilin.pta.FakeMain"; + IdentifierFactory fact = view.getIdentifierFactory(); + ClassType declaringClassSignature = JavaIdentifierFactory.getInstance().getClassType(className); + FieldSignature ctSig = + fact.getFieldSignature("currentThread", declaringClassSignature, "java.lang.Thread"); + SootField currentThread = + new SootField(ctSig, EnumSet.of(Modifier.STATIC), NoPositionInformation.getInstance()); + FieldSignature gtSig = + fact.getFieldSignature("globalThrow", declaringClassSignature, "java.lang.Exception"); + SootField globalThrow = + new SootField(gtSig, EnumSet.of(Modifier.STATIC), NoPositionInformation.getInstance()); + // fakeClass.addMethod(this.method); + // fakeClass.addField(currentThread); + // fakeClass.addField(globalThrow); + + MethodSignature methodSignatureOne = + view.getIdentifierFactory() + .getMethodSignature("main", className, "void", Collections.emptyList()); + + StmtPositionInfo noPosInfo = StmtPositionInfo.createNoStmtPositionInfo(); + final JReturnVoidStmt returnVoidStmt = new JReturnVoidStmt(noPosInfo); + final JNopStmt jNop = new JNopStmt(noPosInfo); + this.bodyBuilder = Body.builder(); + makeFakeMain(currentThread); + bodyBuilder.getStmtGraph().addBlock(stmtList); + bodyBuilder + .setStartingStmt(jNop) + .addFlow(jNop, stmtList.get(0)) + .addFlow(stmtList.get(stmtList.size() - 1), returnVoidStmt) + .setMethodSignature(methodSignatureOne) + .setPosition(NoPositionInformation.getInstance()); + Body bodyOne = bodyBuilder.build(); + SootMethod dummyMainMethod = + new SootMethod( + new OverridingBodySource(methodSignatureOne, bodyOne), + methodSignatureOne, + EnumSet.of(Modifier.PUBLIC, Modifier.STATIC), + Collections.emptyList(), + NoPositionInformation.getInstance()); + this.method = dummyMainMethod; + this.fakeClass = + new SootClass( + new OverridingClassSource( + Collections.singleton(dummyMainMethod), + new LinkedHashSet<>(Arrays.asList(currentThread, globalThrow)), + EnumSet.of(Modifier.PUBLIC), + null, + JavaIdentifierFactory.getInstance().getClassType("java.lang.Object"), + null, + NoPositionInformation.getInstance(), + null, + view.getIdentifierFactory().getClassType(className), + new EagerInputLocation()), + SourceType.Application); + } + + public SootMethod getFakeMain() { + // if (bodyBuilder == null) { + // synchronized (this) { + // if (bodyBuilder == null) { + // this.method.setSource((m, phaseName) -> new JimpleBody(this.method)); + // makeFakeMain(); + // this.body = PTAUtils.getMethodBody(method); + // } + // } + // } + return this.method; + } + + private List getEntryPoints() { + List ret = new ArrayList<>(); + if (CoreConfig.v().getPtaConfig().clinitMode == CoreConfig.ClinitMode.FULL) { + ret.addAll(entryPoints.clinits()); + } else { + // on the fly mode, resolve the clinit methods on the fly. + ret.addAll(Collections.emptySet()); } - public SootMethod getFakeMain() { -// if (bodyBuilder == null) { -// synchronized (this) { -// if (bodyBuilder == null) { -// this.method.setSource((m, phaseName) -> new JimpleBody(this.method)); -// makeFakeMain(); -// this.body = PTAUtils.getMethodBody(method); -// } -// } -// } - return this.method; + if (CoreConfig.v().getPtaConfig().singleentry) { + List entries = entryPoints.application(); + if (entries.isEmpty()) { + throw new RuntimeException("Must specify MAINCLASS when appmode enabled!!!"); + } else { + ret.addAll(entries); + } + } else { + System.out.println("include implicit entry!"); + ret.addAll(entryPoints.application()); + ret.addAll(entryPoints.implicit()); } + System.out.println("#EntrySize:" + ret.size()); + return ret; + } + + public Value getFieldCurrentThread() { + return getStaticFieldRef("FakeMain", "currentThread"); + } + + public Value getFieldGlobalThrow() { + return getStaticFieldRef("FakeMain", "globalThrow"); + } - private List getEntryPoints() { - List ret = new ArrayList<>(); - if (CoreConfig.v().getPtaConfig().clinitMode == CoreConfig.ClinitMode.FULL) { - ret.addAll(EntryPoints.v().clinits()); - } else { - // on the fly mode, resolve the clinit methods on the fly. - ret.addAll(Collections.emptySet()); + private void makeFakeMain(SootField currentThread) { + implicitCallEdges = 0; + for (SootMethod entry : getEntryPoints()) { + if (entry.isStatic()) { + if (entry + .getSignature() + .getSubSignature() + .toString() + .equals("void main(java.lang.String[])")) { + Value mockStr = getNew(PTAUtils.getClassType("java.lang.String")); + Immediate strArray = getNewArray(PTAUtils.getClassType("java.lang.String")); + addAssign(getArrayRef(strArray), mockStr); + addInvoke(entry.getSignature().toString(), strArray); + implicitCallEdges++; + } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY + || !PTAUtils.isStaticInitializer(entry)) { + // in the on fly mode, we won't add a call directly for methods. + addInvoke(entry.getSignature().toString()); + implicitCallEdges++; } + } + } + if (CoreConfig.v().getPtaConfig().singleentry) { + return; + } + Local sv = getNextLocal(PTAUtils.getClassType("java.lang.String")); + Local mainThread = getNew(PTAUtils.getClassType("java.lang.Thread")); + Local mainThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); + Local systemThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); - if (CoreConfig.v().getPtaConfig().singleentry) { - List entries = EntryPoints.v().application(); - if (entries.isEmpty()) { - throw new RuntimeException("Must specify MAINCLASS when appmode enabled!!!"); - } else { - ret.addAll(entries); - } - } else { - System.out.println("include implicit entry!"); - ret.addAll(EntryPoints.v().application()); - ret.addAll(EntryPoints.v().implicit()); + Value gCurrentThread = Jimple.newStaticFieldRef(currentThread.getSignature()); + addAssign(gCurrentThread, mainThread); // Store + Local vRunnable = getNextLocal(PTAUtils.getClassType("java.lang.Runnable")); + + Local lThreadGroup = getNextLocal(PTAUtils.getClassType("java.lang.ThreadGroup")); + addInvoke( + mainThread, + "(java.lang.ThreadGroup,java.lang.String)>", + mainThreadGroup, + sv); + Local tmpThread = getNew(PTAUtils.getClassType("java.lang.Thread")); + addInvoke( + tmpThread, + "(java.lang.ThreadGroup,java.lang.Runnable)>", + lThreadGroup, + vRunnable); + addInvoke(tmpThread, ""); + + addInvoke(systemThreadGroup, "()>"); + addInvoke( + mainThreadGroup, + "(java.lang.ThreadGroup,java.lang.String)>", + systemThreadGroup, + sv); + + Local lThread = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); + Local lThrowable = getNextLocal(PTAUtils.getClassType("java.lang.Throwable")); + Local tmpThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); + addInvoke( + tmpThreadGroup, + "", + lThread, + lThrowable); // TODO. + + // ClassLoader + Local defaultClassLoader = getNew(PTAUtils.getClassType("sun.misc.Launcher$AppClassLoader")); + addInvoke(defaultClassLoader, "()>"); + Local vClass = getNextLocal(PTAUtils.getClassType("java.lang.Class")); + Local vDomain = getNextLocal(PTAUtils.getClassType("java.security.ProtectionDomain")); + addInvoke( + defaultClassLoader, + "", + sv); + addInvoke( + defaultClassLoader, + "", + vClass, + vDomain); + addInvoke( + defaultClassLoader, "", vClass); + + // PrivilegedActionException + Local privilegedActionException = + getNew(PTAUtils.getClassType("java.security.PrivilegedActionException")); + Local gLthrow = getNextLocal(PTAUtils.getClassType("java.lang.Exception")); + addInvoke( + privilegedActionException, + "(java.lang.Exception)>", + gLthrow); + } + + public class EntryPoints { + + final MethodSubSignature sigMain; + final MethodSubSignature sigFinalize; + final MethodSubSignature sigExit; + final MethodSubSignature sigClinit; + final MethodSubSignature sigInit; + final MethodSubSignature sigStart; + final MethodSubSignature sigRun; + final MethodSubSignature sigObjRun; + final MethodSubSignature sigForName; + + private EntryPoints() { + sigMain = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_MAIN); + sigFinalize = + JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_FINALIZE); + + sigExit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_EXIT); + sigClinit = + JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_CLINIT); + sigInit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_INIT); + sigStart = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_START); + sigRun = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_RUN); + sigObjRun = + JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_OBJ_RUN); + sigForName = + JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_FOR_NAME); + } + + protected void addMethod(List set, SootClass cls, MethodSubSignature methodSubSig) { + Optional osm = cls.getMethod(methodSubSig); + osm.ifPresent(set::add); + } + + protected void addMethod(List set, String methodSig) { + MethodSignature ms = JavaIdentifierFactory.getInstance().parseMethodSignature(methodSig); + Optional osm = view.getMethod(ms); + osm.ifPresent(set::add); + } + + /** + * Returns only the application entry points, not including entry points invoked implicitly by + * the VM. + */ + public List application() { + List ret = new ArrayList(); + if (mainClass != null) { + addMethod(ret, mainClass, sigMain); + for (SootMethod clinit : clinitsOf(mainClass)) { + ret.add(clinit); } - System.out.println("#EntrySize:" + ret.size()); - return ret; + } + return ret; + } + + /** Returns only the entry points invoked implicitly by the VM. */ + public List implicit() { + List ret = new ArrayList(); + + // if (Options.v().src_prec() == Options.src_prec_dotnet) { + // return ret; + // } + + addMethod(ret, JavaMethods.INITIALIZE_SYSTEM_CLASS); + addMethod(ret, JavaMethods.THREAD_GROUP_INIT); + // addMethod( ret, ""); + addMethod(ret, JavaMethods.THREAD_EXIT); + addMethod(ret, JavaMethods.THREADGROUP_UNCAUGHT_EXCEPTION); + // addMethod( ret, ""); + addMethod(ret, JavaMethods.CLASSLOADER_INIT); + addMethod(ret, JavaMethods.CLASSLOADER_LOAD_CLASS_INTERNAL); + addMethod(ret, JavaMethods.CLASSLOADER_CHECK_PACKAGE_ACC); + addMethod(ret, JavaMethods.CLASSLOADER_ADD_CLASS); + addMethod(ret, JavaMethods.CLASSLOADER_FIND_NATIVE); + addMethod(ret, JavaMethods.PRIV_ACTION_EXC_INIT); + // addMethod( ret, ""); + addMethod(ret, JavaMethods.RUN_FINALIZE); + addMethod(ret, JavaMethods.THREAD_INIT_RUNNABLE); + addMethod(ret, JavaMethods.THREAD_INIT_STRING); + return ret; } - public Value getFieldCurrentThread() { - return getStaticFieldRef("FakeMain", "currentThread"); + /** Returns all the entry points. */ + public List all() { + List ret = new ArrayList(); + ret.addAll(application()); + ret.addAll(implicit()); + return ret; } - public Value getFieldGlobalThrow() { - return getStaticFieldRef("FakeMain", "globalThrow"); + /** Returns a list of all static initializers. */ + public List clinits() { + List ret = new ArrayList(); + Collection classes = view.getClasses(); + for (SootClass cl : classes) { + addMethod(ret, cl, sigClinit); + } + return ret; } - private void makeFakeMain() { - implicitCallEdges = 0; - for (SootMethod entry : getEntryPoints()) { - if (entry.isStatic()) { - if (entry.getSignature().getSubSignature().toString().equals("void main(java.lang.String[])")) { - Value mockStr = getNew(PTAUtils.getClassType("java.lang.String")); - Immediate strArray = getNewArray(PTAUtils.getClassType("java.lang.String")); - addAssign(getArrayRef(strArray), mockStr); - addInvoke(entry.getSignature().toString(), strArray); - implicitCallEdges++; - } else if (CoreConfig.v().getPtaConfig().clinitMode != CoreConfig.ClinitMode.ONFLY || !PTAUtils.isStaticInitializer(entry)) { - // in the on fly mode, we won't add a call directly for methods. - addInvoke(entry.getSignature().toString()); - implicitCallEdges++; + /** Returns a list of all clinits of class cl and its superclasses. */ + public Iterable clinitsOf(SootClass cl) { + // Do not create an actual list, since this method gets called quite often + // Instead, callers usually just want to iterate over the result. + Optional oinit = cl.getMethod(sigClinit); + Optional osuperClass = cl.getSuperclass(); + // check super classes until finds a constructor or no super class there anymore. + while (oinit.isPresent() && osuperClass.isPresent()) { + oinit = osuperClass.get().getMethod(sigClinit); + osuperClass = osuperClass.get().getSuperclass(); + } + if (!oinit.isPresent()) { + return Collections.emptyList(); + } + SootMethod initStart = oinit.get(); + return new Iterable() { + + @Override + public Iterator iterator() { + return new Iterator() { + SootMethod current = initStart; + + @Override + public SootMethod next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + SootMethod n = current; + + // Pre-fetch the next element + current = null; + SootClass currentClass = (SootClass) view.getClass(n.getDeclaringClassType()).get(); + while (true) { + Optional osuperClass = currentClass.getSuperclass(); + if (!osuperClass.isPresent()) { + break; } + + Optional om = osuperClass.get().getMethod(sigClinit); + if (om.isPresent()) { + current = om.get(); + break; + } + + currentClass = osuperClass.get(); + } + + return n; } + + @Override + public boolean hasNext() { + return current != null; + } + }; } - if (CoreConfig.v().getPtaConfig().singleentry) { - return; - } - Local sv = getNextLocal(PTAUtils.getClassType("java.lang.String")); - Local mainThread = getNew(PTAUtils.getClassType("java.lang.Thread")); - Local mainThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); - Local systemThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); - - Value gCurrentThread = getFieldCurrentThread(); - addAssign(gCurrentThread, mainThread); // Store - Local vRunnable = getNextLocal(PTAUtils.getClassType("java.lang.Runnable")); - - Local lThreadGroup = getNextLocal(PTAUtils.getClassType("java.lang.ThreadGroup")); - addInvoke(mainThread, "(java.lang.ThreadGroup,java.lang.String)>", mainThreadGroup, sv); - Local tmpThread = getNew(PTAUtils.getClassType("java.lang.Thread")); - addInvoke(tmpThread, "(java.lang.ThreadGroup,java.lang.Runnable)>", lThreadGroup, vRunnable); - addInvoke(tmpThread, ""); - - addInvoke(systemThreadGroup, "()>"); - addInvoke(mainThreadGroup, "(java.lang.ThreadGroup,java.lang.String)>", systemThreadGroup, sv); - - Local lThread = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); - Local lThrowable = getNextLocal(PTAUtils.getClassType("java.lang.Throwable")); - Local tmpThreadGroup = getNew(PTAUtils.getClassType("java.lang.ThreadGroup")); - addInvoke(tmpThreadGroup, "", lThread, lThrowable); // TODO. - - - // ClassLoader - Local defaultClassLoader = getNew(PTAUtils.getClassType("sun.misc.Launcher$AppClassLoader")); - addInvoke(defaultClassLoader, "()>"); - Local vClass = getNextLocal(PTAUtils.getClassType("java.lang.Class")); - Local vDomain = getNextLocal(PTAUtils.getClassType("java.security.ProtectionDomain")); - addInvoke(defaultClassLoader, "", sv); - addInvoke(defaultClassLoader, "", vClass, vDomain); - addInvoke(defaultClassLoader, "", vClass); - - // PrivilegedActionException - Local privilegedActionException = getNew(PTAUtils.getClassType("java.security.PrivilegedActionException")); - Local gLthrow = getNextLocal(PTAUtils.getClassType("java.lang.Exception")); - addInvoke(privilegedActionException, "(java.lang.Exception)>", gLthrow); + }; } + } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java index b0b95a947f9..30afd0c48a3 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/MethodNodeFactory.java @@ -18,6 +18,9 @@ package qilin.core.builder; +import java.util.Collections; +import java.util.Optional; +import javax.annotation.Nonnull; import qilin.CoreConfig; import qilin.core.PTAScene; import qilin.core.PointsToAnalysis; @@ -62,304 +65,321 @@ import sootup.core.types.Type; import sootup.java.core.language.JavaJimple; -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.Optional; - /** * @author Ondrej Lhotak */ public class MethodNodeFactory { - protected PAG pag; - protected MethodPAG mpag; - protected SootMethod method; - - public MethodNodeFactory(PAG pag, MethodPAG mpag) { - this.pag = pag; - this.mpag = mpag; - method = mpag.getMethod(); + protected PAG pag; + protected MethodPAG mpag; + protected SootMethod method; + + public MethodNodeFactory(PAG pag, MethodPAG mpag) { + this.pag = pag; + this.mpag = mpag; + method = mpag.getMethod(); + } + + public Node getNode(Value v) { + if (v instanceof Local l) { + return caseLocal(l); + } else if (v instanceof JCastExpr castExpr) { + return caseCastExpr(castExpr); + } else if (v instanceof JNewExpr ne) { + return caseNewExpr(ne); + } else if (v instanceof JStaticFieldRef sfr) { + return caseStaticFieldRef(sfr); + } else if (v instanceof JNewArrayExpr nae) { + return caseNewArrayExpr(nae); + } else if (v instanceof JArrayRef ar) { + return caseArrayRef(ar); + } else if (v instanceof ClassConstant cc) { + return caseClassConstant(cc); + } else if (v instanceof StringConstant sc) { + return caseStringConstant(sc); + } else if (v instanceof JCaughtExceptionRef cef) { + return caseCaughtExceptionRef(cef); + } else if (v instanceof JParameterRef pr) { + return caseParameterRef(pr); + } else if (v instanceof NullConstant nc) { + return caseNullConstant(nc); + } else if (v instanceof JInstanceFieldRef ifr) { + return caseInstanceFieldRef(ifr); + } else if (v instanceof JThisRef) { + return caseThis(); + } else if (v instanceof JNewMultiArrayExpr nmae) { + return caseNewMultiArrayExpr(nmae); } - - public Node getNode(Value v) { - if (v instanceof Local l) { - return caseLocal(l); - } else if (v instanceof JCastExpr castExpr) { - return caseCastExpr(castExpr); - } else if (v instanceof JNewExpr ne) { - return caseNewExpr(ne); - } else if (v instanceof JStaticFieldRef sfr) { - return caseStaticFieldRef(sfr); - } else if (v instanceof JNewArrayExpr nae) { - return caseNewArrayExpr(nae); - } else if (v instanceof JArrayRef ar) { - return caseArrayRef(ar); - } else if (v instanceof ClassConstant cc) { - return caseClassConstant(cc); - } else if (v instanceof StringConstant sc) { - return caseStringConstant(sc); - } else if (v instanceof JCaughtExceptionRef cef) { - return caseCaughtExceptionRef(cef); - } else if (v instanceof JParameterRef pr) { - return caseParameterRef(pr); - } else if (v instanceof NullConstant nc) { - return caseNullConstant(nc); - } else if (v instanceof JInstanceFieldRef ifr) { - return caseInstanceFieldRef(ifr); - } else if (v instanceof JThisRef) { - return caseThis(); - } else if (v instanceof JNewMultiArrayExpr nmae) { - return caseNewMultiArrayExpr(nmae); - } - System.out.println(v + ";;" + v.getClass()); - return null; + System.out.println(v + ";;" + v.getClass()); + return null; + } + + /** Adds the edges required for this statement to the graph. */ + public final void handleStmt(Stmt s) { + if (s.containsInvokeExpr()) { + mpag.addCallStmt(s); + handleInvokeStmt(s); + } else { + handleIntraStmt(s); } - - /** - * Adds the edges required for this statement to the graph. - */ - final public void handleStmt(Stmt s) { - if (s.containsInvokeExpr()) { - mpag.addCallStmt(s); - handleInvokeStmt(s); - } else { - handleIntraStmt(s); - } + } + + /** + * Adds the edges required for this statement to the graph. Add throw stmt if the invoke method + * throws an Exception. + */ + protected void handleInvokeStmt(Stmt s) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + getNode(arg); } - - /** - * Adds the edges required for this statement to the graph. Add throw stmt if - * the invoke method throws an Exception. - */ - protected void handleInvokeStmt(Stmt s) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { - continue; - } - getNode(arg); - } - if (s instanceof JAssignStmt assignStmt) { - Value l = assignStmt.getLeftOp(); - if ((l.getType() instanceof ReferenceType)) { - getNode(l); - } - } - if (ie instanceof AbstractInstanceInvokeExpr aie) { - getNode(aie.getBase()); - } + if (s instanceof JAssignStmt assignStmt) { + Value l = assignStmt.getLeftOp(); + if ((l.getType() instanceof ReferenceType)) { + getNode(l); + } } - - private void resolveClinit(JStaticFieldRef staticFieldRef) { - FieldSignature fieldSig = staticFieldRef.getFieldSignature(); - SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); - ClassType classType = field.getDeclaringClassType(); - SootClass sootClass = (SootClass) PTAScene.v().getView().getClass(classType).get(); - PTAUtils.clinitsOf(sootClass).forEach(mpag::addTriggeredClinit); + if (ie instanceof AbstractInstanceInvokeExpr aie) { + getNode(aie.getBase()); } - - /** - * Adds the edges required for this statement to the graph. - */ - private void handleIntraStmt(Stmt s) { - s.accept(new AbstractStmtVisitor<>() { - @Override - public void caseAssignStmt(@Nonnull JAssignStmt stmt) { - Value l = stmt.getLeftOp(); - Value r = stmt.getRightOp(); - if (l instanceof JStaticFieldRef) { - resolveClinit((JStaticFieldRef) l); - } else if (r instanceof JStaticFieldRef) { - resolveClinit((JStaticFieldRef) r); - } - - if (!(l.getType() instanceof ReferenceType)) - return; - // check for improper casts, with mal-formed code we might get - // l = (refliketype)int_type, if so just return - if (r instanceof JCastExpr && (!(((JCastExpr) r).getOp().getType() instanceof ReferenceType))) { - return; - } - - if (!(r.getType() instanceof ReferenceType)) - throw new RuntimeException("Type mismatch in assignment (rhs not a RefLikeType) " + stmt - + " in method " + method.getSignature()); - Node dest = getNode(l); - Node src = getNode(r); - mpag.addInternalEdge(src, dest); + } + + private void resolveClinit(JStaticFieldRef staticFieldRef) { + FieldSignature fieldSig = staticFieldRef.getFieldSignature(); + SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); + ClassType classType = field.getDeclaringClassType(); + SootClass sootClass = (SootClass) PTAScene.v().getView().getClass(classType).get(); + PTAUtils.clinitsOf(sootClass).forEach(mpag::addTriggeredClinit); + } + + /** Adds the edges required for this statement to the graph. */ + private void handleIntraStmt(Stmt s) { + s.accept( + new AbstractStmtVisitor<>() { + @Override + public void caseAssignStmt(@Nonnull JAssignStmt stmt) { + Value l = stmt.getLeftOp(); + Value r = stmt.getRightOp(); + if (l instanceof JStaticFieldRef) { + resolveClinit((JStaticFieldRef) l); + } else if (r instanceof JStaticFieldRef) { + resolveClinit((JStaticFieldRef) r); } - @Override - public void caseIdentityStmt(@Nonnull JIdentityStmt stmt) { - if (!(stmt.getLeftOp().getType() instanceof ReferenceType)) { - return; - } - Node dest = getNode(stmt.getLeftOp()); - Node src = getNode(stmt.getRightOp()); - mpag.addInternalEdge(src, dest); + if (!(l.getType() instanceof ReferenceType)) return; + // check for improper casts, with mal-formed code we might get + // l = (refliketype)int_type, if so just return + if (r instanceof JCastExpr + && (!(((JCastExpr) r).getOp().getType() instanceof ReferenceType))) { + return; } - @Override - public void caseExitMonitorStmt(@Nonnull JExitMonitorStmt stmt) { - defaultCaseStmt(stmt); + if (!(r.getType() instanceof ReferenceType)) + throw new RuntimeException( + "Type mismatch in assignment (rhs not a RefLikeType) " + + stmt + + " in method " + + method.getSignature()); + Node dest = getNode(l); + Node src = getNode(r); + mpag.addInternalEdge(src, dest); + } + + @Override + public void caseIdentityStmt(@Nonnull JIdentityStmt stmt) { + if (!(stmt.getLeftOp().getType() instanceof ReferenceType)) { + return; } - - @Override - public void caseReturnStmt(@Nonnull JReturnStmt stmt) { - if (!(stmt.getOp().getType() instanceof ReferenceType)) - return; - Node retNode = getNode(stmt.getOp()); - mpag.addInternalEdge(retNode, caseRet()); - } - - @Override - public void caseThrowStmt(@Nonnull JThrowStmt stmt) { - if (!CoreConfig.v().getPtaConfig().preciseExceptions) { - mpag.addInternalEdge(getNode(stmt.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); - } + Node dest = getNode(stmt.getLeftOp()); + Node src = getNode(stmt.getRightOp()); + mpag.addInternalEdge(src, dest); + } + + @Override + public void caseExitMonitorStmt(@Nonnull JExitMonitorStmt stmt) { + defaultCaseStmt(stmt); + } + + @Override + public void caseReturnStmt(@Nonnull JReturnStmt stmt) { + if (!(stmt.getOp().getType() instanceof ReferenceType)) return; + Node retNode = getNode(stmt.getOp()); + mpag.addInternalEdge(retNode, caseRet()); + } + + @Override + public void caseThrowStmt(@Nonnull JThrowStmt stmt) { + if (!CoreConfig.v().getPtaConfig().preciseExceptions) { + mpag.addInternalEdge( + getNode(stmt.getOp()), getNode(PTAScene.v().getFieldGlobalThrow())); } + } }); + } + + private VarNode caseLocal(Local l) { + return pag.makeLocalVarNode(l, l.getType(), method); + } + + private AllocNode caseNewArrayExpr(JNewArrayExpr nae) { + return pag.makeAllocNode(nae, nae.getType(), method); + } + + private AllocNode caseNewExpr(JNewExpr ne) { + SootClass cl = PTAScene.v().getSootClass(ne.getType().toString()); + PTAUtils.clinitsOf(cl).forEach(mpag::addTriggeredClinit); + return pag.makeAllocNode(ne, ne.getType(), method); + } + + private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { + FieldSignature fieldSig = ifr.getFieldSignature(); + Optional osf = PTAScene.v().getView().getField(fieldSig); + SootField sf; + if (osf.isEmpty()) { + sf = + new SootField( + fieldSig, + Collections.singleton(Modifier.PUBLIC), + NoPositionInformation.getInstance()); + System.out.println("Warnning:" + ifr + " is resolved to be a null field in Scene."); + } else { + sf = osf.get(); } - - private VarNode caseLocal(Local l) { - return pag.makeLocalVarNode(l, l.getType(), method); - } - - private AllocNode caseNewArrayExpr(JNewArrayExpr nae) { - return pag.makeAllocNode(nae, nae.getType(), method); - } - - private AllocNode caseNewExpr(JNewExpr ne) { - SootClass cl = PTAScene.v().loadClassAndSupport(ne.getType().toString()); - PTAUtils.clinitsOf(cl).forEach(mpag::addTriggeredClinit); - return pag.makeAllocNode(ne, ne.getType(), method); - } - - private FieldRefNode caseInstanceFieldRef(JInstanceFieldRef ifr) { - FieldSignature fieldSig = ifr.getFieldSignature(); - Optional osf = PTAScene.v().getView().getField(fieldSig); - SootField sf; - if (osf.isEmpty()) { - sf = new SootField(fieldSig, Collections.singleton(Modifier.PUBLIC), NoPositionInformation.getInstance()); - System.out.println("Warnning:" + ifr + " is resolved to be a null field in Scene."); - } else { - sf = osf.get(); - } - return pag.makeFieldRefNode(pag.makeLocalVarNode(ifr.getBase(), ifr.getBase().getType(), method), new Field(sf)); + return pag.makeFieldRefNode( + pag.makeLocalVarNode(ifr.getBase(), ifr.getBase().getType(), method), new Field(sf)); + } + + private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { + ArrayType type = (ArrayType) nmae.getType(); + int pos = 0; + AllocNode prevAn = + pag.makeAllocNode( + JavaJimple.getInstance().newNewArrayExpr(type, nmae.getSize(pos)), type, method); + VarNode prevVn = pag.makeLocalVarNode(prevAn.getNewExpr(), prevAn.getType(), method); + mpag.addInternalEdge(prevAn, prevVn); // new + VarNode ret = prevVn; + while (true) { + Type t = type.getArrayElementType(); + if (!(t instanceof ArrayType)) { + break; + } + type = (ArrayType) t; + ++pos; + Immediate sizeVal; + if (pos < nmae.getSizeCount()) { + sizeVal = nmae.getSize(pos); + } else { + sizeVal = IntConstant.getInstance(1); + } + AllocNode an = + pag.makeAllocNode(JavaJimple.getInstance().newNewArrayExpr(type, sizeVal), type, method); + VarNode vn = pag.makeLocalVarNode(an.getNewExpr(), an.getType(), method); + mpag.addInternalEdge(an, vn); // new + mpag.addInternalEdge(vn, pag.makeFieldRefNode(prevVn, ArrayElement.v())); // store + prevVn = vn; } - - private VarNode caseNewMultiArrayExpr(JNewMultiArrayExpr nmae) { - ArrayType type = (ArrayType) nmae.getType(); - int pos = 0; - AllocNode prevAn = pag.makeAllocNode(JavaJimple.getInstance().newNewArrayExpr(type, nmae.getSize(pos)), type, method); - VarNode prevVn = pag.makeLocalVarNode(prevAn.getNewExpr(), prevAn.getType(), method); - mpag.addInternalEdge(prevAn, prevVn); // new - VarNode ret = prevVn; - while (true) { - Type t = type.getArrayElementType(); - if (!(t instanceof ArrayType)) { - break; - } - type = (ArrayType) t; - ++pos; - Immediate sizeVal; - if (pos < nmae.getSizeCount()) { - sizeVal = nmae.getSize(pos); - } else { - sizeVal = IntConstant.getInstance(1); - } - AllocNode an = pag.makeAllocNode(JavaJimple.getInstance().newNewArrayExpr(type, sizeVal), type, method); - VarNode vn = pag.makeLocalVarNode(an.getNewExpr(), an.getType(), method); - mpag.addInternalEdge(an, vn); // new - mpag.addInternalEdge(vn, pag.makeFieldRefNode(prevVn, ArrayElement.v())); // store - prevVn = vn; - } - return ret; - } - - private VarNode caseCastExpr(JCastExpr ce) { - Node opNode = getNode(ce.getOp()); - VarNode castNode = pag.makeLocalVarNode(ce, ce.getType(), method); - mpag.addInternalEdge(opNode, castNode); - return castNode; + return ret; + } + + private VarNode caseCastExpr(JCastExpr ce) { + Node opNode = getNode(ce.getOp()); + VarNode castNode = pag.makeLocalVarNode(ce, ce.getType(), method); + mpag.addInternalEdge(opNode, castNode); + return castNode; + } + + public VarNode caseThis() { + Type type = + method.isStatic() + ? PTAUtils.getClassType("java.lang.Object") + : method.getDeclaringClassType(); + VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THIS_NODE), type, method); + ret.setInterProcTarget(); + return ret; + } + + public VarNode caseParm(int index) { + VarNode ret = + pag.makeLocalVarNode(new Parm(method, index), method.getParameterType(index), method); + ret.setInterProcTarget(); + return ret; + } + + public VarNode caseRet() { + VarNode ret = + pag.makeLocalVarNode( + new Parm(method, PointsToAnalysis.RETURN_NODE), method.getReturnType(), method); + ret.setInterProcSource(); + return ret; + } + + public VarNode caseMethodThrow() { + VarNode ret = + pag.makeLocalVarNode( + new Parm(method, PointsToAnalysis.THROW_NODE), + PTAUtils.getClassType("java.lang.Throwable"), + method); + ret.setInterProcSource(); + return ret; + } + + public final FieldRefNode caseArray(VarNode base) { + return pag.makeFieldRefNode(base, ArrayElement.v()); + } + + private Node caseCaughtExceptionRef(JCaughtExceptionRef cer) { + if (CoreConfig.v().getPtaConfig().preciseExceptions) { + // we model caughtException expression as an local assignment. + return pag.makeLocalVarNode(cer, cer.getType(), method); + } else { + return getNode(PTAScene.v().getFieldGlobalThrow()); } - - public VarNode caseThis() { - Type type = method.isStatic() ? PTAUtils.getClassType("java.lang.Object") : method.getDeclaringClassType(); - VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THIS_NODE), type, method); - ret.setInterProcTarget(); - return ret; - } - - public VarNode caseParm(int index) { - VarNode ret = pag.makeLocalVarNode(new Parm(method, index), method.getParameterType(index), method); - ret.setInterProcTarget(); - return ret; - } - - public VarNode caseRet() { - VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.RETURN_NODE), method.getReturnType(), method); - ret.setInterProcSource(); - return ret; - } - - public VarNode caseMethodThrow() { - VarNode ret = pag.makeLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE), PTAUtils.getClassType("java.lang.Throwable"), method); - ret.setInterProcSource(); - return ret; - } - - final public FieldRefNode caseArray(VarNode base) { - return pag.makeFieldRefNode(base, ArrayElement.v()); - } - - private Node caseCaughtExceptionRef(JCaughtExceptionRef cer) { - if (CoreConfig.v().getPtaConfig().preciseExceptions) { - // we model caughtException expression as an local assignment. - return pag.makeLocalVarNode(cer, cer.getType(), method); - } else { - return getNode(PTAScene.v().getFieldGlobalThrow()); - } - } - - private FieldRefNode caseArrayRef(JArrayRef ar) { - return caseArray(caseLocal(ar.getBase())); - } - - private VarNode caseParameterRef(JParameterRef pr) { - return caseParm(pr.getIndex()); - } - - private VarNode caseStaticFieldRef(JStaticFieldRef sfr) { - return pag.makeGlobalVarNode(sfr.getFieldSignature(), sfr.getType()); - } - - private Node caseNullConstant(NullConstant nr) { - return null; - } - - private VarNode caseStringConstant(StringConstant sc) { - AllocNode stringConstantNode = pag.makeStringConstantNode(sc); - VarNode stringConstantVar = pag.makeGlobalVarNode(sc, PTAUtils.getClassType("java.lang.String")); - mpag.addInternalEdge(stringConstantNode, stringConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, sc), PTAUtils.getClassType("java.lang.String"), method); - mpag.addInternalEdge(stringConstantVar, vn); - return vn; - } - - public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { - return pag.makeLocalVarNode(invoke, PTAUtils.getClassType("java.lang.Throwable"), method); - } - - final public VarNode caseClassConstant(ClassConstant cc) { - AllocNode classConstant = pag.makeClassConstantNode(cc); - VarNode classConstantVar = pag.makeGlobalVarNode(cc, PTAUtils.getClassType("java.lang.Class")); - mpag.addInternalEdge(classConstant, classConstantVar); - VarNode vn = pag.makeLocalVarNode(new Pair<>(method, cc), PTAUtils.getClassType("java.lang.Class"), method); - mpag.addInternalEdge(classConstantVar, vn); - return vn; - } - - + } + + private FieldRefNode caseArrayRef(JArrayRef ar) { + return caseArray(caseLocal(ar.getBase())); + } + + private VarNode caseParameterRef(JParameterRef pr) { + return caseParm(pr.getIndex()); + } + + private VarNode caseStaticFieldRef(JStaticFieldRef sfr) { + return pag.makeGlobalVarNode(sfr.getFieldSignature(), sfr.getType()); + } + + private Node caseNullConstant(NullConstant nr) { + return null; + } + + private VarNode caseStringConstant(StringConstant sc) { + AllocNode stringConstantNode = pag.makeStringConstantNode(sc); + VarNode stringConstantVar = + pag.makeGlobalVarNode(sc, PTAUtils.getClassType("java.lang.String")); + mpag.addInternalEdge(stringConstantNode, stringConstantVar); + VarNode vn = + pag.makeLocalVarNode( + new Pair<>(method, sc), PTAUtils.getClassType("java.lang.String"), method); + mpag.addInternalEdge(stringConstantVar, vn); + return vn; + } + + public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { + return pag.makeLocalVarNode(invoke, PTAUtils.getClassType("java.lang.Throwable"), method); + } + + public final VarNode caseClassConstant(ClassConstant cc) { + AllocNode classConstant = pag.makeClassConstantNode(cc); + VarNode classConstantVar = pag.makeGlobalVarNode(cc, PTAUtils.getClassType("java.lang.Class")); + mpag.addInternalEdge(classConstant, classConstantVar); + VarNode vn = + pag.makeLocalVarNode( + new Pair<>(method, cc), PTAUtils.getClassType("java.lang.Class"), method); + mpag.addInternalEdge(classConstantVar, vn); + return vn; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/context/ContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/ContextElement.java index bb4a896eab6..5bec7e90783 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/ContextElement.java +++ b/sootup.qilin/src/main/java/qilin/core/context/ContextElement.java @@ -19,9 +19,9 @@ package qilin.core.context; public interface ContextElement { - @Override - int hashCode(); + @Override + int hashCode(); - @Override - boolean equals(Object obj); + @Override + boolean equals(Object obj); } diff --git a/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java b/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java index 2e186994d55..f8528c0b9b3 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java +++ b/sootup.qilin/src/main/java/qilin/core/context/ContextElements.java @@ -18,110 +18,103 @@ package qilin.core.context; -import soot.Context; - import java.util.Arrays; +import soot.Context; public class ContextElements implements Context { - private final ContextElement[] array; - private final int size; - private int hashCode = 0; - - public ContextElements(ContextElement[] array, int s) { - this.array = array; - this.size = s; - } - - public ContextElement[] getElements() { - return array; - } - - public ContextElement get(int i) { - return array[i]; - } - - public boolean contains(ContextElement heap) { - for (int i = 0; i < size; ++i) { - if (array[i] == heap) { - return true; - } - } - return false; + private final ContextElement[] array; + private final int size; + private int hashCode = 0; + + public ContextElements(ContextElement[] array, int s) { + this.array = array; + this.size = s; + } + + public ContextElement[] getElements() { + return array; + } + + public ContextElement get(int i) { + return array[i]; + } + + public boolean contains(ContextElement heap) { + for (int i = 0; i < size; ++i) { + if (array[i] == heap) { + return true; + } } + return false; + } - public boolean isEmpty() { - return size == 0; - } + public boolean isEmpty() { + return size == 0; + } - public int size() { - return size; - } + public int size() { + return size; + } - @Override - public int hashCode() { - if (hashCode == 0) { - hashCode = Arrays.hashCode(array); - } - return hashCode; + @Override + public int hashCode() { + if (hashCode == 0) { + hashCode = Arrays.hashCode(array); } + return hashCode; + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (getClass() != obj.getClass()) - return false; - ContextElements other = (ContextElements) obj; - - // if (!Arrays.equals(array, other.array)) return false; + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (getClass() != obj.getClass()) return false; + ContextElements other = (ContextElements) obj; - // custom array equals for context - // allows for checking of different sized arrays, but represent same - // context-sensitive heap object - if (this.array == null || other.array == null) - return false; + // if (!Arrays.equals(array, other.array)) return false; - if (this.size() != other.size()) - return false; + // custom array equals for context + // allows for checking of different sized arrays, but represent same + // context-sensitive heap object + if (this.array == null || other.array == null) return false; - for (int i = 0; i < size(); i++) { - Object o1 = this.array[i]; - Object o2 = other.array[i]; - if (!(o1 == null ? o2 == null : o1.equals(o2))) - return false; - } + if (this.size() != other.size()) return false; - return true; + for (int i = 0; i < size(); i++) { + Object o1 = this.array[i]; + Object o2 = other.array[i]; + if (!(o1 == null ? o2 == null : o1.equals(o2))) return false; } - @Override - public String toString() { - StringBuilder localStringBuilder = new StringBuilder(); - localStringBuilder.append('['); - for (int i = 0; i < array.length; i++) { - localStringBuilder.append(array[i]); - if (i < array.length - 1) { - localStringBuilder.append(", "); - } - } - localStringBuilder.append(']'); - return localStringBuilder.toString(); + return true; + } + + @Override + public String toString() { + StringBuilder localStringBuilder = new StringBuilder(); + localStringBuilder.append('['); + for (int i = 0; i < array.length; i++) { + localStringBuilder.append(array[i]); + if (i < array.length - 1) { + localStringBuilder.append(", "); + } } - - /** - * Compose a new context by a given context and a heap. - * The depth of new context is also required. - */ - public static ContextElements newContext(ContextElements c, ContextElement ce, int depth) { - ContextElement[] array; - if (c.size() < depth) { - array = new ContextElement[c.size() + 1]; - System.arraycopy(c.getElements(), 0, array, 1, c.size()); - } else { - array = new ContextElement[depth]; - System.arraycopy(c.getElements(), 0, array, 1, depth - 1); - } - array[0] = ce; - return new ContextElements(array, array.length); + localStringBuilder.append(']'); + return localStringBuilder.toString(); + } + + /** + * Compose a new context by a given context and a heap. The depth of new context is also required. + */ + public static ContextElements newContext(ContextElements c, ContextElement ce, int depth) { + ContextElement[] array; + if (c.size() < depth) { + array = new ContextElement[c.size() + 1]; + System.arraycopy(c.getElements(), 0, array, 1, c.size()); + } else { + array = new ContextElement[depth]; + System.arraycopy(c.getElements(), 0, array, 1, depth - 1); } + array[0] = ce; + return new ContextElements(array, array.length); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java index 9c50aef412a..5886a20056a 100644 --- a/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java +++ b/sootup.qilin/src/main/java/qilin/core/context/TypeContextElement.java @@ -25,59 +25,54 @@ import sootup.core.model.SootMethod; import sootup.core.types.Type; -/** - * Type based context element in the points to analysis. - */ +/** Type based context element in the points to analysis. */ public class TypeContextElement implements ContextElement { - private final Type type; + private final Type type; - private TypeContextElement(Type type) { - this.type = type; - } + private TypeContextElement(Type type) { + this.type = type; + } - public static TypeContextElement getTypeContextElement(AllocNode a) { - SootMethod declaringMethod = a.getMethod(); - Type declType = PTAUtils.getClassType("java.lang.Object"); - if (declaringMethod != null) { - declType = declaringMethod.getDeclaringClassType(); - } else if (a instanceof ClassConstantNode) { - declType = PTAUtils.getClassType("java.lang.System"); - } else if (a instanceof StringConstantNode) { - declType = PTAUtils.getClassType("java.lang.String"); - } - return new TypeContextElement(declType); + public static TypeContextElement getTypeContextElement(AllocNode a) { + SootMethod declaringMethod = a.getMethod(); + Type declType = PTAUtils.getClassType("java.lang.Object"); + if (declaringMethod != null) { + declType = declaringMethod.getDeclaringClassType(); + } else if (a instanceof ClassConstantNode) { + declType = PTAUtils.getClassType("java.lang.System"); + } else if (a instanceof StringConstantNode) { + declType = PTAUtils.getClassType("java.lang.String"); } + return new TypeContextElement(declType); + } - public Type getType() { - return type; - } + public Type getType() { + return type; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((type == null) ? 0 : type.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - TypeContextElement other = (TypeContextElement) obj; - if (type == null) { - return other.type == null; - } else { - return type.equals(other.type); - } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + TypeContextElement other = (TypeContextElement) obj; + if (type == null) { + return other.type == null; + } else { + return type.equals(other.type); } + } - public String toString() { - return "TypeContext: " + type; - } + public String toString() { + return "TypeContext: " + type; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java index 508b7f6e11a..4f72d78729c 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemGetFileSystemNative.java @@ -23,21 +23,20 @@ import sootup.core.model.SootMethod; public class JavaIoFileSystemGetFileSystemNative extends NativeMethod { - public JavaIoFileSystemGetFileSystemNative(SootMethod method) { - super(method); - } + public JavaIoFileSystemGetFileSystemNative(SootMethod method) { + super(method); + } - /************************ java.io.FileSystem ***********************/ - /** - * Returns a variable pointing to the file system constant - *

- * public static native java.io.FileSystem getFileSystem(); - * only exists in old version of JDK(e.g., JDK6). - */ - public void simulate() { - Local newLocal0 = getNew(PTAUtils.getClassType("java.io.UnixFileSystem")); - addInvoke(newLocal0, "()>"); - addReturn(newLocal0); - - } + /** ********************** java.io.FileSystem ********************** */ + /** + * Returns a variable pointing to the file system constant + * + *

public static native java.io.FileSystem getFileSystem(); only exists in old version of + * JDK(e.g., JDK6). + */ + protected void simulateImpl() { + Local newLocal0 = getNew(PTAUtils.getClassType("java.io.UnixFileSystem")); + addInvoke(newLocal0, "()>"); + addReturn(newLocal0); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java index c6a00a6c1e7..de21140e23e 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaIoFileSystemListNative.java @@ -24,20 +24,17 @@ import sootup.core.model.SootMethod; public class JavaIoFileSystemListNative extends NativeMethod { - public JavaIoFileSystemListNative(SootMethod method) { - super(method); - } + public JavaIoFileSystemListNative(SootMethod method) { + super(method); + } - /************************ java.io.FileSystem ***********************/ - /** - * Returns a String[] - * only exists in old JDK(e.g., JDK6). - */ - public void simulate() { - Immediate arrLocal = getNewArray(PTAUtils.getClassType("java.lang.String")); - Value elem = getNew(PTAUtils.getClassType("java.lang.String")); -// addInvoke(elem, "()>"); - addAssign(getArrayRef(arrLocal), elem); - addReturn(arrLocal); - } + /** ********************** java.io.FileSystem ********************** */ + /** Returns a String[] only exists in old JDK(e.g., JDK6). */ + protected void simulateImpl() { + Immediate arrLocal = getNewArray(PTAUtils.getClassType("java.lang.String")); + Value elem = getNew(PTAUtils.getClassType("java.lang.String")); + // addInvoke(elem, "()>"); + addAssign(getArrayRef(arrLocal), elem); + addReturn(arrLocal); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java index fb61e9e7069..908538d8ebb 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangObjectCloneNative.java @@ -18,23 +18,21 @@ package qilin.core.natives; - import sootup.core.jimple.basic.Local; import sootup.core.model.SootMethod; public class JavaLangObjectCloneNative extends NativeMethod { - public JavaLangObjectCloneNative(SootMethod method) { - super(method); - } - - /** - * Implements the abstract method simulateMethod. It distributes the request to - * the corresponding methods by signatures. - */ - public void simulate() { - Local r0 = getThis(); - addReturn(r0); - } + public JavaLangObjectCloneNative(SootMethod method) { + super(method); + } + /** + * Implements the abstract method simulateMethod. It distributes the request to the corresponding + * methods by signatures. + */ + protected void simulateImpl() { + Local r0 = getThis(); + addReturn(r0); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java index 99b4bbea9aa..b579bdd8ba5 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangRefFinalizerInvokeFinalizeMethodNative.java @@ -19,19 +19,16 @@ package qilin.core.natives; import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; public class JavaLangRefFinalizerInvokeFinalizeMethodNative extends NativeMethod { - public JavaLangRefFinalizerInvokeFinalizeMethodNative(SootMethod method) { - super(method); - } + public JavaLangRefFinalizerInvokeFinalizeMethodNative(SootMethod method) { + super(method); + } - /** - * "" - */ - public void simulate() { - Local r0 = getPara(0); - addInvoke(r0, ""); - } + /** "" */ + protected void simulateImpl() { + Local r0 = getPara(0); + addInvoke(r0, ""); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java index 4badd6e426e..120977e17e1 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArrayGet.java @@ -30,17 +30,17 @@ * */ public class JavaLangReflectArrayGet extends NativeMethod { - JavaLangReflectArrayGet(SootMethod method) { - super(method); - } + JavaLangReflectArrayGet(SootMethod method) { + super(method); + } - @Override - void simulate() { - ClassType objType = PTAUtils.getClassType("java.lang.Object"); - Value arrayBase = getPara(0, new ArrayType(objType, 1)); - Value arrayRef = getArrayRef(arrayBase); - Local ret = getNextLocal(objType); - addAssign(ret, arrayRef); - addReturn(ret); - } + @Override + protected void simulateImpl() { + ClassType objType = PTAUtils.getClassType("java.lang.Object"); + Value arrayBase = getPara(0, new ArrayType(objType, 1)); + Value arrayRef = getArrayRef(arrayBase); + Local ret = getNextLocal(objType); + addAssign(ret, arrayRef); + addReturn(ret); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java index c688f7154cb..93b6cbfe56d 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangReflectArraySet.java @@ -29,16 +29,16 @@ * */ public class JavaLangReflectArraySet extends NativeMethod { - JavaLangReflectArraySet(SootMethod method) { - super(method); - } + JavaLangReflectArraySet(SootMethod method) { + super(method); + } - @Override - void simulate() { - ClassType objType = PTAUtils.getClassType("java.lang.Object"); - Value arrayBase = getPara(0, new ArrayType(objType, 1)); - Value rightValue = getPara(2); - Value arrayRef = getArrayRef(arrayBase); - addAssign(arrayRef, rightValue); // a[] = b; - } + @Override + protected void simulateImpl() { + ClassType objType = PTAUtils.getClassType("java.lang.Object"); + Value arrayBase = getPara(0, new ArrayType(objType, 1)); + Value rightValue = getPara(2); + Value arrayRef = getArrayRef(arrayBase); + addAssign(arrayRef, rightValue); // a[] = b; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java index 6e8ca177e04..79fffb1a3b4 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemArraycopyNative.java @@ -29,24 +29,23 @@ * Thus it will make qilin.spark less precise than its counterpart in Doop. * */ public class JavaLangSystemArraycopyNative extends NativeMethod { - public JavaLangSystemArraycopyNative(SootMethod method) { - super(method); - } + public JavaLangSystemArraycopyNative(SootMethod method) { + super(method); + } - /** - * never make a[] = b[], it violates the principle of jimple statement. make a - * temporary variable. - */ - public void simulate() { -// Value srcArr = getPara(0); -// Value dstArr = getPara(2); - ClassType objType = PTAUtils.getClassType("java.lang.Object"); - Value srcArr = getPara(0, new ArrayType(objType, 1)); - Value dstArr = getPara(2, new ArrayType(objType, 1)); - Value src = getArrayRef(srcArr); - Value dst = getArrayRef(dstArr); - Value temp = getNextLocal(objType); - addAssign(temp, src); - addAssign(dst, temp); - } + /** + * never make a[] = b[], it violates the principle of jimple statement. make a temporary variable. + */ + protected void simulateImpl() { + // Value srcArr = getPara(0); + // Value dstArr = getPara(2); + ClassType objType = PTAUtils.getClassType("java.lang.Object"); + Value srcArr = getPara(0, new ArrayType(objType, 1)); + Value dstArr = getPara(2, new ArrayType(objType, 1)); + Value src = getArrayRef(srcArr); + Value dst = getArrayRef(dstArr); + Value temp = getNextLocal(objType); + addAssign(temp, src); + addAssign(dst, temp); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java index 632ebf1cbfc..cb2cc318244 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetErr0Native.java @@ -22,19 +22,19 @@ import sootup.core.model.SootMethod; public class JavaLangSystemSetErr0Native extends NativeMethod { - public JavaLangSystemSetErr0Native(SootMethod method) { - super(method); - } + public JavaLangSystemSetErr0Native(SootMethod method) { + super(method); + } - /** - * NOTE: this native method is not documented in JDK API. It should have the - * side effect: System.err = parameter - *

- * private static native void setErr0(java.io.PrintStream); - */ - public void simulate() { - Value r1 = getPara(0); - Value systemErr = getStaticFieldRef("java.lang.System", "err"); - addAssign(systemErr, r1); - } + /** + * NOTE: this native method is not documented in JDK API. It should have the side effect: + * System.err = parameter + * + *

private static native void setErr0(java.io.PrintStream); + */ + protected void simulateImpl() { + Value r1 = getPara(0); + Value systemErr = getStaticFieldRef("java.lang.System", "err"); + addAssign(systemErr, r1); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java index d427bca5444..9be314a800f 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetIn0Native.java @@ -22,19 +22,19 @@ import sootup.core.model.SootMethod; public class JavaLangSystemSetIn0Native extends NativeMethod { - public JavaLangSystemSetIn0Native(SootMethod method) { - super(method); - } + public JavaLangSystemSetIn0Native(SootMethod method) { + super(method); + } - /** - * NOTE: this native method is not documented in JDK API. It should have the - * side effect: System.in = parameter - *

- * private static native void setIn0(java.io.InputStream); - */ - public void simulate() { - Value r1 = getPara(0); - Value systemIn = getStaticFieldRef("java.lang.System", "in"); - addAssign(systemIn, r1); - } + /** + * NOTE: this native method is not documented in JDK API. It should have the side effect: + * System.in = parameter + * + *

private static native void setIn0(java.io.InputStream); + */ + protected void simulateImpl() { + Value r1 = getPara(0); + Value systemIn = getStaticFieldRef("java.lang.System", "in"); + addAssign(systemIn, r1); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java index 7356f3f3fd3..d2a93ab24ca 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangSystemSetOut0Native.java @@ -18,24 +18,23 @@ package qilin.core.natives; - import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; public class JavaLangSystemSetOut0Native extends NativeMethod { - public JavaLangSystemSetOut0Native(SootMethod method) { - super(method); - } + public JavaLangSystemSetOut0Native(SootMethod method) { + super(method); + } - /** - * NOTE: this native method is not documented in JDK API. It should have the - * side effect: System.out = parameter - *

- * private static native void setOut0(java.io.PrintStream); - */ - public void simulate() { - Value r1 = getPara(0); - Value systemOut = getStaticFieldRef("java.lang.System", "out"); - addAssign(systemOut, r1); - } + /** + * NOTE: this native method is not documented in JDK API. It should have the side effect: + * System.out = parameter + * + *

private static native void setOut0(java.io.PrintStream); + */ + protected void simulateImpl() { + Value r1 = getPara(0); + Value systemOut = getStaticFieldRef("java.lang.System", "out"); + addAssign(systemOut, r1); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java index 3aa180e08b4..918f0c5f144 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadCurrentThread.java @@ -25,15 +25,15 @@ import sootup.core.model.SootMethod; public class JavaLangThreadCurrentThread extends NativeMethod { - JavaLangThreadCurrentThread(SootMethod method) { - super(method); - } + JavaLangThreadCurrentThread(SootMethod method) { + super(method); + } - @Override - void simulate() { - Local lv = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); - Value rv = PTAScene.v().getFieldCurrentThread(); - addAssign(lv, rv); - addReturn(lv); - } + @Override + protected void simulateImpl() { + Local lv = getNextLocal(PTAUtils.getClassType("java.lang.Thread")); + Value rv = PTAScene.v().getFieldCurrentThread(); + addAssign(lv, rv); + addReturn(lv); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java index c87cf33991f..18e0b85b110 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaLangThreadStart0Native.java @@ -25,22 +25,20 @@ public class JavaLangThreadStart0Native extends NativeMethod { - public JavaLangThreadStart0Native(SootMethod method) { - super(method); - } + public JavaLangThreadStart0Native(SootMethod method) { + super(method); + } - /** - * Calls to Thread.start() get redirected to Thread.run. - *

- * In JRE 1.5 and JRE 1.6 Thread.start() is defined in Java - * and there is native method start0. - */ - - @Override - void simulate() { - Local mThis = getThis(); - addInvoke(mThis, ""); - Value lv = PTAScene.v().getFieldCurrentThread(); - addAssign(lv, mThis); // store. - } + /** + * Calls to Thread.start() get redirected to Thread.run. + * + *

In JRE 1.5 and JRE 1.6 Thread.start() is defined in Java and there is native method start0. + */ + @Override + protected void simulateImpl() { + Local mThis = getThis(); + addInvoke(mThis, ""); + Value lv = PTAScene.v().getFieldCurrentThread(); + addAssign(lv, mThis); // store. + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java index a6ad1e4bd3f..ff8c3485fe2 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivilegedNative.java @@ -21,19 +21,18 @@ import sootup.core.model.SootMethod; public class JavaSecurityAccessControllerDoPrivilegedNative extends NativeMethod { - public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { - super(method); - } + public JavaSecurityAccessControllerDoPrivilegedNative(SootMethod method) { + super(method); + } - /** - * public static native java.lang.Object - * doPrivileged(java.security.PrivilegedAction) public static native - * java.lang.Object - * doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext) - */ - public void simulate() { - Local r0 = getPara(0); - Local r1 = getInvoke(r0, ""); - addReturn(r1); - } + /** + * public static native java.lang.Object doPrivileged(java.security.PrivilegedAction) public + * static native java.lang.Object + * doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext) + */ + protected void simulateImpl() { + Local r0 = getPara(0); + Local r1 = getInvoke(r0, ""); + addReturn(r1); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java index 8f803712a84..3f4aa673fcd 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/JavaSecurityAccessControllerDoPrivileged_ExceptionNative.java @@ -19,23 +19,21 @@ package qilin.core.natives; import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; import sootup.core.model.SootMethod; public class JavaSecurityAccessControllerDoPrivileged_ExceptionNative extends NativeMethod { - public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod method) { - super(method); - } + public JavaSecurityAccessControllerDoPrivileged_ExceptionNative(SootMethod method) { + super(method); + } - /** - * public static native java.lang.Object - * doPrivileged(java.security.PrivilegedExceptionAction) public static native - * java.lang.Object - * doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext) - */ - public void simulate() { - Local r0 = getPara(0); - Local r1 = getInvoke(r0, ""); - addReturn(r1); - } + /** + * public static native java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction) + * public static native java.lang.Object + * doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext) + */ + protected void simulateImpl() { + Local r0 = getPara(0); + Local r1 = getInvoke(r0, ""); + addReturn(r1); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java index 18c54813023..f4c9994e16b 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethod.java @@ -18,27 +18,32 @@ package qilin.core.natives; +import java.util.Collections; import qilin.core.ArtificialMethod; +import qilin.core.PTAScene; +import qilin.util.PTAUtils; import sootup.core.jimple.basic.Local; import sootup.core.model.Body; import sootup.core.model.SootMethod; -import java.util.Collections; - public abstract class NativeMethod extends ArtificialMethod { - NativeMethod(SootMethod method) { - this.method = method; - if (method.isConcrete()) { - Body body = method.getBody(); - this.bodyBuilder = Body.builder(body, Collections.emptySet()); - } else { - this.bodyBuilder = Body.builder(); - } - int paraCount = method.getParameterCount(); - paraLocals = new Local[paraCount]; - this.paraStart = method.isStatic() ? 0 : 1; - this.localStart = this.paraStart + paraCount; - } + NativeMethod(SootMethod method) { + super(PTAScene.v().getView()); + this.method = method; + Body body = PTAUtils.getMethodBody(method); + this.bodyBuilder = Body.builder(body, Collections.emptySet()); + int paraCount = method.getParameterCount(); + paraLocals = new Local[paraCount]; + this.paraStart = method.isStatic() ? 0 : 1; + this.localStart = this.paraStart + paraCount; + } + + protected abstract void simulateImpl(); - abstract void simulate(); + public void simulate() { + simulateImpl(); + bodyBuilder.getStmtGraph().addBlock(stmtList); + bodyBuilder.getStmtGraph().setStartingStmt(stmtList.get(0)); + PTAUtils.updateMethodBody(method, bodyBuilder.build()); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java index 5be8c9372b5..f608a6923f6 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/NativeMethodDriver.java @@ -22,63 +22,63 @@ import sootup.core.model.SootMethod; public class NativeMethodDriver { - public void buildNative(SootMethod method) { - if (!PTAScene.v().nativeBuilt.add(method)) { - return; - } - String sig = method.getSignature().toString(); - switch (sig) { - case "": - case "": - new JavaLangObjectCloneNative(method).simulate(); - break; - case "": - new JavaLangSystemSetIn0Native(method).simulate(); - break; - case "": - new JavaLangSystemSetOut0Native(method).simulate(); - break; - case "": - new JavaLangSystemSetErr0Native(method).simulate(); - break; -// case "": -// new JavaLangSystemArraycopyNative(method).simulate(); -// break; - case "": - case "": - new JavaIoFileSystemGetFileSystemNative(method).simulate(); - break; - case "": - case "": - new JavaIoFileSystemListNative(method).simulate(); - break; - case "": - new JavaLangRefFinalizerInvokeFinalizeMethodNative(method).simulate(); - break; - case "": - case "": - new JavaSecurityAccessControllerDoPrivilegedNative(method).simulate(); - break; - case "": - case "": - new JavaSecurityAccessControllerDoPrivileged_ExceptionNative(method).simulate(); - break; - case "": - new JavaLangThreadCurrentThread(method).simulate(); - break; - case "": - new JavaLangThreadStart0Native(method).simulate(); - break; - case "": -// new JavaLangReflectArrayGet(method).simulate(); - break; - case "": -// new JavaLangReflectArraySet(method).simulate(); - break; - default: - // System.out.println("Warning: unhandled native method " + sig); - break; - } + public void buildNative(SootMethod method) { + if (!PTAScene.v().nativeBuilt.add(method)) { + return; } - + String sig = method.getSignature().toString(); + switch (sig) { + case "": + case "": + new JavaLangObjectCloneNative(method).simulate(); + break; + case "": + new JavaLangSystemSetIn0Native(method).simulate(); + break; + case "": + new JavaLangSystemSetOut0Native(method).simulate(); + break; + case "": + new JavaLangSystemSetErr0Native(method).simulate(); + break; + // case "": + // new JavaLangSystemArraycopyNative(method).simulate(); + // break; + case "": + case "": + new JavaIoFileSystemGetFileSystemNative(method).simulate(); + break; + case "": + case "": + new JavaIoFileSystemListNative(method).simulate(); + break; + case "": + new JavaLangRefFinalizerInvokeFinalizeMethodNative(method).simulate(); + break; + case "": + case "": + new JavaSecurityAccessControllerDoPrivilegedNative(method).simulate(); + break; + case "": + case "": + new JavaSecurityAccessControllerDoPrivileged_ExceptionNative(method).simulate(); + break; + case "": + new JavaLangThreadCurrentThread(method).simulate(); + break; + case "": + new JavaLangThreadStart0Native(method).simulate(); + break; + case "": + // new JavaLangReflectArrayGet(method).simulate(); + break; + case "": + // new JavaLangReflectArraySet(method).simulate(); + break; + default: + // System.out.println("Warning: unhandled native method " + sig); + break; + } + } } diff --git a/sootup.qilin/src/main/java/qilin/core/natives/package-info.java b/sootup.qilin/src/main/java/qilin/core/natives/package-info.java index 8c45204821b..4ee4ce5aeba 100644 --- a/sootup.qilin/src/main/java/qilin/core/natives/package-info.java +++ b/sootup.qilin/src/main/java/qilin/core/natives/package-info.java @@ -4,4 +4,4 @@ * In this package, we currently only handle a subset of native methods that are supported in Doop. * In the future, we will append more simulations to native methods that are frequently used by * real-world applications. - * */ \ No newline at end of file + * */ diff --git a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java index 189626009aa..61a859c2ef4 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/AllocNode.java @@ -18,6 +18,7 @@ package qilin.core.pag; +import java.util.Optional; import qilin.CoreConfig; import qilin.core.PTAScene; import qilin.core.context.ContextElement; @@ -28,53 +29,49 @@ import sootup.core.types.Type; import sootup.core.views.View; -import java.util.Optional; - /** * Represents an allocation site node in the pointer assignment graph. * * @author Ondrej Lhotak */ public class AllocNode extends Node implements ContextElement, Numberable { - protected Object newExpr; - private final SootMethod method; + protected Object newExpr; + private final SootMethod method; - public AllocNode(Object newExpr, Type t, SootMethod m) { - super(t); - this.method = m; - if (t instanceof ClassType rt) { - View view = PTAScene.v().getView(); - Optional osc = view.getClass(rt); - if (osc.isPresent() && osc.get().isAbstract()) { - boolean usesReflectionLog = CoreConfig.v().getAppConfig().REFLECTION_LOG != null; - if (!usesReflectionLog) { - throw new RuntimeException("Attempt to create allocnode with abstract type " + t); - } - } + public AllocNode(Object newExpr, Type t, SootMethod m) { + super(t); + this.method = m; + if (t instanceof ClassType rt) { + View view = PTAScene.v().getView(); + Optional osc = view.getClass(rt); + if (osc.isPresent() && osc.get().isAbstract()) { + boolean usesReflectionLog = CoreConfig.v().getAppConfig().REFLECTION_LOG != null; + if (!usesReflectionLog) { + throw new RuntimeException("Attempt to create allocnode with abstract type " + t); } - this.newExpr = newExpr; + } } + this.newExpr = newExpr; + } - /** - * Returns the new expression of this allocation site. - */ - public Object getNewExpr() { - return newExpr; - } + /** Returns the new expression of this allocation site. */ + public Object getNewExpr() { + return newExpr; + } - public String toString() { - return "AllocNode " + getNumber() + " " + newExpr + " in method " + method; - } + public String toString() { + return "AllocNode " + getNumber() + " " + newExpr + " in method " + method; + } - public String toString2() { - return newExpr + " in method " + method; - } + public String toString2() { + return newExpr + " in method " + method; + } - public SootMethod getMethod() { - return method; - } + public SootMethod getMethod() { + return method; + } - public AllocNode base() { - return this; - } + public AllocNode base() { + return this; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java index 6d488276b32..40b6d758010 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ArrayElement.java @@ -27,29 +27,29 @@ * @author Ondrej Lhotak */ public class ArrayElement implements SparkField { - private static ArrayElement instance = null; - private int number = 0; + private static ArrayElement instance = null; + private int number = 0; - public static ArrayElement v() { + public static ArrayElement v() { + if (instance == null) { + synchronized (ArrayElement.class) { if (instance == null) { - synchronized (ArrayElement.class) { - if (instance == null) { - instance = new ArrayElement(); - } - } + instance = new ArrayElement(); } - return instance; + } } + return instance; + } - public final int getNumber() { - return number; - } + public final int getNumber() { + return number; + } - public final void setNumber(int number) { - this.number = number; - } + public final void setNumber(int number) { + this.number = number; + } - public Type getType() { - return PTAUtils.getClassType("java.lang.Object"); - } + public Type getType() { + return PTAUtils.getClassType("java.lang.Object"); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java index 8e31efd4d52..c2c7e742b9c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/CallSite.java @@ -21,48 +21,43 @@ import qilin.core.context.ContextElement; import sootup.core.jimple.common.stmt.Stmt; -/** - * callsite based context element in the points to analysis. - */ +/** callsite based context element in the points to analysis. */ public class CallSite implements ContextElement { - private final Stmt unit; - - public CallSite(Stmt unit) { - this.unit = unit; + private final Stmt unit; + + public CallSite(Stmt unit) { + this.unit = unit; + } + + public Stmt getUnit() { + return unit; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((unit == null) ? 0 : unit.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + CallSite other = (CallSite) obj; + if (unit == null) { + return other.unit == null; + } else if (other.unit == null) { + return false; + } else { + return unit.equals(other.unit); } + } - public Stmt getUnit() { - return unit; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((unit == null) ? 0 : unit.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - CallSite other = (CallSite) obj; - if (unit == null) { - return other.unit == null; - } else if (other.unit == null) { - return false; - } else { - return unit.equals(other.unit); - } - } - - public String toString() { - return "CallSite: " + unit; - } + public String toString() { + return "CallSite: " + unit; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java index a5274720c15..e454f28ae24 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ClassConstantNode.java @@ -27,15 +27,15 @@ * @author Ondrej Lhotak */ public class ClassConstantNode extends ConstantNode { - public ClassConstantNode(ClassConstant cc) { - super(cc, PTAUtils.getClassType("java.lang.Class"), null); - } + public ClassConstantNode(ClassConstant cc) { + super(cc, PTAUtils.getClassType("java.lang.Class"), null); + } - public String toString() { - return "ClassConstantNode " + getNumber() + " " + newExpr; - } + public String toString() { + return "ClassConstantNode " + getNumber() + " " + newExpr; + } - public ClassConstant getClassConstant() { - return (ClassConstant) newExpr; - } + public ClassConstant getClassConstant() { + return (ClassConstant) newExpr; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java index a1f9a72029c..11035b9f074 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ConstantNode.java @@ -22,7 +22,7 @@ import sootup.core.types.Type; public abstract class ConstantNode extends AllocNode { - protected ConstantNode(Object newExpr, Type t, SootMethod m) { - super(newExpr, t, m); - } + protected ConstantNode(Object newExpr, Type t, SootMethod m) { + super(newExpr, t, m); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java index 484f26aa521..e212e2534d9 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextAllocNode.java @@ -21,26 +21,25 @@ import soot.Context; public class ContextAllocNode extends AllocNode { - private final Context context; - private final AllocNode base; - - public ContextAllocNode(AllocNode base, Context context) { - super(base.getNewExpr(), base.getType(), base.getMethod()); - this.context = context; - this.base = base; - } - - public Context context() { - return context; - } - - @Override - public AllocNode base() { - return base; - } - - public String toString() { - return "ContextAllocNode " + getNumber() + "(" + base + ", " + context + ")"; - } - + private final Context context; + private final AllocNode base; + + public ContextAllocNode(AllocNode base, Context context) { + super(base.getNewExpr(), base.getType(), base.getMethod()); + this.context = context; + this.base = base; + } + + public Context context() { + return context; + } + + @Override + public AllocNode base() { + return base; + } + + public String toString() { + return "ContextAllocNode " + getNumber() + "(" + base + ", " + context + ")"; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java index 684da80d0b7..e95cb4f303f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextField.java @@ -27,60 +27,56 @@ import sootup.core.types.Type; public class ContextField extends ValNode { - protected Context context; - protected SparkField field; + protected Context context; + protected SparkField field; - public ContextField(Context context, SparkField field) { - super(refineFieldType(context, field)); - this.context = context; - this.field = field; - } + public ContextField(Context context, SparkField field) { + super(refineFieldType(context, field)); + this.context = context; + this.field = field; + } - private static Type refineFieldType(Context context, SparkField field) { - if (!CoreConfig.v().getPtaConfig().preciseArrayElement) { - return PTAUtils.getClassType("java.lang.Object"); - } - if (field instanceof ArrayElement) { - ContextElement[] contextElements = ((ContextElements) context).getElements(); - if (contextElements.length > 0) { - Type baseHeapType = ((AllocNode) ((ContextElements) context).getElements()[0]).getType(); - if (baseHeapType instanceof ArrayType arrayType) { - return arrayType.getArrayElementType(); - } else { - throw new RuntimeException(baseHeapType + " is not an array type."); - } - } else { - throw new RuntimeException("Context does not have any elements:" + context + ";" + field); - } + private static Type refineFieldType(Context context, SparkField field) { + if (!CoreConfig.v().getPtaConfig().preciseArrayElement) { + return PTAUtils.getClassType("java.lang.Object"); + } + if (field instanceof ArrayElement) { + ContextElement[] contextElements = ((ContextElements) context).getElements(); + if (contextElements.length > 0) { + Type baseHeapType = ((AllocNode) ((ContextElements) context).getElements()[0]).getType(); + if (baseHeapType instanceof ArrayType arrayType) { + return arrayType.getArrayElementType(); + } else { + throw new RuntimeException(baseHeapType + " is not an array type."); } - return field.getType(); + } else { + throw new RuntimeException("Context does not have any elements:" + context + ";" + field); + } } + return field.getType(); + } - /** - * Returns the base AllocNode. - */ - public Context getContext() { - return context; - } + /** Returns the base AllocNode. */ + public Context getContext() { + return context; + } - public boolean hasBase() { - ContextElements ctxs = (ContextElements) context; - return ctxs.size() > 0; - } + public boolean hasBase() { + ContextElements ctxs = (ContextElements) context; + return ctxs.size() > 0; + } - public AllocNode getBase() { - ContextElements ctxs = (ContextElements) context; - return (AllocNode) ctxs.getElements()[0]; - } + public AllocNode getBase() { + ContextElements ctxs = (ContextElements) context; + return (AllocNode) ctxs.getElements()[0]; + } - /** - * Returns the field of this node. - */ - public SparkField getField() { - return field; - } + /** Returns the field of this node. */ + public SparkField getField() { + return field; + } - public String toString() { - return "ContextField " + getNumber() + " " + getBase() + "." + field; - } + public String toString() { + return "ContextField " + getNumber() + " " + getBase() + "." + field; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java index 8ee8bb705d6..2a69cef36ef 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextMethod.java @@ -23,35 +23,35 @@ import sootup.core.model.SootMethod; public final class ContextMethod implements MethodOrMethodContext { - private final SootMethod method; - private final Context context; - - public SootMethod method() { - return this.method; - } - - public Context context() { - return this.context; - } - - public ContextMethod(SootMethod method, Context context) { - this.method = method; - this.context = context; + private final SootMethod method; + private final Context context; + + public SootMethod method() { + return this.method; + } + + public Context context() { + return this.context; + } + + public ContextMethod(SootMethod method, Context context) { + this.method = method; + this.context = context; + } + + public int hashCode() { + return this.method.hashCode() + this.context.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof ContextMethod other)) { + return false; + } else { + return this.method.equals(other.method) && this.context.equals(other.context); } + } - public int hashCode() { - return this.method.hashCode() + this.context.hashCode(); - } - - public boolean equals(Object o) { - if (!(o instanceof ContextMethod other)) { - return false; - } else { - return this.method.equals(other.method) && this.context.equals(other.context); - } - } - - public String toString() { - return "Method " + this.method + " in context " + this.context; - } + public String toString() { + return "Method " + this.method + " in context " + this.context; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java index 70430c9e4d3..98bba48d154 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ContextVarNode.java @@ -21,37 +21,36 @@ import soot.Context; public class ContextVarNode extends VarNode { - private final Context context; - private final VarNode base; - - public ContextVarNode(VarNode base, Context context) { - super(base.getVariable(), base.getType()); - this.context = context; - this.base = base; - } - - - @Override - public boolean isInterProcTarget() { - return base.isInterProcTarget(); - } - - @Override - public boolean isInterProcSource() { - return base.isInterProcSource(); - } - - @Override - public Context context() { - return context; - } - - @Override - public VarNode base() { - return base; - } - - public String toString() { - return "ContextVarNode " + getNumber() + "(" + base + ", " + context + ")"; - } + private final Context context; + private final VarNode base; + + public ContextVarNode(VarNode base, Context context) { + super(base.getVariable(), base.getType()); + this.context = context; + this.base = base; + } + + @Override + public boolean isInterProcTarget() { + return base.isInterProcTarget(); + } + + @Override + public boolean isInterProcSource() { + return base.isInterProcSource(); + } + + @Override + public Context context() { + return context; + } + + @Override + public VarNode base() { + return base; + } + + public String toString() { + return "ContextVarNode " + getNumber() + "(" + base + ", " + context + ")"; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java index 554997ebc29..fb546e9f69f 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ExceptionThrowSite.java @@ -18,44 +18,45 @@ package qilin.core.pag; +import java.util.Objects; import soot.MethodOrMethodContext; import sootup.core.jimple.common.stmt.Stmt; -import java.util.Objects; - public class ExceptionThrowSite { - private final Stmt unit; - private final VarNode throwNode; - private final MethodOrMethodContext container; - - public ExceptionThrowSite(VarNode throwNode, Stmt unit, MethodOrMethodContext container) { - this.unit = unit; - this.container = container; - this.throwNode = throwNode; - } - - public MethodOrMethodContext container() { - return container; - } - - public VarNode getThrowNode() { - return throwNode; - } - - public Stmt getUnit() { - return unit; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ExceptionThrowSite that = (ExceptionThrowSite) o; - return Objects.equals(unit, that.unit) && Objects.equals(throwNode, that.throwNode) && Objects.equals(container, that.container); - } - - @Override - public int hashCode() { - return Objects.hash(unit, throwNode, container); - } + private final Stmt unit; + private final VarNode throwNode; + private final MethodOrMethodContext container; + + public ExceptionThrowSite(VarNode throwNode, Stmt unit, MethodOrMethodContext container) { + this.unit = unit; + this.container = container; + this.throwNode = throwNode; + } + + public MethodOrMethodContext container() { + return container; + } + + public VarNode getThrowNode() { + return throwNode; + } + + public Stmt getUnit() { + return unit; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExceptionThrowSite that = (ExceptionThrowSite) o; + return Objects.equals(unit, that.unit) + && Objects.equals(throwNode, that.throwNode) + && Objects.equals(container, that.container); + } + + @Override + public int hashCode() { + return Objects.hash(unit, throwNode, container); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Field.java b/sootup.qilin/src/main/java/qilin/core/pag/Field.java index a3e93438628..85335a8e61e 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Field.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Field.java @@ -18,55 +18,52 @@ package qilin.core.pag; +import java.util.Objects; import sootup.core.model.SootField; import sootup.core.types.Type; -import java.util.Objects; - -/** - * a wrapper of normal field. - */ +/** a wrapper of normal field. */ public class Field implements SparkField { - private final SootField field; + private final SootField field; - public Field(SootField sf) { - this.field = sf; - } + public Field(SootField sf) { + this.field = sf; + } -// @Override -// public int getNumber() { -// return field.getNumber(); -// } -// -// @Override -// public void setNumber(int number) { -// throw new UnsupportedOperationException(); -// } + // @Override + // public int getNumber() { + // return field.getNumber(); + // } + // + // @Override + // public void setNumber(int number) { + // throw new UnsupportedOperationException(); + // } - @Override - public Type getType() { - return field.getType(); - } + @Override + public Type getType() { + return field.getType(); + } - public SootField getField() { - return field; - } + public SootField getField() { + return field; + } - @Override - public String toString() { - return "FieldNode " + field; - } + @Override + public String toString() { + return "FieldNode " + field; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Field field1 = (Field) o; - return field.equals(field1.field); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Field field1 = (Field) o; + return field.equals(field1.field); + } - @Override - public int hashCode() { - return Objects.hash(field); - } + @Override + public int hashCode() { + return Objects.hash(field); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java index 7fa4a8e3ad2..ef778470225 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldRefNode.java @@ -26,31 +26,27 @@ * @author Ondrej Lhotak */ public class FieldRefNode extends Node implements Numberable { - protected VarNode base; - protected SparkField field; + protected VarNode base; + protected SparkField field; - public FieldRefNode(VarNode base, SparkField field) { - super(field.getType()); - this.base = base; - this.field = field; - base.addField(this, field); - } + public FieldRefNode(VarNode base, SparkField field) { + super(field.getType()); + this.base = base; + this.field = field; + base.addField(this, field); + } - /** - * Returns the base of this field reference. - */ - public VarNode getBase() { - return base; - } + /** Returns the base of this field reference. */ + public VarNode getBase() { + return base; + } - /** - * Returns the field of this field reference. - */ - public SparkField getField() { - return field; - } + /** Returns the field of this field reference. */ + public SparkField getField() { + return field; + } - public String toString() { - return "FieldRefNode " + getNumber() + " " + base + "." + field; - } + public String toString() { + return "FieldRefNode " + getNumber() + " " + base + "." + field; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java index 390cbbd64f2..16f14fcda06 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/FieldValNode.java @@ -19,16 +19,16 @@ package qilin.core.pag; public class FieldValNode extends ValNode { - // note, field could only be ArrayElement or Field type. - // Parm should be a local variable in some methods. - private final SparkField field; + // note, field could only be ArrayElement or Field type. + // Parm should be a local variable in some methods. + private final SparkField field; - public FieldValNode(SparkField field) { - super(field.getType()); - this.field = field; - } + public FieldValNode(SparkField field) { + super(field.getType()); + this.field = field; + } - public SparkField getField() { - return field; - } + public SparkField getField() { + return field; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java index 9fc0396bdf1..b3df1df57da 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/GlobalVarNode.java @@ -18,37 +18,36 @@ package qilin.core.pag; - import qilin.core.PTAScene; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.types.Type; /** - * Represents a simple variable node in the pointer assignment graph that is not associated with any particular - * method invocation. + * Represents a simple variable node in the pointer assignment graph that is not associated with any + * particular method invocation. * * @author Ondrej Lhotak */ public class GlobalVarNode extends VarNode { - public GlobalVarNode(Object variable, Type t) { - super(variable, t); - } - - @Override - public VarNode base() { - return this; + public GlobalVarNode(Object variable, Type t) { + super(variable, t); + } + + @Override + public VarNode base() { + return this; + } + + public String toString() { + return "GlobalVarNode " + getNumber() + " " + variable; + } + + public SootClass getDeclaringClass() { + if (variable instanceof SootField sf) { + return (SootClass) PTAScene.v().getView().getClass(sf.getDeclaringClassType()).get(); } - public String toString() { - return "GlobalVarNode " + getNumber() + " " + variable; - } - - public SootClass getDeclaringClass() { - if (variable instanceof SootField sf) { - return (SootClass) PTAScene.v().getView().getClass(sf.getDeclaringClassType()).get(); - } - - return null; - } + return null; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java index 7134e2139a6..a0f66fa7bca 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/LocalVarNode.java @@ -18,7 +18,6 @@ package qilin.core.pag; - import sootup.core.model.SootMethod; import sootup.core.types.Type; @@ -26,40 +25,38 @@ * @author Ondrej Lhotak */ public class LocalVarNode extends VarNode { - protected SootMethod method; + protected SootMethod method; - public LocalVarNode(Object variable, Type t, SootMethod m) { - super(variable, t); - this.method = m; - } + public LocalVarNode(Object variable, Type t, SootMethod m) { + super(variable, t); + this.method = m; + } - public SootMethod getMethod() { - return method; - } + public SootMethod getMethod() { + return method; + } - public String toString() { - return "LocalVarNode " + getNumber() + " " + variable + " " + method; - } + public String toString() { + return "LocalVarNode " + getNumber() + " " + variable + " " + method; + } - /** - * Returns true if this VarNode represents the THIS pointer - */ - public boolean isThis() { - if (variable instanceof Parm parm) { - return parm.isThis(); - } - return false; + /** Returns true if this VarNode represents the THIS pointer */ + public boolean isThis() { + if (variable instanceof Parm parm) { + return parm.isThis(); } + return false; + } - public boolean isReturn() { - if (variable instanceof Parm parm) { - return parm.isReturn(); - } - return false; + public boolean isReturn() { + if (variable instanceof Parm parm) { + return parm.isReturn(); } + return false; + } - @Override - public VarNode base() { - return this; - } + @Override + public VarNode base() { + return this; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java index 1ef0701580e..e21a1ed7c27 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MergedNewExpr.java @@ -18,21 +18,19 @@ package qilin.core.pag; +import java.util.Map; import qilin.util.DataFactory; import sootup.core.types.ReferenceType; -import java.util.Map; - public class MergedNewExpr { - private final ReferenceType type; - private static final Map map = DataFactory.createMap(); - - private MergedNewExpr(ReferenceType type) { - this.type = type; - } + private final ReferenceType type; + private static final Map map = DataFactory.createMap(); - public static MergedNewExpr v(ReferenceType type) { - return map.computeIfAbsent(type, k -> new MergedNewExpr(type)); - } + private MergedNewExpr(ReferenceType type) { + this.type = type; + } + public static MergedNewExpr v(ReferenceType type) { + return map.computeIfAbsent(type, k -> new MergedNewExpr(type)); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java index 5645aa2a5f7..c8ed43c2e6e 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/MethodPAG.java @@ -18,12 +18,12 @@ package qilin.core.pag; +import java.util.*; import qilin.CoreConfig; import qilin.core.PTAScene; -import qilin.util.DataFactory; import qilin.core.builder.MethodNodeFactory; +import qilin.util.DataFactory; import qilin.util.PTAUtils; - import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; import sootup.core.graph.StmtGraph; @@ -37,198 +37,210 @@ import sootup.core.model.SootField; import sootup.core.model.SootMethod; -import java.util.*; - /** * Part of a pointer assignment graph for a single method. * * @author Ondrej Lhotak */ public class MethodPAG { - private final ChunkedQueue internalEdges = new ChunkedQueue<>(); - private final QueueReader internalReader = internalEdges.reader(); - private final Set clinits = DataFactory.createSet(); - private final Collection invokeStmts = DataFactory.createSet(); - public Body body; - /** - * Since now the exception analysis is handled on-the-fly, we should record the - * exception edges explicitly for Eagle and Turner. - */ - private final Map> exceptionEdges = DataFactory.createMap(); - protected MethodNodeFactory nodeFactory; - SootMethod method; + private final ChunkedQueue internalEdges = new ChunkedQueue<>(); + private final QueueReader internalReader = internalEdges.reader(); + private final Set clinits = DataFactory.createSet(); + private final Collection invokeStmts = DataFactory.createSet(); + public Body body; + + /** + * Since now the exception analysis is handled on-the-fly, we should record the exception edges + * explicitly for Eagle and Turner. + */ + private final Map> exceptionEdges = DataFactory.createMap(); + + protected MethodNodeFactory nodeFactory; + SootMethod method; + /* + * List[i-1] is wrappered in List[i]. + * We have to extend the following structure from Map> to + * Map>> because there exists cases where the same + * node are thrown more than once and lies in different catch blocks. + * */ + public final Map> stmt2wrapperedTraps = DataFactory.createMap(); + public final Map>> node2wrapperedTraps = DataFactory.createMap(); + + public MethodPAG(PAG pag, SootMethod m, Body body) { + this.method = m; + this.nodeFactory = new MethodNodeFactory(pag, this); + this.body = body; + build(); + } + + public SootMethod getMethod() { + return method; + } + + public MethodNodeFactory nodeFactory() { + return nodeFactory; + } + + public Collection getInvokeStmts() { + return invokeStmts; + } + + public boolean addCallStmt(Stmt unit) { + return this.invokeStmts.add(unit); + } + + protected void build() { + // this method is invalid but exists in pmd-deps.jar + if (method.getSignature().equals("")) { + return; + } + buildException(); + buildNormal(); + addMiscEdges(); + } + + protected void buildNormal() { + if (method.isStatic()) { + Optional osc = PTAScene.v().getView().getClass(method.getDeclaringClassType()); + if (osc.isPresent()) { + SootClass sc = osc.get(); + PTAUtils.clinitsOf(sc).forEach(this::addTriggeredClinit); + } else { + System.out.println("why?eoweiweoiew:" + method.getSignature()); + } + } + for (Stmt unit : body.getStmts()) { + try { + nodeFactory.handleStmt(unit); + } catch (Exception e) { + System.out.println("Warning:" + e); + } + } + } + + protected void buildException() { + // we use the same logic as doop (library/exceptions/precise.logic). + if (!CoreConfig.v().getPtaConfig().preciseExceptions) { + return; + } + List traps = body.getTraps(); +// List units = body.getStmts(); + Set inTraps = DataFactory.createSet(); /* - * List[i-1] is wrappered in List[i]. - * We have to extend the following structure from Map> to - * Map>> because there exists cases where the same - * node are thrown more than once and lies in different catch blocks. + * The traps is already visited in order. , ; implies is a previous Trap of . * */ - public final Map> stmt2wrapperedTraps = DataFactory.createMap(); - public final Map>> node2wrapperedTraps = DataFactory.createMap(); - - public MethodPAG(PAG pag, SootMethod m, Body body) { - this.method = m; - this.nodeFactory = new MethodNodeFactory(pag, this); - this.body = body; - build(); - } - - public SootMethod getMethod() { - return method; - } - - public MethodNodeFactory nodeFactory() { - return nodeFactory; - } - - public Collection getInvokeStmts() { - return invokeStmts; - } - - public boolean addCallStmt(Stmt unit) { - return this.invokeStmts.add(unit); - } - - protected void build() { - // this method is invalid but exists in pmd-deps.jar - if (method.getSignature().equals("")) { - return; - } - buildException(); - buildNormal(); - addMiscEdges(); - } - - protected void buildNormal() { - if (method.isStatic()) { - SootClass sc = (SootClass) PTAScene.v().getView().getClass(method.getDeclaringClassType()).get(); - PTAUtils.clinitsOf(sc).forEach(this::addTriggeredClinit); - } - for (Stmt unit : body.getStmts()) { - try { - nodeFactory.handleStmt(unit); - } catch (Exception e) { - System.out.println("Warning:" + e); + traps.forEach( + trap -> { + StmtGraph stmtGraph = body.getStmtGraph(); + List succs = stmtGraph.getAllSuccessors(trap.getBeginStmt()); + while (true) { + if (succs.contains(trap.getEndStmt())) { + break; } - } - } - - protected void buildException() { - // we use the same logic as doop (library/exceptions/precise.logic). - if (!CoreConfig.v().getPtaConfig().preciseExceptions) { - return; - } - List traps = body.getTraps(); - List units = body.getStmts(); - Set inTraps = DataFactory.createSet(); - /* - * The traps is already visited in order. , ; implies is a previous Trap of . - * */ - traps.forEach(trap -> { - StmtGraph stmtGraph = body.getStmtGraph(); - List succs = stmtGraph.getAllSuccessors(trap.getBeginStmt()); - while(true) { - if (succs.contains(trap.getEndStmt())) { - break; - } - if (succs.size() == 0) { - break; - } - List tmp = new ArrayList<>(); - for (Stmt stmt : succs) { - inTraps.add(stmt); - Node src = null; - if (stmt.containsInvokeExpr()) { - // note, method.getExceptions() does not return implicit exceptions. - src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); - } else if (stmt instanceof JThrowStmt ts) { - src = nodeFactory.getNode(ts.getOp()); - } - if (src != null) { - addStmtTrap(src, stmt, trap); - } - tmp.addAll(stmtGraph.getAllSuccessors(stmt)); - } - succs = tmp; + if (succs.size() == 0) { + break; } -// units.iterator(trap.getBeginStmt(), trap.getEndStmt()).forEachRemaining(unit -> { -// if (unit == trap.getEndUnit()) { -// return; -// } -// inTraps.add(unit); -// Stmt stmt = unit; -// Node src = null; -// if (stmt.containsInvokeExpr()) { -// // note, method.getExceptions() does not return implicit exceptions. -// src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); -// } else if (stmt instanceof JThrowStmt ts) { -// src = nodeFactory.getNode(ts.getOp()); -// } -// if (src != null) { -// addStmtTrap(src, stmt, trap); -// } -// }); - }); - - for (Stmt stmt : body.getStmts()) { - if (inTraps.contains(stmt)) { - continue; - } - Node src = null; - if (stmt.containsInvokeExpr()) { + List tmp = new ArrayList<>(); + for (Stmt stmt : succs) { + inTraps.add(stmt); + Node src = null; + if (stmt.containsInvokeExpr()) { + // note, method.getExceptions() does not return implicit exceptions. src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); - } else if (stmt instanceof JThrowStmt ts) { + } else if (stmt instanceof JThrowStmt ts) { src = nodeFactory.getNode(ts.getOp()); + } + if (src != null) { + addStmtTrap(src, stmt, trap); + } + tmp.addAll(stmtGraph.getAllSuccessors(stmt)); } - if (src != null) { - node2wrapperedTraps.computeIfAbsent(src, k -> DataFactory.createMap()); - stmt2wrapperedTraps.computeIfAbsent(stmt, k -> DataFactory.createList()); - } - } - } - - private void addStmtTrap(Node src, Stmt stmt, Trap trap) { - Map> stmt2Traps = node2wrapperedTraps.computeIfAbsent(src, k -> DataFactory.createMap()); - List trapList = stmt2Traps.computeIfAbsent(stmt, k -> DataFactory.createList()); - trapList.add(trap); - stmt2wrapperedTraps.computeIfAbsent(stmt, k -> DataFactory.createList()).add(trap); - } - - protected void addMiscEdges() { - if (method.getSignature().equals("(java.lang.Object,java.lang.ref.ReferenceQueue)>")) { - // Implements the special status of java.lang.ref.Reference just as in Doop (library/reference.logic). - SootClass sootClass = PTAScene.v().getSootClass("java.lang.ref.Reference"); - SootField sf = (SootField) sootClass.getField("pending").get(); - JStaticFieldRef sfr = Jimple.newStaticFieldRef(sf.getSignature()); - addInternalEdge(nodeFactory.caseThis(), nodeFactory.getNode(sfr)); - } - } - - public void addInternalEdge(Node src, Node dst) { - if (src == null) { - return; - } - internalEdges.add(src); - internalEdges.add(dst); - } - - public QueueReader getInternalReader() { - return internalReader; - } - - public void addTriggeredClinit(SootMethod clinit) { - clinits.add(clinit); - } - - public Iterator triggeredClinits() { - return clinits.iterator(); - } - - public void addExceptionEdge(Node from, Node to) { - this.exceptionEdges.computeIfAbsent(from, k -> DataFactory.createSet()).add(to); - } + succs = tmp; + } + // units.iterator(trap.getBeginStmt(), trap.getEndStmt()).forEachRemaining(unit + // -> { + // if (unit == trap.getEndUnit()) { + // return; + // } + // inTraps.add(unit); + // Stmt stmt = unit; + // Node src = null; + // if (stmt.containsInvokeExpr()) { + // // note, method.getExceptions() does not return implicit exceptions. + // src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); + // } else if (stmt instanceof JThrowStmt ts) { + // src = nodeFactory.getNode(ts.getOp()); + // } + // if (src != null) { + // addStmtTrap(src, stmt, trap); + // } + // }); + }); - public Map> getExceptionEdges() { - return this.exceptionEdges; - } + for (Stmt stmt : body.getStmts()) { + if (inTraps.contains(stmt)) { + continue; + } + Node src = null; + if (stmt.containsInvokeExpr()) { + src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, method); + } else if (stmt instanceof JThrowStmt ts) { + src = nodeFactory.getNode(ts.getOp()); + } + if (src != null) { + node2wrapperedTraps.computeIfAbsent(src, k -> DataFactory.createMap()); + stmt2wrapperedTraps.computeIfAbsent(stmt, k -> DataFactory.createList()); + } + } + } + + private void addStmtTrap(Node src, Stmt stmt, Trap trap) { + Map> stmt2Traps = + node2wrapperedTraps.computeIfAbsent(src, k -> DataFactory.createMap()); + List trapList = stmt2Traps.computeIfAbsent(stmt, k -> DataFactory.createList()); + trapList.add(trap); + stmt2wrapperedTraps.computeIfAbsent(stmt, k -> DataFactory.createList()).add(trap); + } + + protected void addMiscEdges() { + if (method + .getSignature() + .equals( + "(java.lang.Object,java.lang.ref.ReferenceQueue)>")) { + // Implements the special status of java.lang.ref.Reference just as in Doop + // (library/reference.logic). + SootClass sootClass = PTAScene.v().getSootClass("java.lang.ref.Reference"); + SootField sf = (SootField) sootClass.getField("pending").get(); + JStaticFieldRef sfr = Jimple.newStaticFieldRef(sf.getSignature()); + addInternalEdge(nodeFactory.caseThis(), nodeFactory.getNode(sfr)); + } + } + + public void addInternalEdge(Node src, Node dst) { + if (src == null) { + return; + } + internalEdges.add(src); + internalEdges.add(dst); + } + + public QueueReader getInternalReader() { + return internalReader; + } + + public void addTriggeredClinit(SootMethod clinit) { + clinits.add(clinit); + } + + public Iterator triggeredClinits() { + return clinits.iterator(); + } + + public void addExceptionEdge(Node from, Node to) { + this.exceptionEdges.computeIfAbsent(from, k -> DataFactory.createSet()).add(to); + } + + public Map> getExceptionEdges() { + return this.exceptionEdges; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Node.java b/sootup.qilin/src/main/java/qilin/core/pag/Node.java index b33cb5e002e..9994348d32b 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Node.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Node.java @@ -29,41 +29,37 @@ * @author Ondrej Lhotak */ public class Node implements Numberable { - protected Type type; - protected DoublePointsToSet p2set; - private int number = 0; + protected Type type; + protected DoublePointsToSet p2set; + private int number = 0; - /** - * Creates a new node of pointer assignment graph pag, with type type. - */ - protected Node(Type type) { - if (PTAUtils.isUnresolved(type)) { - throw new RuntimeException("Unresolved type " + type); - } - this.type = type; + /** Creates a new node of pointer assignment graph pag, with type type. */ + protected Node(Type type) { + if (PTAUtils.isUnresolved(type)) { + throw new RuntimeException("Unresolved type " + type); } + this.type = type; + } - @Override - public final int hashCode() { - return number; - } + @Override + public final int hashCode() { + return number; + } - public final boolean equals(Object other) { - return this == other; - } + public final boolean equals(Object other) { + return this == other; + } - /** - * Returns the declared type of this node, null for unknown. - */ - public Type getType() { - return type; - } + /** Returns the declared type of this node, null for unknown. */ + public Type getType() { + return type; + } - public final int getNumber() { - return number; - } + public final int getNumber() { + return number; + } - public final void setNumber(int number) { - this.number = number; - } + public final void setNumber(int number) { + this.number = number; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java index 785e1c87a0b..38049c193e5 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/PAG.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/PAG.java @@ -18,6 +18,9 @@ package qilin.core.pag; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; @@ -52,568 +55,572 @@ import sootup.core.types.Type; import sootup.java.core.language.JavaJimple; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - /** * Pointer assignment graph. * * @author Ondrej Lhotak */ public class PAG { - protected final NativeMethodDriver nativeDriver; - protected final ReflectionModel reflectionModel; - - // ========================= context-sensitive nodes ================================= - protected final Map> contextVarNodeMap; - protected final Map> contextAllocNodeMap; - protected final Map> contextMethodMap; - protected final Map> addedContexts; - protected final Map> contextFieldMap; - - // ==========================data========================= - protected ArrayNumberer allocNodeNumberer = new ArrayNumberer<>(); - protected ArrayNumberer valNodeNumberer = new ArrayNumberer<>(); - protected ArrayNumberer fieldRefNodeNumberer = new ArrayNumberer<>(); - private static AtomicInteger maxFinishNumber = new AtomicInteger(0); - - // ========================= ir to Node ============================================== - protected final Map valToAllocNode; - protected final Map valToValNode; - protected final Map methodToPag; - protected final Set globals; - protected final Set locals; - // ==========================outer objects============================== - protected ChunkedQueue edgeQueue; - - protected final Map> simple; - protected final Map> simpleInv; - protected final Map> load; - protected final Map> loadInv; - protected final Map> alloc; - protected final Map> allocInv; - protected final Map> store; - protected final Map> storeInv; - - protected final PTA pta; - - public PAG(PTA pta) { - this.pta = pta; - this.simple = DataFactory.createMap(); - this.simpleInv = DataFactory.createMap(); - this.load = DataFactory.createMap(); - this.loadInv = DataFactory.createMap(); - this.alloc = DataFactory.createMap(); - this.allocInv = DataFactory.createMap(); - this.store = DataFactory.createMap(); - this.storeInv = DataFactory.createMap(); - this.nativeDriver = new NativeMethodDriver(); - this.reflectionModel = createReflectionModel(); - this.contextVarNodeMap = DataFactory.createMap(16000); - this.contextAllocNodeMap = DataFactory.createMap(6000); - this.contextMethodMap = DataFactory.createMap(6000); - this.addedContexts = DataFactory.createMap(); - this.contextFieldMap = DataFactory.createMap(6000); - this.valToAllocNode = DataFactory.createMap(10000); - this.valToValNode = DataFactory.createMap(100000); - this.methodToPag = DataFactory.createMap(); - this.globals = DataFactory.createSet(100000); - this.locals = DataFactory.createSet(100000); - } - - public void setEdgeQueue(ChunkedQueue edgeQueue) { - this.edgeQueue = edgeQueue; - } - - public Map> getAlloc() { - return alloc; - } - - public Map> getSimple() { - return simple; - } - - public Map> getSimpleInv() { - return simpleInv; - } - - public Map> getLoad() { - return load; - } - - public Map> getStoreInv() { - return storeInv; - } - - public PTA getPta() { - return this.pta; - } - - public QueueReader edgeReader() { - return edgeQueue.reader(); - } - - // =======================add edge=============================== - protected boolean addToMap(Map> m, K key, V value) { - Set valueList = m.computeIfAbsent(key, k -> DataFactory.createSet(4)); - return valueList.add(value); - } - - private boolean addAllocEdge(AllocNode from, VarNode to) { - if (addToMap(alloc, from, to)) { - addToMap(allocInv, to, from); - return true; - } - return false; - } - - private boolean addSimpleEdge(ValNode from, ValNode to) { - if (addToMap(simple, from, to)) { - addToMap(simpleInv, to, from); - return true; - } - return false; - } - - private boolean addStoreEdge(VarNode from, FieldRefNode to) { - if (addToMap(storeInv, to, from)) { - addToMap(store, from, to); - return true; - } - return false; - } - - private boolean addLoadEdge(FieldRefNode from, VarNode to) { - if (addToMap(load, from, to)) { - addToMap(loadInv, to, from); - return true; - } - return false; - } - - public void addGlobalPAGEdge(Node from, Node to) { - from = pta.parameterize(from, pta.emptyContext()); - to = pta.parameterize(to, pta.emptyContext()); - addEdge(from, to); - } - - /** - * Adds an edge to the graph, returning false if it was already there. - */ - public final void addEdge(Node from, Node to) { - if (addEdgeIntenal(from, to)) { - edgeQueue.add(from); - edgeQueue.add(to); - } - } - - private boolean addEdgeIntenal(Node from, Node to) { - if (from instanceof ValNode) { - if (to instanceof ValNode) { - return addSimpleEdge((ValNode) from, (ValNode) to); - } else { - return addStoreEdge((VarNode) from, (FieldRefNode) to); - } - } else if (from instanceof FieldRefNode) { - return addLoadEdge((FieldRefNode) from, (VarNode) to); - } else { - AllocNode heap = (AllocNode) from; - return addAllocEdge(heap, (VarNode) to); - } - } - - // ======================lookups=========================== - protected Set lookup(Map> m, K key) { - return m.getOrDefault(key, Collections.emptySet()); - } - - public Set allocLookup(AllocNode key) { - return lookup(alloc, key); - } - - public Set allocInvLookup(VarNode key) { - return lookup(allocInv, key); - } - - public Set simpleLookup(ValNode key) { - return lookup(simple, key); - } - - public Set simpleInvLookup(ValNode key) { - return lookup(simpleInv, key); - } - - public Set loadInvLookup(VarNode key) { - return lookup(loadInv, key); - } - - public Set loadLookup(FieldRefNode key) { - return lookup(load, key); - } - - public Set storeLookup(VarNode key) { - return lookup(store, key); - } - - public Set storeInvLookup(FieldRefNode key) { - return lookup(storeInv, key); - } - - public static int nextFinishNumber() { - return maxFinishNumber.incrementAndGet(); - } - - public ArrayNumberer getAllocNodeNumberer() { - return allocNodeNumberer; - } - - public ArrayNumberer getFieldRefNodeNumberer() { - return fieldRefNodeNumberer; - } - - public ArrayNumberer getValNodeNumberer() { - return valNodeNumberer; - } - - public Collection getValNodes() { - return valToValNode.values(); - } - - public Collection getAllocNodes() { - return valToAllocNode.values(); - } - - public Set getGlobalPointers() { - return globals; - } - - public Set getLocalPointers() { - return locals; - } - - /** - * Finds the ValNode for the variable value, or returns null. - */ - public ValNode findValNode(Object value) { - return valToValNode.get(value); - } - - public AllocNode findAllocNode(Object obj) { - return valToAllocNode.get(obj); - } - - // ==========================create nodes================================== - public AllocNode makeAllocNode(Object newExpr, Type type, SootMethod m) { - AllocNode ret = valToAllocNode.get(newExpr); - if (ret == null) { - valToAllocNode.put(newExpr, ret = new AllocNode(newExpr, type, m)); - allocNodeNumberer.add(ret); - } else if (!(ret.getType().equals(type))) { - throw new RuntimeException("NewExpr " + newExpr + " of type " + type + " previously had type " + ret.getType()); - } - return ret; - } - - public AllocNode makeStringConstantNode(StringConstant sc) { - StringConstant stringConstant = sc; - if (!CoreConfig.v().getPtaConfig().stringConstants) { - stringConstant = JavaJimple.getInstance().newStringConstant(PointsToAnalysis.STRING_NODE); - } - AllocNode ret = valToAllocNode.get(stringConstant); - if (ret == null) { - valToAllocNode.put(stringConstant, ret = new StringConstantNode(stringConstant)); - allocNodeNumberer.add(ret); - } - return ret; - } - - public AllocNode makeClassConstantNode(ClassConstant cc) { - AllocNode ret = valToAllocNode.get(cc); - if (ret == null) { - valToAllocNode.put(cc, ret = new ClassConstantNode(cc)); - allocNodeNumberer.add(ret); - } - return ret; - } - - /** - * Finds or creates the GlobalVarNode for the variable value, of type type. - */ - public GlobalVarNode makeGlobalVarNode(Object value, Type type) { - GlobalVarNode ret = (GlobalVarNode) valToValNode.get(value); - if (ret == null) { - ret = (GlobalVarNode) valToValNode.computeIfAbsent(value, k -> new GlobalVarNode(value, type)); - valNodeNumberer.add(ret); - if (value instanceof SootField) { - globals.add((SootField) value); + protected final NativeMethodDriver nativeDriver; + protected final ReflectionModel reflectionModel; + + // ========================= context-sensitive nodes ================================= + protected final Map> contextVarNodeMap; + protected final Map> contextAllocNodeMap; + protected final Map> contextMethodMap; + protected final Map> addedContexts; + protected final Map> contextFieldMap; + + // ==========================data========================= + protected ArrayNumberer allocNodeNumberer = new ArrayNumberer<>(); + protected ArrayNumberer valNodeNumberer = new ArrayNumberer<>(); + protected ArrayNumberer fieldRefNodeNumberer = new ArrayNumberer<>(); + private static AtomicInteger maxFinishNumber = new AtomicInteger(0); + + // ========================= ir to Node ============================================== + protected final Map valToAllocNode; + protected final Map valToValNode; + protected final Map methodToPag; + protected final Set globals; + protected final Set locals; + // ==========================outer objects============================== + protected ChunkedQueue edgeQueue; + + protected final Map> simple; + protected final Map> simpleInv; + protected final Map> load; + protected final Map> loadInv; + protected final Map> alloc; + protected final Map> allocInv; + protected final Map> store; + protected final Map> storeInv; + + protected final PTA pta; + + public PAG(PTA pta) { + this.pta = pta; + this.simple = DataFactory.createMap(); + this.simpleInv = DataFactory.createMap(); + this.load = DataFactory.createMap(); + this.loadInv = DataFactory.createMap(); + this.alloc = DataFactory.createMap(); + this.allocInv = DataFactory.createMap(); + this.store = DataFactory.createMap(); + this.storeInv = DataFactory.createMap(); + this.nativeDriver = new NativeMethodDriver(); + this.reflectionModel = createReflectionModel(); + this.contextVarNodeMap = DataFactory.createMap(16000); + this.contextAllocNodeMap = DataFactory.createMap(6000); + this.contextMethodMap = DataFactory.createMap(6000); + this.addedContexts = DataFactory.createMap(); + this.contextFieldMap = DataFactory.createMap(6000); + this.valToAllocNode = DataFactory.createMap(10000); + this.valToValNode = DataFactory.createMap(100000); + this.methodToPag = DataFactory.createMap(); + this.globals = DataFactory.createSet(100000); + this.locals = DataFactory.createSet(100000); + } + + public void setEdgeQueue(ChunkedQueue edgeQueue) { + this.edgeQueue = edgeQueue; + } + + public Map> getAlloc() { + return alloc; + } + + public Map> getSimple() { + return simple; + } + + public Map> getSimpleInv() { + return simpleInv; + } + + public Map> getLoad() { + return load; + } + + public Map> getStoreInv() { + return storeInv; + } + + public PTA getPta() { + return this.pta; + } + + public QueueReader edgeReader() { + return edgeQueue.reader(); + } + + // =======================add edge=============================== + protected boolean addToMap(Map> m, K key, V value) { + Set valueList = m.computeIfAbsent(key, k -> DataFactory.createSet(4)); + return valueList.add(value); + } + + private boolean addAllocEdge(AllocNode from, VarNode to) { + if (addToMap(alloc, from, to)) { + addToMap(allocInv, to, from); + return true; + } + return false; + } + + private boolean addSimpleEdge(ValNode from, ValNode to) { + if (addToMap(simple, from, to)) { + addToMap(simpleInv, to, from); + return true; + } + return false; + } + + private boolean addStoreEdge(VarNode from, FieldRefNode to) { + if (addToMap(storeInv, to, from)) { + addToMap(store, from, to); + return true; + } + return false; + } + + private boolean addLoadEdge(FieldRefNode from, VarNode to) { + if (addToMap(load, from, to)) { + addToMap(loadInv, to, from); + return true; + } + return false; + } + + public void addGlobalPAGEdge(Node from, Node to) { + from = pta.parameterize(from, pta.emptyContext()); + to = pta.parameterize(to, pta.emptyContext()); + addEdge(from, to); + } + + /** Adds an edge to the graph, returning false if it was already there. */ + public final void addEdge(Node from, Node to) { + if (addEdgeIntenal(from, to)) { + edgeQueue.add(from); + edgeQueue.add(to); + } + } + + private boolean addEdgeIntenal(Node from, Node to) { + if (from instanceof ValNode) { + if (to instanceof ValNode) { + return addSimpleEdge((ValNode) from, (ValNode) to); + } else { + return addStoreEdge((VarNode) from, (FieldRefNode) to); + } + } else if (from instanceof FieldRefNode) { + return addLoadEdge((FieldRefNode) from, (VarNode) to); + } else { + AllocNode heap = (AllocNode) from; + return addAllocEdge(heap, (VarNode) to); + } + } + + // ======================lookups=========================== + protected Set lookup(Map> m, K key) { + return m.getOrDefault(key, Collections.emptySet()); + } + + public Set allocLookup(AllocNode key) { + return lookup(alloc, key); + } + + public Set allocInvLookup(VarNode key) { + return lookup(allocInv, key); + } + + public Set simpleLookup(ValNode key) { + return lookup(simple, key); + } + + public Set simpleInvLookup(ValNode key) { + return lookup(simpleInv, key); + } + + public Set loadInvLookup(VarNode key) { + return lookup(loadInv, key); + } + + public Set loadLookup(FieldRefNode key) { + return lookup(load, key); + } + + public Set storeLookup(VarNode key) { + return lookup(store, key); + } + + public Set storeInvLookup(FieldRefNode key) { + return lookup(storeInv, key); + } + + public static int nextFinishNumber() { + return maxFinishNumber.incrementAndGet(); + } + + public ArrayNumberer getAllocNodeNumberer() { + return allocNodeNumberer; + } + + public ArrayNumberer getFieldRefNodeNumberer() { + return fieldRefNodeNumberer; + } + + public ArrayNumberer getValNodeNumberer() { + return valNodeNumberer; + } + + public Collection getValNodes() { + return valToValNode.values(); + } + + public Collection getAllocNodes() { + return valToAllocNode.values(); + } + + public Set getGlobalPointers() { + return globals; + } + + public Set getLocalPointers() { + return locals; + } + + /** Finds the ValNode for the variable value, or returns null. */ + public ValNode findValNode(Object value) { + return valToValNode.get(value); + } + + public AllocNode findAllocNode(Object obj) { + return valToAllocNode.get(obj); + } + + // ==========================create nodes================================== + public AllocNode makeAllocNode(Object newExpr, Type type, SootMethod m) { + AllocNode ret = valToAllocNode.get(newExpr); + if (ret == null) { + valToAllocNode.put(newExpr, ret = new AllocNode(newExpr, type, m)); + allocNodeNumberer.add(ret); + } else if (!(ret.getType().equals(type))) { + throw new RuntimeException( + "NewExpr " + newExpr + " of type " + type + " previously had type " + ret.getType()); + } + return ret; + } + + public AllocNode makeStringConstantNode(StringConstant sc) { + StringConstant stringConstant = sc; + if (!CoreConfig.v().getPtaConfig().stringConstants) { + stringConstant = JavaJimple.getInstance().newStringConstant(PointsToAnalysis.STRING_NODE); + } + AllocNode ret = valToAllocNode.get(stringConstant); + if (ret == null) { + valToAllocNode.put(stringConstant, ret = new StringConstantNode(stringConstant)); + allocNodeNumberer.add(ret); + } + return ret; + } + + public AllocNode makeClassConstantNode(ClassConstant cc) { + AllocNode ret = valToAllocNode.get(cc); + if (ret == null) { + valToAllocNode.put(cc, ret = new ClassConstantNode(cc)); + allocNodeNumberer.add(ret); + } + return ret; + } + + /** Finds or creates the GlobalVarNode for the variable value, of type type. */ + public GlobalVarNode makeGlobalVarNode(Object value, Type type) { + GlobalVarNode ret = (GlobalVarNode) valToValNode.get(value); + if (ret == null) { + ret = + (GlobalVarNode) valToValNode.computeIfAbsent(value, k -> new GlobalVarNode(value, type)); + valNodeNumberer.add(ret); + if (value instanceof SootField) { + globals.add((SootField) value); + } + } else if (!(ret.getType().equals(type))) { + throw new RuntimeException( + "Value " + value + " of type " + type + " previously had type " + ret.getType()); + } + return ret; + } + + /** Finds or creates the LocalVarNode for the variable value, of type type. */ + public LocalVarNode makeLocalVarNode(Object value, Type type, SootMethod method) { + LocalVarNode ret = (LocalVarNode) valToValNode.get(value); + if (ret == null) { + valToValNode.put(value, ret = new LocalVarNode(value, type, method)); + valNodeNumberer.add(ret); + if (value instanceof Local local) { + // if (local.getNumber() == 0) { + // PTAScene.v().getLocalNumberer().add(local); + // } + locals.add(local); + } + } else if (!(ret.getType().equals(type))) { + throw new RuntimeException( + "Value " + value + " of type " + type + " previously had type " + ret.getType()); + } + return ret; + } + + /** + * Finds or creates the FieldVarNode for the Java field or array element. Treat Java field and + * array element as normal local variable. + */ + public FieldValNode makeFieldValNode(SparkField field) { + FieldValNode ret = (FieldValNode) valToValNode.get(field); + if (ret == null) { + valToValNode.put(field, ret = new FieldValNode(field)); + valNodeNumberer.add(ret); + } + return ret; + } + + /** Finds or creates the FieldRefNode for base variable base and field field, of type type. */ + public FieldRefNode makeFieldRefNode(VarNode base, SparkField field) { + FieldRefNode ret = base.dot(field); + if (ret == null) { + ret = new FieldRefNode(base, field); + fieldRefNodeNumberer.add(ret); + } + return ret; + } + + /** Finds or creates the ContextVarNode for base variable base and context. */ + public ContextVarNode makeContextVarNode(VarNode base, Context context) { + Map contextMap = + contextVarNodeMap.computeIfAbsent(base, k1 -> DataFactory.createMap()); + ContextVarNode ret = contextMap.get(context); + if (ret == null) { + contextMap.put(context, ret = new ContextVarNode(base, context)); + valNodeNumberer.add(ret); + } + return ret; + } + + /** Finds or creates the ContextAllocNode for base alloc site and context. */ + public ContextAllocNode makeContextAllocNode(AllocNode allocNode, Context context) { + Map contextMap = + contextAllocNodeMap.computeIfAbsent(allocNode, k1 -> DataFactory.createMap()); + ContextAllocNode ret = contextMap.get(context); + if (ret == null) { + contextMap.put(context, ret = new ContextAllocNode(allocNode, context)); + allocNodeNumberer.add(ret); + } + return ret; + } + + /** Finds or creates the ContextMethod for method and context. */ + public MethodOrMethodContext makeContextMethod(Context context, SootMethod method) { + Map contextMap = + contextMethodMap.computeIfAbsent(method, k1 -> DataFactory.createMap()); + return contextMap.computeIfAbsent(context, k -> new ContextMethod(method, context)); + } + + public AllocNode getAllocNode(Object val) { + return valToAllocNode.get(val); + } + + public Map> getMethod2ContextsMap() { + return addedContexts; + } + + public boolean containsMethodPAG(SootMethod m) { + return methodToPag.containsKey(m); + } + + public Collection getContextFields() { + return contextFieldMap.values().stream() + .flatMap(m -> m.values().stream()) + .collect(Collectors.toSet()); + } + + public Map> getContextVarNodeMap() { + return contextVarNodeMap; + } + + public Map> getContextAllocNodeMap() { + return contextAllocNodeMap; + } + + public Map> getContextMethodMap() { + return contextMethodMap; + } + + public Map> getContextFieldVarNodeMap() { + return contextFieldMap; + } + + public ContextField makeContextField(Context context, FieldValNode fieldValNode) { + SparkField field = fieldValNode.getField(); + Map field2odotf = + contextFieldMap.computeIfAbsent(context, k -> DataFactory.createMap()); + ContextField ret = field2odotf.get(field); + if (ret == null) { + field2odotf.put(field, ret = new ContextField(context, field)); + valNodeNumberer.add(ret); + } + return ret; + } + + public Collection getVarNodes(Local local) { + Map subMap = contextVarNodeMap.get(findLocalVarNode(local)); + if (subMap == null) { + return Collections.emptySet(); + } + return new HashSet<>(subMap.values()); + } + + // ===================find nodes============================== + + /** Finds the GlobalVarNode for the variable value, or returns null. */ + public GlobalVarNode findGlobalVarNode(Object value) { + return (GlobalVarNode) findValNode(value); + } + + /** Finds the LocalVarNode for the variable value, or returns null. */ + public LocalVarNode findLocalVarNode(Object value) { + ValNode ret = findValNode(value); + if (ret instanceof LocalVarNode) { + return (LocalVarNode) ret; + } + return null; + } + + /** Finds the ContextVarNode for base variable value and context context, or returns null. */ + public ContextVarNode findContextVarNode(Local baseValue, Context context) { + Map contextMap = contextVarNodeMap.get(findLocalVarNode(baseValue)); + return contextMap == null ? null : contextMap.get(context); + } + + protected ReflectionModel createReflectionModel() { + ReflectionModel model; + if (CoreConfig.v().getAppConfig().REFLECTION_LOG != null + && CoreConfig.v().getAppConfig().REFLECTION_LOG.length() > 0) { + model = new TamiflexModel(); + } else { + model = new NopReflectionModel(); + } + return model; + } + + public MethodPAG getMethodPAG(SootMethod m) { + if (methodToPag.containsKey(m)) { + return methodToPag.get(m); + } + if (m.isConcrete()) { + reflectionModel.buildReflection(m); + } + if (m.isNative()) { + nativeDriver.buildNative(m); + } else { + // we will revert these back in the future. + /* + * To keep same with Doop, we move the simulation of + * + * directly to its caller methods. + * */ + if (PTAScene.v().arraycopyBuilt.add(m)) { + handleArrayCopy(m); + } + } + Body body = PTAUtils.getMethodBody(m); + return methodToPag.computeIfAbsent(m, k -> new MethodPAG(this, m, body)); + } + + private void handleArrayCopy(SootMethod method) { + Map> newUnits = DataFactory.createMap(); + Body body = PTAUtils.getMethodBody(method); + Body.BodyBuilder builder = Body.builder(body, Collections.emptySet()); + int localCount = body.getLocalCount(); + for (Stmt s : body.getStmts()) { + if (s.containsInvokeExpr()) { + AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); + if (invokeExpr instanceof JStaticInvokeExpr sie) { + String sig = sie.getMethodSignature().toString(); + if (sig.equals( + "")) { + Value srcArr = sie.getArg(0); + if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { + continue; } - } else if (!(ret.getType().equals(type))) { - throw new RuntimeException("Value " + value + " of type " + type + " previously had type " + ret.getType()); - } - return ret; - } - - /** - * Finds or creates the LocalVarNode for the variable value, of type type. - */ - public LocalVarNode makeLocalVarNode(Object value, Type type, SootMethod method) { - LocalVarNode ret = (LocalVarNode) valToValNode.get(value); - if (ret == null) { - valToValNode.put(value, ret = new LocalVarNode(value, type, method)); - valNodeNumberer.add(ret); - if (value instanceof Local local) { -// if (local.getNumber() == 0) { -// PTAScene.v().getLocalNumberer().add(local); -// } - locals.add(local); + Type objType = PTAUtils.getClassType("java.lang.Object"); + if (srcArr.getType() == objType) { + Local localSrc = + Jimple.newLocal("intermediate/" + (localCount++), new ArrayType(objType, 1)); + builder.addLocal(localSrc); + newUnits + .computeIfAbsent(s, k -> new HashSet<>()) + .add( + new JAssignStmt<>( + localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); + srcArr = localSrc; } - } else if (!(ret.getType().equals(type))) { - throw new RuntimeException("Value " + value + " of type " + type + " previously had type " + ret.getType()); - } - return ret; - } - - /** - * Finds or creates the FieldVarNode for the Java field or array element. - * Treat Java field and array element as normal local variable. - */ - public FieldValNode makeFieldValNode(SparkField field) { - FieldValNode ret = (FieldValNode) valToValNode.get(field); - if (ret == null) { - valToValNode.put(field, ret = new FieldValNode(field)); - valNodeNumberer.add(ret); - } - return ret; - } - - /** - * Finds or creates the FieldRefNode for base variable base and field field, of - * type type. - */ - public FieldRefNode makeFieldRefNode(VarNode base, SparkField field) { - FieldRefNode ret = base.dot(field); - if (ret == null) { - ret = new FieldRefNode(base, field); - fieldRefNodeNumberer.add(ret); - } - return ret; - } - - /** - * Finds or creates the ContextVarNode for base variable base and context. - */ - public ContextVarNode makeContextVarNode(VarNode base, Context context) { - Map contextMap = contextVarNodeMap.computeIfAbsent(base, k1 -> DataFactory.createMap()); - ContextVarNode ret = contextMap.get(context); - if (ret == null) { - contextMap.put(context, ret = new ContextVarNode(base, context)); - valNodeNumberer.add(ret); - } - return ret; - } - - /** - * Finds or creates the ContextAllocNode for base alloc site and context. - */ - public ContextAllocNode makeContextAllocNode(AllocNode allocNode, Context context) { - Map contextMap = contextAllocNodeMap.computeIfAbsent(allocNode, k1 -> DataFactory.createMap()); - ContextAllocNode ret = contextMap.get(context); - if (ret == null) { - contextMap.put(context, ret = new ContextAllocNode(allocNode, context)); - allocNodeNumberer.add(ret); - } - return ret; - } - - /** - * Finds or creates the ContextMethod for method and context. - */ - public MethodOrMethodContext makeContextMethod(Context context, SootMethod method) { - Map contextMap = contextMethodMap.computeIfAbsent(method, k1 -> DataFactory.createMap()); - return contextMap.computeIfAbsent(context, k -> new ContextMethod(method, context)); - } - - public AllocNode getAllocNode(Object val) { - return valToAllocNode.get(val); - } - - public Map> getMethod2ContextsMap() { - return addedContexts; - } - - public boolean containsMethodPAG(SootMethod m) { - return methodToPag.containsKey(m); - } - - public Collection getContextFields() { - return contextFieldMap.values().stream().flatMap(m -> m.values().stream()).collect(Collectors.toSet()); - } - - public Map> getContextVarNodeMap() { - return contextVarNodeMap; - } - - public Map> getContextAllocNodeMap() { - return contextAllocNodeMap; - } - - public Map> getContextMethodMap() { - return contextMethodMap; - } - - public Map> getContextFieldVarNodeMap() { - return contextFieldMap; - } - - public ContextField makeContextField(Context context, FieldValNode fieldValNode) { - SparkField field = fieldValNode.getField(); - Map field2odotf = contextFieldMap.computeIfAbsent(context, k -> DataFactory.createMap()); - ContextField ret = field2odotf.get(field); - if (ret == null) { - field2odotf.put(field, ret = new ContextField(context, field)); - valNodeNumberer.add(ret); - } - return ret; - } - - public Collection getVarNodes(Local local) { - Map subMap = contextVarNodeMap.get(findLocalVarNode(local)); - if (subMap == null) { - return Collections.emptySet(); - } - return new HashSet<>(subMap.values()); - } - - // ===================find nodes============================== - - /** - * Finds the GlobalVarNode for the variable value, or returns null. - */ - public GlobalVarNode findGlobalVarNode(Object value) { - return (GlobalVarNode) findValNode(value); - } - - /** - * Finds the LocalVarNode for the variable value, or returns null. - */ - public LocalVarNode findLocalVarNode(Object value) { - ValNode ret = findValNode(value); - if (ret instanceof LocalVarNode) { - return (LocalVarNode) ret; - } - return null; - } - - /** - * Finds the ContextVarNode for base variable value and context context, or - * returns null. - */ - public ContextVarNode findContextVarNode(Local baseValue, Context context) { - Map contextMap = contextVarNodeMap.get(findLocalVarNode(baseValue)); - return contextMap == null ? null : contextMap.get(context); - } - - protected ReflectionModel createReflectionModel() { - ReflectionModel model; - if (CoreConfig.v().getAppConfig().REFLECTION_LOG != null && CoreConfig.v().getAppConfig().REFLECTION_LOG.length() > 0) { - model = new TamiflexModel(); - } else { - model = new NopReflectionModel(); - } - return model; - } - - public MethodPAG getMethodPAG(SootMethod m) { - if (methodToPag.containsKey(m)) { - return methodToPag.get(m); - } - if (m.isConcrete()) { - reflectionModel.buildReflection(m); - } - if (m.isNative()) { - nativeDriver.buildNative(m); - } else { - // we will revert these back in the future. - /* - * To keep same with Doop, we move the simulation of - * - * directly to its caller methods. - * */ - if (PTAScene.v().arraycopyBuilt.add(m)) { - handleArrayCopy(m); + Value dstArr = sie.getArg(2); + if (PTAUtils.isPrimitiveArrayType(dstArr.getType())) { + continue; } - } - Body body = PTAUtils.getMethodBody(m); - return methodToPag.computeIfAbsent(m, k -> new MethodPAG(this, m, body)); - } - - private void handleArrayCopy(SootMethod method) { - Map> newUnits = DataFactory.createMap(); - Body body = PTAUtils.getMethodBody(method); - Body.BodyBuilder builder = Body.builder(body, Collections.emptySet()); - int localCount = body.getLocalCount(); - for (Stmt s : body.getStmts()) { - if (s.containsInvokeExpr()) { - AbstractInvokeExpr invokeExpr = s.getInvokeExpr(); - if (invokeExpr instanceof JStaticInvokeExpr sie) { - String sig = sie.getMethodSignature().toString(); - if (sig.equals("")) { - Value srcArr = sie.getArg(0); - if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { - continue; - } - Type objType = PTAUtils.getClassType("java.lang.Object"); - if (srcArr.getType() == objType) { - Local localSrc = Jimple.newLocal("intermediate/" + (localCount ++), new ArrayType(objType, 1)); - builder.addLocal(localSrc); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt<>(localSrc, srcArr, StmtPositionInfo.createNoStmtPositionInfo())); - srcArr = localSrc; - } - Value dstArr = sie.getArg(2); - if (PTAUtils.isPrimitiveArrayType(dstArr.getType())) { - continue; - } - if (dstArr.getType() == objType) { - Local localDst = Jimple.newLocal("intermediate/" + (localCount ++), new ArrayType(objType, 1)); - builder.addLocal(localDst); - newUnits.computeIfAbsent(s, k -> new HashSet<>()).add(new JAssignStmt<>(localDst, dstArr,StmtPositionInfo.createNoStmtPositionInfo())); - dstArr = localDst; - } - Value src = JavaJimple.getInstance().newArrayRef((Local) srcArr, IntConstant.getInstance(0)); - Value dst = JavaJimple.getInstance().newArrayRef((Local) dstArr, IntConstant.getInstance(0)); - Local local = Jimple.newLocal("nativeArrayCopy" + (localCount ++), PTAUtils.getClassType("java.lang.Object")); - builder.addLocal(local); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt<>(local, src, StmtPositionInfo.createNoStmtPositionInfo())); - newUnits.computeIfAbsent(s, k -> DataFactory.createSet()).add(new JAssignStmt<>(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); - } - } - } - } - - for (Stmt unit : newUnits.keySet()) { - for (Stmt succ : newUnits.get(unit)) { - builder.addFlow(unit, succ); + if (dstArr.getType() == objType) { + Local localDst = + Jimple.newLocal("intermediate/" + (localCount++), new ArrayType(objType, 1)); + builder.addLocal(localDst); + newUnits + .computeIfAbsent(s, k -> new HashSet<>()) + .add( + new JAssignStmt<>( + localDst, dstArr, StmtPositionInfo.createNoStmtPositionInfo())); + dstArr = localDst; } + Value src = + JavaJimple.getInstance().newArrayRef((Local) srcArr, IntConstant.getInstance(0)); + Value dst = + JavaJimple.getInstance().newArrayRef((Local) dstArr, IntConstant.getInstance(0)); + Local local = + Jimple.newLocal( + "nativeArrayCopy" + (localCount++), PTAUtils.getClassType("java.lang.Object")); + builder.addLocal(local); + newUnits + .computeIfAbsent(s, k -> DataFactory.createSet()) + .add(new JAssignStmt<>(local, src, StmtPositionInfo.createNoStmtPositionInfo())); + newUnits + .computeIfAbsent(s, k -> DataFactory.createSet()) + .add(new JAssignStmt<>(dst, local, StmtPositionInfo.createNoStmtPositionInfo())); + } } - PTAUtils.updateMethodBody(method, builder.build()); - } - - public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { - return makeLocalVarNode(invoke, PTAUtils.getClassType("java.lang.Throwable"), method); - } - - public HeapAbstractor heapAbstractor() { - return pta.heapAbstractor(); - } - - - public void resetPointsToSet() { - this.addedContexts.clear(); - contextVarNodeMap.values().stream().flatMap(m -> m.values().stream()).forEach(ValNode::discardP2Set); - contextFieldMap.values().stream().flatMap(m -> m.values().stream()).forEach(ValNode::discardP2Set); - valToValNode.values().forEach(ValNode::discardP2Set); - addedContexts.clear(); - } - -} \ No newline at end of file + } + } + + for (Stmt unit : newUnits.keySet()) { + for (Stmt succ : newUnits.get(unit)) { + builder.addFlow(unit, succ); + } + } + PTAUtils.updateMethodBody(method, builder.build()); + } + + public LocalVarNode makeInvokeStmtThrowVarNode(Stmt invoke, SootMethod method) { + return makeLocalVarNode(invoke, PTAUtils.getClassType("java.lang.Throwable"), method); + } + + public HeapAbstractor heapAbstractor() { + return pta.heapAbstractor(); + } + + public void resetPointsToSet() { + this.addedContexts.clear(); + contextVarNodeMap.values().stream() + .flatMap(m -> m.values().stream()) + .forEach(ValNode::discardP2Set); + contextFieldMap.values().stream() + .flatMap(m -> m.values().stream()) + .forEach(ValNode::discardP2Set); + valToValNode.values().forEach(ValNode::discardP2Set); + addedContexts.clear(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java index 9275248b75f..c6ceb51a583 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/Parm.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/Parm.java @@ -18,78 +18,78 @@ package qilin.core.pag; +import java.util.Objects; import qilin.core.PointsToAnalysis; import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.Type; -import java.util.Objects; - /** * Represents a method parameter. * * @author Ondrej Lhotak */ public class Parm { - private final int index; - private final SootMethod method; + private final int index; + private final SootMethod method; - public Parm(SootMethod m, int i) { - index = i; - method = m; - } + public Parm(SootMethod m, int i) { + index = i; + method = m; + } - public String toString() { - if (index == PointsToAnalysis.THIS_NODE) { - return "Parm THIS_NODE to " + method; - } else if (index == PointsToAnalysis.RETURN_NODE) { - return "Parm RETURN to " + method; - } else { - return "Parm " + index + " to " + method; - } + public String toString() { + if (index == PointsToAnalysis.THIS_NODE) { + return "Parm THIS_NODE to " + method; + } else if (index == PointsToAnalysis.RETURN_NODE) { + return "Parm RETURN to " + method; + } else { + return "Parm " + index + " to " + method; } + } - public int getIndex() { - return index; - } + public int getIndex() { + return index; + } - public boolean isThis() { - return index == PointsToAnalysis.THIS_NODE; - } + public boolean isThis() { + return index == PointsToAnalysis.THIS_NODE; + } - public boolean isReturn() { - return index == PointsToAnalysis.RETURN_NODE; - } + public boolean isReturn() { + return index == PointsToAnalysis.RETURN_NODE; + } - public boolean isThrowRet() { - return index == PointsToAnalysis.THROW_NODE; - } - - public Type getType() { - if (index == PointsToAnalysis.RETURN_NODE) { - return method.getReturnType(); - } else if (index == PointsToAnalysis.THIS_NODE) { - return method.isStatic() ? PTAUtils.getClassType("java.lang.Object") : method.getDeclaringClassType(); - } + public boolean isThrowRet() { + return index == PointsToAnalysis.THROW_NODE; + } - return method.getParameterType(index); + public Type getType() { + if (index == PointsToAnalysis.RETURN_NODE) { + return method.getReturnType(); + } else if (index == PointsToAnalysis.THIS_NODE) { + return method.isStatic() + ? PTAUtils.getClassType("java.lang.Object") + : method.getDeclaringClassType(); } - public SootMethod method() { - return method; - } + return method.getParameterType(index); + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Parm parm = (Parm) o; - return index == parm.index && - method.equals(parm.method); - } + public SootMethod method() { + return method; + } - @Override - public int hashCode() { - return Objects.hash(index, method); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Parm parm = (Parm) o; + return index == parm.index && method.equals(parm.method); + } + + @Override + public int hashCode() { + return Objects.hash(index, method); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java index 726a3b536e5..e23c7dc9d91 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/SparkField.java @@ -22,7 +22,6 @@ * #L% */ -import soot.util.Numberable; import sootup.core.types.Type; /** @@ -30,8 +29,7 @@ * * @author Ondrej Lhotak */ -//public interface SparkField extends Numberable { +// public interface SparkField extends Numberable { public interface SparkField { - public Type getType(); + public Type getType(); } - diff --git a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java index 4d36b647df2..51d70927f9c 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/StringConstantNode.java @@ -27,15 +27,15 @@ * @author Ondrej Lhotak */ public class StringConstantNode extends ConstantNode { - public StringConstantNode(StringConstant sc) { - super(sc, PTAUtils.getClassType("java.lang.String"), null); - } + public StringConstantNode(StringConstant sc) { + super(sc, PTAUtils.getClassType("java.lang.String"), null); + } - public String toString() { - return "StringConstantNode " + getNumber() + " " + newExpr; - } + public String toString() { + return "StringConstantNode " + getNumber() + " " + newExpr; + } - public String getString() { - return ((StringConstant) newExpr).getValue(); - } + public String getString() { + return ((StringConstant) newExpr).getValue(); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java index f02e1e2b08c..e057fd88a39 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/ValNode.java @@ -22,37 +22,30 @@ import soot.util.Numberable; import sootup.core.types.Type; -/** - * Represents a simple of pointer node in the pointer assignment graph. - */ +/** Represents a simple of pointer node in the pointer assignment graph. */ public class ValNode extends Node implements Comparable, Numberable { - protected ValNode(Type t) { - super(t); - } - - public int compareTo(Object o) { - ValNode other = (ValNode) o; - return other.getNumber() - this.getNumber(); - } - - /** - * Returns the points-to set for this node. - */ - public DoublePointsToSet getP2Set() { - if (p2set != null) { - return p2set; - } else { - p2set = new DoublePointsToSet(); - return p2set; - } - } - - /** - * Delete current points-to set and make a new one - */ - public void discardP2Set() { - p2set = null; + protected ValNode(Type t) { + super(t); + } + + public int compareTo(Object o) { + ValNode other = (ValNode) o; + return other.getNumber() - this.getNumber(); + } + + /** Returns the points-to set for this node. */ + public DoublePointsToSet getP2Set() { + if (p2set != null) { + return p2set; + } else { + p2set = new DoublePointsToSet(); + return p2set; } + } + /** Delete current points-to set and make a new one */ + public void discardP2Set() { + p2set = null; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java index 8484650efdc..7aaad38dc9b 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VarNode.java @@ -18,109 +18,103 @@ package qilin.core.pag; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; import qilin.util.DataFactory; -//import soot.AnySubType; +// import soot.AnySubType; import soot.Context; import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - /** * Represents a simple variable node in the pointer assignment graph. * * @author Ondrej Lhotak */ public abstract class VarNode extends ValNode { - protected Object variable; - protected Map fields; + protected Object variable; + protected Map fields; - protected boolean interProcTarget = false; - protected boolean interProcSource = false; + protected boolean interProcTarget = false; + protected boolean interProcSource = false; - protected VarNode(Object variable, Type t) { - super(t); - if (!(t instanceof ReferenceType) /*|| t instanceof AnySubType*/ ) { - throw new RuntimeException("Attempt to create VarNode of type " + t); - } - this.variable = variable; - } - - public Context context() { - return null; + protected VarNode(Object variable, Type t) { + super(t); + if (!(t instanceof ReferenceType) /*|| t instanceof AnySubType*/) { + throw new RuntimeException("Attempt to create VarNode of type " + t); } + this.variable = variable; + } - /** - * Returns all field ref nodes having this node as their base. - */ - public Collection getAllFieldRefs() { - if (fields == null) { - return Collections.emptyList(); - } - return fields.values(); - } + public Context context() { + return null; + } - /** - * Returns the field ref node having this node as its base, and field as its field; null if nonexistent. - */ - public FieldRefNode dot(SparkField field) { - return fields == null ? null : fields.get(field); + /** Returns all field ref nodes having this node as their base. */ + public Collection getAllFieldRefs() { + if (fields == null) { + return Collections.emptyList(); } - - /** - * Returns the underlying variable that this node represents. - */ - public Object getVariable() { - return variable; - } - - /** - * Designates this node as the potential target of a interprocedural assignment edge which may be added during on-the-fly - * call graph updating. - */ - public void setInterProcTarget() { - interProcTarget = true; - } - - /** - * Returns true if this node is the potential target of a interprocedural assignment edge which may be added during - * on-the-fly call graph updating. - */ - public boolean isInterProcTarget() { - return interProcTarget; - } - - /** - * Designates this node as the potential source of a interprocedural assignment edge which may be added during on-the-fly - * call graph updating. - */ - public void setInterProcSource() { - interProcSource = true; - } - - /** - * Returns true if this node is the potential source of a interprocedural assignment edge which may be added during - * on-the-fly call graph updating. - */ - public boolean isInterProcSource() { - return interProcSource; - } - - public abstract VarNode base(); - - /** - * Registers a frn as having this node as its base. - */ - void addField(FieldRefNode frn, SparkField field) { + return fields.values(); + } + + /** + * Returns the field ref node having this node as its base, and field as its field; null if + * nonexistent. + */ + public FieldRefNode dot(SparkField field) { + return fields == null ? null : fields.get(field); + } + + /** Returns the underlying variable that this node represents. */ + public Object getVariable() { + return variable; + } + + /** + * Designates this node as the potential target of a interprocedural assignment edge which may be + * added during on-the-fly call graph updating. + */ + public void setInterProcTarget() { + interProcTarget = true; + } + + /** + * Returns true if this node is the potential target of a interprocedural assignment edge which + * may be added during on-the-fly call graph updating. + */ + public boolean isInterProcTarget() { + return interProcTarget; + } + + /** + * Designates this node as the potential source of a interprocedural assignment edge which may be + * added during on-the-fly call graph updating. + */ + public void setInterProcSource() { + interProcSource = true; + } + + /** + * Returns true if this node is the potential source of a interprocedural assignment edge which + * may be added during on-the-fly call graph updating. + */ + public boolean isInterProcSource() { + return interProcSource; + } + + public abstract VarNode base(); + + /** Registers a frn as having this node as its base. */ + void addField(FieldRefNode frn, SparkField field) { + if (fields == null) { + synchronized (this) { if (fields == null) { - synchronized (this) { - if (fields == null) { - fields = DataFactory.createMap(); - } - } + fields = DataFactory.createMap(); } - fields.put(field, frn); + } } + fields.put(field, frn); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java index bcb4361ef47..3336e3c02ce 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/VirtualCallSite.java @@ -18,68 +18,75 @@ package qilin.core.pag; +import java.util.Objects; import soot.Kind; import soot.MethodOrMethodContext; -import soot.util.NumberedString; import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.signatures.MethodSubSignature; -import java.util.Objects; - /** * Holds relevant information about a particular virtual call site. * * @author Ondrej Lhotak */ public class VirtualCallSite extends CallSite { - private final VarNode recNode; - private final MethodOrMethodContext container; - private final AbstractInstanceInvokeExpr iie; - private final MethodSubSignature subSig; - private final Kind kind; + private final VarNode recNode; + private final MethodOrMethodContext container; + private final AbstractInstanceInvokeExpr iie; + private final MethodSubSignature subSig; + private final Kind kind; - public VirtualCallSite(VarNode recNode, Stmt stmt, MethodOrMethodContext container, AbstractInstanceInvokeExpr iie, - MethodSubSignature subSig, Kind kind) { - super(stmt); - this.recNode = recNode; - this.container = container; - this.iie = iie; - this.subSig = subSig; - this.kind = kind; - } + public VirtualCallSite( + VarNode recNode, + Stmt stmt, + MethodOrMethodContext container, + AbstractInstanceInvokeExpr iie, + MethodSubSignature subSig, + Kind kind) { + super(stmt); + this.recNode = recNode; + this.container = container; + this.iie = iie; + this.subSig = subSig; + this.kind = kind; + } - public VarNode recNode() { - return recNode; - } + public VarNode recNode() { + return recNode; + } - public MethodOrMethodContext container() { - return container; - } + public MethodOrMethodContext container() { + return container; + } - public AbstractInstanceInvokeExpr iie() { - return iie; - } + public AbstractInstanceInvokeExpr iie() { + return iie; + } - public MethodSubSignature subSig() { - return subSig; - } + public MethodSubSignature subSig() { + return subSig; + } - public Kind kind() { - return kind; - } + public Kind kind() { + return kind; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - VirtualCallSite that = (VirtualCallSite) o; - return recNode.equals(that.recNode) && container.equals(that.container) && iie.equals(that.iie) && subSig.equals(that.subSig) && kind.equals(that.kind); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + VirtualCallSite that = (VirtualCallSite) o; + return recNode.equals(that.recNode) + && container.equals(that.container) + && iie.equals(that.iie) + && subSig.equals(that.subSig) + && kind.equals(that.kind); + } - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), recNode, container, iie, subSig, kind); - } + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), recNode, container, iie, subSig, kind); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/pag/package-info.java b/sootup.qilin/src/main/java/qilin/core/pag/package-info.java index 64368593443..11dd57abbe9 100644 --- a/sootup.qilin/src/main/java/qilin/core/pag/package-info.java +++ b/sootup.qilin/src/main/java/qilin/core/pag/package-info.java @@ -4,4 +4,4 @@ * Most of the class files in this package can be seen in the Soot/jimple/spark/pag. * We have changed them a lot but (at least) their names are kept the same here. * We hope our framework could be merged into soot and replace the original Spark one day. - * */ \ No newline at end of file + * */ diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java index 86cedb19b89..f6370901adb 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/NopReflectionModel.java @@ -18,10 +18,9 @@ package qilin.core.reflection; -import sootup.core.jimple.common.stmt.Stmt; - import java.util.Collection; import java.util.Collections; +import sootup.core.jimple.common.stmt.Stmt; /* * This is an empty reflection model which does nothing for reflection statements. @@ -29,48 +28,48 @@ public class NopReflectionModel extends ReflectionModel { - @Override - Collection transformClassForName(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformClassForName(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformClassNewInstance(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformClassNewInstance(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformContructorNewInstance(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformContructorNewInstance(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformMethodInvoke(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformMethodInvoke(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformFieldSet(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformFieldSet(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformFieldGet(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformFieldGet(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformArrayNewInstance(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformArrayNewInstance(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformArrayGet(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformArrayGet(Stmt s) { + return Collections.emptySet(); + } - @Override - Collection transformArraySet(Stmt s) { - return Collections.emptySet(); - } + @Override + Collection transformArraySet(Stmt s) { + return Collections.emptySet(); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java index f950fc560b8..692c534be44 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionKind.java @@ -19,21 +19,30 @@ package qilin.core.reflection; public enum ReflectionKind { - ClassForName, ClassNewInstance, ConstructorNewInstance, MethodInvoke, FieldSet, FieldGet, MethodGet, ArrayNewInstance, - ArrayGet, ArraySet, FieldGetName; + ClassForName, + ClassNewInstance, + ConstructorNewInstance, + MethodInvoke, + FieldSet, + FieldGet, + MethodGet, + ArrayNewInstance, + ArrayGet, + ArraySet, + FieldGetName; - public static ReflectionKind parse(String kindStr) { - return switch (kindStr) { - case "Class.forName" -> ClassForName; - case "Class.newInstance" -> ClassNewInstance; - case "Constructor.newInstance" -> ConstructorNewInstance; - case "Method.invoke" -> MethodInvoke; - case "Method.getName" -> MethodGet; - case "Field.set*" -> FieldSet; - case "Field.get*" -> FieldGet; - case "Field.getName" -> FieldGetName; - case "Array.newInstance" -> ArrayNewInstance; - default -> null; - }; - } -} \ No newline at end of file + public static ReflectionKind parse(String kindStr) { + return switch (kindStr) { + case "Class.forName" -> ClassForName; + case "Class.newInstance" -> ClassNewInstance; + case "Constructor.newInstance" -> ConstructorNewInstance; + case "Method.invoke" -> MethodInvoke; + case "Method.getName" -> MethodGet; + case "Field.set*" -> FieldSet; + case "Field.get*" -> FieldGet; + case "Field.getName" -> FieldGetName; + case "Array.newInstance" -> ArrayNewInstance; + default -> null; + }; + } +} diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java index 53973427dc0..33b76eeefd7 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/ReflectionModel.java @@ -18,6 +18,10 @@ package qilin.core.reflection; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; import qilin.core.PTAScene; import qilin.util.DataFactory; import qilin.util.PTAUtils; @@ -26,86 +30,96 @@ import sootup.core.model.Body; import sootup.core.model.SootMethod; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - public abstract class ReflectionModel { - protected final String sigForName = ""; - protected final String sigForName2 = ""; - protected final String sigClassNewInstance = ""; - protected final String sigConstructorNewInstance = ""; - protected final String sigMethodInvoke = ""; - protected final String sigFieldSet = ""; - protected final String sigFieldGet = ""; - protected final String sigArrayNewInstance = ""; - protected final String sigArrayGet = ""; - protected final String sigArraySet = ""; - protected final String sigReifiedField = ""; - protected final String sigReifiedDeclaredField = ""; - protected final String sigReifiedFieldArray = ""; - protected final String sigReifiedDeclaredFieldArray = ""; - protected final String sigReifiedMethod = ""; - protected final String sigReifiedDeclaredMethod = ""; - protected final String sigReifiedMethodArray = ""; - protected final String sigReifiedDeclaredMethodArray = ""; + protected final String sigForName = + ""; + protected final String sigForName2 = + ""; + protected final String sigClassNewInstance = ""; + protected final String sigConstructorNewInstance = + ""; + protected final String sigMethodInvoke = + ""; + protected final String sigFieldSet = + ""; + protected final String sigFieldGet = + ""; + protected final String sigArrayNewInstance = + ""; + protected final String sigArrayGet = + ""; + protected final String sigArraySet = + ""; + protected final String sigReifiedField = + ""; + protected final String sigReifiedDeclaredField = + ""; + protected final String sigReifiedFieldArray = + ""; + protected final String sigReifiedDeclaredFieldArray = + ""; + protected final String sigReifiedMethod = + ""; + protected final String sigReifiedDeclaredMethod = + ""; + protected final String sigReifiedMethodArray = + ""; + protected final String sigReifiedDeclaredMethodArray = + ""; - private Collection transform(Stmt s) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - return switch (ie.getMethodSignature().toString()) { - case sigForName, sigForName2 -> transformClassForName(s); - case sigClassNewInstance -> transformClassNewInstance(s); - case sigConstructorNewInstance -> transformContructorNewInstance(s); - case sigMethodInvoke -> transformMethodInvoke(s); - case sigFieldSet -> transformFieldSet(s); - case sigFieldGet -> transformFieldGet(s); - case sigArrayNewInstance -> transformArrayNewInstance(s); - case sigArrayGet -> transformArrayGet(s); - case sigArraySet -> transformArraySet(s); - default -> Collections.emptySet(); - }; - } + private Collection transform(Stmt s) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + return switch (ie.getMethodSignature().toString()) { + case sigForName, sigForName2 -> transformClassForName(s); + case sigClassNewInstance -> transformClassNewInstance(s); + case sigConstructorNewInstance -> transformContructorNewInstance(s); + case sigMethodInvoke -> transformMethodInvoke(s); + case sigFieldSet -> transformFieldSet(s); + case sigFieldGet -> transformFieldGet(s); + case sigArrayNewInstance -> transformArrayNewInstance(s); + case sigArrayGet -> transformArrayGet(s); + case sigArraySet -> transformArraySet(s); + default -> Collections.emptySet(); + }; + } - /** - * replace reflection call with appropriate statements - */ - public void buildReflection(SootMethod m) { - if (!PTAScene.v().reflectionBuilt.add(m)) { - return; - } - Map> newUnits = DataFactory.createMap(); - Body body = PTAUtils.getMethodBody(m); - List units = body.getStmts(); - for (final Stmt u : units) { - if (u.containsInvokeExpr()) { - newUnits.put(u, transform(u)); - } - } - Body.BodyBuilder builder = Body.builder(body, Collections.emptySet()); - for (Stmt unit : newUnits.keySet()) { - for (Stmt succ : newUnits.get(unit)) { - builder.addFlow(unit, succ); - } - } - PTAUtils.updateMethodBody(m, builder.build()); + /** replace reflection call with appropriate statements */ + public void buildReflection(SootMethod m) { + if (!PTAScene.v().reflectionBuilt.add(m)) { + return; + } + Map> newUnits = DataFactory.createMap(); + Body body = PTAUtils.getMethodBody(m); + List units = body.getStmts(); + for (final Stmt u : units) { + if (u.containsInvokeExpr()) { + newUnits.put(u, transform(u)); + } + } + Body.BodyBuilder builder = Body.builder(body, Collections.emptySet()); + for (Stmt unit : newUnits.keySet()) { + for (Stmt succ : newUnits.get(unit)) { + builder.addFlow(unit, succ); + } } + PTAUtils.updateMethodBody(m, builder.build()); + } - abstract Collection transformClassForName(Stmt s); + abstract Collection transformClassForName(Stmt s); - abstract Collection transformClassNewInstance(Stmt s); + abstract Collection transformClassNewInstance(Stmt s); - abstract Collection transformContructorNewInstance(Stmt s); + abstract Collection transformContructorNewInstance(Stmt s); - abstract Collection transformMethodInvoke(Stmt s); + abstract Collection transformMethodInvoke(Stmt s); - abstract Collection transformFieldSet(Stmt s); + abstract Collection transformFieldSet(Stmt s); - abstract Collection transformFieldGet(Stmt s); + abstract Collection transformFieldGet(Stmt s); - abstract Collection transformArrayNewInstance(Stmt s); + abstract Collection transformArrayNewInstance(Stmt s); - abstract Collection transformArrayGet(Stmt s); + abstract Collection transformArrayGet(Stmt s); - abstract Collection transformArraySet(Stmt s); + abstract Collection transformArraySet(Stmt s); } diff --git a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java index f96d2e7f2cc..0bc03c306c3 100644 --- a/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java +++ b/sootup.qilin/src/main/java/qilin/core/reflection/TamiflexModel.java @@ -18,6 +18,11 @@ package qilin.core.reflection; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; import qilin.CoreConfig; import qilin.core.PTAScene; import qilin.util.DataFactory; @@ -31,8 +36,8 @@ import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.constant.NullConstant; import sootup.core.jimple.common.expr.AbstractInvokeExpr; -import sootup.core.jimple.common.expr.JNewExpr; import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.expr.JVirtualInvokeExpr; @@ -52,389 +57,416 @@ import sootup.java.core.JavaIdentifierFactory; import sootup.java.core.language.JavaJimple; -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.*; - /** - * This reflection model handles reflection according to the dynamic traces recorded through Tamiflex. + * This reflection model handles reflection according to the dynamic traces recorded through + * Tamiflex. */ public class TamiflexModel extends ReflectionModel { - protected Map>> reflectionMap; + protected Map>> reflectionMap; - public TamiflexModel() { - reflectionMap = DataFactory.createMap(); - parseTamiflexLog(CoreConfig.v().getAppConfig().REFLECTION_LOG, true); - } + public TamiflexModel() { + reflectionMap = DataFactory.createMap(); + parseTamiflexLog(CoreConfig.v().getAppConfig().REFLECTION_LOG, true); + } - @Override - Collection transformClassForName(Stmt s) { - // - // - Collection ret = DataFactory.createSet(); - Map> classForNames = reflectionMap.getOrDefault(ReflectionKind.ClassForName, Collections.emptyMap()); - if (classForNames.containsKey(s)) { - Collection fornames = classForNames.get(s); - for (String clazz : fornames) { - //!TODO potential bug - ClassConstant cc = JavaJimple.getInstance().newClassConstant(clazz); - if (s instanceof JAssignStmt) { - Value lvalue = ((JAssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt<>(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); - } - } + @Override + Collection transformClassForName(Stmt s) { + // + // + Collection ret = DataFactory.createSet(); + Map> classForNames = + reflectionMap.getOrDefault(ReflectionKind.ClassForName, Collections.emptyMap()); + if (classForNames.containsKey(s)) { + Collection fornames = classForNames.get(s); + for (String clazz : fornames) { + // !TODO potential bug + ClassConstant cc = JavaJimple.getInstance().newClassConstant(clazz); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt<>(lvalue, cc, StmtPositionInfo.createNoStmtPositionInfo())); } - return ret; + } } + return ret; + } - @Override - protected Collection transformClassNewInstance(Stmt s) { - // - if (!(s instanceof JAssignStmt)) { - return Collections.emptySet(); - } - Value lvalue = ((JAssignStmt) s).getLeftOp(); - Collection ret = DataFactory.createSet(); - Map> classNewInstances = reflectionMap.getOrDefault(ReflectionKind.ClassNewInstance, Collections.emptyMap()); - if (classNewInstances.containsKey(s)) { - Collection classNames = classNewInstances.get(s); - for (String clsName : classNames) { - SootClass cls = PTAScene.v().getSootClass(clsName); - MethodSubSignature initSubSig = JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); - Optional omthd = cls.getMethod(initSubSig); - if (omthd.isPresent()) { - JNewExpr newExpr = new JNewExpr(cls.getType()); - ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); - SootMethod constructor = omthd.get(); - ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), Collections.emptyList()), StmtPositionInfo.createNoStmtPositionInfo())); - } - } + @Override + protected Collection transformClassNewInstance(Stmt s) { + // + if (!(s instanceof JAssignStmt)) { + return Collections.emptySet(); + } + Value lvalue = ((JAssignStmt) s).getLeftOp(); + Collection ret = DataFactory.createSet(); + Map> classNewInstances = + reflectionMap.getOrDefault(ReflectionKind.ClassNewInstance, Collections.emptyMap()); + if (classNewInstances.containsKey(s)) { + Collection classNames = classNewInstances.get(s); + for (String clsName : classNames) { + SootClass cls = PTAScene.v().getSootClass(clsName); + MethodSubSignature initSubSig = + JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); + Optional omthd = cls.getMethod(initSubSig); + if (omthd.isPresent()) { + JNewExpr newExpr = new JNewExpr(cls.getType()); + ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + SootMethod constructor = omthd.get(); + ret.add( + new JInvokeStmt( + new JSpecialInvokeExpr( + (Local) lvalue, constructor.getSignature(), Collections.emptyList()), + StmtPositionInfo.createNoStmtPositionInfo())); } - return ret; + } } + return ret; + } - @Override - protected Collection transformContructorNewInstance(Stmt s) { - // - if (!(s instanceof JAssignStmt)) { - return Collections.emptySet(); - } - Value lvalue = ((JAssignStmt) s).getLeftOp(); - Collection ret = DataFactory.createSet(); - Map> constructorNewInstances = reflectionMap.getOrDefault(ReflectionKind.ConstructorNewInstance, Collections.emptyMap()); - if (constructorNewInstances.containsKey(s)) { - Collection constructorSignatures = constructorNewInstances.get(s); - AbstractInvokeExpr iie = s.getInvokeExpr(); - Value args = iie.getArg(0); - JArrayRef arrayRef = JavaJimple.getInstance().newArrayRef((Local) args, IntConstant.getInstance(0)); - Immediate arg = Jimple.newLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); - ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); - for (String constructorSignature : constructorSignatures) { - SootMethod constructor = PTAScene.v().getMethod(constructorSignature); - JNewExpr newExpr = new JNewExpr(constructor.getDeclaringClassType()); - ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); - int argCount = constructor.getParameterCount(); - List mArgs = new ArrayList<>(argCount); - for (int i = 0; i < argCount; i++) { - mArgs.add(arg); - } - ret.add(new JInvokeStmt(new JSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), mArgs), StmtPositionInfo.createNoStmtPositionInfo())); - } + @Override + protected Collection transformContructorNewInstance(Stmt s) { + // + if (!(s instanceof JAssignStmt)) { + return Collections.emptySet(); + } + Value lvalue = ((JAssignStmt) s).getLeftOp(); + Collection ret = DataFactory.createSet(); + Map> constructorNewInstances = + reflectionMap.getOrDefault(ReflectionKind.ConstructorNewInstance, Collections.emptyMap()); + if (constructorNewInstances.containsKey(s)) { + Collection constructorSignatures = constructorNewInstances.get(s); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value args = iie.getArg(0); + JArrayRef arrayRef = + JavaJimple.getInstance().newArrayRef((Local) args, IntConstant.getInstance(0)); + Immediate arg = + Jimple.newLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); + ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + for (String constructorSignature : constructorSignatures) { + SootMethod constructor = PTAScene.v().getMethod(constructorSignature); + JNewExpr newExpr = new JNewExpr(constructor.getDeclaringClassType()); + ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + int argCount = constructor.getParameterCount(); + List mArgs = new ArrayList<>(argCount); + for (int i = 0; i < argCount; i++) { + mArgs.add(arg); } - return ret; + ret.add( + new JInvokeStmt( + new JSpecialInvokeExpr((Local) lvalue, constructor.getSignature(), mArgs), + StmtPositionInfo.createNoStmtPositionInfo())); + } } + return ret; + } - @Override - protected Collection transformMethodInvoke(Stmt s) { - // - Collection ret = DataFactory.createSet(); - Map> methodInvokes = reflectionMap.getOrDefault(ReflectionKind.MethodInvoke, Collections.emptyMap()); - if (methodInvokes.containsKey(s)) { - Collection methodSignatures = methodInvokes.get(s); - AbstractInvokeExpr iie = s.getInvokeExpr(); - Value base = iie.getArg(0); - Value args = iie.getArg(1); - Immediate arg = null; - if (args.getType() instanceof ArrayType) { - JArrayRef arrayRef = JavaJimple.getInstance().newArrayRef((Local) args, IntConstant.getInstance(0)); - arg = Jimple.newLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); - ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); - } + @Override + protected Collection transformMethodInvoke(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> methodInvokes = + reflectionMap.getOrDefault(ReflectionKind.MethodInvoke, Collections.emptyMap()); + if (methodInvokes.containsKey(s)) { + Collection methodSignatures = methodInvokes.get(s); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + Value args = iie.getArg(1); + Immediate arg = null; + if (args.getType() instanceof ArrayType) { + JArrayRef arrayRef = + JavaJimple.getInstance().newArrayRef((Local) args, IntConstant.getInstance(0)); + arg = + Jimple.newLocal("intermediate/" + arrayRef, PTAUtils.getClassType("java.lang.Object")); + ret.add(new JAssignStmt<>(arg, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + } - for (String methodSignature : methodSignatures) { - SootMethod method = PTAScene.v().getMethod(methodSignature); - int argCount = method.getParameterCount(); - List mArgs = new ArrayList<>(argCount); - for (int i = 0; i < argCount; i++) { - mArgs.add(arg); - } - AbstractInvokeExpr ie; - if (method.isStatic()) { - assert base instanceof NullConstant; - ie = new JStaticInvokeExpr(method.getSignature(), mArgs); - } else { - assert !(base instanceof NullConstant); - ie = new JVirtualInvokeExpr((Local) base, method.getSignature(), mArgs); - } - if (s instanceof JAssignStmt) { - Value lvalue = ((JAssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt<>(lvalue, ie, StmtPositionInfo.createNoStmtPositionInfo())); - } else { - ret.add(new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo())); - } - } + for (String methodSignature : methodSignatures) { + SootMethod method = PTAScene.v().getMethod(methodSignature); + int argCount = method.getParameterCount(); + List mArgs = new ArrayList<>(argCount); + for (int i = 0; i < argCount; i++) { + mArgs.add(arg); } - return ret; - } - - @Override - protected Collection transformFieldSet(Stmt s) { - // - Collection ret = DataFactory.createSet(); - Map> fieldSets = reflectionMap.getOrDefault(ReflectionKind.FieldSet, Collections.emptyMap()); - if (fieldSets.containsKey(s)) { - Collection fieldSignatures = fieldSets.get(s); - AbstractInvokeExpr iie = s.getInvokeExpr(); - Value base = iie.getArg(0); - Value rValue = iie.getArg(1); - for (String fieldSignature : fieldSignatures) { - FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); - SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); - JFieldRef fieldRef; - if (field.isStatic()) { - assert base instanceof NullConstant; - fieldRef = Jimple.newStaticFieldRef(field.getSignature()); - } else { - assert !(base instanceof NullConstant); - fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); - } - Stmt stmt = new JAssignStmt<>(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); - ret.add(stmt); - } + AbstractInvokeExpr ie; + if (method.isStatic()) { + assert base instanceof NullConstant; + ie = new JStaticInvokeExpr(method.getSignature(), mArgs); + } else { + assert !(base instanceof NullConstant); + ie = new JVirtualInvokeExpr((Local) base, method.getSignature(), mArgs); } - return ret; - } - - @Override - protected Collection transformFieldGet(Stmt s) { - // - Collection ret = DataFactory.createSet(); - Map> fieldGets = reflectionMap.getOrDefault(ReflectionKind.FieldGet, Collections.emptyMap()); - if (fieldGets.containsKey(s) && s instanceof JAssignStmt) { - Collection fieldSignatures = fieldGets.get(s); - Value lvalue = ((JAssignStmt) s).getLeftOp(); - AbstractInvokeExpr iie = s.getInvokeExpr(); - Value base = iie.getArg(0); - for (String fieldSignature : fieldSignatures) { - FieldSignature fieldSig = JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); - SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); - JFieldRef fieldRef; - if (field.isStatic()) { - assert base instanceof NullConstant; - fieldRef = Jimple.newStaticFieldRef(field.getSignature()); - } else { - assert !(base instanceof NullConstant); - fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); - } - if (fieldRef.getType() instanceof ReferenceType) { - Stmt stmt = new JAssignStmt<>(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); - ret.add(stmt); - } - } + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt<>(lvalue, ie, StmtPositionInfo.createNoStmtPositionInfo())); + } else { + ret.add(new JInvokeStmt(ie, StmtPositionInfo.createNoStmtPositionInfo())); } - return ret; + } } + return ret; + } - @Override - protected Collection transformArrayNewInstance(Stmt s) { - // - Collection ret = DataFactory.createSet(); - Map> mappedToArrayTypes = reflectionMap.getOrDefault(ReflectionKind.ArrayNewInstance, Collections.emptyMap()); - Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); - for (String arrayType : arrayTypes) { - ArrayType at = (ArrayType) JavaIdentifierFactory.getInstance().getType(arrayType); - JNewArrayExpr newExpr = JavaJimple.getInstance().newNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1)); - if (s instanceof JAssignStmt) { - Value lvalue = ((JAssignStmt) s).getLeftOp(); - ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); - } + @Override + protected Collection transformFieldSet(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> fieldSets = + reflectionMap.getOrDefault(ReflectionKind.FieldSet, Collections.emptyMap()); + if (fieldSets.containsKey(s)) { + Collection fieldSignatures = fieldSets.get(s); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + Value rValue = iie.getArg(1); + for (String fieldSignature : fieldSignatures) { + FieldSignature fieldSig = + JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); + JFieldRef fieldRef; + if (field.isStatic()) { + assert base instanceof NullConstant; + fieldRef = Jimple.newStaticFieldRef(field.getSignature()); + } else { + assert !(base instanceof NullConstant); + fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); } - return ret; + Stmt stmt = + new JAssignStmt<>(fieldRef, rValue, StmtPositionInfo.createNoStmtPositionInfo()); + ret.add(stmt); + } } + return ret; + } - @Override - Collection transformArrayGet(Stmt s) { - Collection ret = DataFactory.createSet(); - AbstractInvokeExpr iie = s.getInvokeExpr(); - Value base = iie.getArg(0); - if (s instanceof JAssignStmt) { - Value lvalue = ((JAssignStmt) s).getLeftOp(); - Value arrayRef = null; - if (base.getType() instanceof ArrayType) { - arrayRef = JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); - } else if (base.getType() == PTAUtils.getClassType("java.lang.Object")) { - Local local = Jimple.newLocal("intermediate/" + base, new ArrayType(PTAUtils.getClassType("java.lang.Object"), 1)); - ret.add(new JAssignStmt<>(local, base, StmtPositionInfo.createNoStmtPositionInfo())); - arrayRef = JavaJimple.getInstance().newArrayRef(local, IntConstant.getInstance(0)); - } - if (arrayRef != null) { - ret.add(new JAssignStmt<>(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); - } + @Override + protected Collection transformFieldGet(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> fieldGets = + reflectionMap.getOrDefault(ReflectionKind.FieldGet, Collections.emptyMap()); + if (fieldGets.containsKey(s) && s instanceof JAssignStmt) { + Collection fieldSignatures = fieldGets.get(s); + Value lvalue = ((JAssignStmt) s).getLeftOp(); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + for (String fieldSignature : fieldSignatures) { + FieldSignature fieldSig = + JavaIdentifierFactory.getInstance().parseFieldSignature(fieldSignature); + SootField field = (SootField) PTAScene.v().getView().getField(fieldSig).get(); + JFieldRef fieldRef; + if (field.isStatic()) { + assert base instanceof NullConstant; + fieldRef = Jimple.newStaticFieldRef(field.getSignature()); + } else { + assert !(base instanceof NullConstant); + fieldRef = Jimple.newInstanceFieldRef((Local) base, field.getSignature()); } - return ret; + if (fieldRef.getType() instanceof ReferenceType) { + Stmt stmt = + new JAssignStmt<>(lvalue, fieldRef, StmtPositionInfo.createNoStmtPositionInfo()); + ret.add(stmt); + } + } } + return ret; + } - @Override - Collection transformArraySet(Stmt s) { - Collection ret = DataFactory.createSet(); - AbstractInvokeExpr iie = s.getInvokeExpr(); - Value base = iie.getArg(0); - if (base.getType() instanceof ArrayType) { - Value from = iie.getArg(2); - Value arrayRef = JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); - ret.add(new JAssignStmt<>(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); - } - return ret; + @Override + protected Collection transformArrayNewInstance(Stmt s) { + // + Collection ret = DataFactory.createSet(); + Map> mappedToArrayTypes = + reflectionMap.getOrDefault(ReflectionKind.ArrayNewInstance, Collections.emptyMap()); + Collection arrayTypes = mappedToArrayTypes.getOrDefault(s, Collections.emptySet()); + for (String arrayType : arrayTypes) { + ArrayType at = (ArrayType) JavaIdentifierFactory.getInstance().getType(arrayType); + JNewArrayExpr newExpr = + JavaJimple.getInstance() + .newNewArrayExpr(at.getArrayElementType(), IntConstant.getInstance(1)); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + ret.add(new JAssignStmt<>(lvalue, newExpr, StmtPositionInfo.createNoStmtPositionInfo())); + } } + return ret; + } + @Override + Collection transformArrayGet(Stmt s) { + Collection ret = DataFactory.createSet(); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + if (s instanceof JAssignStmt) { + Value lvalue = ((JAssignStmt) s).getLeftOp(); + Value arrayRef = null; + if (base.getType() instanceof ArrayType) { + arrayRef = JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); + } else if (base.getType() == PTAUtils.getClassType("java.lang.Object")) { + Local local = + Jimple.newLocal( + "intermediate/" + base, + new ArrayType(PTAUtils.getClassType("java.lang.Object"), 1)); + ret.add(new JAssignStmt<>(local, base, StmtPositionInfo.createNoStmtPositionInfo())); + arrayRef = JavaJimple.getInstance().newArrayRef(local, IntConstant.getInstance(0)); + } + if (arrayRef != null) { + ret.add(new JAssignStmt<>(lvalue, arrayRef, StmtPositionInfo.createNoStmtPositionInfo())); + } + } + return ret; + } - /* - * parse reflection log generated by Tamiflex. - * */ - private void parseTamiflexLog(String logFile, boolean verbose) { - try { - BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(logFile))); - String line; - while ((line = reader.readLine()) != null) { - String[] portions = line.split(";", -1); - if (portions.length < 4) { - if (verbose) { - System.out.println("Warning: illegal tamiflex log: " + line); - } - continue; - } - ReflectionKind kind = ReflectionKind.parse(portions[0]); - String mappedTarget = portions[1]; - String inClzDotMthdStr = portions[2]; - int lineNumber = portions[3].length() == 0 ? -1 : Integer.parseInt(portions[3]); - // sanity check. - if (kind == null) { - if (verbose) { - System.out.println("Warning: illegal tamiflex reflection kind: " + portions[0]); - } - continue; - } - switch (kind) { - case ClassForName: - break; - case ClassNewInstance: - if (!PTAScene.v().containsClass(mappedTarget)) { - if (verbose) { - System.out.println("Warning: Unknown mapped class for signature: " + mappedTarget); - } - continue; - } - break; - case ConstructorNewInstance: - case MethodInvoke: - if (!PTAScene.v().containsMethod(mappedTarget)) { - if (verbose) { - System.out.println("Warning: Unknown mapped method for signature: " + mappedTarget); - } - continue; - } - break; - case FieldSet: - case FieldGet: - if (!PTAScene.v().containsField(mappedTarget)) { - if (verbose) { - System.out.println("Warning: Unknown mapped field for signature: " + mappedTarget); - } - continue; - } - break; - case ArrayNewInstance: - break; - default: - if (verbose) { - System.out.println("Warning: Unsupported reflection kind: " + kind); - } - break; - } - Collection possibleSourceStmts = inferSourceStmt(inClzDotMthdStr, kind, lineNumber); - for (Stmt stmt : possibleSourceStmts) { - reflectionMap.computeIfAbsent(kind, m -> DataFactory.createMap()). - computeIfAbsent(stmt, k -> DataFactory.createSet()).add(mappedTarget); - } - } - reader.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } + @Override + Collection transformArraySet(Stmt s) { + Collection ret = DataFactory.createSet(); + AbstractInvokeExpr iie = s.getInvokeExpr(); + Value base = iie.getArg(0); + if (base.getType() instanceof ArrayType) { + Value from = iie.getArg(2); + Value arrayRef = + JavaJimple.getInstance().newArrayRef((Local) base, IntConstant.getInstance(0)); + ret.add(new JAssignStmt<>(arrayRef, from, StmtPositionInfo.createNoStmtPositionInfo())); } + return ret; + } - private Collection inferSourceMethod(String inClzDotMthd) { - String inClassStr = inClzDotMthd.substring(0, inClzDotMthd.lastIndexOf(".")); - String inMethodStr = inClzDotMthd.substring(inClzDotMthd.lastIndexOf(".") + 1); - if (!PTAScene.v().containsClass(inClassStr)) { - System.out.println("Warning: unknown class \"" + inClassStr + "\" is referenced."); + /* + * parse reflection log generated by Tamiflex. + * */ + private void parseTamiflexLog(String logFile, boolean verbose) { + try { + BufferedReader reader = + new BufferedReader(new InputStreamReader(new FileInputStream(logFile))); + String line; + while ((line = reader.readLine()) != null) { + String[] portions = line.split(";", -1); + if (portions.length < 4) { + if (verbose) { + System.out.println("Warning: illegal tamiflex log: " + line); + } + continue; } - SootClass sootClass = PTAScene.v().getSootClass(inClassStr); - Set ret = DataFactory.createSet(); - Set declMethods = sootClass.getMethods(); - for (SootMethod m : declMethods) { - if (m.isConcrete() && m.getName().equals(inMethodStr)) { - ret.add(m); - } + ReflectionKind kind = ReflectionKind.parse(portions[0]); + String mappedTarget = portions[1]; + String inClzDotMthdStr = portions[2]; + int lineNumber = portions[3].length() == 0 ? -1 : Integer.parseInt(portions[3]); + // sanity check. + if (kind == null) { + if (verbose) { + System.out.println("Warning: illegal tamiflex reflection kind: " + portions[0]); + } + continue; } - return ret; - } - - private Collection inferSourceStmt(String inClzDotMthd, ReflectionKind kind, int lineNumber) { - Set ret = DataFactory.createSet(); - Set potential = DataFactory.createSet(); - Collection sourceMethods = inferSourceMethod(inClzDotMthd); - for (SootMethod sm : sourceMethods) { - Body body = PTAUtils.getMethodBody(sm); - for (Stmt stmt : body.getStmts()) { - if (stmt.containsInvokeExpr()) { - String methodSig = stmt.getInvokeExpr().getMethodSignature().toString(); - if (matchReflectionKind(kind, methodSig)) { - potential.add(stmt); - } - } + switch (kind) { + case ClassForName: + break; + case ClassNewInstance: + if (!PTAScene.v().containsClass(mappedTarget)) { + if (verbose) { + System.out.println("Warning: Unknown mapped class for signature: " + mappedTarget); + } + continue; } - } - for (Stmt stmt : potential) { - int firstLine = stmt.getPositionInfo().getStmtPosition().getFirstLine(); - int lastLine = stmt.getPositionInfo().getStmtPosition().getLastLine(); - // !TODO potential bug here - if (lineNumber < 0 || firstLine <= lineNumber && lineNumber <= lastLine) { - ret.add(stmt); + break; + case ConstructorNewInstance: + case MethodInvoke: + if (!PTAScene.v().containsMethod(mappedTarget)) { + if (verbose) { + System.out.println("Warning: Unknown mapped method for signature: " + mappedTarget); + } + continue; + } + break; + case FieldSet: + case FieldGet: + if (!PTAScene.v().containsField(mappedTarget)) { + if (verbose) { + System.out.println("Warning: Unknown mapped field for signature: " + mappedTarget); + } + continue; } + break; + case ArrayNewInstance: + break; + default: + if (verbose) { + System.out.println("Warning: Unsupported reflection kind: " + kind); + } + break; } - if (ret.size() == 0 && potential.size() > 0) { - System.out.print("Warning: Mismatch between statement and reflection log entry - "); - System.out.println(kind + ";" + inClzDotMthd + ";" + lineNumber + ";"); - return potential; - } else { - return ret; + Collection possibleSourceStmts = inferSourceStmt(inClzDotMthdStr, kind, lineNumber); + for (Stmt stmt : possibleSourceStmts) { + reflectionMap + .computeIfAbsent(kind, m -> DataFactory.createMap()) + .computeIfAbsent(stmt, k -> DataFactory.createSet()) + .add(mappedTarget); } + } + reader.close(); + } catch (IOException e) { + throw new RuntimeException(e); } + } - private boolean matchReflectionKind(ReflectionKind kind, String methodSig) { - return switch (kind) { - case ClassForName -> methodSig.equals(sigForName) || methodSig.equals(sigForName2); - case ClassNewInstance -> methodSig.equals(sigClassNewInstance); - case ConstructorNewInstance -> methodSig.equals(sigConstructorNewInstance); - case MethodInvoke -> methodSig.equals(sigMethodInvoke); - case FieldSet -> methodSig.equals(sigFieldSet); - case FieldGet -> methodSig.equals(sigFieldGet); - case ArrayNewInstance -> methodSig.equals(sigArrayNewInstance); - default -> false; - }; + private Collection inferSourceMethod(String inClzDotMthd) { + String inClassStr = inClzDotMthd.substring(0, inClzDotMthd.lastIndexOf(".")); + String inMethodStr = inClzDotMthd.substring(inClzDotMthd.lastIndexOf(".") + 1); + if (!PTAScene.v().containsClass(inClassStr)) { + System.out.println("Warning: unknown class \"" + inClassStr + "\" is referenced."); } + SootClass sootClass = PTAScene.v().getSootClass(inClassStr); + Set ret = DataFactory.createSet(); + Set declMethods = sootClass.getMethods(); + for (SootMethod m : declMethods) { + if (m.isConcrete() && m.getName().equals(inMethodStr)) { + ret.add(m); + } + } + return ret; + } + + private Collection inferSourceStmt( + String inClzDotMthd, ReflectionKind kind, int lineNumber) { + Set ret = DataFactory.createSet(); + Set potential = DataFactory.createSet(); + Collection sourceMethods = inferSourceMethod(inClzDotMthd); + for (SootMethod sm : sourceMethods) { + Body body = PTAUtils.getMethodBody(sm); + for (Stmt stmt : body.getStmts()) { + if (stmt.containsInvokeExpr()) { + String methodSig = stmt.getInvokeExpr().getMethodSignature().toString(); + if (matchReflectionKind(kind, methodSig)) { + potential.add(stmt); + } + } + } + } + for (Stmt stmt : potential) { + int firstLine = stmt.getPositionInfo().getStmtPosition().getFirstLine(); + int lastLine = stmt.getPositionInfo().getStmtPosition().getLastLine(); + // !TODO potential bug here + if (lineNumber < 0 || firstLine <= lineNumber && lineNumber <= lastLine) { + ret.add(stmt); + } + } + if (ret.size() == 0 && potential.size() > 0) { + System.out.print("Warning: Mismatch between statement and reflection log entry - "); + System.out.println(kind + ";" + inClzDotMthd + ";" + lineNumber + ";"); + return potential; + } else { + return ret; + } + } + + private boolean matchReflectionKind(ReflectionKind kind, String methodSig) { + return switch (kind) { + case ClassForName -> methodSig.equals(sigForName) || methodSig.equals(sigForName2); + case ClassNewInstance -> methodSig.equals(sigClassNewInstance); + case ConstructorNewInstance -> methodSig.equals(sigConstructorNewInstance); + case MethodInvoke -> methodSig.equals(sigMethodInvoke); + case FieldSet -> methodSig.equals(sigFieldSet); + case FieldGet -> methodSig.equals(sigFieldGet); + case ArrayNewInstance -> methodSig.equals(sigArrayNewInstance); + default -> false; + }; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java index de6a888afc2..303d4f8f58c 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/DoublePointsToSet.java @@ -21,135 +21,117 @@ import java.util.Iterator; /** - * Implementation of points-to set that holds two sets: one for new elements that have not yet been propagated, and the other - * for elements that have already been propagated. + * Implementation of points-to set that holds two sets: one for new elements that have not yet been + * propagated, and the other for elements that have already been propagated. * * @author Ondrej Lhotak */ public class DoublePointsToSet extends PointsToSetInternal { - protected HybridPointsToSet newSet; - protected HybridPointsToSet oldSet; - - public DoublePointsToSet() { - newSet = new HybridPointsToSet(); - oldSet = new HybridPointsToSet(); - } - - /** - * Returns true if this set contains no run-time objects. - */ - @Override - public boolean isEmpty() { - return oldSet.isEmpty() && newSet.isEmpty(); - } - - /** - * Returns true if this set shares some objects with other. - */ - public boolean hasNonEmptyIntersection(PointsToSetInternal other) { - return oldSet.hasNonEmptyIntersection(other) || newSet.hasNonEmptyIntersection(other); - } + protected HybridPointsToSet newSet; + protected HybridPointsToSet oldSet; + + public DoublePointsToSet() { + newSet = new HybridPointsToSet(); + oldSet = new HybridPointsToSet(); + } + + /** Returns true if this set contains no run-time objects. */ + @Override + public boolean isEmpty() { + return oldSet.isEmpty() && newSet.isEmpty(); + } + + /** Returns true if this set shares some objects with other. */ + public boolean hasNonEmptyIntersection(PointsToSetInternal other) { + return oldSet.hasNonEmptyIntersection(other) || newSet.hasNonEmptyIntersection(other); + } + + @Override + public int size() { + return oldSet.size() + newSet.size(); + } + + private class DoublePTSIterator implements Iterator { + private final Iterator oldIt = oldSet.iterator(); + private final Iterator newIt = newSet.iterator(); @Override - public int size() { - return oldSet.size() + newSet.size(); + public boolean hasNext() { + return oldIt.hasNext() || newIt.hasNext(); } - private class DoublePTSIterator implements Iterator { - private final Iterator oldIt = oldSet.iterator(); - private final Iterator newIt = newSet.iterator(); - - @Override - public boolean hasNext() { - return oldIt.hasNext() || newIt.hasNext(); - } - - @Override - public Integer next() { - if (oldIt.hasNext()) { - return oldIt.next(); - } else { - return newIt.next(); - } - } - } - - public Iterator iterator() { - return new DoublePTSIterator(); - } - - /* - * Empty this set. - * */ @Override - public void clear() { - oldSet.clear(); - newSet.clear(); + public Integer next() { + if (oldIt.hasNext()) { + return oldIt.next(); + } else { + return newIt.next(); + } } - - /** - * Adds contents of other into this set, returns true if this set changed. - */ - public boolean addAll(PointsToSetInternal other, PointsToSetInternal exclude) { - if (exclude != null) { - throw new RuntimeException("exclude set must be null."); - } - return newSet.addAll(other, oldSet); + } + + public Iterator iterator() { + return new DoublePTSIterator(); + } + + /* + * Empty this set. + * */ + @Override + public void clear() { + oldSet.clear(); + newSet.clear(); + } + + /** Adds contents of other into this set, returns true if this set changed. */ + public boolean addAll(PointsToSetInternal other, PointsToSetInternal exclude) { + if (exclude != null) { + throw new RuntimeException("exclude set must be null."); } - - /** - * Calls v's visit method on all nodes in this set. - */ - @Override - public boolean forall(P2SetVisitor v) { - oldSet.forall(v); - newSet.forall(v); - return v.getReturnValue(); - } - - /** - * Adds n to this set, returns true if idx was not already in this set. - */ - public boolean add(int idx) { - if (oldSet.contains(idx)) { - return false; - } - return newSet.add(idx); - } - - /** - * Returns set of nodes already present before last call to flushNew. - */ - public HybridPointsToSet getOldSet() { - return oldSet; - } - - /** - * Returns set of newly-added nodes since last call to flushNew. - */ - public HybridPointsToSet getNewSet() { - return newSet; - } - - public HybridPointsToSet getNewSetCopy() { - HybridPointsToSet newCopy = new HybridPointsToSet(); - newCopy.addAll(newSet, null); - return newCopy; - } - - /** - * Sets all newly-added nodes to old nodes. - */ - public void flushNew() { - oldSet.addAll(newSet, null); - newSet = new HybridPointsToSet(); - } - - /** - * Returns true iff the set contains idx. - */ - @Override - public boolean contains(int idx) { - return oldSet.contains(idx) || newSet.contains(idx); + return newSet.addAll(other, oldSet); + } + + /** Calls v's visit method on all nodes in this set. */ + @Override + public boolean forall(P2SetVisitor v) { + oldSet.forall(v); + newSet.forall(v); + return v.getReturnValue(); + } + + /** Adds n to this set, returns true if idx was not already in this set. */ + public boolean add(int idx) { + if (oldSet.contains(idx)) { + return false; } + return newSet.add(idx); + } + + /** Returns set of nodes already present before last call to flushNew. */ + public HybridPointsToSet getOldSet() { + return oldSet; + } + + /** Returns set of newly-added nodes since last call to flushNew. */ + public HybridPointsToSet getNewSet() { + return newSet; + } + + public HybridPointsToSet getNewSetCopy() { + HybridPointsToSet newCopy = new HybridPointsToSet(); + newCopy.addAll(newSet, null); + return newCopy; + } + + /** Sets all newly-added nodes to old nodes. */ + public void flushNew() { + oldSet.addAll(newSet, null); + newSet = new HybridPointsToSet(); + } + + /** Returns true iff the set contains idx. */ + @Override + public boolean contains(int idx) { + return oldSet.contains(idx) || newSet.contains(idx); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java index d38f8c7de83..aadcbe6a231 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/HybridPointsToSet.java @@ -18,181 +18,170 @@ package qilin.core.sets; -import soot.util.BitSetIterator; -import soot.util.BitVector; - import java.util.Arrays; import java.util.Iterator; +import soot.util.BitSetIterator; +import soot.util.BitVector; /** - * Hybrid implementation of points-to set, which uses an explicit array for small sets, and a bit vector for large sets. + * Hybrid implementation of points-to set, which uses an explicit array for small sets, and a bit + * vector for large sets. * * @author Ondrej Lhotak */ public final class HybridPointsToSet extends PointsToSetInternal { - private static HybridPointsToSet emptySet = null; + private static HybridPointsToSet emptySet = null; - public static HybridPointsToSet getEmptySet() { - if (emptySet == null) { - emptySet = new HybridPointsToSet(); - } - return emptySet; + public static HybridPointsToSet getEmptySet() { + if (emptySet == null) { + emptySet = new HybridPointsToSet(); } - - private final int[] nodeIdxs = new int[16]; - private BitVector bits = null; - private int size = 0; - - private boolean empty = true; - - /** - * Returns true if this set contains no run-time objects. - */ - @Override - public boolean isEmpty() { - return empty; + return emptySet; + } + + private final int[] nodeIdxs = new int[16]; + private BitVector bits = null; + private int size = 0; + + private boolean empty = true; + + /** Returns true if this set contains no run-time objects. */ + @Override + public boolean isEmpty() { + return empty; + } + + @Override + public void clear() { + Arrays.fill(nodeIdxs, 0); + bits = null; + empty = true; + size = 0; + } + + private boolean nativeAddAll(HybridPointsToSet other, PointsToSetInternal exclude) { + boolean ret = false; + for (Iterator it = other.iterator(); it.hasNext(); ) { + int idx = it.next(); + if (exclude == null || !exclude.contains(idx)) { + ret |= add(idx); + } } + return ret; + } - @Override - public void clear() { - Arrays.fill(nodeIdxs, 0); - bits = null; - empty = true; - size = 0; + /** Adds contents of other into this set, returns true if this set changed. */ + public boolean addAll(final PointsToSetInternal other, final PointsToSetInternal exclude) { + if (other == null) { + return false; } - - private boolean nativeAddAll(HybridPointsToSet other, PointsToSetInternal exclude) { - boolean ret = false; - for (Iterator it = other.iterator(); it.hasNext(); ) { - int idx = it.next(); - if (exclude == null || !exclude.contains(idx)) { - ret |= add(idx); - } - } - return ret; - } - - /** - * Adds contents of other into this set, returns true if this set changed. - */ - public boolean addAll(final PointsToSetInternal other, final PointsToSetInternal exclude) { - if (other == null) { - return false; - } - if (other instanceof DoublePointsToSet dpts) { - return nativeAddAll(dpts.getNewSet(), exclude) | nativeAddAll(dpts.getOldSet(), exclude); - } - return nativeAddAll((HybridPointsToSet) other, exclude); + if (other instanceof DoublePointsToSet dpts) { + return nativeAddAll(dpts.getNewSet(), exclude) | nativeAddAll(dpts.getOldSet(), exclude); } - - private class HybridPTSIterator implements Iterator { - private BitSetIterator it; - private int idx; - - public HybridPTSIterator() { - if (bits == null) { - idx = 0; - } else { - it = bits.iterator(); - } - } - - @Override - public boolean hasNext() { - if (bits == null) { - return idx < nodeIdxs.length && nodeIdxs[idx] != 0; - } else { - return it.hasNext(); - } - } - - @Override - public Integer next() { - if (bits == null) { - return nodeIdxs[idx++]; - } else { - return it.next(); - } - } + return nativeAddAll((HybridPointsToSet) other, exclude); + } + + private class HybridPTSIterator implements Iterator { + private BitSetIterator it; + private int idx; + + public HybridPTSIterator() { + if (bits == null) { + idx = 0; + } else { + it = bits.iterator(); + } } @Override - public Iterator iterator() { - return new HybridPTSIterator(); + public boolean hasNext() { + if (bits == null) { + return idx < nodeIdxs.length && nodeIdxs[idx] != 0; + } else { + return it.hasNext(); + } } @Override - public int size() { - return size; + public Integer next() { + if (bits == null) { + return nodeIdxs[idx++]; + } else { + return it.next(); + } } - - /** - * Calls v's visit method on all nodes in this set. - */ - public boolean forall(P2SetVisitor v) { - if (bits == null) { - for (int nodeIdx : nodeIdxs) { - if (nodeIdx == 0) { - return v.getReturnValue(); - } - v.visit(nodeIdx); - } - } else { - for (BitSetIterator it = bits.iterator(); it.hasNext(); ) { - v.visit(it.next()); - } + } + + @Override + public Iterator iterator() { + return new HybridPTSIterator(); + } + + @Override + public int size() { + return size; + } + + /** Calls v's visit method on all nodes in this set. */ + public boolean forall(P2SetVisitor v) { + if (bits == null) { + for (int nodeIdx : nodeIdxs) { + if (nodeIdx == 0) { + return v.getReturnValue(); } - return v.getReturnValue(); + v.visit(nodeIdx); + } + } else { + for (BitSetIterator it = bits.iterator(); it.hasNext(); ) { + v.visit(it.next()); + } } - - /** - * Returns true iff the set contains node idx. - */ - public boolean contains(int idx) { - if (bits == null) { - for (int nodeIdx : nodeIdxs) { - if (idx == nodeIdx) { - return true; - } - if (nodeIdx == 0) { - break; - } - } - return false; - } else { - return bits.get(idx); + return v.getReturnValue(); + } + + /** Returns true iff the set contains node idx. */ + public boolean contains(int idx) { + if (bits == null) { + for (int nodeIdx : nodeIdxs) { + if (idx == nodeIdx) { + return true; + } + if (nodeIdx == 0) { + break; } + } + return false; + } else { + return bits.get(idx); } - - /** - * Adds idx to this set, returns true if idx was not already in this set. - */ - public boolean add(int idx) { - if (bits == null) { - for (int i = 0; i < nodeIdxs.length; i++) { - if (nodeIdxs[i] == 0) { - empty = false; - nodeIdxs[i] = idx; - ++size; - return true; - } else if (nodeIdxs[i] == idx) { - return false; - } - } - // convert to Bits - bits = new BitVector(); - for (int nodeIdx : nodeIdxs) { - if (nodeIdx != 0) { - bits.set(nodeIdx); - } - } + } + + /** Adds idx to this set, returns true if idx was not already in this set. */ + public boolean add(int idx) { + if (bits == null) { + for (int i = 0; i < nodeIdxs.length; i++) { + if (nodeIdxs[i] == 0) { + empty = false; + nodeIdxs[i] = idx; + ++size; + return true; + } else if (nodeIdxs[i] == idx) { + return false; } - boolean ret = bits.set(idx); - if (ret) { - ++size; - empty = false; + } + // convert to Bits + bits = new BitVector(); + for (int nodeIdx : nodeIdxs) { + if (nodeIdx != 0) { + bits.set(nodeIdx); } - return ret; + } } - + boolean ret = bits.set(idx); + if (ret) { + ++size; + empty = false; + } + return ret; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java b/sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java index 624e82cd7b8..46b3fff8f45 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/P2SetVisitor.java @@ -27,22 +27,21 @@ * @author Ondrej Lhotak */ public abstract class P2SetVisitor { - protected boolean returnValue = false; - protected final PTA pta; + protected boolean returnValue = false; + protected final PTA pta; - protected P2SetVisitor(PTA pta) { - this.pta = pta; - } + protected P2SetVisitor(PTA pta) { + this.pta = pta; + } + protected abstract void visit(Node n); - protected abstract void visit(Node n); + public void visit(long idx) { + Node node = pta.getPag().getAllocNodeNumberer().get(idx); + visit(node); + } - public void visit(long idx) { - Node node = pta.getPag().getAllocNodeNumberer().get(idx); - visit(node); - } - - public boolean getReturnValue() { - return returnValue; - } + public boolean getReturnValue() { + return returnValue; + } } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java index e70092569d4..df0ee5b0418 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSet.java @@ -18,13 +18,12 @@ package qilin.core.sets; -import qilin.core.pag.AllocNode; -import sootup.core.jimple.common.constant.ClassConstant; -import sootup.core.types.Type; - import java.util.Collection; import java.util.Iterator; import java.util.Set; +import qilin.core.pag.AllocNode; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.types.Type; /** * A generic interface to some set of runtime objects computed by a pointer analysis. @@ -32,67 +31,61 @@ * @author Ondrej Lhotak */ public interface PointsToSet { - /** - * Returns true if this set contains no run-time objects. - */ - boolean isEmpty(); - - /** - * Returns true iff the set contains n. - */ - boolean contains(AllocNode n); - - /** - * Returns true if this set shares some objects with other. - */ - boolean hasNonEmptyIntersection(PointsToSet other); - - /** - * Set of all possible run-time types of objects in the set. - */ - Set possibleTypes(); - - /** - * If this points-to set consists entirely of string constants, returns a set of these constant strings. If this point-to - * set may contain something other than constant strings, returns null. - */ - Set possibleStringConstants(); - - /** - * If this points-to set consists entirely of objects of type java.lang.Class of a known class, returns a set of - * ClassConstant's that are these classes. If this point-to set may contain something else, returns null. - */ - Set possibleClassConstants(); - - /** - * Size of objects in this set. - * - * @author Dongjie He - */ - int size(); - - /* - * Empty this set. - * - * @author Dongjie He - * */ - void clear(); - - /** - * Computes a hash code based on the contents of the points-to set. Note that hashCode() is not overwritten on purpose. - * This is because Spark relies on comparison by object identity. - */ - int pointsToSetHashCode(); - - /** - * Returns true if and only if other holds the same alloc nodes as this. Note that equals() is not overwritten - * on purpose. This is because Spark relies on comparison by object identity. - */ - boolean pointsToSetEquals(Object other); - - PointsToSet toCIPointsToSet(); - - Collection toCollection(); - - Iterator iterator(); + /** Returns true if this set contains no run-time objects. */ + boolean isEmpty(); + + /** Returns true iff the set contains n. */ + boolean contains(AllocNode n); + + /** Returns true if this set shares some objects with other. */ + boolean hasNonEmptyIntersection(PointsToSet other); + + /** Set of all possible run-time types of objects in the set. */ + Set possibleTypes(); + + /** + * If this points-to set consists entirely of string constants, returns a set of these constant + * strings. If this point-to set may contain something other than constant strings, returns null. + */ + Set possibleStringConstants(); + + /** + * If this points-to set consists entirely of objects of type java.lang.Class of a known class, + * returns a set of ClassConstant's that are these classes. If this point-to set may contain + * something else, returns null. + */ + Set possibleClassConstants(); + + /** + * Size of objects in this set. + * + * @author Dongjie He + */ + int size(); + + /* + * Empty this set. + * + * @author Dongjie He + * */ + void clear(); + + /** + * Computes a hash code based on the contents of the points-to set. Note that hashCode() is not + * overwritten on purpose. This is because Spark relies on comparison by object identity. + */ + int pointsToSetHashCode(); + + /** + * Returns true if and only if other holds the same alloc nodes as this. Note that + * equals() is not overwritten on purpose. This is because Spark relies on comparison by object + * identity. + */ + boolean pointsToSetEquals(Object other); + + PointsToSet toCIPointsToSet(); + + Collection toCollection(); + + Iterator iterator(); } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java index 42ce659f6f3..6435587cd86 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/PointsToSetInternal.java @@ -26,39 +26,34 @@ * @author Ondrej Lhotak */ public abstract class PointsToSetInternal { - /** - * Calls v's visit method on all nodes in this set. - */ - public abstract boolean forall(P2SetVisitor v); + /** Calls v's visit method on all nodes in this set. */ + public abstract boolean forall(P2SetVisitor v); - public abstract boolean addAll(final PointsToSetInternal other, final PointsToSetInternal exclude); + public abstract boolean addAll( + final PointsToSetInternal other, final PointsToSetInternal exclude); - /** - * Adds node index idx to this set, returns true if idx was not already in this set. - */ - public abstract boolean add(int idx); + /** Adds node index idx to this set, returns true if idx was not already in this set. */ + public abstract boolean add(int idx); - /** - * Returns true iff the set contains the node number index. - */ - public abstract boolean contains(int idx); + /** Returns true iff the set contains the node number index. */ + public abstract boolean contains(int idx); - public abstract Iterator iterator(); + public abstract Iterator iterator(); - public abstract void clear(); + public abstract void clear(); - public abstract boolean isEmpty(); + public abstract boolean isEmpty(); - public boolean hasNonEmptyIntersection(final PointsToSetInternal other) { - Iterator it = iterator(); - while (it.hasNext()) { - int idx = it.next(); - if (other.contains(idx)) { - return true; - } - } - return false; + public boolean hasNonEmptyIntersection(final PointsToSetInternal other) { + Iterator it = iterator(); + while (it.hasNext()) { + int idx = it.next(); + if (other.contains(idx)) { + return true; + } } + return false; + } - public abstract int size(); + public abstract int size(); } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java index 971c69730c9..34676f7b0fe 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/UnmodifiablePointsToSet.java @@ -18,6 +18,7 @@ package qilin.core.sets; +import java.util.*; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.pag.AllocNode; @@ -30,192 +31,200 @@ import sootup.core.types.Type; import sootup.core.views.View; -import java.util.*; - public class UnmodifiablePointsToSet implements PointsToSet { - private final PointsToSetInternal pts; - private final PTA pta; - - public UnmodifiablePointsToSet(PTA pta, PointsToSetInternal pts) { - this.pta = pta; - this.pts = pts; - } - - @Override - public boolean isEmpty() { - return pts.isEmpty(); - } - - @Override - public boolean contains(AllocNode n) { - return pts.contains(n.getNumber()); - } - - @Override - public boolean hasNonEmptyIntersection(PointsToSet other) { - if (other instanceof UnmodifiablePointsToSet uother) { - return pta == uother.pta && pts.hasNonEmptyIntersection(uother.pts); - } - return false; - } - - @Override - public Set possibleTypes() { - final Set ret = new HashSet<>(); - pts.forall(new P2SetVisitor(pta) { - public void visit(Node n) { - Type t = n.getType(); - if (t instanceof ClassType rt) { - View view = PTAScene.v().getView(); - Optional osc = (Optional) view.getClass(rt); - if (osc.isPresent() && osc.get().isAbstract()) { - return; - } - } - ret.add(t); + private final PointsToSetInternal pts; + private final PTA pta; + + public UnmodifiablePointsToSet(PTA pta, PointsToSetInternal pts) { + this.pta = pta; + this.pts = pts; + } + + @Override + public boolean isEmpty() { + return pts.isEmpty(); + } + + @Override + public boolean contains(AllocNode n) { + return pts.contains(n.getNumber()); + } + + @Override + public boolean hasNonEmptyIntersection(PointsToSet other) { + if (other instanceof UnmodifiablePointsToSet uother) { + return pta == uother.pta && pts.hasNonEmptyIntersection(uother.pts); + } + return false; + } + + @Override + public Set possibleTypes() { + final Set ret = new HashSet<>(); + pts.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { + Type t = n.getType(); + if (t instanceof ClassType rt) { + View view = PTAScene.v().getView(); + Optional osc = (Optional) view.getClass(rt); + if (osc.isPresent() && osc.get().isAbstract()) { + return; + } } + ret.add(t); + } }); - return ret; - } - - @Override - public Set possibleStringConstants() { - final Set ret = new HashSet<>(); - return pts.forall(new P2SetVisitor(pta) { - public void visit(Node n) { + return ret; + } + + @Override + public Set possibleStringConstants() { + final Set ret = new HashSet<>(); + return pts.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { if (n instanceof StringConstantNode) { - ret.add(((StringConstantNode) n).getString()); + ret.add(((StringConstantNode) n).getString()); } else { - returnValue = true; + returnValue = true; } - } - }) ? null : ret; - } - - @Override - public Set possibleClassConstants() { - final Set ret = new HashSet<>(); - return pts.forall(new P2SetVisitor(pta) { - public void visit(Node n) { + } + }) + ? null + : ret; + } + + @Override + public Set possibleClassConstants() { + final Set ret = new HashSet<>(); + return pts.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { if (n instanceof ClassConstantNode) { - ret.add(((ClassConstantNode) n).getClassConstant()); + ret.add(((ClassConstantNode) n).getClassConstant()); } else { - returnValue = true; + returnValue = true; } - } - }) ? null : ret; - } - - @Override - public int size() { - return pts.size(); - } - - @Override - public void clear() { - pts.clear(); - } - - @Override - public String toString() { - final StringBuffer ret = new StringBuffer(); - pts.forall(new P2SetVisitor(pta) { - public void visit(Node n) { - ret.append(n).append(","); - } + } + }) + ? null + : ret; + } + + @Override + public int size() { + return pts.size(); + } + + @Override + public void clear() { + pts.clear(); + } + + @Override + public String toString() { + final StringBuffer ret = new StringBuffer(); + pts.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { + ret.append(n).append(","); + } }); - return ret.toString(); - } - - @Override - public int pointsToSetHashCode() { - long intValue = 1; - final long PRIME = 31; - for (Iterator it = pts.iterator(); it.hasNext(); ) { - intValue = PRIME * intValue + it.next(); - } - return (int) intValue; - } - - @Override - public boolean pointsToSetEquals(Object other) { - if (this == other) { - return true; - } - if (other instanceof UnmodifiablePointsToSet otherPts) { - if (otherPts.pta != pta) { - return false; - } - // both sets are equal if they are supersets of each other - return superSetOf(otherPts.pts, pts) && superSetOf(pts, otherPts.pts); - } + return ret.toString(); + } + + @Override + public int pointsToSetHashCode() { + long intValue = 1; + final long PRIME = 31; + for (Iterator it = pts.iterator(); it.hasNext(); ) { + intValue = PRIME * intValue + it.next(); + } + return (int) intValue; + } + + @Override + public boolean pointsToSetEquals(Object other) { + if (this == other) { + return true; + } + if (other instanceof UnmodifiablePointsToSet otherPts) { + if (otherPts.pta != pta) { return false; - } - - @Override - public PointsToSet toCIPointsToSet() { - PointsToSetInternal ptoSet = new HybridPointsToSet(); - pts.forall(new P2SetVisitor(pta) { - @Override - public void visit(Node n) { - AllocNode heap = (AllocNode) n; - ptoSet.add(heap.base().getNumber()); - } + } + // both sets are equal if they are supersets of each other + return superSetOf(otherPts.pts, pts) && superSetOf(pts, otherPts.pts); + } + return false; + } + + @Override + public PointsToSet toCIPointsToSet() { + PointsToSetInternal ptoSet = new HybridPointsToSet(); + pts.forall( + new P2SetVisitor(pta) { + @Override + public void visit(Node n) { + AllocNode heap = (AllocNode) n; + ptoSet.add(heap.base().getNumber()); + } }); - return new UnmodifiablePointsToSet(pta, ptoSet); - } - - @Override - public Collection toCollection() { - Set ret = new HashSet<>(); - for (Iterator it = iterator(); it.hasNext(); ) { - ret.add(it.next()); - } - return ret; - } - - /** - * Returns true if onePts is a (non-strict) superset of otherPts. - */ - private boolean superSetOf(PointsToSetInternal onePts, final PointsToSetInternal otherPts) { - Iterator it = onePts.iterator(); - while (it.hasNext()) { - int idx = it.next(); - if (!otherPts.contains(idx)) { - return false; - } - } - return true; - } - - public Iterator iterator() { - return new UnmodifiablePTSIterator(); + return new UnmodifiablePointsToSet(pta, ptoSet); + } + + @Override + public Collection toCollection() { + Set ret = new HashSet<>(); + for (Iterator it = iterator(); it.hasNext(); ) { + ret.add(it.next()); + } + return ret; + } + + /** + * Returns true if onePts is a (non-strict) superset of otherPts + * . + */ + private boolean superSetOf(PointsToSetInternal onePts, final PointsToSetInternal otherPts) { + Iterator it = onePts.iterator(); + while (it.hasNext()) { + int idx = it.next(); + if (!otherPts.contains(idx)) { + return false; + } } + return true; + } - private class UnmodifiablePTSIterator implements Iterator { - Iterator it = pts.iterator(); + public Iterator iterator() { + return new UnmodifiablePTSIterator(); + } - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public AllocNode next() { - int idx = it.next(); - return pta.getPag().getAllocNodeNumberer().get(idx); - } - } + private class UnmodifiablePTSIterator implements Iterator { + Iterator it = pts.iterator(); @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - return pointsToSetEquals(o); + public boolean hasNext() { + return it.hasNext(); } @Override - public int hashCode() { - return Objects.hash(pointsToSetHashCode(), pta); - } + public AllocNode next() { + int idx = it.next(); + return pta.getPag().getAllocNodeNumberer().get(idx); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + return pointsToSetEquals(o); + } + + @Override + public int hashCode() { + return Objects.hash(pointsToSetHashCode(), pta); + } } diff --git a/sootup.qilin/src/main/java/qilin/core/sets/package-info.java b/sootup.qilin/src/main/java/qilin/core/sets/package-info.java index b35233665ed..86cc93076b3 100644 --- a/sootup.qilin/src/main/java/qilin/core/sets/package-info.java +++ b/sootup.qilin/src/main/java/qilin/core/sets/package-info.java @@ -3,4 +3,4 @@ /* * We reuse the data structures of points-to set which are originally designed for Spark in Soot. * In future, we plan to design more memory-efficient data structures for replacements. - * */ \ No newline at end of file + * */ diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Propagator.java b/sootup.qilin/src/main/java/qilin/core/solver/Propagator.java index 355173d4ed5..d15f1993dcc 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Propagator.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Propagator.java @@ -19,14 +19,12 @@ package qilin.core.solver; /** - * Abstract base class for a propagator that propagates points-to sets along pointer assignment graph. + * Abstract base class for a propagator that propagates points-to sets along pointer assignment + * graph. * * @author Ondrej Lhotak */ - public abstract class Propagator { - /** - * Actually does the propagation. - */ - public abstract void propagate(); + /** Actually does the propagation. */ + public abstract void propagate(); } diff --git a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java index 7422b3c5d92..cd1098d6d7c 100644 --- a/sootup.qilin/src/main/java/qilin/core/solver/Solver.java +++ b/sootup.qilin/src/main/java/qilin/core/solver/Solver.java @@ -18,6 +18,7 @@ package qilin.core.solver; +import java.util.*; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; @@ -33,7 +34,6 @@ import soot.Kind; import soot.MethodOrMethodContext; import soot.jimple.toolkits.callgraph.Edge; -import soot.util.NumberedString; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; import sootup.core.jimple.basic.Local; @@ -46,286 +46,300 @@ import sootup.core.signatures.MethodSignature; import sootup.core.signatures.MethodSubSignature; -import java.util.*; - public class Solver extends Propagator { - private final TreeSet valNodeWorkList = new TreeSet<>(); - private final PAG pag; - private final PTA pta; - private final CallGraphBuilder cgb; - private final ExceptionHandler eh; - private final ChunkedQueue throwSiteQueue = new ChunkedQueue<>(); - private final ChunkedQueue virtualCallSiteQueue = new ChunkedQueue<>(); - private final ChunkedQueue edgeQueue = new ChunkedQueue<>(); + private final TreeSet valNodeWorkList = new TreeSet<>(); + private final PAG pag; + private final PTA pta; + private final CallGraphBuilder cgb; + private final ExceptionHandler eh; + private final ChunkedQueue throwSiteQueue = new ChunkedQueue<>(); + private final ChunkedQueue virtualCallSiteQueue = new ChunkedQueue<>(); + private final ChunkedQueue edgeQueue = new ChunkedQueue<>(); - private final ChunkedQueue rmQueue = new ChunkedQueue<>(); + private final ChunkedQueue rmQueue = new ChunkedQueue<>(); - public Solver(PTA pta) { - this.cgb = pta.getCgb(); - this.cgb.setRMQueue(rmQueue); - this.pag = pta.getPag(); - this.pag.setEdgeQueue(edgeQueue); - this.eh = pta.getExceptionHandler(); - this.pta = pta; - } + public Solver(PTA pta) { + this.cgb = pta.getCgb(); + this.cgb.setRMQueue(rmQueue); + this.pag = pta.getPag(); + this.pag.setEdgeQueue(edgeQueue); + this.eh = pta.getExceptionHandler(); + this.pta = pta; + } - @Override - public void propagate() { - final QueueReader newRMs = rmQueue.reader(); - final QueueReader newPAGEdges = edgeQueue.reader(); - final QueueReader newThrows = throwSiteQueue.reader(); - final QueueReader newCalls = virtualCallSiteQueue.reader(); - cgb.initReachableMethods(); - processStmts(newRMs); - pag.getAlloc().forEach((a, set) -> set.forEach(v -> propagatePTS(v, a))); - while (!valNodeWorkList.isEmpty()) { - ValNode curr = valNodeWorkList.pollFirst(); - // Step 1: Resolving Direct Constraints - assert curr != null; - final DoublePointsToSet pts = curr.getP2Set(); - final PointsToSetInternal newset = pts.getNewSet(); - pag.simpleLookup(curr).forEach(to -> propagatePTS(to, newset)); + @Override + public void propagate() { + final QueueReader newRMs = rmQueue.reader(); + final QueueReader newPAGEdges = edgeQueue.reader(); + final QueueReader newThrows = throwSiteQueue.reader(); + final QueueReader newCalls = virtualCallSiteQueue.reader(); + cgb.initReachableMethods(); + processStmts(newRMs); + pag.getAlloc().forEach((a, set) -> set.forEach(v -> propagatePTS(v, a))); + while (!valNodeWorkList.isEmpty()) { + ValNode curr = valNodeWorkList.pollFirst(); + // Step 1: Resolving Direct Constraints + assert curr != null; + final DoublePointsToSet pts = curr.getP2Set(); + final PointsToSetInternal newset = pts.getNewSet(); + pag.simpleLookup(curr).forEach(to -> propagatePTS(to, newset)); - if (curr instanceof VarNode mSrc) { - // Step 1 continues. - Collection throwSites = eh.throwSitesLookUp(mSrc); - for (ExceptionThrowSite site : throwSites) { - eh.exceptionDispatch(newset, site); - } - // Step 2: Resolving Indirect Constraints. - handleStoreAndLoadOnBase(mSrc); - // Step 3: Collecting New Constraints. - Collection sites = cgb.callSitesLookUp(mSrc); - for (VirtualCallSite site : sites) { - cgb.virtualCallDispatch(newset, site); - } - processStmts(newRMs); - } - pts.flushNew(); - // Step 4: Activating New Constraints. - activateConstraints(newCalls, newRMs, newThrows, newPAGEdges); + if (curr instanceof VarNode mSrc) { + // Step 1 continues. + Collection throwSites = eh.throwSitesLookUp(mSrc); + for (ExceptionThrowSite site : throwSites) { + eh.exceptionDispatch(newset, site); } - } - - public void processStmts(Iterator newRMs) { - while (newRMs.hasNext()) { - MethodOrMethodContext momc = newRMs.next(); - SootMethod method = momc.method(); - if (!method.isConcrete()) { - continue; - } - MethodPAG mpag = pag.getMethodPAG(method); - addToPAG(mpag, momc.context()); - // !FIXME in a context-sensitive pointer analysis, clinits in a method maybe added multiple times. - if (CoreConfig.v().getPtaConfig().clinitMode == CoreConfig.ClinitMode.ONFLY) { - // add find in the method to reachableMethods. - Iterator it = mpag.triggeredClinits(); - while (it.hasNext()) { - SootMethod sm = it.next(); - cgb.injectCallEdge(sm.getDeclaringClassType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); - } - } - recordCallStmts(momc, mpag.getInvokeStmts()); - recordThrowStmts(momc, mpag.stmt2wrapperedTraps.keySet()); + // Step 2: Resolving Indirect Constraints. + handleStoreAndLoadOnBase(mSrc); + // Step 3: Collecting New Constraints. + Collection sites = cgb.callSitesLookUp(mSrc); + for (VirtualCallSite site : sites) { + cgb.virtualCallDispatch(newset, site); } + processStmts(newRMs); + } + pts.flushNew(); + // Step 4: Activating New Constraints. + activateConstraints(newCalls, newRMs, newThrows, newPAGEdges); } + } - private void recordCallStmts(MethodOrMethodContext m, Collection units) { - for (final Stmt s : units) { - if (s.containsInvokeExpr()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof AbstractInstanceInvokeExpr iie) { - Local receiver = iie.getBase(); - VarNode recNode = cgb.getReceiverVarNode(receiver, m); - MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); - VirtualCallSite virtualCallSite = new VirtualCallSite(recNode, s, m, iie, subSig, Edge.ieToKind(iie)); - if (cgb.recordVirtualCallSite(recNode, virtualCallSite)) { - virtualCallSiteQueue.add(virtualCallSite); - } - } else { - MethodSignature tgtSig = ie.getMethodSignature(); - Optional otgt = PTAScene.v().getView().getMethod(tgtSig); - if (otgt.isPresent()) { - // static invoke or dynamic invoke - VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); - recNode = (VarNode) pta.parameterize(recNode, m.context()); - if (ie instanceof JDynamicInvokeExpr) { - // !TODO dynamicInvoke is provided in JDK after Java 7. - // currently, PTA does not handle dynamicInvokeExpr. - } else { - cgb.addStaticEdge(m, s, otgt.get(), Edge.ieToKind(ie)); - } - } else { - // - } - } - } + public void processStmts(Iterator newRMs) { + while (newRMs.hasNext()) { + MethodOrMethodContext momc = newRMs.next(); + SootMethod method = momc.method(); + if (!method.isConcrete()) { + continue; + } + MethodPAG mpag = pag.getMethodPAG(method); + addToPAG(mpag, momc.context()); + // !FIXME in a context-sensitive pointer analysis, clinits in a method maybe added multiple + // times. + if (CoreConfig.v().getPtaConfig().clinitMode == CoreConfig.ClinitMode.ONFLY) { + // add find in the method to reachableMethods. + Iterator it = mpag.triggeredClinits(); + while (it.hasNext()) { + SootMethod sm = it.next(); + cgb.injectCallEdge( + sm.getDeclaringClassType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); } + } + recordCallStmts(momc, mpag.getInvokeStmts()); + recordThrowStmts(momc, mpag.stmt2wrapperedTraps.keySet()); } + } - private void recordThrowStmts(MethodOrMethodContext m, Collection stmts) { - for (final Stmt stmt : stmts) { - SootMethod sm = m.method(); - MethodPAG mpag = pag.getMethodPAG(sm); - MethodNodeFactory nodeFactory = mpag.nodeFactory(); - Node src; - if (stmt.containsInvokeExpr()) { - src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, sm); + private void recordCallStmts(MethodOrMethodContext m, Collection units) { + for (final Stmt s : units) { + if (s.containsInvokeExpr()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof AbstractInstanceInvokeExpr iie) { + Local receiver = iie.getBase(); + VarNode recNode = cgb.getReceiverVarNode(receiver, m); + MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); + VirtualCallSite virtualCallSite = + new VirtualCallSite(recNode, s, m, iie, subSig, Edge.ieToKind(iie)); + if (cgb.recordVirtualCallSite(recNode, virtualCallSite)) { + virtualCallSiteQueue.add(virtualCallSite); + } + } else { + MethodSignature tgtSig = ie.getMethodSignature(); + Optional otgt = PTAScene.v().getView().getMethod(tgtSig); + if (otgt.isPresent()) { + // static invoke or dynamic invoke + VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); + recNode = (VarNode) pta.parameterize(recNode, m.context()); + if (ie instanceof JDynamicInvokeExpr) { + // !TODO dynamicInvoke is provided in JDK after Java 7. + // currently, PTA does not handle dynamicInvokeExpr. } else { - assert stmt instanceof JThrowStmt; - JThrowStmt ts = (JThrowStmt) stmt; - src = nodeFactory.getNode(ts.getOp()); - } - VarNode throwNode = (VarNode) pta.parameterize(src, m.context()); - ExceptionThrowSite throwSite = new ExceptionThrowSite(throwNode, stmt, m); - if (eh.addThrowSite(throwNode, throwSite)) { - throwSiteQueue.add(throwSite); + cgb.addStaticEdge(m, s, otgt.get(), Edge.ieToKind(ie)); } + } else { + // + } } + } } + } - private void addToPAG(MethodPAG mpag, Context cxt) { - Set contexts = pag.getMethod2ContextsMap().computeIfAbsent(mpag, k1 -> new HashSet<>()); - if (!contexts.add(cxt)) { - return; - } - for (QueueReader reader = mpag.getInternalReader().clone(); reader.hasNext(); ) { - Node from = reader.next(); - Node to = reader.next(); - if (from instanceof AllocNode heap) { - from = pta.heapAbstractor().abstractHeap(heap); - } - if (from instanceof AllocNode && to instanceof GlobalVarNode) { - pag.addGlobalPAGEdge(from, to); - } else { - from = pta.parameterize(from, cxt); - to = pta.parameterize(to, cxt); - if (from instanceof AllocNode) { - handleImplicitCallToFinalizerRegister((AllocNode) from); - } - pag.addEdge(from, to); - } - } + private void recordThrowStmts(MethodOrMethodContext m, Collection stmts) { + for (final Stmt stmt : stmts) { + SootMethod sm = m.method(); + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory nodeFactory = mpag.nodeFactory(); + Node src; + if (stmt.containsInvokeExpr()) { + src = nodeFactory.makeInvokeStmtThrowVarNode(stmt, sm); + } else { + assert stmt instanceof JThrowStmt; + JThrowStmt ts = (JThrowStmt) stmt; + src = nodeFactory.getNode(ts.getOp()); + } + VarNode throwNode = (VarNode) pta.parameterize(src, m.context()); + ExceptionThrowSite throwSite = new ExceptionThrowSite(throwNode, stmt, m); + if (eh.addThrowSite(throwNode, throwSite)) { + throwSiteQueue.add(throwSite); + } } + } - // handle implicit calls to java.lang.ref.Finalizer.register by the JVM. - // please refer to library/finalization.logic in doop. - private void handleImplicitCallToFinalizerRegister(AllocNode heap) { - if (PTAUtils.supportFinalize(heap)) { - SootMethod rm = PTAScene.v().getMethod(""); - MethodPAG tgtmpag = pag.getMethodPAG(rm); - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - Node parm = tgtnf.caseParm(0); - Context calleeCtx = pta.emptyContext(); - AllocNode baseHeap = heap.base(); - parm = pta.parameterize(parm, calleeCtx); - pag.addEdge(heap, parm); - cgb.injectCallEdge(baseHeap, pta.parameterize(rm, calleeCtx), Kind.STATIC); + private void addToPAG(MethodPAG mpag, Context cxt) { + Set contexts = + pag.getMethod2ContextsMap().computeIfAbsent(mpag, k1 -> new HashSet<>()); + if (!contexts.add(cxt)) { + return; + } + for (QueueReader reader = mpag.getInternalReader().clone(); reader.hasNext(); ) { + Node from = reader.next(); + Node to = reader.next(); + if (from instanceof AllocNode heap) { + from = pta.heapAbstractor().abstractHeap(heap); + } + if (from instanceof AllocNode && to instanceof GlobalVarNode) { + pag.addGlobalPAGEdge(from, to); + } else { + from = pta.parameterize(from, cxt); + to = pta.parameterize(to, cxt); + if (from instanceof AllocNode) { + handleImplicitCallToFinalizerRegister((AllocNode) from); } + pag.addEdge(from, to); + } } + } - private void handleStoreAndLoadOnBase(VarNode base) { - for (final FieldRefNode fr : base.getAllFieldRefs()) { - for (final VarNode v : pag.storeInvLookup(fr)) { - handleStoreEdge(base.getP2Set().getNewSet(), fr.getField(), v); - } - for (final VarNode to : pag.loadLookup(fr)) { - handleLoadEdge(base.getP2Set().getNewSet(), fr.getField(), to); - } - } + // handle implicit calls to java.lang.ref.Finalizer.register by the JVM. + // please refer to library/finalization.logic in doop. + private void handleImplicitCallToFinalizerRegister(AllocNode heap) { + if (PTAUtils.supportFinalize(heap)) { + SootMethod rm = + PTAScene.v().getMethod(""); + MethodPAG tgtmpag = pag.getMethodPAG(rm); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + Node parm = tgtnf.caseParm(0); + Context calleeCtx = pta.emptyContext(); + AllocNode baseHeap = heap.base(); + parm = pta.parameterize(parm, calleeCtx); + pag.addEdge(heap, parm); + cgb.injectCallEdge(baseHeap, pta.parameterize(rm, calleeCtx), Kind.STATIC); } + } - private void handleStoreEdge(PointsToSetInternal baseHeaps, SparkField field, ValNode from) { - baseHeaps.forall(new P2SetVisitor(pta) { - public void visit(Node n) { - if (disallowStoreOrLoadOn((AllocNode) n)) { - return; - } - final FieldValNode fvn = pag.makeFieldValNode(field); - final ValNode oDotF = (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); - pag.addEdge(from, oDotF); - } - }); + private void handleStoreAndLoadOnBase(VarNode base) { + for (final FieldRefNode fr : base.getAllFieldRefs()) { + for (final VarNode v : pag.storeInvLookup(fr)) { + handleStoreEdge(base.getP2Set().getNewSet(), fr.getField(), v); + } + for (final VarNode to : pag.loadLookup(fr)) { + handleLoadEdge(base.getP2Set().getNewSet(), fr.getField(), to); + } } + } - private void handleLoadEdge(PointsToSetInternal baseHeaps, SparkField field, ValNode to) { - baseHeaps.forall(new P2SetVisitor(pta) { - public void visit(Node n) { - if (disallowStoreOrLoadOn((AllocNode) n)) { - return; - } - final FieldValNode fvn = pag.makeFieldValNode(field); - final ValNode oDotF = (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); - pag.addEdge(oDotF, to); + private void handleStoreEdge(PointsToSetInternal baseHeaps, SparkField field, ValNode from) { + baseHeaps.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { + if (disallowStoreOrLoadOn((AllocNode) n)) { + return; } + final FieldValNode fvn = pag.makeFieldValNode(field); + final ValNode oDotF = + (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); + pag.addEdge(from, oDotF); + } }); - } + } - private void activateConstraints(QueueReader newCalls, QueueReader newRMs, QueueReader newThrows, QueueReader addedEdges) { - while (newCalls.hasNext()) { - while (newCalls.hasNext()) { - final VirtualCallSite site = newCalls.next(); - final VarNode receiver = site.recNode(); - cgb.virtualCallDispatch(receiver.getP2Set().getOldSet(), site); + private void handleLoadEdge(PointsToSetInternal baseHeaps, SparkField field, ValNode to) { + baseHeaps.forall( + new P2SetVisitor(pta) { + public void visit(Node n) { + if (disallowStoreOrLoadOn((AllocNode) n)) { + return; } - processStmts(newRMs); // may produce new calls, thus an out-loop is a must. - } + final FieldValNode fvn = pag.makeFieldValNode(field); + final ValNode oDotF = + (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); + pag.addEdge(oDotF, to); + } + }); + } - while (newThrows.hasNext()) { - final ExceptionThrowSite ets = newThrows.next(); - final VarNode throwNode = ets.getThrowNode(); - eh.exceptionDispatch(throwNode.getP2Set().getOldSet(), ets); - } - /* - * there are some actual parameter to formal parameter edges whose source nodes are not in the worklist. - * For this case, we should use the following loop to update the target nodes and insert the - * target nodes into the worklist if nesseary. - * */ - while (addedEdges.hasNext()) { - final Node addedSrc = addedEdges.next(); - final Node addedTgt = addedEdges.next(); - if (addedSrc instanceof VarNode && addedTgt instanceof VarNode - || addedSrc instanceof ContextField || addedTgt instanceof ContextField - ) { // x = y; x = o.f; o.f = y; - final ValNode srcv = (ValNode) addedSrc; - final ValNode tgtv = (ValNode) addedTgt; - propagatePTS(tgtv, srcv.getP2Set().getOldSet()); - } else if (addedSrc instanceof final FieldRefNode srcfrn) { // b = a.f - handleLoadEdge(srcfrn.getBase().getP2Set().getOldSet(), srcfrn.getField(), (ValNode) addedTgt); - } else if (addedTgt instanceof final FieldRefNode tgtfrn) { // a.f = b; - handleStoreEdge(tgtfrn.getBase().getP2Set().getOldSet(), tgtfrn.getField(), (ValNode) addedSrc); - } else if (addedSrc instanceof AllocNode) { // alloc x = new T; - propagatePTS((VarNode) addedTgt, (AllocNode) addedSrc); - } - } + private void activateConstraints( + QueueReader newCalls, + QueueReader newRMs, + QueueReader newThrows, + QueueReader addedEdges) { + while (newCalls.hasNext()) { + while (newCalls.hasNext()) { + final VirtualCallSite site = newCalls.next(); + final VarNode receiver = site.recNode(); + cgb.virtualCallDispatch(receiver.getP2Set().getOldSet(), site); + } + processStmts(newRMs); // may produce new calls, thus an out-loop is a must. } - protected void propagatePTS(final ValNode pointer, PointsToSetInternal other) { - final DoublePointsToSet addTo = pointer.getP2Set(); - P2SetVisitor p2SetVisitor = new P2SetVisitor(pta) { - @Override - public void visit(Node n) { - if (PTAUtils.addWithTypeFiltering(addTo, pointer.getType(), n)) { - returnValue = true; - } + while (newThrows.hasNext()) { + final ExceptionThrowSite ets = newThrows.next(); + final VarNode throwNode = ets.getThrowNode(); + eh.exceptionDispatch(throwNode.getP2Set().getOldSet(), ets); + } + /* + * there are some actual parameter to formal parameter edges whose source nodes are not in the worklist. + * For this case, we should use the following loop to update the target nodes and insert the + * target nodes into the worklist if nesseary. + * */ + while (addedEdges.hasNext()) { + final Node addedSrc = addedEdges.next(); + final Node addedTgt = addedEdges.next(); + if (addedSrc instanceof VarNode && addedTgt instanceof VarNode + || addedSrc instanceof ContextField + || addedTgt instanceof ContextField) { // x = y; x = o.f; o.f = y; + final ValNode srcv = (ValNode) addedSrc; + final ValNode tgtv = (ValNode) addedTgt; + propagatePTS(tgtv, srcv.getP2Set().getOldSet()); + } else if (addedSrc instanceof final FieldRefNode srcfrn) { // b = a.f + handleLoadEdge( + srcfrn.getBase().getP2Set().getOldSet(), srcfrn.getField(), (ValNode) addedTgt); + } else if (addedTgt instanceof final FieldRefNode tgtfrn) { // a.f = b; + handleStoreEdge( + tgtfrn.getBase().getP2Set().getOldSet(), tgtfrn.getField(), (ValNode) addedSrc); + } else if (addedSrc instanceof AllocNode) { // alloc x = new T; + propagatePTS((VarNode) addedTgt, (AllocNode) addedSrc); + } + } + } + + protected void propagatePTS(final ValNode pointer, PointsToSetInternal other) { + final DoublePointsToSet addTo = pointer.getP2Set(); + P2SetVisitor p2SetVisitor = + new P2SetVisitor(pta) { + @Override + public void visit(Node n) { + if (PTAUtils.addWithTypeFiltering(addTo, pointer.getType(), n)) { + returnValue = true; } + } }; - other.forall(p2SetVisitor); - if (p2SetVisitor.getReturnValue()) { - valNodeWorkList.add(pointer); - } + other.forall(p2SetVisitor); + if (p2SetVisitor.getReturnValue()) { + valNodeWorkList.add(pointer); } + } - protected void propagatePTS(final ValNode pointer, AllocNode heap) { - if (PTAUtils.addWithTypeFiltering(pointer.getP2Set(), pointer.getType(), heap)) { - valNodeWorkList.add(pointer); - } + protected void propagatePTS(final ValNode pointer, AllocNode heap) { + if (PTAUtils.addWithTypeFiltering(pointer.getP2Set(), pointer.getType(), heap)) { + valNodeWorkList.add(pointer); } + } - // we do not allow store to and load from constant heap/empty array. - private boolean disallowStoreOrLoadOn(AllocNode heap) { - AllocNode base = heap.base(); - // return base instanceof StringConstantNode || PTAUtils.isEmptyArray(base); - return PTAUtils.isEmptyArray(base); - } + // we do not allow store to and load from constant heap/empty array. + private boolean disallowStoreOrLoadOn(AllocNode heap) { + AllocNode base = heap.base(); + // return base instanceof StringConstantNode || PTAUtils.isEmptyArray(base); + return PTAUtils.isEmptyArray(base); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java index 27211f4bf40..c2810488f6f 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CallsiteCtxConstructor.java @@ -28,16 +28,20 @@ public class CallsiteCtxConstructor implements CtxConstructor { - @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { - Context callerContext = caller.context(); - assert callerContext instanceof ContextElements; - ContextElements ctxElems = (ContextElements) callerContext; - int s = ctxElems.size(); - ContextElement[] cxt = ctxElems.getElements(); - ContextElement[] array = new ContextElement[s + 1]; - array[0] = callSite; - System.arraycopy(cxt, 0, array, 1, s); - return new ContextElements(array, s + 1); - } -} \ No newline at end of file + @Override + public Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target) { + Context callerContext = caller.context(); + assert callerContext instanceof ContextElements; + ContextElements ctxElems = (ContextElements) callerContext; + int s = ctxElems.size(); + ContextElement[] cxt = ctxElems.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = callSite; + System.arraycopy(cxt, 0, array, 1, s); + return new ContextElements(array, s + 1); + } +} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java index 691a3a39957..623af17a9af 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/CtxConstructor.java @@ -27,7 +27,11 @@ import sootup.core.model.SootMethod; public interface CtxConstructor { - Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target); + Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target); - Context emptyContext = new ContextElements(new ContextElement[0], 0); -} \ No newline at end of file + Context emptyContext = new ContextElements(new ContextElement[0], 0); +} diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java index c1d44066c8d..28093e22870 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybObjCtxConstructor.java @@ -28,42 +28,46 @@ // implementation of selective hybrid context...(Yannis pldi'13) public class HybObjCtxConstructor implements CtxConstructor { - /* - * Support Sb-1obj, S-2obj+H, ... - * */ - @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { - Context callerContext = caller.context(); - if (receiverNode == null) { // static invoke - assert callerContext instanceof ContextElements; - ContextElements callerCtx = (ContextElements) callerContext; - ContextElement[] cxtAllocs = callerCtx.getElements(); - int s = callerCtx.size(); - ContextElement[] array; - if (s >= 1) { - array = new ContextElement[s + 1]; - array[1] = callSite; - array[0] = cxtAllocs[0]; - if (s > 1) { - System.arraycopy(cxtAllocs, 1, array, 2, s - 1); - } - return new ContextElements(array, s + 1); - } else { - array = new ContextElement[2]; - array[1] = callSite; - array[0] = null; - return new ContextElements(array, 2); - } - } else { - Context context = receiverNode.context(); - assert context instanceof ContextElements; - ContextElements ctx = (ContextElements) context; - int s = ctx.size(); - ContextElement[] cxtAllocs = ctx.getElements(); - ContextElement[] array = new ContextElement[s + 1]; - array[0] = receiverNode.base(); - System.arraycopy(cxtAllocs, 0, array, 1, s); - return new ContextElements(array, s + 1); + /* + * Support Sb-1obj, S-2obj+H, ... + * */ + @Override + public Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + assert callerContext instanceof ContextElements; + ContextElements callerCtx = (ContextElements) callerContext; + ContextElement[] cxtAllocs = callerCtx.getElements(); + int s = callerCtx.size(); + ContextElement[] array; + if (s >= 1) { + array = new ContextElement[s + 1]; + array[1] = callSite; + array[0] = cxtAllocs[0]; + if (s > 1) { + System.arraycopy(cxtAllocs, 1, array, 2, s - 1); } + return new ContextElements(array, s + 1); + } else { + array = new ContextElement[2]; + array[1] = callSite; + array[0] = null; + return new ContextElements(array, 2); + } + } else { + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctx = (ContextElements) context; + int s = ctx.size(); + ContextElement[] cxtAllocs = ctx.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = receiverNode.base(); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); } + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java index 78553c791bf..ab77ad8b670 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/HybTypeCtxConstructor.java @@ -30,31 +30,35 @@ // implementation of selective hybrid context...(Yannis pldi'13) public class HybTypeCtxConstructor implements CtxConstructor { - @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { - Context callerContext = caller.context(); - if (receiverNode == null) { // static invoke - assert callerContext instanceof ContextElements; - ContextElements callerCtxs = (ContextElements) callerContext; - ContextElement[] cxtAllocs = callerCtxs.getElements(); - int s = callerCtxs.size(); - ContextElement[] array = new ContextElement[s + 1]; - array[1] = callSite; - array[0] = cxtAllocs[0]; - if (s > 1) { - System.arraycopy(cxtAllocs, 1, array, 2, s - 1); - } - return new ContextElements(array, s + 1); - } else { - Context context = receiverNode.context(); - assert context instanceof ContextElements; - ContextElements ctx = (ContextElements) context; - int s = ctx.size(); - ContextElement[] cxtAllocs = ctx.getElements(); - ContextElement[] array = new ContextElement[s + 1]; - array[0] = TypeContextElement.getTypeContextElement(receiverNode.base()); - System.arraycopy(cxtAllocs, 0, array, 1, s); - return new ContextElements(array, s + 1); - } + @Override + public Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + assert callerContext instanceof ContextElements; + ContextElements callerCtxs = (ContextElements) callerContext; + ContextElement[] cxtAllocs = callerCtxs.getElements(); + int s = callerCtxs.size(); + ContextElement[] array = new ContextElement[s + 1]; + array[1] = callSite; + array[0] = cxtAllocs[0]; + if (s > 1) { + System.arraycopy(cxtAllocs, 1, array, 2, s - 1); + } + return new ContextElements(array, s + 1); + } else { + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctx = (ContextElements) context; + int s = ctx.size(); + ContextElement[] cxtAllocs = ctx.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = TypeContextElement.getTypeContextElement(receiverNode.base()); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); } + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java index 39a111a800f..62e882a7a29 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/InsensCtxConstructor.java @@ -26,8 +26,12 @@ public class InsensCtxConstructor implements CtxConstructor { - @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { - return emptyContext; - } + @Override + public Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target) { + return emptyContext; + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java index 79a973cd89c..82b4ea456ec 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/ObjCtxConstructor.java @@ -29,20 +29,24 @@ // implementation of obj context...(Ana Tosem'05) public class ObjCtxConstructor implements CtxConstructor { - @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { - Context callerContext = caller.context(); - if (receiverNode == null) { // static invoke - return callerContext; - } - Context context = receiverNode.context(); - assert context instanceof ContextElements; - ContextElements ctxElems = (ContextElements) context; - int s = ctxElems.size(); - ContextElement[] cxtAllocs = ctxElems.getElements(); - ContextElement[] array = new ContextElement[s + 1]; - array[0] = receiverNode.base(); - System.arraycopy(cxtAllocs, 0, array, 1, s); - return new ContextElements(array, s + 1); + @Override + public Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + return callerContext; } + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctxElems = (ContextElements) context; + int s = ctxElems.size(); + ContextElement[] cxtAllocs = ctxElems.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + array[0] = receiverNode.base(); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java index 4bbdbffe5c5..ee989f8ae01 100644 --- a/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java +++ b/sootup.qilin/src/main/java/qilin/parm/ctxcons/TypeCtxConstructor.java @@ -31,21 +31,25 @@ // implementation of type context...(Yannis popl'11) public class TypeCtxConstructor implements CtxConstructor { - @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { - Context callerContext = caller.context(); - if (receiverNode == null) { // static invoke - return callerContext; - } - Context context = receiverNode.context(); - assert context instanceof ContextElements; - ContextElements ctxElems = (ContextElements) context; - int s = ctxElems.size(); - ContextElement[] cxtAllocs = ctxElems.getElements(); - ContextElement[] array = new ContextElement[s + 1]; - AllocNode base = receiverNode.base(); - array[0] = TypeContextElement.getTypeContextElement(base); - System.arraycopy(cxtAllocs, 0, array, 1, s); - return new ContextElements(array, s + 1); + @Override + public Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target) { + Context callerContext = caller.context(); + if (receiverNode == null) { // static invoke + return callerContext; } + Context context = receiverNode.context(); + assert context instanceof ContextElements; + ContextElements ctxElems = (ContextElements) context; + int s = ctxElems.size(); + ContextElement[] cxtAllocs = ctxElems.getElements(); + ContextElement[] array = new ContextElement[s + 1]; + AllocNode base = receiverNode.base(); + array[0] = TypeContextElement.getTypeContextElement(base); + System.arraycopy(cxtAllocs, 0, array, 1, s); + return new ContextElements(array, s + 1); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java index 3c8a03e1cdd..df01abf3f36 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/AllocSiteAbstractor.java @@ -21,8 +21,8 @@ import qilin.core.pag.AllocNode; public class AllocSiteAbstractor implements HeapAbstractor { - @Override - public AllocNode abstractHeap(AllocNode heap) { - return heap; - } + @Override + public AllocNode abstractHeap(AllocNode heap) { + return heap; + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java index 027e7079de3..70cb0eec8a4 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeapAbstractor.java @@ -21,5 +21,5 @@ import qilin.core.pag.AllocNode; public interface HeapAbstractor { - AllocNode abstractHeap(AllocNode heap); + AllocNode abstractHeap(AllocNode heap); } diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java index 575282f9503..c7d1ba32927 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/HeuristicAbstractor.java @@ -18,6 +18,7 @@ package qilin.parm.heapabst; +import java.util.Set; import qilin.core.pag.AllocNode; import qilin.core.pag.MergedNewExpr; import qilin.core.pag.PAG; @@ -27,26 +28,24 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.Set; - public class HeuristicAbstractor implements HeapAbstractor { - private final PAG pag; - private final Set mergedTypes = DataFactory.createSet(); + private final PAG pag; + private final Set mergedTypes = DataFactory.createSet(); - public HeuristicAbstractor(PAG pag) { - this.pag = pag; - mergedTypes.add(PTAUtils.getClassType("java.lang.StringBuffer")); - mergedTypes.add(PTAUtils.getClassType("java.lang.StringBuilder")); - } + public HeuristicAbstractor(PAG pag) { + this.pag = pag; + mergedTypes.add(PTAUtils.getClassType("java.lang.StringBuffer")); + mergedTypes.add(PTAUtils.getClassType("java.lang.StringBuilder")); + } - @Override - public AllocNode abstractHeap(AllocNode heap) { - Type type = heap.getType(); - SootMethod m = heap.getMethod(); - if (mergedTypes.contains(type) || (PTAUtils.isThrowable(type) && mergedTypes.add(type))) { - return pag.makeAllocNode(MergedNewExpr.v((ReferenceType) type), type, null); - } else { - return heap; - } + @Override + public AllocNode abstractHeap(AllocNode heap) { + Type type = heap.getType(); + SootMethod m = heap.getMethod(); + if (mergedTypes.contains(type) || (PTAUtils.isThrowable(type) && mergedTypes.add(type))) { + return pag.makeAllocNode(MergedNewExpr.v((ReferenceType) type), type, null); + } else { + return heap; } + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java index e822f6c5030..9113e4dd54a 100644 --- a/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java +++ b/sootup.qilin/src/main/java/qilin/parm/heapabst/MahjongAbstractor.java @@ -18,40 +18,39 @@ package qilin.parm.heapabst; +import java.util.Map; +import java.util.Set; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.Type; -import java.util.Map; -import java.util.Set; - public class MahjongAbstractor implements HeapAbstractor { - private final Set mergedHeap; - private final Map heapModelMap; - private final PAG pag; + private final Set mergedHeap; + private final Map heapModelMap; + private final PAG pag; - public MahjongAbstractor(PAG pag, Set mergedHeap, Map heapModelMap) { - this.pag = pag; - this.mergedHeap = mergedHeap; - this.heapModelMap = heapModelMap; - } + public MahjongAbstractor(PAG pag, Set mergedHeap, Map heapModelMap) { + this.pag = pag; + this.mergedHeap = mergedHeap; + this.heapModelMap = heapModelMap; + } - @Override - public AllocNode abstractHeap(AllocNode heap) { - Object newExpr = heap.getNewExpr(); - Type type = heap.getType(); - SootMethod m = heap.getMethod(); - Object mergedIr = this.heapModelMap.get(newExpr); - if (this.mergedHeap.contains(mergedIr)) { - return pag.makeAllocNode(mergedIr, type, null); - } else { - if (PTAUtils.isThrowable(type)) { - // Mahjong still needs heuristics to handle throwable types. - return pag.makeAllocNode("Merged " + type, type, null); - } - return pag.makeAllocNode(newExpr, type, m); - } + @Override + public AllocNode abstractHeap(AllocNode heap) { + Object newExpr = heap.getNewExpr(); + Type type = heap.getType(); + SootMethod m = heap.getMethod(); + Object mergedIr = this.heapModelMap.get(newExpr); + if (this.mergedHeap.contains(mergedIr)) { + return pag.makeAllocNode(mergedIr, type, null); + } else { + if (PTAUtils.isThrowable(type)) { + // Mahjong still needs heuristics to handle throwable types. + return pag.makeAllocNode("Merged " + type, type, null); + } + return pag.makeAllocNode(newExpr, type, m); } + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java index 642fdd2b672..989cf748539 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/BeanSelector.java @@ -18,6 +18,7 @@ package qilin.parm.select; +import java.util.Map; import qilin.core.context.ContextElement; import qilin.core.context.ContextElements; import qilin.core.pag.AllocNode; @@ -27,60 +28,58 @@ import soot.Context; import sootup.core.model.SootMethod; -import java.util.Map; - public class BeanSelector extends CtxSelector { - private final PAG pag; - private final Map>> beanNexCtxMap; - // currently, we only support k = 2 and hk = 1; - // we will generalize Bean in future. - private final int k = 2; - private final int hk = 1; + private final PAG pag; + private final Map>> beanNexCtxMap; + // currently, we only support k = 2 and hk = 1; + // we will generalize Bean in future. + private final int k = 2; + private final int hk = 1; - public BeanSelector(PAG pag, Map>> beanNexCtxMap) { - this.pag = pag; - this.beanNexCtxMap = beanNexCtxMap; - } + public BeanSelector(PAG pag, Map>> beanNexCtxMap) { + this.pag = pag; + this.beanNexCtxMap = beanNexCtxMap; + } - @Override - public Context select(SootMethod m, Context context) { - return contextTailor(context, k); - } + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, k); + } - @Override - public Context select(LocalVarNode lvn, Context context) { - return contextTailor(context, k); - } + @Override + public Context select(LocalVarNode lvn, Context context) { + return contextTailor(context, k); + } - @Override - public Context select(FieldValNode fvn, Context context) { - return contextTailor(context, k); - } + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } - @Override - public Context select(AllocNode heap, Context context) { - assert context instanceof ContextElements; - ContextElements ctxElems = (ContextElements) context; - int s = ctxElems.size(); - if (s > 1) { - ContextElement[] cxtAllocs = ctxElems.getElements(); - AllocNode allocator = (AllocNode) cxtAllocs[0]; - if (beanNexCtxMap.containsKey(heap.getNewExpr())) { - Map> mMap1 = beanNexCtxMap.get(heap.getNewExpr()); - if (mMap1.containsKey(allocator.getNewExpr())) { - Map mMap2 = mMap1.get(allocator.getNewExpr()); - AllocNode allocAllocNode = (AllocNode) cxtAllocs[1]; - if (allocAllocNode != null && mMap2.containsKey(allocAllocNode.getNewExpr())) { - Object newCtxNode = mMap2.get(allocAllocNode.getNewExpr()); - AllocNode newCtxAllocNode = pag.getAllocNode(newCtxNode); - ContextElement[] array = new ContextElement[s]; - System.arraycopy(cxtAllocs, 0, array, 0, s); - array[0] = newCtxAllocNode; - context = new ContextElements(array, s); - } - } - } + @Override + public Context select(AllocNode heap, Context context) { + assert context instanceof ContextElements; + ContextElements ctxElems = (ContextElements) context; + int s = ctxElems.size(); + if (s > 1) { + ContextElement[] cxtAllocs = ctxElems.getElements(); + AllocNode allocator = (AllocNode) cxtAllocs[0]; + if (beanNexCtxMap.containsKey(heap.getNewExpr())) { + Map> mMap1 = beanNexCtxMap.get(heap.getNewExpr()); + if (mMap1.containsKey(allocator.getNewExpr())) { + Map mMap2 = mMap1.get(allocator.getNewExpr()); + AllocNode allocAllocNode = (AllocNode) cxtAllocs[1]; + if (allocAllocNode != null && mMap2.containsKey(allocAllocNode.getNewExpr())) { + Object newCtxNode = mMap2.get(allocAllocNode.getNewExpr()); + AllocNode newCtxAllocNode = pag.getAllocNode(newCtxNode); + ContextElement[] array = new ContextElement[s]; + System.arraycopy(cxtAllocs, 0, array, 0, s); + array[0] = newCtxAllocNode; + context = new ContextElements(array, s); + } } - return contextTailor(context, hk); + } } + return contextTailor(context, hk); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java index b7144776919..1ccfff4d507 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/CtxSelector.java @@ -28,25 +28,25 @@ import sootup.core.model.SootMethod; public abstract class CtxSelector { - public abstract Context select(SootMethod m, Context context); + public abstract Context select(SootMethod m, Context context); - public abstract Context select(LocalVarNode lvn, Context context); + public abstract Context select(LocalVarNode lvn, Context context); - public abstract Context select(FieldValNode fvn, Context context); + public abstract Context select(FieldValNode fvn, Context context); - public abstract Context select(AllocNode heap, Context context); + public abstract Context select(AllocNode heap, Context context); - protected Context contextTailor(Context context, int length) { - if (length == 0) { - return CtxConstructor.emptyContext; - } - ContextElements ctx = (ContextElements) context; - ContextElement[] fullContexts = ctx.getElements(); - if (length >= ctx.size()) { - return context; - } - ContextElement[] newContexts = new ContextElement[length]; - System.arraycopy(fullContexts, 0, newContexts, 0, length); - return new ContextElements(newContexts, length); + protected Context contextTailor(Context context, int length) { + if (length == 0) { + return CtxConstructor.emptyContext; } + ContextElements ctx = (ContextElements) context; + ContextElement[] fullContexts = ctx.getElements(); + if (length >= ctx.size()) { + return context; + } + ContextElement[] newContexts = new ContextElement[length]; + System.arraycopy(fullContexts, 0, newContexts, 0, length); + return new ContextElements(newContexts, length); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java index 6b7aeba44c0..afab7d3e8aa 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/DebloatingSelector.java @@ -18,6 +18,7 @@ package qilin.parm.select; +import java.util.Set; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; @@ -25,38 +26,36 @@ import soot.Context; import sootup.core.model.SootMethod; -import java.util.Set; - public class DebloatingSelector extends CtxSelector { - protected final Set ctxDepHeaps; - - public DebloatingSelector(Set ctxDepHeaps) { - this.ctxDepHeaps = ctxDepHeaps; - } - - @Override - public Context select(SootMethod m, Context context) { - return context; - } - - @Override - public Context select(LocalVarNode lvn, Context context) { - return context; - } - - @Override - public Context select(FieldValNode fvn, Context context) { - return context; - } - - @Override - public Context select(AllocNode heap, Context context) { - Object ir = heap.getNewExpr(); - if (ctxDepHeaps.contains(ir)) { - return context; - } else { - return CtxConstructor.emptyContext; - } + protected final Set ctxDepHeaps; + + public DebloatingSelector(Set ctxDepHeaps) { + this.ctxDepHeaps = ctxDepHeaps; + } + + @Override + public Context select(SootMethod m, Context context) { + return context; + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return context; + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return context; + } + + @Override + public Context select(AllocNode heap, Context context) { + Object ir = heap.getNewExpr(); + if (ctxDepHeaps.contains(ir)) { + return context; + } else { + return CtxConstructor.emptyContext; } + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java index fbbecc78cda..11249617a53 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/FullMethodLvSelector.java @@ -18,45 +18,44 @@ package qilin.parm.select; +import java.util.Map; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import soot.Context; import sootup.core.model.SootMethod; -import java.util.Map; - public class FullMethodLvSelector extends CtxSelector { - private final int k; - /* - * Methods and its corresponding context length obtained by Data-driven (OOPSLA 2017). - * */ - private final Map m2len; - - public FullMethodLvSelector(Map m2len, int k) { - this.m2len = m2len; - this.k = k; - } - - @Override - public Context select(SootMethod m, Context context) { - return contextTailor(context, m2len.getOrDefault(m, 0)); - } - - @Override - public Context select(LocalVarNode lvn, Context context) { - SootMethod sm = lvn.getMethod(); - return contextTailor(context, m2len.getOrDefault(sm, 0)); - } - - @Override - public Context select(FieldValNode fvn, Context context) { - return contextTailor(context, k); - } - - @Override - public Context select(AllocNode heap, Context context) { - SootMethod sm = heap.getMethod(); - return contextTailor(context, Math.max(0, m2len.getOrDefault(sm, 0) - 1)); - } + private final int k; + /* + * Methods and its corresponding context length obtained by Data-driven (OOPSLA 2017). + * */ + private final Map m2len; + + public FullMethodLvSelector(Map m2len, int k) { + this.m2len = m2len; + this.k = k; + } + + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, m2len.getOrDefault(m, 0)); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + SootMethod sm = lvn.getMethod(); + return contextTailor(context, m2len.getOrDefault(sm, 0)); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(AllocNode heap, Context context) { + SootMethod sm = heap.getMethod(); + return contextTailor(context, Math.max(0, m2len.getOrDefault(sm, 0) - 1)); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java index 94fdf2eaa1d..acc2e80d760 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/HeuristicSelector.java @@ -28,26 +28,27 @@ public class HeuristicSelector extends CtxSelector { - @Override - public Context select(SootMethod m, Context context) { - return context; - } + @Override + public Context select(SootMethod m, Context context) { + return context; + } - @Override - public Context select(LocalVarNode lvn, Context context) { - return context; - } + @Override + public Context select(LocalVarNode lvn, Context context) { + return context; + } - @Override - public Context select(FieldValNode fvn, Context context) { - return context; - } + @Override + public Context select(FieldValNode fvn, Context context) { + return context; + } - @Override - public Context select(AllocNode heap, Context context) { - if (PTAUtils.isThrowable(heap.getType()) || PTAUtils.subtypeOfAbstractStringBuilder(heap.getType())) { - return CtxConstructor.emptyContext; - } - return context; + @Override + public Context select(AllocNode heap, Context context) { + if (PTAUtils.isThrowable(heap.getType()) + || PTAUtils.subtypeOfAbstractStringBuilder(heap.getType())) { + return CtxConstructor.emptyContext; } + return context; + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java index 637279bab33..9ca4d42696b 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/InsenSelector.java @@ -26,23 +26,23 @@ import sootup.core.model.SootMethod; public class InsenSelector extends CtxSelector { - @Override - public Context select(SootMethod m, Context context) { - return CtxConstructor.emptyContext; - } + @Override + public Context select(SootMethod m, Context context) { + return CtxConstructor.emptyContext; + } - @Override - public Context select(LocalVarNode lvn, Context context) { - return CtxConstructor.emptyContext; - } + @Override + public Context select(LocalVarNode lvn, Context context) { + return CtxConstructor.emptyContext; + } - @Override - public Context select(FieldValNode fvn, Context context) { - return contextTailor(context, 1); - } + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, 1); + } - @Override - public Context select(AllocNode heap, Context context) { - return CtxConstructor.emptyContext; - } + @Override + public Context select(AllocNode heap, Context context) { + return CtxConstructor.emptyContext; + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java index 93ed4142a68..3b5b7287214 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialMethodLvSelector.java @@ -18,6 +18,7 @@ package qilin.parm.select; +import java.util.Set; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; @@ -25,51 +26,49 @@ import soot.Context; import sootup.core.model.SootMethod; -import java.util.Set; - public class PartialMethodLvSelector extends CtxSelector { - private final int k; - private final int hk; - // precision-critical methods selected by the method-level approaches, e.g., Zipper. - private final Set pcm; + private final int k; + private final int hk; + // precision-critical methods selected by the method-level approaches, e.g., Zipper. + private final Set pcm; - public PartialMethodLvSelector(int k, int hk, Set pcm) { - this.k = k; - this.hk = hk; - this.pcm = pcm; - } + public PartialMethodLvSelector(int k, int hk, Set pcm) { + this.k = k; + this.hk = hk; + this.pcm = pcm; + } - @Override - public Context select(SootMethod m, Context context) { - if (pcm.contains(m)) { - return contextTailor(context, k); - } else { - return CtxConstructor.emptyContext; - } + @Override + public Context select(SootMethod m, Context context) { + if (pcm.contains(m)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; } + } - @Override - public Context select(LocalVarNode lvn, Context context) { - SootMethod sm = lvn.getMethod(); - if (pcm.contains(sm)) { - return contextTailor(context, k); - } else { - return CtxConstructor.emptyContext; - } + @Override + public Context select(LocalVarNode lvn, Context context) { + SootMethod sm = lvn.getMethod(); + if (pcm.contains(sm)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; } + } - @Override - public Context select(FieldValNode fvn, Context context) { - return contextTailor(context, k); - } + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } - @Override - public Context select(AllocNode heap, Context context) { - SootMethod sm = heap.getMethod(); - if (pcm.contains(sm)) { - return contextTailor(context, hk); - } else { - return context; - } + @Override + public Context select(AllocNode heap, Context context) { + SootMethod sm = heap.getMethod(); + if (pcm.contains(sm)) { + return contextTailor(context, hk); + } else { + return context; } + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java index 97e1d5348bd..e663f21a801 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PartialVarSelector.java @@ -18,6 +18,7 @@ package qilin.parm.select; +import java.util.Set; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; @@ -25,58 +26,56 @@ import soot.Context; import sootup.core.model.SootMethod; -import java.util.Set; - public class PartialVarSelector extends CtxSelector { - private final int k; - private final int hk; - // precision-critical nodes selected by the partial-variable-level approaches, e.g., Eagle, Turner. - private final Set csnodes; - private final Set pcm; + private final int k; + private final int hk; + // precision-critical nodes selected by the partial-variable-level approaches, e.g., Eagle, + // Turner. + private final Set csnodes; + private final Set pcm; - public PartialVarSelector(int k, int hk, Set csnodes, Set pcm) { - this.k = k; - this.hk = hk; - this.csnodes = csnodes; - this.pcm = pcm; - } + public PartialVarSelector(int k, int hk, Set csnodes, Set pcm) { + this.k = k; + this.hk = hk; + this.csnodes = csnodes; + this.pcm = pcm; + } - @Override - public Context select(SootMethod m, Context context) { - if (pcm.contains(m)) { - return contextTailor(context, k); - } else { - return CtxConstructor.emptyContext; - } + @Override + public Context select(SootMethod m, Context context) { + if (pcm.contains(m)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; } + } - @Override - public Context select(LocalVarNode lvn, Context context) { - Object ir = lvn.getVariable(); - if (csnodes.contains(ir)) { - return contextTailor(context, k); - } else { - return CtxConstructor.emptyContext; - } + @Override + public Context select(LocalVarNode lvn, Context context) { + Object ir = lvn.getVariable(); + if (csnodes.contains(ir)) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; } + } - - @Override - public Context select(FieldValNode fvn, Context context) { - if (csnodes.contains(fvn.getField())) { - return contextTailor(context, k); - } else { - return CtxConstructor.emptyContext; - } + @Override + public Context select(FieldValNode fvn, Context context) { + if (csnodes.contains(fvn.getField())) { + return contextTailor(context, k); + } else { + return CtxConstructor.emptyContext; } + } - @Override - public Context select(AllocNode heap, Context context) { - Object ir = heap.getNewExpr(); - if (csnodes.contains(ir)) { - return contextTailor(context, hk); - } else { - return CtxConstructor.emptyContext; - } + @Override + public Context select(AllocNode heap, Context context) { + Object ir = heap.getNewExpr(); + if (csnodes.contains(ir)) { + return contextTailor(context, hk); + } else { + return CtxConstructor.emptyContext; } + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java index 630b0b4b279..3721114b992 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/PipelineSelector.java @@ -28,31 +28,31 @@ * A pipeline context selector which selects context by firstly using ctxSelA and then ctxSelB. * */ public class PipelineSelector extends CtxSelector { - private final CtxSelector ctxSelA; - private final CtxSelector ctxSelB; - - public PipelineSelector(CtxSelector lenSelA, CtxSelector lenSelB) { - this.ctxSelA = lenSelA; - this.ctxSelB = lenSelB; - } - - @Override - public Context select(SootMethod m, Context context) { - return ctxSelB.select(m, ctxSelA.select(m, context)); - } - - @Override - public Context select(LocalVarNode lvn, Context context) { - return ctxSelA.select(lvn, ctxSelB.select(lvn, context)); - } - - @Override - public Context select(FieldValNode fvn, Context context) { - return ctxSelA.select(fvn, ctxSelB.select(fvn, context)); - } - - @Override - public Context select(AllocNode heap, Context context) { - return ctxSelA.select(heap, ctxSelB.select(heap, context)); - } + private final CtxSelector ctxSelA; + private final CtxSelector ctxSelB; + + public PipelineSelector(CtxSelector lenSelA, CtxSelector lenSelB) { + this.ctxSelA = lenSelA; + this.ctxSelB = lenSelB; + } + + @Override + public Context select(SootMethod m, Context context) { + return ctxSelB.select(m, ctxSelA.select(m, context)); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return ctxSelA.select(lvn, ctxSelB.select(lvn, context)); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return ctxSelA.select(fvn, ctxSelB.select(fvn, context)); + } + + @Override + public Context select(AllocNode heap, Context context) { + return ctxSelA.select(heap, ctxSelB.select(heap, context)); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java index c5e3c3ea26f..4ab2c0d1f1f 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/UniformSelector.java @@ -25,31 +25,31 @@ import sootup.core.model.SootMethod; public class UniformSelector extends CtxSelector { - private final int k; - private final int hk; - - public UniformSelector(int k, int hk) { - this.k = k; - this.hk = hk; - } - - @Override - public Context select(SootMethod m, Context context) { - return contextTailor(context, k); - } - - @Override - public Context select(LocalVarNode lvn, Context context) { - return contextTailor(context, k); - } - - @Override - public Context select(FieldValNode fvn, Context context) { - return contextTailor(context, k); - } - - @Override - public Context select(AllocNode heap, Context context) { - return contextTailor(context, hk); - } + private final int k; + private final int hk; + + public UniformSelector(int k, int hk) { + this.k = k; + this.hk = hk; + } + + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(LocalVarNode lvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, k); + } + + @Override + public Context select(AllocNode heap, Context context) { + return contextTailor(context, hk); + } } diff --git a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java index 4f49bdaee19..b19406d02a6 100644 --- a/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java +++ b/sootup.qilin/src/main/java/qilin/parm/select/VarLvSelector.java @@ -18,52 +18,52 @@ package qilin.parm.select; +import java.util.Map; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; import soot.Context; import sootup.core.model.SootMethod; -import java.util.Map; - /* * This class is for a future technique and thus currently has no usage. * */ public class VarLvSelector extends CtxSelector { - private final int k; - private final int hk; - /* mapping from nodes to the context length they require. - * This is designed for a future approaches. - */ - private final Map node2Len; - private final Map mthd2Len; + private final int k; + private final int hk; + /* mapping from nodes to the context length they require. + * This is designed for a future approaches. + */ + private final Map node2Len; + private final Map mthd2Len; - public VarLvSelector(int k, int hk, Map node2Len, Map m2len) { - this.k = k; - this.hk = hk; - this.node2Len = node2Len; - this.mthd2Len = m2len; - } + public VarLvSelector( + int k, int hk, Map node2Len, Map m2len) { + this.k = k; + this.hk = hk; + this.node2Len = node2Len; + this.mthd2Len = m2len; + } - @Override - public Context select(SootMethod m, Context context) { - return contextTailor(context, Math.min(k, mthd2Len.getOrDefault(m, 0))); - } + @Override + public Context select(SootMethod m, Context context) { + return contextTailor(context, Math.min(k, mthd2Len.getOrDefault(m, 0))); + } - @Override - public Context select(LocalVarNode lvn, Context context) { - Object ir = lvn.getVariable(); - return contextTailor(context, Math.min(k, node2Len.getOrDefault(ir, 0))); - } + @Override + public Context select(LocalVarNode lvn, Context context) { + Object ir = lvn.getVariable(); + return contextTailor(context, Math.min(k, node2Len.getOrDefault(ir, 0))); + } - @Override - public Context select(FieldValNode fvn, Context context) { - return contextTailor(context, Math.min(k, node2Len.getOrDefault(fvn.getField(), 0))); - } + @Override + public Context select(FieldValNode fvn, Context context) { + return contextTailor(context, Math.min(k, node2Len.getOrDefault(fvn.getField(), 0))); + } - @Override - public Context select(AllocNode heap, Context context) { - Object ir = heap.getNewExpr(); - return contextTailor(context, Math.min(hk, node2Len.getOrDefault(ir, 0))); - } + @Override + public Context select(AllocNode heap, Context context) { + Object ir = heap.getNewExpr(); + return contextTailor(context, Math.min(hk, node2Len.getOrDefault(ir, 0))); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java b/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java index 87995973128..671ef62f9e7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java +++ b/sootup.qilin/src/main/java/qilin/pta/PTAConfig.java @@ -23,64 +23,52 @@ import qilin.pta.tools.DebloatedPTA; public class PTAConfig extends CoreConfig { - private static PTAConfig config = null; + private static PTAConfig config = null; - public static PTAConfig v() { - if (config == null) { - config = new PTAConfig(); - coreConfig = config; - } - return config; + public static PTAConfig v() { + if (config == null) { + config = new PTAConfig(); + coreConfig = config; } + return config; + } - public static void reset() { - CoreConfig.reset(); - config = null; - } - - public static class PointerAnalysisConfiguration extends CorePTAConfiguration { - public PTAPattern ptaPattern; + public static void reset() { + CoreConfig.reset(); + config = null; + } - /** - * If this option is turned on, then main analysis will not run. - */ - public boolean preAnalysisOnly = false; + public static class PointerAnalysisConfiguration extends CorePTAConfiguration { + public PTAPattern ptaPattern; - /** - * If this option is turned on, we will apply context debloating techniques. - */ - public boolean ctxDebloating = false; - public DebloatedPTA.DebloatApproach debloatApproach = DebloatedPTA.DebloatApproach.CONCH; - - } + /** If this option is turned on, then main analysis will not run. */ + public boolean preAnalysisOnly = false; - /* - * Notice that the DEFAULT option is equivalent to Full Turner. - * PHASE_TWO: all objects are assumed to be CS-likely. - * PHASE_ONE: only non-CS-likely objects are analyzed context-insensitively. All other variables and objects - * are analyzed context-sensitively. - * */ - public enum TurnerConfig { - DEFAULT, PHASE_TWO, PHASE_ONE - } + /** If this option is turned on, we will apply context debloating techniques. */ + public boolean ctxDebloating = false; - public TurnerConfig turnerConfig = TurnerConfig.DEFAULT; + public DebloatedPTA.DebloatApproach debloatApproach = DebloatedPTA.DebloatApproach.CONCH; + } - private PTAConfig() { - this.ptaConfig = new PointerAnalysisConfiguration(); - } + /* + * Notice that the DEFAULT option is equivalent to Full Turner. + * PHASE_TWO: all objects are assumed to be CS-likely. + * PHASE_ONE: only non-CS-likely objects are analyzed context-insensitively. All other variables and objects + * are analyzed context-sensitively. + * */ + public enum TurnerConfig { + DEFAULT, + PHASE_TWO, + PHASE_ONE + } - public PointerAnalysisConfiguration getPtaConfig() { - return (PointerAnalysisConfiguration) this.ptaConfig; - } + public TurnerConfig turnerConfig = TurnerConfig.DEFAULT; - /* - * Configures the callgraph options - * */ - public enum CallgraphAlgorithm { - /*CHA, VTA, RTA, GEOM, and SPARK are all provided by Soot */ - CHA, VTA, RTA, GEOM, SPARK, QILIN - } + private PTAConfig() { + this.ptaConfig = new PointerAnalysisConfiguration(); + } - public CallgraphAlgorithm callgraphAlg = CallgraphAlgorithm.QILIN; + public PointerAnalysisConfiguration getPtaConfig() { + return (PointerAnalysisConfiguration) this.ptaConfig; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java index abbc0ece48e..5d743a2af8b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/Bean.java @@ -18,6 +18,9 @@ package qilin.pta.toolkits.bean; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import qilin.core.PTA; import qilin.core.context.ContextElements; import qilin.core.pag.AllocNode; @@ -26,52 +29,64 @@ import qilin.util.Pair; import qilin.util.Stopwatch; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - public class Bean { - public static void run(PTA pta, Map>> beanNexCtxMap) { - System.out.println("Constructing object allocation graph (OAG) ..."); - Stopwatch timer = Stopwatch.newAndStart("OAG construction"); - OAG oag = new OAG(pta); - oag.build(); - timer.stop(); - System.out.print(ANSIColor.BOLD + "OAG construction: " + ANSIColor.GREEN + - String.format("%.2fs", timer.elapsed()) + ANSIColor.RESET + "\n"); + public static void run(PTA pta, Map>> beanNexCtxMap) { + System.out.println("Constructing object allocation graph (OAG) ..."); + Stopwatch timer = Stopwatch.newAndStart("OAG construction"); + OAG oag = new OAG(pta); + oag.build(); + timer.stop(); + System.out.print( + ANSIColor.BOLD + + "OAG construction: " + + ANSIColor.GREEN + + String.format("%.2fs", timer.elapsed()) + + ANSIColor.RESET + + "\n"); - System.out.println("Computing contexts..."); - timer.restart(); - // The depth indicates the depth of heap context. - // The method context has 1 more level than heap context. - // Here depth is 1 which corresponds to 2-object-sensitive analysis - // with 1 heap context. - ContextSelector cs = new RepresentativeContextSelector(oag, 1); - timer.stop(); - System.out.print(ANSIColor.BOLD + "Context computation: " + ANSIColor.GREEN + - String.format("%.2fs", timer.elapsed()) + ANSIColor.RESET + "\n"); + System.out.println("Computing contexts..."); + timer.restart(); + // The depth indicates the depth of heap context. + // The method context has 1 more level than heap context. + // Here depth is 1 which corresponds to 2-object-sensitive analysis + // with 1 heap context. + ContextSelector cs = new RepresentativeContextSelector(oag, 1); + timer.stop(); + System.out.print( + ANSIColor.BOLD + + "Context computation: " + + ANSIColor.GREEN + + String.format("%.2fs", timer.elapsed()) + + ANSIColor.RESET + + "\n"); - writeContext(cs, oag, beanNexCtxMap); - } + writeContext(cs, oag, beanNexCtxMap); + } - /* - * Should be generalized for k >= 3. - * */ - private static void writeContext(ContextSelector cs, OAG oag, Map>> beanNexCtxMap) { - oag.allNodes().forEach(allocator -> { - Set ctxs = cs.contextsOf(allocator); - for (ContextElements ctx : ctxs) { + /* + * Should be generalized for k >= 3. + * */ + private static void writeContext( + ContextSelector cs, OAG oag, Map>> beanNexCtxMap) { + oag.allNodes() + .forEach( + allocator -> { + Set ctxs = cs.contextsOf(allocator); + for (ContextElements ctx : ctxs) { AllocNode allocHctx = (AllocNode) ctx.get(0); Set> csheaps = cs.allocatedBy(ctx, allocator); if (csheaps != null) { - csheaps.forEach(csheap -> { + csheaps.forEach( + csheap -> { AllocNode newHctx = (AllocNode) csheap.getFirst().get(0); AllocNode heap = csheap.getSecond(); - beanNexCtxMap.computeIfAbsent(heap.getNewExpr(), k -> new HashMap<>()).computeIfAbsent(allocator.getNewExpr(), k -> new HashMap<>()).put(allocHctx.getNewExpr(), newHctx.getNewExpr()); - }); + beanNexCtxMap + .computeIfAbsent(heap.getNewExpr(), k -> new HashMap<>()) + .computeIfAbsent(allocator.getNewExpr(), k -> new HashMap<>()) + .put(allocHctx.getNewExpr(), newHctx.getNewExpr()); + }); } - } - }); - } - + } + }); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java index a3ee4260ac2..f9223e10ce3 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/ContextSelector.java @@ -18,48 +18,46 @@ package qilin.pta.toolkits.bean; -import qilin.core.context.ContextElements; -import qilin.core.pag.AllocNode; -import qilin.pta.toolkits.common.OAG; -import qilin.util.Pair; - import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import qilin.core.context.ContextElements; +import qilin.core.pag.AllocNode; +import qilin.pta.toolkits.common.OAG; +import qilin.util.Pair; -/** - * Compute the contexts of each heap object via OAG. - */ +/** Compute the contexts of each heap object via OAG. */ public abstract class ContextSelector { - protected int depth; // the depth of context - protected Map> contextMap; - protected Map, Set>> allocation = - new HashMap<>(); + protected int depth; // the depth of context + protected Map> contextMap; + protected Map, Set>> + allocation = new HashMap<>(); - protected ContextSelector(OAG oag) { - this(oag, Integer.MAX_VALUE); - } + protected ContextSelector(OAG oag) { + this(oag, Integer.MAX_VALUE); + } - protected ContextSelector(OAG oag, int depth) { - this.depth = depth; - selectContext(oag); - } + protected ContextSelector(OAG oag, int depth) { + this.depth = depth; + selectContext(oag); + } - public Set contextsOf(AllocNode heap) { - return contextMap.get(heap); - } + public Set contextsOf(AllocNode heap) { + return contextMap.get(heap); + } - public Set> allocatedBy(ContextElements ctx, AllocNode heap) { - return allocation.get(new Pair<>(ctx, heap)); - } + public Set> allocatedBy(ContextElements ctx, AllocNode heap) { + return allocation.get(new Pair<>(ctx, heap)); + } - protected abstract void selectContext(OAG oag); + protected abstract void selectContext(OAG oag); - protected void addAllocation(ContextElements ctx, AllocNode heap, ContextElements newCtx, AllocNode succ) { - Pair csheap = new Pair<>(ctx, heap); - allocation.computeIfAbsent(csheap, k -> new HashSet<>()); - allocation.get(csheap).add(new Pair<>(newCtx, succ)); - } + protected void addAllocation( + ContextElements ctx, AllocNode heap, ContextElements newCtx, AllocNode succ) { + Pair csheap = new Pair<>(ctx, heap); + allocation.computeIfAbsent(csheap, k -> new HashSet<>()); + allocation.get(csheap).add(new Pair<>(newCtx, succ)); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java index 95f6acf226e..bca3654bd96 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/bean/RepresentativeContextSelector.java @@ -18,105 +18,112 @@ package qilin.pta.toolkits.bean; +import java.util.*; +import java.util.stream.Collectors; import qilin.core.context.ContextElements; import qilin.core.pag.AllocNode; import qilin.parm.ctxcons.CtxConstructor; import qilin.pta.toolkits.common.OAG; import qilin.util.Triple; -import java.util.*; -import java.util.stream.Collectors; - /** - * Context selector of BEAN. This selector aims to avoid redundant - * context elements while selecting contexts. + * Context selector of BEAN. This selector aims to avoid redundant context elements while selecting + * contexts. */ public class RepresentativeContextSelector extends ContextSelector { - public RepresentativeContextSelector(OAG oag, int depth) { - super(oag, depth); - } + public RepresentativeContextSelector(OAG oag, int depth) { + super(oag, depth); + } - @Override - protected void selectContext(OAG oag) { - contextMap = new HashMap<>(); - oag.tailNodes().forEach(node -> { - mergeContextMap(selectContext(oag, node)); - }); - oag.allNodes().forEach(node -> { - if (!contextMap.containsKey(node)) { + @Override + protected void selectContext(OAG oag) { + contextMap = new HashMap<>(); + oag.tailNodes() + .forEach( + node -> { + mergeContextMap(selectContext(oag, node)); + }); + oag.allNodes() + .forEach( + node -> { + if (!contextMap.containsKey(node)) { mergeContextMap(selectContext(oag, node)); - } - }); - } + } + }); + } - private Map> selectContext(OAG oag, AllocNode dest) { - Map> tempContextMap = new HashMap<>(); - Queue> worklist = new LinkedList<>(); - initialWorkList(worklist, oag, dest); - while (!worklist.isEmpty()) { - Triple triple = worklist.poll(); - AllocNode heap = triple.getFirst(); - ContextElements ctx = triple.getSecond(); - boolean split = triple.getThird(); - if (!tempContextMap.containsKey(heap)) { - tempContextMap.put(heap, new HashSet<>()); - } - if (tempContextMap.get(heap).add(ctx)) { - Set reachSuccs = selectReachNodes(oag.getSuccsOf(heap), dest, oag); - final boolean isFork = reachSuccs.size() > 1; - reachSuccs.forEach(succ -> { - final boolean isJoinSucc = oag.getInDegreeOf(succ) > 1; - ContextElements newCtx; - boolean succSplit = split; - if (split && isJoinSucc && !ctx.contains(heap)) { - newCtx = ContextElements.newContext(ctx, heap, depth); - succSplit = false; - } else { - newCtx = ctx; - } - if (isFork) { - succSplit = true; - } - Set ctxs = tempContextMap.get(succ); - if (ctxs == null || !ctxs.contains(newCtx)) { - addAllocation(ctx, heap, newCtx, succ); - worklist.add(new Triple<>(succ, newCtx, succSplit)); - } - }); - } - } - return tempContextMap; + private Map> selectContext(OAG oag, AllocNode dest) { + Map> tempContextMap = new HashMap<>(); + Queue> worklist = new LinkedList<>(); + initialWorkList(worklist, oag, dest); + while (!worklist.isEmpty()) { + Triple triple = worklist.poll(); + AllocNode heap = triple.getFirst(); + ContextElements ctx = triple.getSecond(); + boolean split = triple.getThird(); + if (!tempContextMap.containsKey(heap)) { + tempContextMap.put(heap, new HashSet<>()); + } + if (tempContextMap.get(heap).add(ctx)) { + Set reachSuccs = selectReachNodes(oag.getSuccsOf(heap), dest, oag); + final boolean isFork = reachSuccs.size() > 1; + reachSuccs.forEach( + succ -> { + final boolean isJoinSucc = oag.getInDegreeOf(succ) > 1; + ContextElements newCtx; + boolean succSplit = split; + if (split && isJoinSucc && !ctx.contains(heap)) { + newCtx = ContextElements.newContext(ctx, heap, depth); + succSplit = false; + } else { + newCtx = ctx; + } + if (isFork) { + succSplit = true; + } + Set ctxs = tempContextMap.get(succ); + if (ctxs == null || !ctxs.contains(newCtx)) { + addAllocation(ctx, heap, newCtx, succ); + worklist.add(new Triple<>(succ, newCtx, succSplit)); + } + }); + } } + return tempContextMap; + } - private void mergeContextMap(Map> anoContextMap) { - anoContextMap.forEach((heap, ctxs) -> { - if (contextMap.containsKey(heap)) { - contextMap.get(heap).addAll(ctxs); - } else { - contextMap.put(heap, ctxs); - } + private void mergeContextMap(Map> anoContextMap) { + anoContextMap.forEach( + (heap, ctxs) -> { + if (contextMap.containsKey(heap)) { + contextMap.get(heap).addAll(ctxs); + } else { + contextMap.put(heap, ctxs); + } }); - } + } - /** - * Select the nodes from a node set which can reach the destination node - * - * @param nodes - * @param dest - * @param oag - * @return - */ - private Set selectReachNodes(Collection nodes, AllocNode dest, OAG oag) { - return nodes.stream().filter(node -> oag.reaches(node, dest)).collect(Collectors.toSet()); - } - - private void initialWorkList(Queue> worklist, OAG oag, AllocNode node) { - Set reachRoots = selectReachNodes(oag.rootNodes(), node, oag); - boolean split = reachRoots.size() > 1; - ContextElements emptyCtx = (ContextElements) CtxConstructor.emptyContext; - reachRoots.forEach(root -> - worklist.add(new Triple<>(root, ContextElements.newContext(emptyCtx, root, depth), split))); - } + /** + * Select the nodes from a node set which can reach the destination node + * + * @param nodes + * @param dest + * @param oag + * @return + */ + private Set selectReachNodes(Collection nodes, AllocNode dest, OAG oag) { + return nodes.stream().filter(node -> oag.reaches(node, dest)).collect(Collectors.toSet()); + } + private void initialWorkList( + Queue> worklist, OAG oag, AllocNode node) { + Set reachRoots = selectReachNodes(oag.rootNodes(), node, oag); + boolean split = reachRoots.size() > 1; + ContextElements emptyCtx = (ContextElements) CtxConstructor.emptyContext; + reachRoots.forEach( + root -> + worklist.add( + new Triple<>(root, ContextElements.newContext(emptyCtx, root, depth), split))); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java index 37a96a38ed8..70675b8ec51 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/DebloatedOAG.java @@ -1,29 +1,26 @@ package qilin.pta.toolkits.common; -import qilin.core.PTA; -import qilin.core.pag.AllocNode; - import java.util.HashSet; import java.util.Set; +import qilin.core.PTA; +import qilin.core.pag.AllocNode; public class DebloatedOAG extends OAG { - private final Set ctxDepHeaps; + private final Set ctxDepHeaps; - public DebloatedOAG(PTA prePta, Set ctxDepHeaps) { - super(prePta); - this.ctxDepHeaps = ctxDepHeaps; - } + public DebloatedOAG(PTA prePta, Set ctxDepHeaps) { + super(prePta); + this.ctxDepHeaps = ctxDepHeaps; + } - @Override - /** - * Add a directed object allocation edge to the OAG. - */ - protected void addEdge(AllocNode src, AllocNode tgt) { - nodes.add(src); - nodes.add(tgt); - if (this.ctxDepHeaps.contains(tgt)) { - this.predecessors.computeIfAbsent(tgt, k -> new HashSet<>()).add(src); - this.successors.computeIfAbsent(src, k -> new HashSet<>()).add(tgt); - } + @Override + /** Add a directed object allocation edge to the OAG. */ + protected void addEdge(AllocNode src, AllocNode tgt) { + nodes.add(src); + nodes.add(tgt); + if (this.ctxDepHeaps.contains(tgt)) { + this.predecessors.computeIfAbsent(tgt, k -> new HashSet<>()).add(src); + this.successors.computeIfAbsent(src, k -> new HashSet<>()).add(tgt); } + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java index 37e6d39b0a5..09b0072f85c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/FieldPointstoGraph.java @@ -18,89 +18,88 @@ package qilin.pta.toolkits.common; +import java.util.*; import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; import qilin.core.pag.SparkField; import qilin.core.sets.PointsToSet; -import java.util.*; - public class FieldPointstoGraph { - private final Map>> pointsTo = new HashMap<>(); - private final Map>> pointedBy = new HashMap<>(); - - public FieldPointstoGraph(PTA pta) { - buildFPG(pta); - } - - private void buildFPG(PTA pta) { - PAG pag = pta.getPag(); - pag.getAllocNodes().forEach(this::insertObj); - pag.getContextFields().forEach(contextField -> { - AllocNode base = contextField.getBase(); - if (base.getMethod() == null) { + private final Map>> pointsTo = new HashMap<>(); + private final Map>> pointedBy = new HashMap<>(); + + public FieldPointstoGraph(PTA pta) { + buildFPG(pta); + } + + private void buildFPG(PTA pta) { + PAG pag = pta.getPag(); + pag.getAllocNodes().forEach(this::insertObj); + pag.getContextFields() + .forEach( + contextField -> { + AllocNode base = contextField.getBase(); + if (base.getMethod() == null) { return; - } - SparkField field = contextField.getField(); - PointsToSet pts = pta.reachingObjects(contextField).toCIPointsToSet(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { + } + SparkField field = contextField.getField(); + PointsToSet pts = pta.reachingObjects(contextField).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { AllocNode n = it.next(); insertFPT(base, field, n); - } - }); - } - - public Set getAllObjs() { - return pointsTo.keySet(); - } - - public Set outFieldsOf(AllocNode baseObj) { - return pointsTo.getOrDefault(baseObj, Collections.emptyMap()).keySet(); - } - - public Set inFieldsOf(AllocNode obj) { - return pointedBy.get(obj).keySet(); - } - - public Set pointsTo(AllocNode baseObj, SparkField field) { - return pointsTo.get(baseObj).get(field); - } - - public Set pointedBy(AllocNode obj, SparkField field) { - return pointedBy.get(obj).get(field); - } - - public boolean hasFieldPointer(AllocNode obj, SparkField field) { - return pointsTo.get(obj).containsKey(field); - } - - - private void insertObj(AllocNode obj) { - pointsTo.computeIfAbsent(obj, k -> new HashMap<>()); - pointedBy.computeIfAbsent(obj, k -> new HashMap<>()); - } - - /** - * Insert field points-to relation. - * - * @param baseObj the base object - * @param field a field of `baseObj' - * @param obj the object pointed by `field' - */ - private void insertFPT(AllocNode baseObj, SparkField field, AllocNode obj) { - insertPointsTo(baseObj, field, obj); - insertPointedBy(baseObj, field, obj); - } - - private void insertPointsTo(AllocNode baseObj, SparkField field, AllocNode obj) { - Map> fpt = pointsTo.computeIfAbsent(baseObj, k -> new HashMap<>()); - fpt.computeIfAbsent(field, k -> new HashSet<>()).add(obj); - } - - private void insertPointedBy(AllocNode baseObj, SparkField field, AllocNode obj) { - Map> fpb = pointedBy.computeIfAbsent(obj, k -> new HashMap<>()); - fpb.computeIfAbsent(field, k -> new HashSet<>()).add(baseObj); - } - + } + }); + } + + public Set getAllObjs() { + return pointsTo.keySet(); + } + + public Set outFieldsOf(AllocNode baseObj) { + return pointsTo.getOrDefault(baseObj, Collections.emptyMap()).keySet(); + } + + public Set inFieldsOf(AllocNode obj) { + return pointedBy.get(obj).keySet(); + } + + public Set pointsTo(AllocNode baseObj, SparkField field) { + return pointsTo.get(baseObj).get(field); + } + + public Set pointedBy(AllocNode obj, SparkField field) { + return pointedBy.get(obj).get(field); + } + + public boolean hasFieldPointer(AllocNode obj, SparkField field) { + return pointsTo.get(obj).containsKey(field); + } + + private void insertObj(AllocNode obj) { + pointsTo.computeIfAbsent(obj, k -> new HashMap<>()); + pointedBy.computeIfAbsent(obj, k -> new HashMap<>()); + } + + /** + * Insert field points-to relation. + * + * @param baseObj the base object + * @param field a field of `baseObj' + * @param obj the object pointed by `field' + */ + private void insertFPT(AllocNode baseObj, SparkField field, AllocNode obj) { + insertPointsTo(baseObj, field, obj); + insertPointedBy(baseObj, field, obj); + } + + private void insertPointsTo(AllocNode baseObj, SparkField field, AllocNode obj) { + Map> fpt = pointsTo.computeIfAbsent(baseObj, k -> new HashMap<>()); + fpt.computeIfAbsent(field, k -> new HashSet<>()).add(obj); + } + + private void insertPointedBy(AllocNode baseObj, SparkField field, AllocNode obj) { + Map> fpb = pointedBy.computeIfAbsent(obj, k -> new HashMap<>()); + fpb.computeIfAbsent(field, k -> new HashSet<>()).add(baseObj); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java index d0c550388b5..1826e32f681 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/OAG.java @@ -18,6 +18,7 @@ package qilin.pta.toolkits.common; +import java.util.*; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.AllocNode; @@ -29,134 +30,130 @@ import soot.util.queue.QueueReader; import sootup.core.model.SootMethod; -import java.util.*; - -/** - * Implementation of Object Allocation Graph (OAG). - */ +/** Implementation of Object Allocation Graph (OAG). */ public class OAG implements DirectedGraph { - protected final PTA pta; - protected final Map> successors; - protected final Map> predecessors; - protected final Set nodes = new HashSet<>(); - protected Collection rootNodes; - protected Collection tailNodes; - - public OAG(PTA prePta) { - this.pta = prePta; - this.predecessors = new HashMap<>(); - this.successors = new HashMap<>(); + protected final PTA pta; + protected final Map> successors; + protected final Map> predecessors; + protected final Set nodes = new HashSet<>(); + protected Collection rootNodes; + protected Collection tailNodes; + + public OAG(PTA prePta) { + this.pta = prePta; + this.predecessors = new HashMap<>(); + this.successors = new HashMap<>(); + } + + public void build() { + buildOAG(); + rootNodes = computeRootNodes(); + tailNodes = computeTailNodes(); + } + + @Override + public Collection allNodes() { + return nodes; + } + + @Override + public Collection predsOf(AllocNode p) { + return getPredsOf(p); + } + + @Override + public Collection succsOf(AllocNode p) { + return getSuccsOf(p); + } + + public Collection rootNodes() { + return rootNodes; + } + + public Collection tailNodes() { + return tailNodes; + } + + public Set getPredsOf(AllocNode n) { + return predecessors.getOrDefault(n, Collections.emptySet()); + } + + public Set getSuccsOf(AllocNode n) { + return successors.getOrDefault(n, Collections.emptySet()); + } + + public int getInDegreeOf(AllocNode n) { + return getPredsOf(n).size(); + } + + /** + * @param source + * @param dest + * @return whether there is a path from source to target in the OAG + */ + Map> reachableMap = new HashMap<>(); + + public boolean reaches(AllocNode source, AllocNode dest) { + Collection reachableNodes = reachableMap.get(source); + if (reachableNodes == null) { + reachableNodes = computeReachableNodes(source); + reachableMap.put(source, reachableNodes); } - - public void build() { - buildOAG(); - rootNodes = computeRootNodes(); - tailNodes = computeTailNodes(); - } - - @Override - public Collection allNodes() { - return nodes; - } - - @Override - public Collection predsOf(AllocNode p) { - return getPredsOf(p); - } - - @Override - public Collection succsOf(AllocNode p) { - return getSuccsOf(p); - } - - public Collection rootNodes() { - return rootNodes; - } - - public Collection tailNodes() { - return tailNodes; - } - - public Set getPredsOf(AllocNode n) { - return predecessors.getOrDefault(n, Collections.emptySet()); - } - - public Set getSuccsOf(AllocNode n) { - return successors.getOrDefault(n, Collections.emptySet()); - } - - public int getInDegreeOf(AllocNode n) { - return getPredsOf(n).size(); - } - - /** - * @param source - * @param dest - * @return whether there is a path from source to target in the OAG - */ - Map> reachableMap = new HashMap<>(); - - public boolean reaches(AllocNode source, AllocNode dest) { - Collection reachableNodes = reachableMap.get(source); - if (reachableNodes == null) { - reachableNodes = computeReachableNodes(source); - reachableMap.put(source, reachableNodes); - } - return reachableNodes.contains(dest); - } - - protected void buildOAG() { - Map> pts = PTAUtils.calcStaticThisPTS(this.pta); - for (SootMethod method : this.pta.getNakedReachableMethods()) { - if (!method.isConcrete()) { - continue; - } - MethodPAG srcmpag = pta.getPag().getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - qilin.core.pag.Node from = reader.next(), to = reader.next(); - if (from instanceof AllocNode tgt) { - if (PTAUtils.isFakeMainMethod(method)) { - // special treatment for fake main - AllocNode src = pta.getRootNode(); - addEdge(src, tgt); - } else if (method.isStatic()) { - pts.getOrDefault(thisRef, Collections.emptySet()).forEach(src -> { - addEdge(src, tgt); - }); - } else { - PointsToSet thisPts = pta.reachingObjects(thisRef).toCIPointsToSet(); - for (Iterator it = thisPts.iterator(); it.hasNext(); ) { - AllocNode src = it.next(); - addEdge(src, tgt); - } - } - } + return reachableNodes.contains(dest); + } + + protected void buildOAG() { + Map> pts = PTAUtils.calcStaticThisPTS(this.pta); + for (SootMethod method : this.pta.getNakedReachableMethods()) { + if (!method.isConcrete()) { + continue; + } + MethodPAG srcmpag = pta.getPag().getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + qilin.core.pag.Node from = reader.next(), to = reader.next(); + if (from instanceof AllocNode tgt) { + if (PTAUtils.isFakeMainMethod(method)) { + // special treatment for fake main + AllocNode src = pta.getRootNode(); + addEdge(src, tgt); + } else if (method.isStatic()) { + pts.getOrDefault(thisRef, Collections.emptySet()) + .forEach( + src -> { + addEdge(src, tgt); + }); + } else { + PointsToSet thisPts = pta.reachingObjects(thisRef).toCIPointsToSet(); + for (Iterator it = thisPts.iterator(); it.hasNext(); ) { + AllocNode src = it.next(); + addEdge(src, tgt); } + } } + } } - - /** - * Add a directed object allocation edge to the OAG. - */ - protected void addEdge(AllocNode src, AllocNode tgt) { - nodes.add(src); - nodes.add(tgt); - this.predecessors.computeIfAbsent(tgt, k -> new HashSet<>()).add(src); - this.successors.computeIfAbsent(src, k -> new HashSet<>()).add(tgt); - } - - public int nodeSize() { - return this.nodes.size(); - } - - public int edgeSize() { - int ret = 0; - for (AllocNode obj : predecessors.keySet()) { - ret += predecessors.get(obj).size(); - } - return ret; + } + + /** Add a directed object allocation edge to the OAG. */ + protected void addEdge(AllocNode src, AllocNode tgt) { + nodes.add(src); + nodes.add(tgt); + this.predecessors.computeIfAbsent(tgt, k -> new HashSet<>()).add(src); + this.successors.computeIfAbsent(src, k -> new HashSet<>()).add(tgt); + } + + public int nodeSize() { + return this.nodes.size(); + } + + public int edgeSize() { + int ret = 0; + for (AllocNode obj : predecessors.keySet()) { + ret += predecessors.get(obj).size(); } + return ret; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java index 9e404d0e604..c84c37049d3 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/common/ToolUtil.java @@ -18,6 +18,9 @@ package qilin.pta.toolkits.common; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; @@ -28,57 +31,53 @@ import sootup.core.types.ClassType; import sootup.core.types.ReferenceType; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - public class ToolUtil { - public static VarNode getThis(PAG pag, SootMethod m) { - MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); - return mthdNF.caseThis(); - } + public static VarNode getThis(PAG pag, SootMethod m) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + return mthdNF.caseThis(); + } - public static Set getParameters(PAG pag, SootMethod m) { - MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); - Set ret = new HashSet<>(); - for (int i = 0; i < m.getParameterCount(); ++i) { - if (m.getParameterType(i) instanceof ReferenceType) { - qilin.core.pag.VarNode param = mthdNF.caseParm(i); - ret.add(param); - } - } - return ret; + public static Set getParameters(PAG pag, SootMethod m) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + Set ret = new HashSet<>(); + for (int i = 0; i < m.getParameterCount(); ++i) { + if (m.getParameterType(i) instanceof ReferenceType) { + qilin.core.pag.VarNode param = mthdNF.caseParm(i); + ret.add(param); + } } + return ret; + } - public static Set getRetVars(PAG pag, SootMethod m) { - MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); - if (m.getReturnType() instanceof ReferenceType) { - VarNode ret = mthdNF.caseRet(); - return Collections.singleton(ret); - } - return Collections.emptySet(); + public static Set getRetVars(PAG pag, SootMethod m) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + if (m.getReturnType() instanceof ReferenceType) { + VarNode ret = mthdNF.caseRet(); + return Collections.singleton(ret); } + return Collections.emptySet(); + } - public static int pointsToSetSizeOf(final PTA pta, VarNode var) { - return pta.reachingObjects(var).toCIPointsToSet().size(); - } + public static int pointsToSetSizeOf(final PTA pta, VarNode var) { + return pta.reachingObjects(var).toCIPointsToSet().size(); + } - /** - * @param pInner potential inner class - * @param pOuter potential outer class - * @return whether pInner is an inner class of pOuter - */ - public static boolean isInnerType(final ClassType pInner, ClassType pOuter) { - final String pInnerStr = pInner.toString(); - while (!pInnerStr.startsWith(pOuter.toString() + "$")) { - SootClass sc = (SootClass) PTAScene.v().getView().getClass(pOuter).get(); - if (sc.hasSuperclass()) { - SootClass otsuper = (SootClass) sc.getSuperclass().get(); - pOuter = otsuper.getType(); - } else { - return false; - } - } - return true; + /** + * @param pInner potential inner class + * @param pOuter potential outer class + * @return whether pInner is an inner class of pOuter + */ + public static boolean isInnerType(final ClassType pInner, ClassType pOuter) { + final String pInnerStr = pInner.toString(); + while (!pInnerStr.startsWith(pOuter.toString() + "$")) { + SootClass sc = (SootClass) PTAScene.v().getView().getClass(pOuter).get(); + if (sc.hasSuperclass()) { + SootClass otsuper = (SootClass) sc.getSuperclass().get(); + pOuter = otsuper.getType(); + } else { + return false; + } } + return true; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java index a2abca8bf06..869e9c73a8d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractConch.java @@ -18,6 +18,7 @@ package qilin.pta.toolkits.conch; +import java.util.*; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; @@ -28,197 +29,208 @@ import sootup.core.types.ArrayType; import sootup.core.types.PrimitiveType; -import java.util.*; - public class AbstractConch { - public final PTA pta; - public final PAG pag; - - protected final Map> invokedMethods = new HashMap<>(); - // field |--> - protected final Map>>> m2thisFStores = new HashMap<>(); - protected final Map>>> o2nonThisFStores = new HashMap<>(); - protected final Map>> m2thisFLoads = new HashMap<>(); - protected final Map>> o2nonThisFLoads = new HashMap<>(); - protected final Map> o2fs = new HashMap<>(); - - public AbstractConch(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - init(); - } - - private void init() { - /* - * Static methods are modeled as a special instance methods of its most recent instance methods' receciver objects. - * thus, inherit its most recent instance methods' contexts (which is standard in the literature). - * The following line computes the receiver objects for the this_ptr of static methods. - * */ - Map> pts = PTAUtils.calcStaticThisPTS(pta); - pta.getNakedReachableMethods().stream().filter(SootMethod::isConcrete).forEach(method -> { - collectStoresIn(method); - collectLoadsIn(method); - buildInvokedOnFor(method, pts); - }); - - buildHeap2AccessedFieldsMap(); - } - - /* - * build a map, heap |--> {fields}. - * */ - private void buildHeap2AccessedFieldsMap() { - for (AllocNode heap : pag.getAllocNodes()) { - Set tmp = new HashSet<>(); - tmp.addAll(o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()).keySet()); - tmp.addAll(o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()).keySet()); - for (SootMethod sm : invokedMethods.getOrDefault(heap, Collections.emptySet())) { - tmp.addAll(m2thisFLoads.getOrDefault(sm, Collections.emptyMap()).keySet()); - tmp.addAll(m2thisFStores.getOrDefault(sm, Collections.emptyMap()).keySet()); - } - o2fs.put(heap, tmp); - } - } - + public final PTA pta; + public final PAG pag; + + protected final Map> invokedMethods = new HashMap<>(); + // field |--> + protected final Map>>> m2thisFStores = + new HashMap<>(); + protected final Map>>> o2nonThisFStores = + new HashMap<>(); + protected final Map>> m2thisFLoads = new HashMap<>(); + protected final Map>> o2nonThisFLoads = new HashMap<>(); + protected final Map> o2fs = new HashMap<>(); + + public AbstractConch(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + init(); + } + + private void init() { /* - * give a method, we map its receiver objects to this method. + * Static methods are modeled as a special instance methods of its most recent instance methods' receciver objects. + * thus, inherit its most recent instance methods' contexts (which is standard in the literature). + * The following line computes the receiver objects for the this_ptr of static methods. * */ - private void buildInvokedOnFor(SootMethod m, Map> pts) { - MethodPAG srcmpag = pag.getMethodPAG(m); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - - if (m.isStatic()) { - pts.getOrDefault(thisRef, Collections.emptySet()).forEach(a -> { - invokedMethods.computeIfAbsent(a, k -> new HashSet<>()).add(m); + Map> pts = PTAUtils.calcStaticThisPTS(pta); + pta.getNakedReachableMethods().stream() + .filter(SootMethod::isConcrete) + .forEach( + method -> { + collectStoresIn(method); + collectLoadsIn(method); + buildInvokedOnFor(method, pts); }); - } else { - PointsToSet thisPts = pta.reachingObjects(thisRef).toCIPointsToSet(); - for (Iterator it = thisPts.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - invokedMethods.computeIfAbsent(n, k -> new HashSet<>()).add(m); - } - } - } - private final Map methodSMPAGMap = new HashMap<>(); - - public SMPAG getSMAPG(MethodPAG mpag) { - return methodSMPAGMap.computeIfAbsent(mpag, k -> new SMPAG(mpag)); + buildHeap2AccessedFieldsMap(); + } + + /* + * build a map, heap |--> {fields}. + * */ + private void buildHeap2AccessedFieldsMap() { + for (AllocNode heap : pag.getAllocNodes()) { + Set tmp = new HashSet<>(); + tmp.addAll(o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()).keySet()); + tmp.addAll(o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()).keySet()); + for (SootMethod sm : invokedMethods.getOrDefault(heap, Collections.emptySet())) { + tmp.addAll(m2thisFLoads.getOrDefault(sm, Collections.emptyMap()).keySet()); + tmp.addAll(m2thisFStores.getOrDefault(sm, Collections.emptyMap()).keySet()); + } + o2fs.put(heap, tmp); } - - private void collectLoadsIn(SootMethod method) { - MethodPAG srcmpag = pag.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - SMPAG smpag = getSMAPG(srcmpag); - for (Pair ld : smpag.getLoads()) { - FieldRefNode fr = (FieldRefNode) ld.getSecond(); - LocalVarNode loadBase = (LocalVarNode) fr.getBase(); - SparkField field = fr.getField(); - if (primitiveField(field)) { - continue; - } - if (PTAUtils.mustAlias(pta, thisRef, loadBase)) { // handle THIS LOAD, i.e., ... = this.f - Map> f2bs = m2thisFLoads.computeIfAbsent(method, k -> new HashMap<>()); - f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(loadBase); - } else { - for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { - if (heap.getMethod() != method) { - /* we filter loads in the containing method, - * since this often not satisfy the second theoretical condition O.f*--)-->v. - */ - Map> f2bs = o2nonThisFLoads.computeIfAbsent(heap, k -> new HashMap<>()); - f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(loadBase); - } - } - } + } + + /* + * give a method, we map its receiver objects to this method. + * */ + private void buildInvokedOnFor(SootMethod m, Map> pts) { + MethodPAG srcmpag = pag.getMethodPAG(m); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + + if (m.isStatic()) { + pts.getOrDefault(thisRef, Collections.emptySet()) + .forEach( + a -> { + invokedMethods.computeIfAbsent(a, k -> new HashSet<>()).add(m); + }); + } else { + PointsToSet thisPts = pta.reachingObjects(thisRef).toCIPointsToSet(); + for (Iterator it = thisPts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + invokedMethods.computeIfAbsent(n, k -> new HashSet<>()).add(m); + } + } + } + + private final Map methodSMPAGMap = new HashMap<>(); + + public SMPAG getSMAPG(MethodPAG mpag) { + return methodSMPAGMap.computeIfAbsent(mpag, k -> new SMPAG(mpag)); + } + + private void collectLoadsIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + SMPAG smpag = getSMAPG(srcmpag); + for (Pair ld : smpag.getLoads()) { + FieldRefNode fr = (FieldRefNode) ld.getSecond(); + LocalVarNode loadBase = (LocalVarNode) fr.getBase(); + SparkField field = fr.getField(); + if (primitiveField(field)) { + continue; + } + if (PTAUtils.mustAlias(pta, thisRef, loadBase)) { // handle THIS LOAD, i.e., ... = this.f + Map> f2bs = + m2thisFLoads.computeIfAbsent(method, k -> new HashMap<>()); + f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(loadBase); + } else { + for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { + if (heap.getMethod() != method) { + /* we filter loads in the containing method, + * since this often not satisfy the second theoretical condition O.f*--)-->v. + */ + Map> f2bs = + o2nonThisFLoads.computeIfAbsent(heap, k -> new HashMap<>()); + f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(loadBase); + } } + } } - - private void collectStoresIn(SootMethod method) { - MethodPAG srcmpag = pag.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - SMPAG smpag = getSMAPG(srcmpag); - for (Pair st : smpag.getStores()) { - LocalVarNode from = (LocalVarNode) st.getSecond(); - FieldRefNode fr = (FieldRefNode) st.getFirst(); - LocalVarNode storeBase = (LocalVarNode) fr.getBase(); - SparkField field = fr.getField(); - if (primitiveField(field)) { - continue; - } - if (PTAUtils.mustAlias(pta, thisRef, storeBase)) { // handle this STORE, i.e., this.f = ... - Map>> m2s = m2thisFStores.computeIfAbsent(method, k -> new HashMap<>()); - m2s.computeIfAbsent(field, k -> new HashSet<>()).add(new Pair<>(storeBase, from)); - } else { - for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { - if (!emptyFieldPts(heap, field)) { - Map>> f2bs = o2nonThisFStores.computeIfAbsent(heap, k -> new HashMap<>()); - f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(new Pair<>(storeBase, from)); - } - } - } + } + + private void collectStoresIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + SMPAG smpag = getSMAPG(srcmpag); + for (Pair st : smpag.getStores()) { + LocalVarNode from = (LocalVarNode) st.getSecond(); + FieldRefNode fr = (FieldRefNode) st.getFirst(); + LocalVarNode storeBase = (LocalVarNode) fr.getBase(); + SparkField field = fr.getField(); + if (primitiveField(field)) { + continue; + } + if (PTAUtils.mustAlias(pta, thisRef, storeBase)) { // handle this STORE, i.e., this.f = ... + Map>> m2s = + m2thisFStores.computeIfAbsent(method, k -> new HashMap<>()); + m2s.computeIfAbsent(field, k -> new HashSet<>()).add(new Pair<>(storeBase, from)); + } else { + for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { + if (!emptyFieldPts(heap, field)) { + Map>> f2bs = + o2nonThisFStores.computeIfAbsent(heap, k -> new HashMap<>()); + f2bs.computeIfAbsent(field, k -> new HashSet<>()).add(new Pair<>(storeBase, from)); + } } + } } - - private boolean primitiveField(SparkField f) { - String s = "java.lang.String"; - if (f.getType() instanceof PrimitiveType) { - return true; - } else if (f.getType() instanceof ArrayType at) { - /* - * here, we let primitive array as primitive type as that in Turner. - * this wont hurt precision of clients. - * */ - return at.getBaseType() instanceof PrimitiveType; - } else return f.getType().toString().equals(s); + } + + private boolean primitiveField(SparkField f) { + String s = "java.lang.String"; + if (f.getType() instanceof PrimitiveType) { + return true; + } else if (f.getType() instanceof ArrayType at) { + /* + * here, we let primitive array as primitive type as that in Turner. + * this wont hurt precision of clients. + * */ + return at.getBaseType() instanceof PrimitiveType; + } else return f.getType().toString().equals(s); + } + + protected boolean emptyFieldPts(AllocNode heap, SparkField field) { + PointsToSet pts = pta.reachingObjectsInternal(heap, field); + Set tmp = new HashSet<>(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + // filter StringConstant. + if (!(n instanceof StringConstantNode)) { + tmp.add(n); + } } - - protected boolean emptyFieldPts(AllocNode heap, SparkField field) { - PointsToSet pts = pta.reachingObjectsInternal(heap, field); - Set tmp = new HashSet<>(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - // filter StringConstant. - if (!(n instanceof StringConstantNode)) { - tmp.add(n); - } - } - return tmp.isEmpty(); + return tmp.isEmpty(); + } + + protected boolean hasLoadOn(AllocNode heap, SparkField field) { + Map> f2bs = o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()); + Set loadBases = f2bs.getOrDefault(field, Collections.emptySet()); + if (!loadBases.isEmpty()) { + return true; } - - protected boolean hasLoadOn(AllocNode heap, SparkField field) { - Map> f2bs = o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()); - Set loadBases = f2bs.getOrDefault(field, Collections.emptySet()); - if (!loadBases.isEmpty()) { - return true; - } - for (SootMethod method : invokedMethods.getOrDefault(heap, Collections.emptySet())) { - Map> f2bsX = m2thisFLoads.getOrDefault(method, Collections.emptyMap()); - Set loadBasesX = f2bsX.getOrDefault(field, Collections.emptySet()); - if (!loadBasesX.isEmpty()) { - return true; - } - } - return false; + for (SootMethod method : invokedMethods.getOrDefault(heap, Collections.emptySet())) { + Map> f2bsX = + m2thisFLoads.getOrDefault(method, Collections.emptyMap()); + Set loadBasesX = f2bsX.getOrDefault(field, Collections.emptySet()); + if (!loadBasesX.isEmpty()) { + return true; + } } - - protected boolean hasStoreOn(AllocNode heap, SparkField field) { - Map>> f2bs = o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); - Set> storeBases = f2bs.getOrDefault(field, Collections.emptySet()); - if (!storeBases.isEmpty()) { - return true; - } - for (SootMethod method : invokedMethods.getOrDefault(heap, Collections.emptySet())) { - Map>> f2bsX = m2thisFStores.getOrDefault(method, Collections.emptyMap()); - Set> storeBasesX = f2bsX.getOrDefault(field, Collections.emptySet()); - if (!storeBasesX.isEmpty()) { - return true; - } - } - return false; + return false; + } + + protected boolean hasStoreOn(AllocNode heap, SparkField field) { + Map>> f2bs = + o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); + Set> storeBases = f2bs.getOrDefault(field, Collections.emptySet()); + if (!storeBases.isEmpty()) { + return true; } - + for (SootMethod method : invokedMethods.getOrDefault(heap, Collections.emptySet())) { + Map>> f2bsX = + m2thisFStores.getOrDefault(method, Collections.emptyMap()); + Set> storeBasesX = f2bsX.getOrDefault(field, Collections.emptySet()); + if (!storeBasesX.isEmpty()) { + return true; + } + } + return false; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java index 2227bf8c703..022b8f91ef4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/AbstractPAG.java @@ -20,6 +20,14 @@ import com.google.common.collect.Streams; import heros.solver.CountingThreadPoolExecutor; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; @@ -30,194 +38,188 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - /* * The abstract pointer assignment graph constructed by rules in Fig. 10 and Fig. 11 in our paper. * our IFDS analysis is running on PAG rather than the conventional control flow graph. * */ public abstract class AbstractPAG { - /* - * A symbolic object is introduced to abstract all the possible objects returned from a callsite. - * */ - protected final Map> symbolicHeaps = new ConcurrentHashMap<>(); - protected final Map> outEdges = new ConcurrentHashMap<>(); - protected final Map> sumEdges = new ConcurrentHashMap<>(); - - protected CountingThreadPoolExecutor executor; - - protected final PTA prePTA; - protected final PAG prePAG; - protected final CallGraph callGraph; - - protected AbstractPAG(PTA prePTA) { - this.prePTA = prePTA; - this.prePAG = prePTA.getPag(); - this.callGraph = prePTA.getCallGraph(); - int threadNum = Runtime.getRuntime().availableProcessors(); - this.executor = new CountingThreadPoolExecutor(threadNum, Integer.MAX_VALUE, 30, - TimeUnit.SECONDS, new LinkedBlockingQueue<>()); - } - - protected void build() { - prePTA.getNakedReachableMethods() - .parallelStream().filter(SootMethod::isConcrete) - .forEach(this::buildFG); - } - - private void buildFG(SootMethod method) { - MethodPAG srcmpag = prePAG.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof LocalVarNode) - this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); - else if (to instanceof FieldRefNode fr) { - this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); - } // local-global - - } else if (from instanceof AllocNode) { - if (to instanceof LocalVarNode) { - this.addNewEdge((AllocNode) from, (LocalVarNode) to); - } // GlobalVarNode - } else if (from instanceof FieldRefNode fr) { - this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); - } // global-local - - } - - // add param and return edges - addParamEdge(thisRef); - - int numParms = method.getParameterCount(); - for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { - LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); - addParamEdge(param); - } - } - if (method.getReturnType() instanceof ReferenceType) { - LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); - addReturnEdge(mret); - } - Node throwNode = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); - if (throwNode != null) { - addThrowEdge(throwNode); - } - } - - protected void addNormalEdge(TranEdge edge) { - outEdges.computeIfAbsent(edge.getSource(), k -> ConcurrentHashMap.newKeySet()).add(edge); - } - - protected void addThrowEdge(Node throwNode) { - addNormalEdge(new TranEdge(throwNode, throwNode, DFA.TranCond.THROW)); - addNormalEdge(new TranEdge(throwNode, throwNode, DFA.TranCond.I_THROW)); - } - - protected void addParamEdge(LocalVarNode param) { - addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); - addNormalEdge(new TranEdge(param, param, DFA.TranCond.I_PARAM)); - } - - protected void addReturnEdge(LocalVarNode mret) { - addNormalEdge(new TranEdge(mret, mret, DFA.TranCond.RETURN)); - addNormalEdge(new TranEdge(mret, mret, DFA.TranCond.I_RETURN)); - } - - protected void addNewEdge(AllocNode from, LocalVarNode to) { - // skip merged heaps. - if (from.getMethod() == null && !(from instanceof ConstantNode)) { - return; - } - TranEdge newEdge = new TranEdge(from, to, DFA.TranCond.NEW); - addNormalEdge(newEdge); - TranEdge newInvEdge = new TranEdge(to, from, DFA.TranCond.I_NEW); - addNormalEdge(newInvEdge); - } - - protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { - TranEdge assignEdge = new TranEdge(from, to, DFA.TranCond.ASSIGN); - addNormalEdge(assignEdge); - TranEdge assignInvEdge = new TranEdge(to, from, DFA.TranCond.I_ASSIGN); - addNormalEdge(assignInvEdge); - } - - protected void addStoreEdge(LocalVarNode from, LocalVarNode base) { - TranEdge storeEdge = new TranEdge(from, base, DFA.TranCond.STORE); - addNormalEdge(storeEdge); - TranEdge storeInvEdge = new TranEdge(base, from, DFA.TranCond.I_STORE); - addNormalEdge(storeInvEdge); - } - - protected void addLoadEdge(LocalVarNode base, LocalVarNode to) { - TranEdge loadEdge = new TranEdge(base, to, DFA.TranCond.LOAD); - addNormalEdge(loadEdge); - TranEdge loadInvEdge = new TranEdge(to, base, DFA.TranCond.I_LOAD); - addNormalEdge(loadInvEdge); - } - - /* - * The following code forms the bases of a multi-threaded IFDS solver. - * The codes is modified from the implementation of the fast IFDS solver in FlowDroid. - */ - protected void solve() { - submitInitialSeeds(); - awaitCompletionComputeValuesAndShutdown(); - } - - protected Collection outAndSummaryEdges(Node node) { - return Streams.concat(outEdges.getOrDefault(node, Collections.emptySet()).stream(), - sumEdges.getOrDefault(node, Collections.emptySet()).stream()).collect(Collectors.toSet()); - } - - protected abstract void submitInitialSeeds(); - - protected void awaitCompletionComputeValuesAndShutdown() { - { - // run executor and await termination of tasks - runExecutorAndAwaitCompletion(); - } - // ask executor to shut down; - // this will cause new submissions to the executor to be rejected, - // but at this point all tasks should have completed anyway - executor.shutdown(); - - // Wait for the executor to be really gone - while (!executor.isTerminated()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - // silently ignore the exception, it's not an issue if the - // thread gets aborted - } - } - executor = null; - } - - private void runExecutorAndAwaitCompletion() { - try { - executor.awaitCompletion(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - Throwable exception = executor.getException(); - if (exception != null) { - throw new RuntimeException("There were exceptions during IFDS analysis. Exiting.", exception); - } - } - - protected AllocNode getSymbolicHeapOf(SootMethod method, Stmt invokeStmt) { - return symbolicHeaps.computeIfAbsent(method, k -> new ConcurrentHashMap<>()).computeIfAbsent(invokeStmt, k -> new AllocNode(invokeStmt, null, method)); - } + /* + * A symbolic object is introduced to abstract all the possible objects returned from a callsite. + * */ + protected final Map> symbolicHeaps = new ConcurrentHashMap<>(); + protected final Map> outEdges = new ConcurrentHashMap<>(); + protected final Map> sumEdges = new ConcurrentHashMap<>(); + + protected CountingThreadPoolExecutor executor; + + protected final PTA prePTA; + protected final PAG prePAG; + protected final CallGraph callGraph; + + protected AbstractPAG(PTA prePTA) { + this.prePTA = prePTA; + this.prePAG = prePTA.getPag(); + this.callGraph = prePTA.getCallGraph(); + int threadNum = Runtime.getRuntime().availableProcessors(); + this.executor = + new CountingThreadPoolExecutor( + threadNum, Integer.MAX_VALUE, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + } + + protected void build() { + prePTA.getNakedReachableMethods().parallelStream() + .filter(SootMethod::isConcrete) + .forEach(this::buildFG); + } + + private void buildFG(SootMethod method) { + MethodPAG srcmpag = prePAG.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + } // local-global + + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + } // global-local + } + + // add param and return edges + addParamEdge(thisRef); + + int numParms = method.getParameterCount(); + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof ReferenceType) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + addParamEdge(param); + } + } + if (method.getReturnType() instanceof ReferenceType) { + LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); + addReturnEdge(mret); + } + Node throwNode = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); + if (throwNode != null) { + addThrowEdge(throwNode); + } + } + + protected void addNormalEdge(TranEdge edge) { + outEdges.computeIfAbsent(edge.getSource(), k -> ConcurrentHashMap.newKeySet()).add(edge); + } + + protected void addThrowEdge(Node throwNode) { + addNormalEdge(new TranEdge(throwNode, throwNode, DFA.TranCond.THROW)); + addNormalEdge(new TranEdge(throwNode, throwNode, DFA.TranCond.I_THROW)); + } + + protected void addParamEdge(LocalVarNode param) { + addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); + addNormalEdge(new TranEdge(param, param, DFA.TranCond.I_PARAM)); + } + + protected void addReturnEdge(LocalVarNode mret) { + addNormalEdge(new TranEdge(mret, mret, DFA.TranCond.RETURN)); + addNormalEdge(new TranEdge(mret, mret, DFA.TranCond.I_RETURN)); + } + + protected void addNewEdge(AllocNode from, LocalVarNode to) { + // skip merged heaps. + if (from.getMethod() == null && !(from instanceof ConstantNode)) { + return; + } + TranEdge newEdge = new TranEdge(from, to, DFA.TranCond.NEW); + addNormalEdge(newEdge); + TranEdge newInvEdge = new TranEdge(to, from, DFA.TranCond.I_NEW); + addNormalEdge(newInvEdge); + } + + protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { + TranEdge assignEdge = new TranEdge(from, to, DFA.TranCond.ASSIGN); + addNormalEdge(assignEdge); + TranEdge assignInvEdge = new TranEdge(to, from, DFA.TranCond.I_ASSIGN); + addNormalEdge(assignInvEdge); + } + + protected void addStoreEdge(LocalVarNode from, LocalVarNode base) { + TranEdge storeEdge = new TranEdge(from, base, DFA.TranCond.STORE); + addNormalEdge(storeEdge); + TranEdge storeInvEdge = new TranEdge(base, from, DFA.TranCond.I_STORE); + addNormalEdge(storeInvEdge); + } + + protected void addLoadEdge(LocalVarNode base, LocalVarNode to) { + TranEdge loadEdge = new TranEdge(base, to, DFA.TranCond.LOAD); + addNormalEdge(loadEdge); + TranEdge loadInvEdge = new TranEdge(to, base, DFA.TranCond.I_LOAD); + addNormalEdge(loadInvEdge); + } + + /* + * The following code forms the bases of a multi-threaded IFDS solver. + * The codes is modified from the implementation of the fast IFDS solver in FlowDroid. + */ + protected void solve() { + submitInitialSeeds(); + awaitCompletionComputeValuesAndShutdown(); + } + + protected Collection outAndSummaryEdges(Node node) { + return Streams.concat( + outEdges.getOrDefault(node, Collections.emptySet()).stream(), + sumEdges.getOrDefault(node, Collections.emptySet()).stream()) + .collect(Collectors.toSet()); + } + + protected abstract void submitInitialSeeds(); + + protected void awaitCompletionComputeValuesAndShutdown() { + { + // run executor and await termination of tasks + runExecutorAndAwaitCompletion(); + } + // ask executor to shut down; + // this will cause new submissions to the executor to be rejected, + // but at this point all tasks should have completed anyway + executor.shutdown(); + + // Wait for the executor to be really gone + while (!executor.isTerminated()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // silently ignore the exception, it's not an issue if the + // thread gets aborted + } + } + executor = null; + } + + private void runExecutorAndAwaitCompletion() { + try { + executor.awaitCompletion(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Throwable exception = executor.getException(); + if (exception != null) { + throw new RuntimeException("There were exceptions during IFDS analysis. Exiting.", exception); + } + } + + protected AllocNode getSymbolicHeapOf(SootMethod method, Stmt invokeStmt) { + return symbolicHeaps + .computeIfAbsent(method, k -> new ConcurrentHashMap<>()) + .computeIfAbsent(invokeStmt, k -> new AllocNode(invokeStmt, null, method)); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java index f7e3b24682e..632661d29a7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/CSDG.java @@ -18,12 +18,11 @@ package qilin.pta.toolkits.conch; -import qilin.core.pag.AllocNode; -import qilin.util.graph.DirectedGraphImpl; - import java.util.Collections; import java.util.HashSet; import java.util.Set; +import qilin.core.pag.AllocNode; +import qilin.util.graph.DirectedGraphImpl; /* * context-sensitivity dependent graph: @@ -34,30 +33,30 @@ * To efficiently check Obs 3(b) (lines 18-23 in Algorithm 1), we introduce this graph structure. * */ public class CSDG extends DirectedGraphImpl { - /* - * Remove node on the graph that does not have successor. - * */ - public void removeNode(final AllocNode to) { - if (succs.containsKey(to) && !succs.get(to).isEmpty()) { - return; - } - succs.remove(to); - if (preds.containsKey(to)) { - for (AllocNode from : preds.get(to)) { - succs.get(from).remove(to); - } - preds.remove(to); - } - nodes.remove(to); + /* + * Remove node on the graph that does not have successor. + * */ + public void removeNode(final AllocNode to) { + if (succs.containsKey(to) && !succs.get(to).isEmpty()) { + return; + } + succs.remove(to); + if (preds.containsKey(to)) { + for (AllocNode from : preds.get(to)) { + succs.get(from).remove(to); + } + preds.remove(to); } + nodes.remove(to); + } - public Set noOutDegreeNodes() { - Set ret = new HashSet<>(); - for (AllocNode node : allNodes()) { - if (succs.getOrDefault(node, Collections.emptySet()).isEmpty()) { - ret.add(node); - } - } - return ret; + public Set noOutDegreeNodes() { + Set ret = new HashSet<>(); + for (AllocNode node : allNodes()) { + if (succs.getOrDefault(node, Collections.emptySet()).isEmpty()) { + ret.add(node); + } } + return ret; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java index ffdf4f6f40f..b70ecd6b493 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Conch.java @@ -18,6 +18,8 @@ package qilin.pta.toolkits.conch; +import java.util.*; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; @@ -33,367 +35,376 @@ import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; -import java.util.*; -import java.util.stream.Collectors; - /* * This classifier will classify heaps into context-dependent and context-independent heaps. * */ public class Conch extends AbstractConch { - private final LeakAnalysis mfg; - private final DepOnParamAnalysis pfg; + private final LeakAnalysis mfg; + private final DepOnParamAnalysis pfg; - private final Set csHeaps = new HashSet<>(); - private final Set ciHeaps = new HashSet<>(); + private final Set csHeaps = new HashSet<>(); + private final Set ciHeaps = new HashSet<>(); - public Set ctxDependentHeaps() { - return csHeaps.stream().map(AllocNode::getNewExpr).collect(Collectors.toSet()); - } + public Set ctxDependentHeaps() { + return csHeaps.stream().map(AllocNode::getNewExpr).collect(Collectors.toSet()); + } - public Set ctxIndenpendentHeaps() { - return ciHeaps; - } + public Set ctxIndenpendentHeaps() { + return ciHeaps; + } - public Set ctxDependentHeaps2() { - return csHeaps; - } + public Set ctxDependentHeaps2() { + return csHeaps; + } - public Conch(PTA pta) { - super(pta); - this.mfg = new LeakAnalysis(pta); - this.pfg = new DepOnParamAnalysis(pta); - } + public Conch(PTA pta) { + super(pta); + this.mfg = new LeakAnalysis(pta); + this.pfg = new DepOnParamAnalysis(pta); + } - private SootMethod findInvokedConstructorOf(AllocNode heap) { - SootMethod containingMethod = heap.getMethod(); - MethodPAG cmpag = pag.getMethodPAG(containingMethod); - MethodNodeFactory nodeFactory = cmpag.nodeFactory(); - for (Stmt unit : cmpag.getInvokeStmts()) { - if (unit instanceof JInvokeStmt invokeStmt) { - AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof JSpecialInvokeExpr iie) { - Value base = iie.getBase(); - VarNode baseNode = (VarNode) nodeFactory.getNode(base); - PointsToSet v1pts = pta.reachingObjects(baseNode); - SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(iie.getMethodSignature()).get(); - if (v1pts.size() == 1 && v1pts.toCIPointsToSet().contains(heap) && PTAUtils.isConstructor(target)) { - return target; - } - } - } + private SootMethod findInvokedConstructorOf(AllocNode heap) { + SootMethod containingMethod = heap.getMethod(); + MethodPAG cmpag = pag.getMethodPAG(containingMethod); + MethodNodeFactory nodeFactory = cmpag.nodeFactory(); + for (Stmt unit : cmpag.getInvokeStmts()) { + if (unit instanceof JInvokeStmt invokeStmt) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JSpecialInvokeExpr iie) { + Value base = iie.getBase(); + VarNode baseNode = (VarNode) nodeFactory.getNode(base); + PointsToSet v1pts = pta.reachingObjects(baseNode); + SootMethod target = + (SootMethod) PTAScene.v().getView().getMethod(iie.getMethodSignature()).get(); + if (v1pts.size() == 1 + && v1pts.toCIPointsToSet().contains(heap) + && PTAUtils.isConstructor(target)) { + return target; + } } - return null; // not found. + } } + return null; // not found. + } - private SootMethod findInvokedConstructorOf(SootMethod outerInit) { - MethodPAG cmpag = pag.getMethodPAG(outerInit); - MethodNodeFactory nodeFactory = cmpag.nodeFactory(); - VarNode thisNode = nodeFactory.caseThis(); - for (Stmt unit : cmpag.getInvokeStmts()) { - if (unit instanceof JInvokeStmt invokeStmt) { - AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof JSpecialInvokeExpr iie) { - Value base = iie.getBase(); - VarNode baseNode = (VarNode) nodeFactory.getNode(base); - MethodSignature targetSig = iie.getMethodSignature(); - SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(targetSig).get(); - if (PTAUtils.mustAlias(pta, thisNode, baseNode) && targetSig.getSubSignature().getName().equals("")) { - return target; - } - } - } + private SootMethod findInvokedConstructorOf(SootMethod outerInit) { + MethodPAG cmpag = pag.getMethodPAG(outerInit); + MethodNodeFactory nodeFactory = cmpag.nodeFactory(); + VarNode thisNode = nodeFactory.caseThis(); + for (Stmt unit : cmpag.getInvokeStmts()) { + if (unit instanceof JInvokeStmt invokeStmt) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JSpecialInvokeExpr iie) { + Value base = iie.getBase(); + VarNode baseNode = (VarNode) nodeFactory.getNode(base); + MethodSignature targetSig = iie.getMethodSignature(); + SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(targetSig).get(); + if (PTAUtils.mustAlias(pta, thisNode, baseNode) + && targetSig.getSubSignature().getName().equals("")) { + return target; + } } - return null; // not found. + } } + return null; // not found. + } - private ArrayList recoverConstructorChain(SootMethod sm, AllocNode heap) { - ArrayList ret = new ArrayList<>(); - SootMethod origInit = findInvokedConstructorOf(heap); - if (origInit != null) { - while (origInit != sm) { - ret.add(0, origInit); - origInit = findInvokedConstructorOf(origInit); - if (origInit == null) { - break; - } - } + private ArrayList recoverConstructorChain(SootMethod sm, AllocNode heap) { + ArrayList ret = new ArrayList<>(); + SootMethod origInit = findInvokedConstructorOf(heap); + if (origInit != null) { + while (origInit != sm) { + ret.add(0, origInit); + origInit = findInvokedConstructorOf(origInit); + if (origInit == null) { + break; } - return ret; + } } + return ret; + } - private Set mappingtoCallerCommingParamsOrHeaps(Set params, SootMethod curr, SootMethod caller) { - MethodPAG cmpag = pag.getMethodPAG(caller); - Set ret = new HashSet<>(); - for (Stmt stmt : cmpag.getInvokeStmts()) { - if (!(stmt.getInvokeExpr() instanceof JSpecialInvokeExpr)) { - continue; - } - MethodSignature methodSig = stmt.getInvokeExpr().getMethodSignature(); - Optional otarget = (Optional) PTAScene.v().getView().getMethod(methodSig); - if (otarget.isPresent() && otarget.get().equals(curr)) { - for (Node n : params) { - if (n instanceof VarNode paramNode) { - LocalVarNode argNode = PTAUtils.paramToArg(pag, stmt, cmpag, paramNode); - if (argNode != null) { - ret.addAll(this.pfg.fetchReachableParamsOf(argNode)); - } - } - } + private Set mappingtoCallerCommingParamsOrHeaps( + Set params, SootMethod curr, SootMethod caller) { + MethodPAG cmpag = pag.getMethodPAG(caller); + Set ret = new HashSet<>(); + for (Stmt stmt : cmpag.getInvokeStmts()) { + if (!(stmt.getInvokeExpr() instanceof JSpecialInvokeExpr)) { + continue; + } + MethodSignature methodSig = stmt.getInvokeExpr().getMethodSignature(); + Optional otarget = + (Optional) PTAScene.v().getView().getMethod(methodSig); + if (otarget.isPresent() && otarget.get().equals(curr)) { + for (Node n : params) { + if (n instanceof VarNode paramNode) { + LocalVarNode argNode = PTAUtils.paramToArg(pag, stmt, cmpag, paramNode); + if (argNode != null) { + ret.addAll(this.pfg.fetchReachableParamsOf(argNode)); } + } } - return ret; + } } + return ret; + } - private boolean containHeaps(Set nodes) { - boolean ret = false; - for (Node n : nodes) { - if (n instanceof AllocNode) { - ret = true; - break; - } - } - return ret; + private boolean containHeaps(Set nodes) { + boolean ret = false; + for (Node n : nodes) { + if (n instanceof AllocNode) { + ret = true; + break; + } } + return ret; + } - private Trilean handleTransitiveConstructors(SootMethod sm, AllocNode heap, Set params) { - SootMethod containingMethod = heap.getMethod(); - ArrayList chain = recoverConstructorChain(sm, heap); - SootMethod caller = sm; - SootMethod curr; - Set ret = params; - boolean notSure = containHeaps(params); - for (SootMethod method : chain) { - curr = caller; - caller = method; - ret = mappingtoCallerCommingParamsOrHeaps(ret, curr, caller); - notSure |= containHeaps(ret); - Trilean res = checkResult(ret); - if (res != Trilean.TRUE) { - if (notSure) { - return Trilean.UNKNOWN; - } else { - return Trilean.FALSE; - } - } - } - curr = caller; - caller = containingMethod; - ret = mappingtoCallerCommingParamsOrHeaps(ret, curr, caller); - Trilean tmpRes2 = checkResult(ret); + private Trilean handleTransitiveConstructors(SootMethod sm, AllocNode heap, Set params) { + SootMethod containingMethod = heap.getMethod(); + ArrayList chain = recoverConstructorChain(sm, heap); + SootMethod caller = sm; + SootMethod curr; + Set ret = params; + boolean notSure = containHeaps(params); + for (SootMethod method : chain) { + curr = caller; + caller = method; + ret = mappingtoCallerCommingParamsOrHeaps(ret, curr, caller); + notSure |= containHeaps(ret); + Trilean res = checkResult(ret); + if (res != Trilean.TRUE) { if (notSure) { - tmpRes2 = Trilean.OR(tmpRes2, Trilean.UNKNOWN); - } - return tmpRes2; - } - - private Trilean checkResult(Set res) { - if (res.isEmpty()) { - return Trilean.FALSE; - } - boolean hasParam = false; - for (Node n : res) { - if (!(n instanceof AllocNode)) { - hasParam = true; - break; - } - } - if (hasParam) { - return Trilean.TRUE; + return Trilean.UNKNOWN; } else { - return Trilean.UNKNOWN; + return Trilean.FALSE; } + } + } + curr = caller; + caller = containingMethod; + ret = mappingtoCallerCommingParamsOrHeaps(ret, curr, caller); + Trilean tmpRes2 = checkResult(ret); + if (notSure) { + tmpRes2 = Trilean.OR(tmpRes2, Trilean.UNKNOWN); } + return tmpRes2; + } - private Trilean isCommingFromParams(LocalVarNode from, SootMethod method, AllocNode heap) { - Set ret = this.pfg.fetchReachableParamsOf(from); - if (PTAUtils.isConstructor(method)) { - return handleTransitiveConstructors(method, heap, ret); - } else { - return checkResult(ret); - } + private Trilean checkResult(Set res) { + if (res.isEmpty()) { + return Trilean.FALSE; + } + boolean hasParam = false; + for (Node n : res) { + if (!(n instanceof AllocNode)) { + hasParam = true; + break; + } } + if (hasParam) { + return Trilean.TRUE; + } else { + return Trilean.UNKNOWN; + } + } - private final Map> notSureFields = new HashMap<>(); + private Trilean isCommingFromParams(LocalVarNode from, SootMethod method, AllocNode heap) { + Set ret = this.pfg.fetchReachableParamsOf(from); + if (PTAUtils.isConstructor(method)) { + return handleTransitiveConstructors(method, heap, ret); + } else { + return checkResult(ret); + } + } - private Trilean checkHeap(AllocNode heap) { - Set fields = o2fs.getOrDefault(heap, Collections.emptySet()); - Trilean ret = Trilean.FALSE; - for (SparkField field : fields) { - Trilean csorci = Trilean.FALSE; - if (!hasLoadOn(heap, field) || !hasStoreOn(heap, field) || emptyFieldPts(heap, field)) { - continue; - } + private final Map> notSureFields = new HashMap<>(); - // check stores: - Map>> f2sts = o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); - Set> pairs = f2sts.getOrDefault(field, Collections.emptySet()); - if (!pairs.isEmpty()) { - for (Pair pair : pairs) { - LocalVarNode storeBase = (LocalVarNode) pair.getFirst(); - VarNode from = pair.getSecond(); - if (storeBase.getMethod() != heap.getMethod()) { - csorci = Trilean.TRUE; - } else { - Trilean fromparam = isCommingFromParams((LocalVarNode) from, storeBase.getMethod(), heap); - csorci = Trilean.OR(csorci, fromparam); - if (fromparam == Trilean.UNKNOWN) { - notSureFields.computeIfAbsent(heap, k -> new HashSet<>()).add(field); - } - } - } - } - Set onMethods = invokedMethods.getOrDefault(heap, Collections.emptySet()); - for (SootMethod method : onMethods) { - Map>> f2stsX = m2thisFStores.getOrDefault(method, Collections.emptyMap()); - Set> thisFStores = f2stsX.getOrDefault(field, Collections.emptySet()); - if (!thisFStores.isEmpty()) { - for (Pair pair : thisFStores) { - VarNode from = pair.getSecond(); - Trilean fromparam = isCommingFromParams((LocalVarNode) from, method, heap); - csorci = Trilean.OR(csorci, fromparam); - } - } - } + private Trilean checkHeap(AllocNode heap) { + Set fields = o2fs.getOrDefault(heap, Collections.emptySet()); + Trilean ret = Trilean.FALSE; + for (SparkField field : fields) { + Trilean csorci = Trilean.FALSE; + if (!hasLoadOn(heap, field) || !hasStoreOn(heap, field) || emptyFieldPts(heap, field)) { + continue; + } - ret = Trilean.OR(ret, csorci); - if (csorci == Trilean.UNKNOWN) { - notSureFields.computeIfAbsent(heap, k -> new HashSet<>()).add(field); + // check stores: + Map>> f2sts = + o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); + Set> pairs = f2sts.getOrDefault(field, Collections.emptySet()); + if (!pairs.isEmpty()) { + for (Pair pair : pairs) { + LocalVarNode storeBase = (LocalVarNode) pair.getFirst(); + VarNode from = pair.getSecond(); + if (storeBase.getMethod() != heap.getMethod()) { + csorci = Trilean.TRUE; + } else { + Trilean fromparam = + isCommingFromParams((LocalVarNode) from, storeBase.getMethod(), heap); + csorci = Trilean.OR(csorci, fromparam); + if (fromparam == Trilean.UNKNOWN) { + notSureFields.computeIfAbsent(heap, k -> new HashSet<>()).add(field); } + } } - return ret; + } + Set onMethods = invokedMethods.getOrDefault(heap, Collections.emptySet()); + for (SootMethod method : onMethods) { + Map>> f2stsX = + m2thisFStores.getOrDefault(method, Collections.emptyMap()); + Set> thisFStores = + f2stsX.getOrDefault(field, Collections.emptySet()); + if (!thisFStores.isEmpty()) { + for (Pair pair : thisFStores) { + VarNode from = pair.getSecond(); + Trilean fromparam = isCommingFromParams((LocalVarNode) from, method, heap); + csorci = Trilean.OR(csorci, fromparam); + } + } + } + + ret = Trilean.OR(ret, csorci); + if (csorci == Trilean.UNKNOWN) { + notSureFields.computeIfAbsent(heap, k -> new HashSet<>()).add(field); + } } + return ret; + } - private boolean hasInstanceFieldWithStoreLoad(AllocNode heap) { - Set fields = o2fs.getOrDefault(heap, Collections.emptySet()); - for (SparkField field : fields) { - boolean hasLoads = hasLoadOn(heap, field); - boolean hasStores = hasStoreOn(heap, field); - boolean emptyFieldPts = emptyFieldPts(heap, field); - if (!hasLoads || !hasStores || emptyFieldPts) { - continue; - } - return true; - } - return false; + private boolean hasInstanceFieldWithStoreLoad(AllocNode heap) { + Set fields = o2fs.getOrDefault(heap, Collections.emptySet()); + for (SparkField field : fields) { + boolean hasLoads = hasLoadOn(heap, field); + boolean hasStores = hasStoreOn(heap, field); + boolean emptyFieldPts = emptyFieldPts(heap, field); + if (!hasLoads || !hasStores || emptyFieldPts) { + continue; + } + return true; } + return false; + } - public void runClassifier() { - Collection allHeaps = pag.getAllocNodes(); - int heapCnt = allHeaps.size(); - int[] condACnt = new int[1]; + public void runClassifier() { + Collection allHeaps = pag.getAllocNodes(); + int heapCnt = allHeaps.size(); + int[] condACnt = new int[1]; - /* - * pre-process. - * Those heaps usually are assigned empty context in a tradition pointer analysis. - * Classify them to be CS or CI does not affect the efficiency of pointer analysis. - * Thus, we handle them in the pre-process. - */ - Set remainToSolve = new HashSet<>(); - allHeaps.forEach(heap -> { - if (heap.getMethod() == null - || heap instanceof ConstantNode - || PTAUtils.isEmptyArray(heap) - || PTAUtils.isOfPrimitiveBaseType(heap)) { - ciHeaps.add(heap); + /* + * pre-process. + * Those heaps usually are assigned empty context in a tradition pointer analysis. + * Classify them to be CS or CI does not affect the efficiency of pointer analysis. + * Thus, we handle them in the pre-process. + */ + Set remainToSolve = new HashSet<>(); + allHeaps.forEach( + heap -> { + if (heap.getMethod() == null + || heap instanceof ConstantNode + || PTAUtils.isEmptyArray(heap) + || PTAUtils.isOfPrimitiveBaseType(heap)) { + ciHeaps.add(heap); + } else { + SootMethod mthd = heap.getMethod(); + if (PTAUtils.isStaticInitializer(mthd)) { + ciHeaps.add(heap); } else { - SootMethod mthd = heap.getMethod(); - if (PTAUtils.isStaticInitializer(mthd)) { - ciHeaps.add(heap); - } else { - remainToSolve.add(heap); - } + remainToSolve.add(heap); } + } }); - // check by rules. - Set unknownyet = new HashSet<>(); - remainToSolve.forEach(heap -> { - // Obs 2 - boolean condA = this.mfg.isLeakObject(heap); - condACnt[0] += (condA ? 1 : 0); - if (!condA) { - ciHeaps.add(heap); - return; - } - // Obs 1 - boolean condB = hasInstanceFieldWithStoreLoad(heap); - if (!condB) { - ciHeaps.add(heap); - return; - } - // Obs 3 (a) - Trilean condExtra = checkHeap(heap); - if (condExtra == Trilean.TRUE) { - csHeaps.add(heap); - } else if (condExtra == Trilean.FALSE) { - ciHeaps.add(heap); - } else { - unknownyet.add(heap); - } + // check by rules. + Set unknownyet = new HashSet<>(); + remainToSolve.forEach( + heap -> { + // Obs 2 + boolean condA = this.mfg.isLeakObject(heap); + condACnt[0] += (condA ? 1 : 0); + if (!condA) { + ciHeaps.add(heap); + return; + } + // Obs 1 + boolean condB = hasInstanceFieldWithStoreLoad(heap); + if (!condB) { + ciHeaps.add(heap); + return; + } + // Obs 3 (a) + Trilean condExtra = checkHeap(heap); + if (condExtra == Trilean.TRUE) { + csHeaps.add(heap); + } else if (condExtra == Trilean.FALSE) { + ciHeaps.add(heap); + } else { + unknownyet.add(heap); + } }); - // Obs 3 (b) - classifyForRemain(unknownyet); - // stat - System.out.println("#Heaps:" + heapCnt); - System.out.println("#CondA:" + condACnt[0]); - System.out.println("#CS:" + csHeaps.size()); - System.out.println("#CI:" + ciHeaps.size()); - } + // Obs 3 (b) + classifyForRemain(unknownyet); + // stat + System.out.println("#Heaps:" + heapCnt); + System.out.println("#CondA:" + condACnt[0]); + System.out.println("#CS:" + csHeaps.size()); + System.out.println("#CI:" + ciHeaps.size()); + } - private void classifyForRemain(Set unknownyet) { - CSDG csdg = new CSDG(); - // build the dependency graph. - for (AllocNode heap : unknownyet) { - Set ifs = notSureFields.getOrDefault(heap, Collections.emptySet()); - boolean cs = false; - boolean existUnknown = false; - Set tos = new HashSet<>(); - for (SparkField sf : ifs) { - PointsToSet pts = pta.reachingObjectsInternal(heap, sf); - for (AllocNode o : pts.toCIPointsToSet().toCollection()) { - // if o is cs, then heap is cs; - if (csHeaps.contains(o)) { - cs = true; - break; - } - if (!ciHeaps.contains(o)) { - // exist unknown. - tos.add(o); - existUnknown = true; - } - } - if (cs) { - break; - } - } - if (cs) { - csHeaps.add(heap); - } else if (existUnknown) { - for (AllocNode to : tos) { - csdg.addEdge(heap, to); - } - } else { - ciHeaps.add(heap); - } + private void classifyForRemain(Set unknownyet) { + CSDG csdg = new CSDG(); + // build the dependency graph. + for (AllocNode heap : unknownyet) { + Set ifs = notSureFields.getOrDefault(heap, Collections.emptySet()); + boolean cs = false; + boolean existUnknown = false; + Set tos = new HashSet<>(); + for (SparkField sf : ifs) { + PointsToSet pts = pta.reachingObjectsInternal(heap, sf); + for (AllocNode o : pts.toCIPointsToSet().toCollection()) { + // if o is cs, then heap is cs; + if (csHeaps.contains(o)) { + cs = true; + break; + } + if (!ciHeaps.contains(o)) { + // exist unknown. + tos.add(o); + existUnknown = true; + } } - // recursively classify heaps for these on CSDG. - System.out.println("#InitOnCSDG:" + csdg.allNodes().size()); - while (true) { - Set noOutDegree = csdg.noOutDegreeNodes(); - if (noOutDegree.isEmpty()) { - break; - } - for (AllocNode nod : noOutDegree) { - if (csHeaps.contains(nod)) { - csHeaps.addAll(csdg.predsOf(nod)); - } else { - ciHeaps.add(nod); - } - csdg.removeNode(nod); - } + if (cs) { + break; + } + } + if (cs) { + csHeaps.add(heap); + } else if (existUnknown) { + for (AllocNode to : tos) { + csdg.addEdge(heap, to); + } + } else { + ciHeaps.add(heap); + } + } + // recursively classify heaps for these on CSDG. + System.out.println("#InitOnCSDG:" + csdg.allNodes().size()); + while (true) { + Set noOutDegree = csdg.noOutDegreeNodes(); + if (noOutDegree.isEmpty()) { + break; + } + for (AllocNode nod : noOutDegree) { + if (csHeaps.contains(nod)) { + csHeaps.addAll(csdg.predsOf(nod)); + } else { + ciHeaps.add(nod); } - System.out.println("#StillOnCSDG:" + csdg.allNodes().size()); - ciHeaps.addAll(csdg.allNodes()); + csdg.removeNode(nod); + } } + System.out.println("#StillOnCSDG:" + csdg.allNodes().size()); + ciHeaps.addAll(csdg.allNodes()); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java index 67f6ca12d46..b0f54b14715 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DFA.java @@ -26,58 +26,77 @@ * This class defines two DFA used for leak analysis and depOnParam analysis introduced in our paper respectively. * */ public class DFA { - public enum State { - O, F, B, E, ERROR; - } + public enum State { + O, + F, + B, + E, + ERROR; + } - public enum TranCond { - PARAM, I_PARAM, RETURN, I_RETURN, THROW, I_THROW, ASSIGN, I_ASSIGN, - LOAD, I_LOAD, - STORE, I_STORE, NEW, I_NEW, - INTER_STORE, INTER_ASSIGN, I_INTER_LOAD; - } + public enum TranCond { + PARAM, + I_PARAM, + RETURN, + I_RETURN, + THROW, + I_THROW, + ASSIGN, + I_ASSIGN, + LOAD, + I_LOAD, + STORE, + I_STORE, + NEW, + I_NEW, + INTER_STORE, + INTER_ASSIGN, + I_INTER_LOAD; + } - private static final Map> transitionFunc = new HashMap<>(); + private static final Map> transitionFunc = new HashMap<>(); - /* - * This is another automaton for PFG. - * */ - private static final Map> transitionFunc2 = new HashMap<>(); + /* + * This is another automaton for PFG. + * */ + private static final Map> transitionFunc2 = new HashMap<>(); - static { - // The first DFA introduced in Figure 13 for leak analysis. - Map mO = transitionFunc.computeIfAbsent(State.O, k -> new HashMap<>()); - mO.put(TranCond.NEW, State.F); + static { + // The first DFA introduced in Figure 13 for leak analysis. + Map mO = transitionFunc.computeIfAbsent(State.O, k -> new HashMap<>()); + mO.put(TranCond.NEW, State.F); - Map mF = transitionFunc.computeIfAbsent(State.F, k -> new HashMap<>()); - mF.put(TranCond.ASSIGN, State.F); - mF.put(TranCond.STORE, State.B); - mF.put(TranCond.INTER_STORE, State.B); - mF.put(TranCond.INTER_ASSIGN, State.F); - mF.put(TranCond.RETURN, State.E); - mF.put(TranCond.THROW, State.E); + Map mF = transitionFunc.computeIfAbsent(State.F, k -> new HashMap<>()); + mF.put(TranCond.ASSIGN, State.F); + mF.put(TranCond.STORE, State.B); + mF.put(TranCond.INTER_STORE, State.B); + mF.put(TranCond.INTER_ASSIGN, State.F); + mF.put(TranCond.RETURN, State.E); + mF.put(TranCond.THROW, State.E); - Map mB = transitionFunc.computeIfAbsent(State.B, k -> new HashMap<>()); - mB.put(TranCond.I_ASSIGN, State.B); - mB.put(TranCond.I_LOAD, State.B); - mB.put(TranCond.I_PARAM, State.E); - mB.put(TranCond.I_INTER_LOAD, State.B); - mB.put(TranCond.I_NEW, State.O); + Map mB = transitionFunc.computeIfAbsent(State.B, k -> new HashMap<>()); + mB.put(TranCond.I_ASSIGN, State.B); + mB.put(TranCond.I_LOAD, State.B); + mB.put(TranCond.I_PARAM, State.E); + mB.put(TranCond.I_INTER_LOAD, State.B); + mB.put(TranCond.I_NEW, State.O); - // The second DFA introduced in Figure 15 for depOnParma analysis. - Map mF2 = transitionFunc2.computeIfAbsent(State.F, k -> new HashMap<>()); - mF2.put(TranCond.NEW, State.F); - mF2.put(TranCond.ASSIGN, State.F); - mF2.put(TranCond.LOAD, State.F); - mF2.put(TranCond.RETURN, State.E); - mF2.put(TranCond.INTER_ASSIGN, State.F); - } + // The second DFA introduced in Figure 15 for depOnParma analysis. + Map mF2 = transitionFunc2.computeIfAbsent(State.F, k -> new HashMap<>()); + mF2.put(TranCond.NEW, State.F); + mF2.put(TranCond.ASSIGN, State.F); + mF2.put(TranCond.LOAD, State.F); + mF2.put(TranCond.RETURN, State.E); + mF2.put(TranCond.INTER_ASSIGN, State.F); + } - public static State nextState(State curr, TranCond tranCond) { - return transitionFunc.getOrDefault(curr, Collections.emptyMap()).getOrDefault(tranCond, State.ERROR); - } + public static State nextState(State curr, TranCond tranCond) { + return transitionFunc + .getOrDefault(curr, Collections.emptyMap()) + .getOrDefault(tranCond, State.ERROR); + } - public static State nextState2(TranCond tranCond) { - return transitionFunc2.get(State.F).getOrDefault(tranCond, State.ERROR); - } + public static State nextState2(TranCond tranCond) { + return transitionFunc2.get(State.F).getOrDefault(tranCond, State.ERROR); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java index a814624fc87..d6c18d11507 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/DepOnParamAnalysis.java @@ -18,6 +18,11 @@ package qilin.pta.toolkits.conch; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; @@ -27,12 +32,6 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - /* * It try to answer where the value of a variable comes from. * (1) comes from p.f* @@ -44,116 +43,117 @@ * */ public class DepOnParamAnalysis extends AbstractPAG { - private final Map> pathEdges = new ConcurrentHashMap<>(); - private final Set initialSeeds = ConcurrentHashMap.newKeySet(); - - public DepOnParamAnalysis(PTA prePTA) { - super(prePTA); - build(); - solve(); - } - - protected void solve() { - System.out.println("start analysis!"); - super.solve(); - System.out.println("finish PFG analysis!"); + private final Map> pathEdges = new ConcurrentHashMap<>(); + private final Set initialSeeds = ConcurrentHashMap.newKeySet(); + + public DepOnParamAnalysis(PTA prePTA) { + super(prePTA); + build(); + solve(); + } + + protected void solve() { + System.out.println("start analysis!"); + super.solve(); + System.out.println("finish PFG analysis!"); + } + + protected void addParamEdge(LocalVarNode param) { + super.addParamEdge(param); + initialSeeds.add(param); + } + + protected void addNewEdge(AllocNode from, LocalVarNode to) { + super.addNewEdge(from, to); + initialSeeds.add(from); + } + + protected void submitInitialSeeds() { + for (Node node : initialSeeds) { + propagate(node, node); } + } - protected void addParamEdge(LocalVarNode param) { - super.addParamEdge(param); - initialSeeds.add(param); + private void propagate(Node srcParam, Node currNode) { + Set fromParams = pathEdges.computeIfAbsent(currNode, k -> ConcurrentHashMap.newKeySet()); + if (!fromParams.contains(srcParam)) { + executor.execute(new PathEdgeProcessingTask(srcParam, currNode)); } + } - protected void addNewEdge(AllocNode from, LocalVarNode to) { - super.addNewEdge(from, to); - initialSeeds.add(from); - } + private class PathEdgeProcessingTask implements Runnable { + private final Node sourceParam; + private final Node currNode; - protected void submitInitialSeeds() { - for (Node node : initialSeeds) { - propagate(node, node); - } + public PathEdgeProcessingTask(Node param, Node node) { + this.sourceParam = param; + this.currNode = node; } - private void propagate(Node srcParam, Node currNode) { - Set fromParams = pathEdges.computeIfAbsent(currNode, k -> ConcurrentHashMap.newKeySet()); - if (!fromParams.contains(srcParam)) { - executor.execute(new PathEdgeProcessingTask(srcParam, currNode)); - } - } - - private class PathEdgeProcessingTask implements Runnable { - private final Node sourceParam; - private final Node currNode; - - public PathEdgeProcessingTask(Node param, Node node) { - this.sourceParam = param; - this.currNode = node; + @Override + public void run() { + pathEdges.computeIfAbsent(currNode, k -> ConcurrentHashMap.newKeySet()).add(sourceParam); + for (TranEdge e : outAndSummaryEdges(currNode)) { + Node nextNode = e.getTarget(); + DFA.TranCond tranCond = e.getTranCond(); + DFA.State nextState = DFA.nextState2(tranCond); + if (nextState == DFA.State.ERROR) { + continue; } - - @Override - public void run() { - pathEdges.computeIfAbsent(currNode, k -> ConcurrentHashMap.newKeySet()).add(sourceParam); - for (TranEdge e : outAndSummaryEdges(currNode)) { - Node nextNode = e.getTarget(); - DFA.TranCond tranCond = e.getTranCond(); - DFA.State nextState = DFA.nextState2(tranCond); - if (nextState == DFA.State.ERROR) { - continue; - } - propagate(sourceParam, nextNode); - if (nextState == DFA.State.E) { - // do something. - SootMethod containingMethod; - if (sourceParam instanceof LocalVarNode pj) { - containingMethod = pj.getMethod(); - } else { - AllocNode heap = (AllocNode) sourceParam; - containingMethod = heap.getMethod(); - } - - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); - while (it.hasNext()) { - Edge edge = it.next(); - SootMethod srcMethod = edge.src(); - MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - Stmt invokeStmt = edge.srcUnit(); - if (invokeStmt instanceof JAssignStmt assignStmt) { - - VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); - if (sourceParam instanceof LocalVarNode pj) { - VarNode aj = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pj); - if (aj != null) { - addSummaryEdge(new TranEdge(aj, r, DFA.TranCond.INTER_ASSIGN)); - } - } else { - AllocNode symbolHeap = getSymbolicHeapOf(srcMethod, invokeStmt); - addSummaryEdge(new TranEdge(symbolHeap, r, DFA.TranCond.NEW)); - propagate(symbolHeap, symbolHeap); - } - } - } + propagate(sourceParam, nextNode); + if (nextState == DFA.State.E) { + // do something. + SootMethod containingMethod; + if (sourceParam instanceof LocalVarNode pj) { + containingMethod = pj.getMethod(); + } else { + AllocNode heap = (AllocNode) sourceParam; + containingMethod = heap.getMethod(); + } + + Iterator it = + callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + Stmt invokeStmt = edge.srcUnit(); + if (invokeStmt instanceof JAssignStmt assignStmt) { + + VarNode r = (VarNode) srcnf.getNode(assignStmt.getLeftOp()); + if (sourceParam instanceof LocalVarNode pj) { + VarNode aj = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pj); + if (aj != null) { + addSummaryEdge(new TranEdge(aj, r, DFA.TranCond.INTER_ASSIGN)); } + } else { + AllocNode symbolHeap = getSymbolicHeapOf(srcMethod, invokeStmt); + addSummaryEdge(new TranEdge(symbolHeap, r, DFA.TranCond.NEW)); + propagate(symbolHeap, symbolHeap); + } } + } } + } } - - private void addSummaryEdge(TranEdge tranEdge) { - Node src = tranEdge.getSource(); - Node tgt = tranEdge.getTarget(); - DFA.TranCond tranCond = tranEdge.getTranCond(); - sumEdges.computeIfAbsent(src, k -> ConcurrentHashMap.newKeySet()).add(tranEdge); - for (Node srcParam : pathEdges.getOrDefault(src, Collections.emptySet())) { - DFA.State nextState = DFA.nextState2(tranCond); - if (nextState == DFA.State.ERROR) { - continue; - } - propagate(srcParam, tgt); - } + } + + private void addSummaryEdge(TranEdge tranEdge) { + Node src = tranEdge.getSource(); + Node tgt = tranEdge.getTarget(); + DFA.TranCond tranCond = tranEdge.getTranCond(); + sumEdges.computeIfAbsent(src, k -> ConcurrentHashMap.newKeySet()).add(tranEdge); + for (Node srcParam : pathEdges.getOrDefault(src, Collections.emptySet())) { + DFA.State nextState = DFA.nextState2(tranCond); + if (nextState == DFA.State.ERROR) { + continue; + } + propagate(srcParam, tgt); } + } - public Set fetchReachableParamsOf(Node node) { - return pathEdges.getOrDefault(node, Collections.emptySet()); - } + public Set fetchReachableParamsOf(Node node) { + return pathEdges.getOrDefault(node, Collections.emptySet()); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java index 83ef03944e9..3f1f01a41a3 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/LeakAnalysis.java @@ -18,6 +18,11 @@ package qilin.pta.toolkits.conch; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import qilin.core.PTA; import qilin.core.pag.*; import qilin.util.PTAUtils; @@ -25,194 +30,191 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - /* * This structure is used to check whether an object could flow out of its containing method. * */ public class LeakAnalysis extends AbstractPAG { - private final Map> pathEdges = new ConcurrentHashMap<>(); - private final Set initialSeeds = ConcurrentHashMap.newKeySet(); - private final Set result = ConcurrentHashMap.newKeySet(); - - public LeakAnalysis(PTA prePTA) { - super(prePTA); - build(); - solve(); + private final Map> pathEdges = new ConcurrentHashMap<>(); + private final Set initialSeeds = ConcurrentHashMap.newKeySet(); + private final Set result = ConcurrentHashMap.newKeySet(); + + public LeakAnalysis(PTA prePTA) { + super(prePTA); + build(); + solve(); + } + + protected void solve() { + System.out.println("start analysis!"); + super.solve(); + System.out.println("finish MFG analysis!"); + } + + protected void submitInitialSeeds() { + initialSeeds.forEach(pe -> executor.execute(new PathEdgeProcessingTask(pe))); + } + + protected void addThrowEdge(Node throwNode) { + super.addThrowEdge(throwNode); + initialSeeds.add(new PathEdge(throwNode, DFA.State.B, throwNode, DFA.State.B)); + } + + protected void addParamEdge(LocalVarNode param) { + super.addParamEdge(param); + initialSeeds.add(new PathEdge(param, DFA.State.F, param, DFA.State.F)); + } + + protected void addReturnEdge(LocalVarNode mret) { + super.addReturnEdge(mret); + initialSeeds.add(new PathEdge(mret, DFA.State.B, mret, DFA.State.B)); + } + + protected void addNewEdge(AllocNode from, LocalVarNode to) { + super.addNewEdge(from, to); + initialSeeds.add(new PathEdge(from, DFA.State.O, from, DFA.State.O)); + } + + private void addPathEdge(PathEdge pe) { + Node tgtNode = pe.getTgtNode(); + pathEdges.computeIfAbsent(tgtNode, k -> ConcurrentHashMap.newKeySet()).add(pe); + } + + private boolean containPathEdge(PathEdge pe) { + Node tgtNode = pe.getTgtNode(); + return pathEdges.getOrDefault(tgtNode, Collections.emptySet()).contains(pe); + } + + private void propagate(PathEdge pe) { + if (!containPathEdge(pe)) { + executor.execute(new PathEdgeProcessingTask(pe)); } + } - protected void solve() { - System.out.println("start analysis!"); - super.solve(); - System.out.println("finish MFG analysis!"); - } - - protected void submitInitialSeeds() { - initialSeeds.forEach(pe -> executor.execute(new PathEdgeProcessingTask(pe))); - } - - protected void addThrowEdge(Node throwNode) { - super.addThrowEdge(throwNode); - initialSeeds.add(new PathEdge(throwNode, DFA.State.B, throwNode, DFA.State.B)); - } - - protected void addParamEdge(LocalVarNode param) { - super.addParamEdge(param); - initialSeeds.add(new PathEdge(param, DFA.State.F, param, DFA.State.F)); - } + private class PathEdgeProcessingTask implements Runnable { + PathEdge pe; - protected void addReturnEdge(LocalVarNode mret) { - super.addReturnEdge(mret); - initialSeeds.add(new PathEdge(mret, DFA.State.B, mret, DFA.State.B)); + public PathEdgeProcessingTask(PathEdge pe) { + this.pe = pe; } - protected void addNewEdge(AllocNode from, LocalVarNode to) { - super.addNewEdge(from, to); - initialSeeds.add(new PathEdge(from, DFA.State.O, from, DFA.State.O)); - } - - private void addPathEdge(PathEdge pe) { - Node tgtNode = pe.getTgtNode(); - pathEdges.computeIfAbsent(tgtNode, k -> ConcurrentHashMap.newKeySet()).add(pe); - } - - private boolean containPathEdge(PathEdge pe) { - Node tgtNode = pe.getTgtNode(); - return pathEdges.getOrDefault(tgtNode, Collections.emptySet()).contains(pe); - } - - private void propagate(PathEdge pe) { - if (!containPathEdge(pe)) { - executor.execute(new PathEdgeProcessingTask(pe)); + @Override + public void run() { + addPathEdge(pe); + DFA.State initState = pe.getSrcState(); + Node sourceNode = pe.getSrcNode(); + DFA.State targetState = pe.getTgtState(); + Node targetNode = pe.getTgtNode(); + + for (TranEdge e : outAndSummaryEdges(targetNode)) { + Node newTargetNode = e.getTarget(); + DFA.TranCond tranCond = e.getTranCond(); + DFA.State nextState = DFA.nextState(targetState, tranCond); + if (nextState == DFA.State.ERROR) { + continue; } - } - - private class PathEdgeProcessingTask implements Runnable { - PathEdge pe; - - public PathEdgeProcessingTask(PathEdge pe) { - this.pe = pe; + if (initState == DFA.State.B && nextState == DFA.State.O) { + // disallow such kinds of pathedge: --> + continue; } - - @Override - public void run() { - addPathEdge(pe); - DFA.State initState = pe.getSrcState(); - Node sourceNode = pe.getSrcNode(); - DFA.State targetState = pe.getTgtState(); - Node targetNode = pe.getTgtNode(); - - for (TranEdge e : outAndSummaryEdges(targetNode)) { - Node newTargetNode = e.getTarget(); - DFA.TranCond tranCond = e.getTranCond(); - DFA.State nextState = DFA.nextState(targetState, tranCond); - if (nextState == DFA.State.ERROR) { - continue; - } - if (initState == DFA.State.B && nextState == DFA.State.O) { - // disallow such kinds of pathedge: --> - continue; - } - PathEdge nPE = new PathEdge(sourceNode, initState, newTargetNode, nextState); - propagate(nPE); - if (nextState != DFA.State.E) { - continue; - } - // reach the end state. - if (initState == DFA.State.O) { - // report a heap flows out of its containing method. - AllocNode sourceHeap = (AllocNode) sourceNode; - result.add(sourceHeap); - SootMethod containingMethod = sourceHeap.getMethod(); - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); - while (it.hasNext()) { - Edge edge = it.next(); - SootMethod srcMethod = edge.src(); - MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); - Stmt invokeStmt = (Stmt) edge.srcUnit(); - if (targetState == DFA.State.F) { // ret.f* = heap - // add S -new-> r summary edge for symbolic heaps. - VarNode ret = (VarNode) targetNode; - VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, ret); - if (r != null) { - AllocNode s = getSymbolicHeapOf(srcMethod, invokeStmt); - addSummaryEdge(new TranEdge(s, r, DFA.TranCond.NEW)); - addSummaryEdge(new TranEdge(r, s, DFA.TranCond.I_NEW)); - } - } - } - } else if (initState == DFA.State.F) { - LocalVarNode pj = (LocalVarNode) sourceNode; - SootMethod containingMethod = pj.getMethod(); - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); - while (it.hasNext()) { - Edge edge = it.next(); - SootMethod srcMethod = edge.src(); - MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); - Stmt invokeStmt = (Stmt) edge.srcUnit(); - VarNode aj = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pj); - // a param reach end state. - if (targetState == DFA.State.B && sourceNode != targetNode) { // pi.f* = pj, pi != pj. - // add aj --> ai summary edge. inter_store. - VarNode pi = (VarNode) targetNode; - VarNode ai = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pi); - if (ai != null && aj != null && ai != aj) { - addSummaryEdge(new TranEdge(aj, ai, DFA.TranCond.INTER_STORE)); - } - } else if (targetState == DFA.State.F) { // ret.f* = pj - // add aj --> r summary edge. inter_load. - VarNode ret = (VarNode) targetNode; - VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, ret); - if (r != null && aj != null) { - addSummaryEdge(new TranEdge(aj, r, DFA.TranCond.INTER_ASSIGN)); - } - } - } - } else if (initState == DFA.State.B && targetState == DFA.State.B) { - // ret = pi.f* - LocalVarNode retOrThrow = (LocalVarNode) sourceNode; - SootMethod containingMethod = retOrThrow.getMethod(); - Iterator it = callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); - VarNode pi = (VarNode) pe.getTgtNode(); - // add r --> ai summary edge inverse_inter_load. - while (it.hasNext()) { - Edge edge = it.next(); - SootMethod srcMethod = edge.src(); - MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); - Stmt invokeStmt = edge.srcUnit(); - VarNode ai = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pi); - VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, retOrThrow); - if (r != null && ai != null) { - addSummaryEdge(new TranEdge(r, ai, DFA.TranCond.I_INTER_LOAD)); - } - } - } - } + PathEdge nPE = new PathEdge(sourceNode, initState, newTargetNode, nextState); + propagate(nPE); + if (nextState != DFA.State.E) { + continue; } - } - - private void addSummaryEdge(TranEdge tranEdge) { - Node src = tranEdge.getSource(); - Node tgt = tranEdge.getTarget(); - DFA.TranCond tranCond = tranEdge.getTranCond(); - sumEdges.computeIfAbsent(src, k -> ConcurrentHashMap.newKeySet()).add(tranEdge); - for (PathEdge pe : pathEdges.getOrDefault(src, Collections.emptySet())) { - DFA.State tgtState = pe.getTgtState(); - DFA.State nextState = DFA.nextState(tgtState, tranCond); - if (nextState == DFA.State.ERROR) { - continue; + // reach the end state. + if (initState == DFA.State.O) { + // report a heap flows out of its containing method. + AllocNode sourceHeap = (AllocNode) sourceNode; + result.add(sourceHeap); + SootMethod containingMethod = sourceHeap.getMethod(); + Iterator it = + callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + Stmt invokeStmt = (Stmt) edge.srcUnit(); + if (targetState == DFA.State.F) { // ret.f* = heap + // add S -new-> r summary edge for symbolic heaps. + VarNode ret = (VarNode) targetNode; + VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, ret); + if (r != null) { + AllocNode s = getSymbolicHeapOf(srcMethod, invokeStmt); + addSummaryEdge(new TranEdge(s, r, DFA.TranCond.NEW)); + addSummaryEdge(new TranEdge(r, s, DFA.TranCond.I_NEW)); + } } - PathEdge nPE = new PathEdge(pe.getSrcNode(), pe.getSrcState(), tgt, nextState); - propagate(nPE); + } + } else if (initState == DFA.State.F) { + LocalVarNode pj = (LocalVarNode) sourceNode; + SootMethod containingMethod = pj.getMethod(); + Iterator it = + callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + Stmt invokeStmt = (Stmt) edge.srcUnit(); + VarNode aj = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pj); + // a param reach end state. + if (targetState == DFA.State.B && sourceNode != targetNode) { // pi.f* = pj, pi != pj. + // add aj --> ai summary edge. inter_store. + VarNode pi = (VarNode) targetNode; + VarNode ai = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pi); + if (ai != null && aj != null && ai != aj) { + addSummaryEdge(new TranEdge(aj, ai, DFA.TranCond.INTER_STORE)); + } + } else if (targetState == DFA.State.F) { // ret.f* = pj + // add aj --> r summary edge. inter_load. + VarNode ret = (VarNode) targetNode; + VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, ret); + if (r != null && aj != null) { + addSummaryEdge(new TranEdge(aj, r, DFA.TranCond.INTER_ASSIGN)); + } + } + } + } else if (initState == DFA.State.B && targetState == DFA.State.B) { + // ret = pi.f* + LocalVarNode retOrThrow = (LocalVarNode) sourceNode; + SootMethod containingMethod = retOrThrow.getMethod(); + Iterator it = + callGraph.edgesInto(new ContextMethod(containingMethod, prePTA.emptyContext())); + VarNode pi = (VarNode) pe.getTgtNode(); + // add r --> ai summary edge inverse_inter_load. + while (it.hasNext()) { + Edge edge = it.next(); + SootMethod srcMethod = edge.src(); + MethodPAG srcmpag = prePAG.getMethodPAG(srcMethod); + Stmt invokeStmt = edge.srcUnit(); + VarNode ai = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, pi); + VarNode r = PTAUtils.paramToArg(prePAG, invokeStmt, srcmpag, retOrThrow); + if (r != null && ai != null) { + addSummaryEdge(new TranEdge(r, ai, DFA.TranCond.I_INTER_LOAD)); + } + } } + } } - - // Condition(A): heap that could flow out of its containing methods. - public boolean isLeakObject(AllocNode heap) { - return result.contains(heap); + } + + private void addSummaryEdge(TranEdge tranEdge) { + Node src = tranEdge.getSource(); + Node tgt = tranEdge.getTarget(); + DFA.TranCond tranCond = tranEdge.getTranCond(); + sumEdges.computeIfAbsent(src, k -> ConcurrentHashMap.newKeySet()).add(tranEdge); + for (PathEdge pe : pathEdges.getOrDefault(src, Collections.emptySet())) { + DFA.State tgtState = pe.getTgtState(); + DFA.State nextState = DFA.nextState(tgtState, tranCond); + if (nextState == DFA.State.ERROR) { + continue; + } + PathEdge nPE = new PathEdge(pe.getSrcNode(), pe.getSrcState(), tgt, nextState); + propagate(nPE); } + } + + // Condition(A): heap that could flow out of its containing methods. + public boolean isLeakObject(AllocNode heap) { + return result.contains(heap); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java index 3f80556d14f..88fa1fb3b94 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/PathEdge.java @@ -24,79 +24,70 @@ * This is the path edge defined as the standard in IFDS algorithm. * */ public class PathEdge { - final Node srcNode; - final DFA.State srcState; - final Node tgtNode; - final DFA.State tgtState; - final int hashCode; + final Node srcNode; + final DFA.State srcState; + final Node tgtNode; + final DFA.State tgtState; + final int hashCode; - public PathEdge(Node srcNode, DFA.State srcState, Node tgtNode, DFA.State tgtState) { - this.srcNode = srcNode; - this.srcState = srcState; - this.tgtNode = tgtNode; - this.tgtState = tgtState; + public PathEdge(Node srcNode, DFA.State srcState, Node tgtNode, DFA.State tgtState) { + this.srcNode = srcNode; + this.srcState = srcState; + this.tgtNode = tgtNode; + this.tgtState = tgtState; - final int prime = 31; - int result = 1; - result = prime * result + ((srcNode == null) ? 0 : srcNode.hashCode()); - result = prime * result + ((srcState == null) ? 0 : srcState.hashCode()); - result = prime * result + ((tgtNode == null) ? 0 : tgtNode.hashCode()); - result = prime * result + ((tgtState == null) ? 0 : tgtState.hashCode()); - this.hashCode = result; - } + final int prime = 31; + int result = 1; + result = prime * result + ((srcNode == null) ? 0 : srcNode.hashCode()); + result = prime * result + ((srcState == null) ? 0 : srcState.hashCode()); + result = prime * result + ((tgtNode == null) ? 0 : tgtNode.hashCode()); + result = prime * result + ((tgtState == null) ? 0 : tgtState.hashCode()); + this.hashCode = result; + } - public Node getSrcNode() { - return srcNode; - } + public Node getSrcNode() { + return srcNode; + } - public DFA.State getSrcState() { - return srcState; - } + public DFA.State getSrcState() { + return srcState; + } - public Node getTgtNode() { - return tgtNode; - } + public Node getTgtNode() { + return tgtNode; + } - public DFA.State getTgtState() { - return tgtState; - } + public DFA.State getTgtState() { + return tgtState; + } - @Override - public int hashCode() { - return hashCode; - } + @Override + public int hashCode() { + return hashCode; + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - PathEdge other = (PathEdge) obj; - if (srcNode == null) { - if (other.srcNode != null) - return false; - } else if (!srcNode.equals(other.srcNode)) - return false; - if (tgtNode == null) { - if (other.tgtNode != null) - return false; - } else if (!tgtNode.equals(other.tgtNode)) - return false; - if (srcState == null) { - if (other.srcState != null) - return false; - } else if (!srcState.equals(other.srcState)) - return false; - if (tgtState == null) { - return other.tgtState == null; - } else return tgtState.equals(other.tgtState); - } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + PathEdge other = (PathEdge) obj; + if (srcNode == null) { + if (other.srcNode != null) return false; + } else if (!srcNode.equals(other.srcNode)) return false; + if (tgtNode == null) { + if (other.tgtNode != null) return false; + } else if (!tgtNode.equals(other.tgtNode)) return false; + if (srcState == null) { + if (other.srcState != null) return false; + } else if (!srcState.equals(other.srcState)) return false; + if (tgtState == null) { + return other.tgtState == null; + } else return tgtState.equals(other.tgtState); + } - @Override - public String toString() { - return "(" + srcNode + "," + srcState + ")\n\t" + "-->" + "(" + tgtNode + "," + tgtState + ")"; - } + @Override + public String toString() { + return "(" + srcNode + "," + srcState + ")\n\t" + "-->" + "(" + tgtNode + "," + tgtState + ")"; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java index 67719f67d54..4c55fd999ad 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/SMPAG.java @@ -18,88 +18,86 @@ package qilin.pta.toolkits.conch; +import java.util.HashSet; +import java.util.Set; import qilin.core.pag.*; import qilin.util.Pair; import qilin.util.graph.DirectedGraphImpl; import qilin.util.queue.UniqueQueue; import soot.util.queue.QueueReader; -import java.util.HashSet; -import java.util.Set; - /* * a simplified method PAG with the effects of static load and store being eliminated. * */ public class SMPAG extends DirectedGraphImpl { - MethodPAG srcmpag; - Set> loads; - Set> stores; - - public SMPAG(MethodPAG srcmpag) { - this.srcmpag = srcmpag; - init(); - } + MethodPAG srcmpag; + Set> loads; + Set> stores; - private void init() { - loads = new HashSet<>(); - stores = new HashSet<>(); - QueueReader reader = srcmpag.getInternalReader().clone(); - UniqueQueue workList = new UniqueQueue<>(); - Set visit = new HashSet<>(); - while (reader.hasNext()) { - qilin.core.pag.Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof LocalVarNode) { - this.addEdge(from, to); // ASSIGN - } else if (to instanceof FieldRefNode) { - this.addEdge(from, to); // STORE - } // local-global : A.f = a; + public SMPAG(MethodPAG srcmpag) { + this.srcmpag = srcmpag; + init(); + } + private void init() { + loads = new HashSet<>(); + stores = new HashSet<>(); + QueueReader reader = srcmpag.getInternalReader().clone(); + UniqueQueue workList = new UniqueQueue<>(); + Set visit = new HashSet<>(); + while (reader.hasNext()) { + qilin.core.pag.Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + this.addEdge(from, to); // ASSIGN + } else if (to instanceof FieldRefNode) { + this.addEdge(from, to); // STORE + } // local-global : A.f = a; - } else if (from instanceof AllocNode) { - this.addEdge(from, to); // NEW - } else if (from instanceof FieldRefNode) { - this.addEdge(from, to); // LOAD - } else { // global-local - workList.add(to); - } + } else if (from instanceof AllocNode) { + this.addEdge(from, to); // NEW + } else if (from instanceof FieldRefNode) { + this.addEdge(from, to); // LOAD + } else { // global-local + workList.add(to); + } + } + while (!workList.isEmpty()) { + Node curr = workList.poll(); + visit.add(curr); + if (this.predsOf(curr).isEmpty()) { + for (Node next : this.succsOf(curr)) { + if (!visit.contains(next)) { + workList.add(next); + } + this.preds.get(next).remove(curr); } - while (!workList.isEmpty()) { - Node curr = workList.poll(); - visit.add(curr); - if (this.predsOf(curr).isEmpty()) { - for (Node next : this.succsOf(curr)) { - if (!visit.contains(next)) { - workList.add(next); - } - this.preds.get(next).remove(curr); - } - if (this.succs.containsKey(curr)) { - this.succs.get(curr).clear(); - } - } + if (this.succs.containsKey(curr)) { + this.succs.get(curr).clear(); } + } + } - // initialize stores and loads - for (Node node : this.allNodes()) { - if (node instanceof FieldRefNode) { - for (Node from : this.predsOf(node)) { - stores.add(new Pair<>(node, from)); - } - for (Node to : this.succsOf(node)) { - loads.add(new Pair<>(to, node)); - } - } + // initialize stores and loads + for (Node node : this.allNodes()) { + if (node instanceof FieldRefNode) { + for (Node from : this.predsOf(node)) { + stores.add(new Pair<>(node, from)); } + for (Node to : this.succsOf(node)) { + loads.add(new Pair<>(to, node)); + } + } } + } - // - public Set> getStores() { - return stores; - } + // + public Set> getStores() { + return stores; + } - // - public Set> getLoads() { - return loads; - } + // + public Set> getLoads() { + return loads; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java index d62f39124ae..149c90686e8 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/TranEdge.java @@ -18,53 +18,52 @@ package qilin.pta.toolkits.conch; -import qilin.core.pag.Node; - import java.util.Objects; +import qilin.core.pag.Node; /* * Transition edges used in define our DFAs. * */ public class TranEdge { - private final Node src; - private final Node dst; - private final DFA.TranCond tranCond; + private final Node src; + private final Node dst; + private final DFA.TranCond tranCond; - public TranEdge(Node s, Node d, DFA.TranCond tran) { - this.src = s; - this.dst = d; - this.tranCond = tran; - } + public TranEdge(Node s, Node d, DFA.TranCond tran) { + this.src = s; + this.dst = d; + this.tranCond = tran; + } - public Node getSource() { - return src; - } + public Node getSource() { + return src; + } - public Node getTarget() { - return dst; - } + public Node getTarget() { + return dst; + } - public DFA.TranCond getTranCond() { - return tranCond; - } + public DFA.TranCond getTranCond() { + return tranCond; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TranEdge tranEdge = (TranEdge) o; - return Objects.equals(src, tranEdge.src) && - Objects.equals(dst, tranEdge.dst) && - tranCond == tranEdge.tranCond; - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TranEdge tranEdge = (TranEdge) o; + return Objects.equals(src, tranEdge.src) + && Objects.equals(dst, tranEdge.dst) + && tranCond == tranEdge.tranCond; + } - @Override - public int hashCode() { - return Objects.hash(src, dst, tranCond); - } + @Override + public int hashCode() { + return Objects.hash(src, dst, tranCond); + } - @Override - public String toString() { - return src + "\n\t--" + tranCond + "-->\n\t" + dst; - } -} \ No newline at end of file + @Override + public String toString() { + return src + "\n\t--" + tranCond + "-->\n\t" + dst; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java index 92f68f1fa8c..3be728e074b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/conch/Trilean.java @@ -19,15 +19,17 @@ package qilin.pta.toolkits.conch; public enum Trilean { - TRUE, FALSE, UNKNOWN; + TRUE, + FALSE, + UNKNOWN; - public static Trilean OR(Trilean x1, Trilean x2) { - if (x1 == TRUE || x2 == TRUE) { - return TRUE; - } else if (x1 == UNKNOWN || x2 == UNKNOWN) { - return UNKNOWN; - } else { - return FALSE; - } + public static Trilean OR(Trilean x1, Trilean x2) { + if (x1 == TRUE || x2 == TRUE) { + return TRUE; + } else if (x1 == UNKNOWN || x2 == UNKNOWN) { + return UNKNOWN; + } else { + return FALSE; } + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java index b16b870e453..aac886d95b8 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/CtxTunnelingFeaturesTrueTable.java @@ -43,178 +43,225 @@ * Context Tunneling" (OOPSLA 2018). * */ public class CtxTunnelingFeaturesTrueTable { - private final boolean[] f = new boolean[24]; - - public CtxTunnelingFeaturesTrueTable(SootMethod sm) { - String sig = sm.getSignature().toString(); - // the 10 atomic signature features. - this.f[1] = sig.contains("java"); - this.f[2] = sig.contains("lang"); - this.f[3] = sig.contains("sun"); - this.f[4] = sig.contains("()"); - this.f[5] = sig.contains("void"); - this.f[6] = sig.contains("security"); - this.f[7] = sig.contains("int"); - this.f[8] = sig.contains("util"); - this.f[9] = sig.contains("String"); - this.f[10] = sig.contains("init"); - // 13 additional features (a bit complex). - this.f[11] = containedInNestedClass(sm); - this.f[12] = sm.getParameterCount() > 1; - - Body body = PTAUtils.getMethodBody(sm); - this.f[15] = body.getLocalCount() > 0; - int heapAllocCnt = 0; - for (Stmt unit : body.getStmts()) { - if (unit instanceof JAssignStmt assignStmt) { - Value left = assignStmt.getLeftOp(); - if (left instanceof Local) { - Value right = assignStmt.getRightOp(); - if (right instanceof Local) { - this.f[14] = true; - } else if (right instanceof JNewExpr || right instanceof JNewArrayExpr || right instanceof JNewMultiArrayExpr) { - heapAllocCnt++; - } else if (right instanceof AbstractInvokeExpr) { - if (right instanceof JStaticInvokeExpr) { - this.f[17] = true; - } else if (right instanceof JVirtualInvokeExpr || right instanceof JInterfaceInvokeExpr) { - this.f[18] = true; - } - } else if (right instanceof JArrayRef) { - this.f[13] = true; - } - } else if (left instanceof JInstanceFieldRef) { - this.f[16] = true; - } - } else if (unit instanceof JInvokeStmt invokeStmt) { - AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); - if (expr instanceof JStaticInvokeExpr) { - this.f[17] = true; - } else if (expr instanceof JVirtualInvokeExpr || expr instanceof JInterfaceInvokeExpr) { - this.f[18] = true; - } - } + private final boolean[] f = new boolean[24]; + + public CtxTunnelingFeaturesTrueTable(SootMethod sm) { + String sig = sm.getSignature().toString(); + // the 10 atomic signature features. + this.f[1] = sig.contains("java"); + this.f[2] = sig.contains("lang"); + this.f[3] = sig.contains("sun"); + this.f[4] = sig.contains("()"); + this.f[5] = sig.contains("void"); + this.f[6] = sig.contains("security"); + this.f[7] = sig.contains("int"); + this.f[8] = sig.contains("util"); + this.f[9] = sig.contains("String"); + this.f[10] = sig.contains("init"); + // 13 additional features (a bit complex). + this.f[11] = containedInNestedClass(sm); + this.f[12] = sm.getParameterCount() > 1; + Body body = PTAUtils.getMethodBody(sm); + this.f[15] = body.getLocalCount() > 0; + int heapAllocCnt = 0; + for (Stmt unit : body.getStmts()) { + if (unit instanceof JAssignStmt assignStmt) { + Value left = assignStmt.getLeftOp(); + if (left instanceof Local) { + Value right = assignStmt.getRightOp(); + if (right instanceof Local) { + this.f[14] = true; + } else if (right instanceof JNewExpr + || right instanceof JNewArrayExpr + || right instanceof JNewMultiArrayExpr) { + heapAllocCnt++; + } else if (right instanceof AbstractInvokeExpr) { + if (right instanceof JStaticInvokeExpr) { + this.f[17] = true; + } else if (right instanceof JVirtualInvokeExpr + || right instanceof JInterfaceInvokeExpr) { + this.f[18] = true; + } + } else if (right instanceof JArrayRef) { + this.f[13] = true; + } + } else if (left instanceof JInstanceFieldRef) { + this.f[16] = true; + } + } else if (unit instanceof JInvokeStmt invokeStmt) { + AbstractInvokeExpr expr = invokeStmt.getInvokeExpr(); + if (expr instanceof JStaticInvokeExpr) { + this.f[17] = true; + } else if (expr instanceof JVirtualInvokeExpr || expr instanceof JInterfaceInvokeExpr) { + this.f[18] = true; } - this.f[19] = sm.isStatic(); - this.f[20] = heapAllocCnt == 1; - this.f[21] = sig.contains("Object"); - this.f[22] = heapAllocCnt >= 1; // note, the original implementation is >=1 not > 1 which is conflict with the paper. - SootClass sc = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); - this.f[23] = sc.getMethods().size() > 20; // their artifact uses 20 as the threshold. + } } + this.f[19] = sm.isStatic(); + this.f[20] = heapAllocCnt == 1; + this.f[21] = sig.contains("Object"); + this.f[22] = + heapAllocCnt + >= 1; // note, the original implementation is >=1 not > 1 which is conflict with the + // paper. + SootClass sc = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); + this.f[23] = sc.getMethods().size() > 20; // their artifact uses 20 as the threshold. + } - public boolean containedInNestedClass(SootMethod sm) { - SootClass sc = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); - return sc.toString().contains("$"); - } + public boolean containedInNestedClass(SootMethod sm) { + SootClass sc = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); + return sc.toString().contains("$"); + } - // corresponding to the Tunneling predicate in its original implementation. - public boolean cfaFormula2() { - boolean subF1 = !f[3] && !f[6] && !f[9] && f[14] && f[15] && !f[18] && !f[19] && !f[23]; - boolean subF2 = f[1] && !f[3] && !f[4] && f[7] && !f[9] && f[12] && f[14] && f[15] && !f[16] && !f[19] && !f[21]; - boolean subF3 = f[1] && !f[2] && !f[3] && !f[6] && !f[9] && f[11] && !f[13] && f[14] && f[15] && !f[16] - && !f[17] && !f[19] && !f[20] && !f[21] && !f[22] && !f[23]; - return subF1 || subF2 || subF3; - } + // corresponding to the Tunneling predicate in its original implementation. + public boolean cfaFormula2() { + boolean subF1 = !f[3] && !f[6] && !f[9] && f[14] && f[15] && !f[18] && !f[19] && !f[23]; + boolean subF2 = + f[1] && !f[3] && !f[4] && f[7] && !f[9] && f[12] && f[14] && f[15] && !f[16] && !f[19] + && !f[21]; + boolean subF3 = + f[1] && !f[2] && !f[3] && !f[6] && !f[9] && f[11] && !f[13] && f[14] && f[15] && !f[16] + && !f[17] && !f[19] && !f[20] && !f[21] && !f[22] && !f[23]; + return subF1 || subF2 || subF3; + } - // corresponding to the TunnelingM in its original implementation. - public boolean cfaFormula1() { - boolean subF1 = f[1] && !f[2] && !f[3] && f[4] && f[5] && !f[6] && !f[7] && f[8] && f[10] && !f[11] - && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && !f[22] && f[23]; + // corresponding to the TunnelingM in its original implementation. + public boolean cfaFormula1() { + boolean subF1 = + f[1] && !f[2] && !f[3] && f[4] && f[5] && !f[6] && !f[7] && f[8] && f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] + && !f[21] && !f[22] && f[23]; - boolean subF2 = !f[6] && f[8] && !f[10] && !f[11] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[22]; + boolean subF2 = + !f[6] && f[8] && !f[10] && !f[11] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] + && !f[20] && !f[22]; - boolean subF3 = f[1] && f[2] && !f[3] && !f[4] && !f[6] && f[8] && !f[9] && !f[10] && !f[11] && f[12] && f[14] - && f[15] && !f[16] && f[17] && f[18] && f[19] && !f[20] && f[21] && !f[22] && f[23]; - return subF1 || subF2 || subF3; - } + boolean subF3 = + f[1] && f[2] && !f[3] && !f[4] && !f[6] && f[8] && !f[9] && !f[10] && !f[11] && f[12] + && f[14] && f[15] && !f[16] && f[17] && f[18] && f[19] && !f[20] && f[21] && !f[22] + && f[23]; + return subF1 || subF2 || subF3; + } - public boolean objFormula2() { - boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[14] && f[15] && !f[19]; - boolean subF2 = f[1] && f[2] && f[3] && !f[4] && f[5] && f[6] && !f[7] && !f[8] && f[9] && f[10] && !f[11] - && f[12] && !f[13] && f[14] && f[15] && f[16] && f[17] && f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; - return subF1 || subF2; - } + public boolean objFormula2() { + boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[14] && f[15] && !f[19]; + boolean subF2 = + f[1] && f[2] && f[3] && !f[4] && f[5] && f[6] && !f[7] && !f[8] && f[9] && f[10] && !f[11] + && f[12] && !f[13] && f[14] && f[15] && f[16] && f[17] && f[18] && !f[19] && !f[20] + && !f[21] && f[22] && f[23]; + return subF1 || subF2; + } - public boolean objFormula1() { - boolean subF1 = !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] && !f[11] && !f[12] - && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; + public boolean objFormula1() { + boolean subF1 = + !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] + && !f[21] && f[22] && !f[23]; - boolean subF2 = f[1] && !f[2] && !f[3] && f[4] && !f[5] && !f[6] && !f[7] && !f[9] && !f[10] && !f[11] && !f[12] - && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && !f[23]; + boolean subF2 = + f[1] && !f[2] && !f[3] && f[4] && !f[5] && !f[6] && !f[7] && !f[9] && !f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && f[20] + && !f[21] && !f[23]; - boolean subF3 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] - && f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; + boolean subF3 = + f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] + && f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] + && !f[21] && f[22] && !f[23]; - boolean subF4 = f[1] && f[2] && !f[3] && !f[4] && !f[5] && !f[6] && !f[7] && f[8] && !f[10] && !f[11] && !f[12] - && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && f[21] && f[23]; - return subF1 || subF2 || subF3 || subF4; - } + boolean subF4 = + f[1] && f[2] && !f[3] && !f[4] && !f[5] && !f[6] && !f[7] && f[8] && !f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[18] && f[21] && f[23]; + return subF1 || subF2 || subF3 || subF4; + } - public boolean typeFormula2() { - boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[14] && f[15] && !f[19] && !f[23]; - boolean subF2 = f[1] && f[2] && !f[5] && !f[7] && !f[8] && f[9] && !f[10] && !f[11] && f[14] - && f[15] && !f[16] && f[17] && !f[19] && !f[20] && f[22] && !f[23]; - boolean subF3 = f[3] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && !f[11] && !f[13] && f[14] && f[15] - && f[18] && !f[19] && !f[20] && !f[22] && f[23]; + public boolean typeFormula2() { + boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[14] && f[15] && !f[19] && !f[23]; + boolean subF2 = + f[1] && f[2] && !f[5] && !f[7] && !f[8] && f[9] && !f[10] && !f[11] && f[14] && f[15] + && !f[16] && f[17] && !f[19] && !f[20] && f[22] && !f[23]; + boolean subF3 = + f[3] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && !f[11] && !f[13] && f[14] && f[15] + && f[18] && !f[19] && !f[20] && !f[22] && f[23]; - boolean subF4 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] - && !f[11] && f[14] && f[15] && f[16] && !f[17] && !f[19] && !f[20] && !f[21]; + boolean subF4 = + f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] + && !f[11] && f[14] && f[15] && f[16] && !f[17] && !f[19] && !f[20] && !f[21]; - boolean subF5 = !f[1] && !f[2] && !f[3] && !f[4] && !f[6] && f[7] && !f[9] && !f[11] && f[12] - && !f[13] && f[14] && f[15] && !f[17] && !f[19] && !f[20] && !f[21] && !f[23]; - return subF1 || subF2 || subF3 || subF4 || subF5; - } + boolean subF5 = + !f[1] && !f[2] && !f[3] && !f[4] && !f[6] && f[7] && !f[9] && !f[11] && f[12] && !f[13] + && f[14] && f[15] && !f[17] && !f[19] && !f[20] && !f[21] && !f[23]; + return subF1 || subF2 || subF3 || subF4 || subF5; + } - public boolean typeFormula1() { - boolean subF1 = f[1] && !f[2] && !f[3] && !f[6] && !f[7] && f[8] && !f[9] && !f[10] && !f[11] - && !f[12] && f[14] && f[15] && !f[16] && !f[17] && !f[19] && f[20] && f[22]; + public boolean typeFormula1() { + boolean subF1 = + f[1] && !f[2] && !f[3] && !f[6] && !f[7] && f[8] && !f[9] && !f[10] && !f[11] && !f[12] + && f[14] && f[15] && !f[16] && !f[17] && !f[19] && f[20] && f[22]; - boolean subF2 = f[1] && !f[2] && !f[3] && f[4] && f[5] && !f[6] && !f[7] && f[8] && !f[9] && f[10] && !f[11] - && !f[12] && !f[13] && !f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + boolean subF2 = + f[1] && !f[2] && !f[3] && f[4] && f[5] && !f[6] && !f[7] && f[8] && !f[9] && f[10] && !f[11] + && !f[12] && !f[13] && !f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] && !f[20] + && !f[21] && f[22] && f[23]; - boolean subF3 = f[1] && f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] && !f[11] - && f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + boolean subF3 = + f[1] && f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] + && !f[11] && f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] + && !f[20] && !f[21] && f[22] && f[23]; - boolean subF4 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] - && !f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[21] && !f[18] && f[20] && f[22] && !f[23]; + boolean subF4 = + f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] + && !f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[21] && !f[18] && f[20] + && f[22] && !f[23]; - boolean subF5 = !f[1] && !f[2] && !f[3] && !f[4] && !f[5] && !f[6] && f[7] && !f[8] && !f[9] && !f[10] && !f[11] - && f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + boolean subF5 = + !f[1] && !f[2] && !f[3] && !f[4] && !f[5] && !f[6] && f[7] && !f[8] && !f[9] && !f[10] + && !f[11] && f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && f[18] && !f[19] + && !f[20] && !f[21] && f[22] && f[23]; - boolean subF6 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && !f[9] - && f[8] && f[10] && !f[11] && f[12] && !f[13] && f[14] && f[15] && f[16] - && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; + boolean subF6 = + f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && !f[9] && f[8] && f[10] && !f[11] + && f[12] && !f[13] && f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] + && !f[21] && f[22] && !f[23]; - boolean subF7 = !f[1] && !f[2] && f[3] && f[4] && f[5] && !f[6] && !f[7] && !f[8] - && !f[9] && f[10] && !f[11] && !f[12] && !f[13] && !f[14] && f[15] && !f[16] - && !f[17] && !f[18] && !f[19] && !f[20] && !f[21] && f[22] && !f[23]; + boolean subF7 = + !f[1] && !f[2] && f[3] && f[4] && f[5] && !f[6] && !f[7] && !f[8] && !f[9] && f[10] + && !f[11] && !f[12] && !f[13] && !f[14] && f[15] && !f[16] && !f[17] && !f[18] && !f[19] + && !f[20] && !f[21] && f[22] && !f[23]; - boolean subF8 = !f[4] && !f[9] && !f[10] && !f[11] && f[13] && f[14] && f[15] && !f[16] && f[18] && f[22]; + boolean subF8 = + !f[4] && !f[9] && !f[10] && !f[11] && f[13] && f[14] && f[15] && !f[16] && f[18] && f[22]; - boolean subF9 = f[1] && !f[2] && !f[3] && f[4] && !f[5] && !f[6] && !f[7] && f[8] && !f[9] && !f[10] && !f[11] - && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && f[18] && !f[19] && !f[20] && !f[21] && f[22] && f[23]; + boolean subF9 = + f[1] && !f[2] && !f[3] && f[4] && !f[5] && !f[6] && !f[7] && f[8] && !f[9] && !f[10] + && !f[11] && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && f[18] && !f[19] + && !f[20] && !f[21] && f[22] && f[23]; - boolean subF10 = !f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[9] - && !f[11] && !f[12] && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[19] && !f[21] && f[22]; - return subF1 || subF2 || subF3 || subF4 || subF5 || subF6 || subF7 || subF8 || subF9 || subF10; - } + boolean subF10 = + !f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && !f[7] && !f[9] && !f[11] && !f[12] + && !f[13] && f[14] && f[15] && !f[16] && !f[17] && !f[19] && !f[21] && f[22]; + return subF1 || subF2 || subF3 || subF4 || subF5 || subF6 || subF7 || subF8 || subF9 || subF10; + } - public boolean hybridFormula2() { - boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[15] && !f[23]; - boolean subF2 = f[1] && !f[3] && !f[4] && !f[6] && f[8] && !f[9] && !f[10] - && !f[11] && f[14] && f[15] && !f[16] && f[19]; - boolean subF3 = f[2] && !f[3] && f[4] && !f[5] && !f[6] && f[8] && !f[9] && !f[11] && !f[13] - && f[14] && f[15] && !f[16] && f[17] && !f[18] && !f[19] && !f[20] && f[23]; - return subF1 || subF2 || subF3; - } + public boolean hybridFormula2() { + boolean subF1 = f[1] && !f[3] && !f[6] && !f[9] && f[11] && f[15] && !f[23]; + boolean subF2 = + f[1] && !f[3] && !f[4] && !f[6] && f[8] && !f[9] && !f[10] && !f[11] && f[14] && f[15] + && !f[16] && f[19]; + boolean subF3 = + f[2] && !f[3] && f[4] && !f[5] && !f[6] && f[8] && !f[9] && !f[11] && !f[13] && f[14] + && f[15] && !f[16] && f[17] && !f[18] && !f[19] && !f[20] && f[23]; + return subF1 || subF2 || subF3; + } - public boolean hybridFormula1() { - boolean subF1 = f[1] && !f[2] && !f[3] && f[4] && !f[6] && !f[8] && !f[9] && !f[11] && !f[13] - && f[14] && f[15] && !f[17] && !f[19] && f[20] && !f[21] && f[22]; - boolean subF2 = f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] && - !f[13] && !f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] && f[22] && !f[23]; - return subF1 || subF2; - } + public boolean hybridFormula1() { + boolean subF1 = + f[1] && !f[2] && !f[3] && f[4] && !f[6] && !f[8] && !f[9] && !f[11] && !f[13] && f[14] + && f[15] && !f[17] && !f[19] && f[20] && !f[21] && f[22]; + boolean subF2 = + f[1] && !f[2] && !f[3] && !f[4] && f[5] && !f[6] && f[7] && f[8] && !f[9] && f[10] && !f[11] + && !f[13] && !f[14] && f[15] && f[16] && !f[17] && !f[18] && !f[19] && f[20] && !f[21] + && f[22] && !f[23]; + return subF1 || subF2; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java index cdc6bf5b8a4..5b86a22c81c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/DataDrivenSelector.java @@ -18,6 +18,8 @@ package qilin.pta.toolkits.dd; +import java.util.HashMap; +import java.util.Map; import qilin.core.pag.AllocNode; import qilin.core.pag.FieldValNode; import qilin.core.pag.LocalVarNode; @@ -29,67 +31,64 @@ import soot.Context; import sootup.core.model.SootMethod; -import java.util.HashMap; -import java.util.Map; - public class DataDrivenSelector extends CtxSelector { - private final Map m2ftt = new HashMap<>(); - private final Class mClass; + private final Map m2ftt = new HashMap<>(); + private final Class mClass; - public DataDrivenSelector(Class mClass) { - this.mClass = mClass; - } + public DataDrivenSelector(Class mClass) { + this.mClass = mClass; + } - private FeaturesTrueTable findOrCreateFeaturesTrueTable(SootMethod sm) { - return m2ftt.computeIfAbsent(sm, k -> new FeaturesTrueTable(sm)); - } + private FeaturesTrueTable findOrCreateFeaturesTrueTable(SootMethod sm) { + return m2ftt.computeIfAbsent(sm, k -> new FeaturesTrueTable(sm)); + } - @Override - public Context select(SootMethod m, Context context) { - FeaturesTrueTable ftt = findOrCreateFeaturesTrueTable(m); - int i = 0; - if (mClass == HybObjCtxConstructor.class) { - if (ftt.hybrid2objFormula2()) { - i = 2; - } else if (ftt.hybrid2objFormula1()) { - i = 1; - } - } else if (mClass == ObjCtxConstructor.class) { - if (ftt.twoObjFormula2()) { - i = 2; - } else if (ftt.twoObjFormula1()) { - i = 1; - } - } else if (mClass == CallsiteCtxConstructor.class) { - if (ftt.twoCFAFormula2()) { - i = 2; - } else if (ftt.twoCFAFormula1()) { - i = 1; - } - } else if (mClass == TypeCtxConstructor.class) { - if (ftt.twoTypeFormula2()) { - i = 2; - } else if (ftt.twoTypeFormula1()) { - i = 1; - } - } else { - throw new RuntimeException("unsupport data-driven pointer analysis!"); - } - return contextTailor(context, i); + @Override + public Context select(SootMethod m, Context context) { + FeaturesTrueTable ftt = findOrCreateFeaturesTrueTable(m); + int i = 0; + if (mClass == HybObjCtxConstructor.class) { + if (ftt.hybrid2objFormula2()) { + i = 2; + } else if (ftt.hybrid2objFormula1()) { + i = 1; + } + } else if (mClass == ObjCtxConstructor.class) { + if (ftt.twoObjFormula2()) { + i = 2; + } else if (ftt.twoObjFormula1()) { + i = 1; + } + } else if (mClass == CallsiteCtxConstructor.class) { + if (ftt.twoCFAFormula2()) { + i = 2; + } else if (ftt.twoCFAFormula1()) { + i = 1; + } + } else if (mClass == TypeCtxConstructor.class) { + if (ftt.twoTypeFormula2()) { + i = 2; + } else if (ftt.twoTypeFormula1()) { + i = 1; + } + } else { + throw new RuntimeException("unsupport data-driven pointer analysis!"); } + return contextTailor(context, i); + } - @Override - public Context select(LocalVarNode lvn, Context context) { - return context; - } + @Override + public Context select(LocalVarNode lvn, Context context) { + return context; + } - @Override - public Context select(FieldValNode fvn, Context context) { - return context; - } + @Override + public Context select(FieldValNode fvn, Context context) { + return context; + } - @Override - public Context select(AllocNode heap, Context context) { - return context; - } + @Override + public Context select(AllocNode heap, Context context) { + return context; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java index 973bc19838c..0cab2b67693 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/FeaturesTrueTable.java @@ -41,112 +41,279 @@ * features and formulas used in "Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017)" * */ public class FeaturesTrueTable { - private final boolean[] features = new boolean[26]; + private final boolean[] features = new boolean[26]; - public FeaturesTrueTable(SootMethod sm) { - String sig = sm.getSignature().toString(); - this.features[1] = sig.contains("java"); - this.features[2] = sig.contains("lang"); - this.features[3] = sig.contains("sun"); - this.features[4] = sig.contains("()"); - this.features[5] = sig.contains("void"); - this.features[6] = sig.contains("security"); - this.features[7] = sig.contains("int"); - this.features[8] = sig.contains("util"); - this.features[9] = sig.contains("String"); - this.features[10] = sig.contains("init"); - Body body = PTAUtils.getMethodBody(sm); - for (Stmt unit : body.getStmts()) { - if (unit instanceof JAssignStmt) { - this.features[11] = true; - } else if (unit instanceof JIdentityStmt) { - this.features[12] = true; - } else if (unit instanceof JInvokeStmt) { - this.features[13] = true; - } else if (unit instanceof JReturnStmt) { - this.features[14] = true; - } else if (unit instanceof JThrowStmt) { - this.features[15] = true; - } else if (unit instanceof JBreakpointStmt) { - this.features[16] = true; - } else if (unit instanceof JEnterMonitorStmt) { - this.features[17] = true; - } else if (unit instanceof JExitMonitorStmt) { - this.features[18] = true; - } else if (unit instanceof JGotoStmt) { - this.features[19] = true; - } else if (unit instanceof JIfStmt) { - this.features[20] = true; - } else if (unit instanceof JSwitchStmt) { - this.features[21] = true; - } else if (unit instanceof JNopStmt) { - this.features[22] = true; - } else if (unit instanceof JRetStmt) { - this.features[23] = true; - } else if (unit instanceof JReturnVoidStmt) { - this.features[24] = true; - } else if (unit instanceof JSwitchStmt) { - this.features[25] = true; - } - } + public FeaturesTrueTable(SootMethod sm) { + String sig = sm.getSignature().toString(); + this.features[1] = sig.contains("java"); + this.features[2] = sig.contains("lang"); + this.features[3] = sig.contains("sun"); + this.features[4] = sig.contains("()"); + this.features[5] = sig.contains("void"); + this.features[6] = sig.contains("security"); + this.features[7] = sig.contains("int"); + this.features[8] = sig.contains("util"); + this.features[9] = sig.contains("String"); + this.features[10] = sig.contains("init"); + Body body = PTAUtils.getMethodBody(sm); + for (Stmt unit : body.getStmts()) { + if (unit instanceof JAssignStmt) { + this.features[11] = true; + } else if (unit instanceof JIdentityStmt) { + this.features[12] = true; + } else if (unit instanceof JInvokeStmt) { + this.features[13] = true; + } else if (unit instanceof JReturnStmt) { + this.features[14] = true; + } else if (unit instanceof JThrowStmt) { + this.features[15] = true; + } else if (unit instanceof JBreakpointStmt) { + this.features[16] = true; + } else if (unit instanceof JEnterMonitorStmt) { + this.features[17] = true; + } else if (unit instanceof JExitMonitorStmt) { + this.features[18] = true; + } else if (unit instanceof JGotoStmt) { + this.features[19] = true; + } else if (unit instanceof JIfStmt) { + this.features[20] = true; + } else if (unit instanceof JSwitchStmt) { + this.features[21] = true; + } else if (unit instanceof JNopStmt) { + this.features[22] = true; + } else if (unit instanceof JRetStmt) { + this.features[23] = true; + } else if (unit instanceof JReturnVoidStmt) { + this.features[24] = true; + } else if (unit instanceof JSwitchStmt) { + this.features[25] = true; + } } + } - // the following two are for hybrid 2-object-sensitive pointer analysis. - public boolean hybrid2objFormula2() { - return features[1] && !features[3] && !features[6] && features[8] && !features[9] && !features[16] - && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] - && !features[22] && !features[23] && !features[24] && !features[25]; - } + // the following two are for hybrid 2-object-sensitive pointer analysis. + public boolean hybrid2objFormula2() { + return features[1] + && !features[3] + && !features[6] + && features[8] + && !features[9] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + } - public boolean hybrid2objFormula1() { - boolean subF1 = features[1] && !features[3] && !features[4] && features[6] && !features[7] && !features[8] && !features[9] && - !features[15] && !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] - && !features[22] && !features[23] && !features[24] && !features[25]; - boolean subF2 = !features[3] && !features[4] && !features[7] && !features[8] && !features[9] && features[10] && features[11] && - features[12] && features[13] && !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && - !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; - boolean subF3 = !features[3] && !features[9] && features[13] && features[14] && features[15] && !features[16] && !features[17] - && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; - boolean subF4 = features[1] && features[2] && !features[3] && features[4] && !features[5] && !features[6] && !features[7] && !features[8] - && !features[9] && !features[10] && !features[13] && !features[15] && !features[16] && !features[17] && !features[18] - && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; - return subF1 || subF2 || subF3 || subF4; - } + public boolean hybrid2objFormula1() { + boolean subF1 = + features[1] + && !features[3] + && !features[4] + && features[6] + && !features[7] + && !features[8] + && !features[9] + && !features[15] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + boolean subF2 = + !features[3] + && !features[4] + && !features[7] + && !features[8] + && !features[9] + && features[10] + && features[11] + && features[12] + && features[13] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + boolean subF3 = + !features[3] + && !features[9] + && features[13] + && features[14] + && features[15] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + boolean subF4 = + features[1] + && features[2] + && !features[3] + && features[4] + && !features[5] + && !features[6] + && !features[7] + && !features[8] + && !features[9] + && !features[10] + && !features[13] + && !features[15] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + return subF1 || subF2 || subF3 || subF4; + } - public boolean twoObjFormula2() { - return hybrid2objFormula2(); - } + public boolean twoObjFormula2() { + return hybrid2objFormula2(); + } - public boolean twoObjFormula1() { - boolean subF1 = features[1] && features[2] && !features[3] && !features[6] && !features[7] && !features[8] && !features[9] && - !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && - !features[23] && !features[24] && !features[25]; - boolean subF2 = !features[1] && !features[2] && features[5] && features[8] && !features[9] && features[11] && features[12] && !features[14] - && !features[15] && !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && - !features[23] && !features[24] && !features[25]; - boolean subF3 = !features[3] && !features[4] && !features[7] && !features[8] && !features[9] && features[10] && features[11] && features[12] && - !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && - !features[23] && !features[24] && !features[25]; - return subF1 || subF2 || subF3; - } + public boolean twoObjFormula1() { + boolean subF1 = + features[1] + && features[2] + && !features[3] + && !features[6] + && !features[7] + && !features[8] + && !features[9] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + boolean subF2 = + !features[1] + && !features[2] + && features[5] + && features[8] + && !features[9] + && features[11] + && features[12] + && !features[14] + && !features[15] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + boolean subF3 = + !features[3] + && !features[4] + && !features[7] + && !features[8] + && !features[9] + && features[10] + && features[11] + && features[12] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + return subF1 || subF2 || subF3; + } - public boolean twoTypeFormula2() { - return hybrid2objFormula2(); - } + public boolean twoTypeFormula2() { + return hybrid2objFormula2(); + } - public boolean twoTypeFormula1() { - return features[1] && features[2] && !features[3] && !features[6] && !features[7] && !features[8] && !features[9] && !features[15] && - !features[16] && !features[17] && !features[18] && !features[19] && !features[20] && !features[21] && !features[22] && - !features[23] && !features[24] && !features[25]; - } + public boolean twoTypeFormula1() { + return features[1] + && features[2] + && !features[3] + && !features[6] + && !features[7] + && !features[8] + && !features[9] + && !features[15] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + } - public boolean twoCFAFormula2() { - return features[1] && !features[6] && !features[7] && features[11] && features[12] && features[13] && !features[16] && !features[17] && !features[18] - && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; - } + public boolean twoCFAFormula2() { + return features[1] + && !features[6] + && !features[7] + && features[11] + && features[12] + && features[13] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + } - public boolean twoCFAFormula1() { - return features[1] && features[2] && !features[7] && !features[16] && !features[17] && !features[18] - && !features[19] && !features[20] && !features[21] && !features[22] && !features[23] && !features[24] && !features[25]; - } + public boolean twoCFAFormula1() { + return features[1] + && features[2] + && !features[7] + && !features[16] + && !features[17] + && !features[18] + && !features[19] + && !features[20] + && !features[21] + && !features[22] + && !features[23] + && !features[24] + && !features[25]; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java index 95b24f85025..63e03e49807 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/dd/TunnelingConstructor.java @@ -18,6 +18,8 @@ package qilin.pta.toolkits.dd; +import java.util.HashMap; +import java.util.Map; import qilin.core.pag.CallSite; import qilin.core.pag.ContextAllocNode; import qilin.parm.ctxcons.*; @@ -25,44 +27,46 @@ import soot.MethodOrMethodContext; import sootup.core.model.SootMethod; -import java.util.HashMap; -import java.util.Map; - public class TunnelingConstructor implements CtxConstructor { - private final CtxConstructor ctxCons; - private final Map m2ftt = new HashMap<>(); + private final CtxConstructor ctxCons; + private final Map m2ftt = new HashMap<>(); - private CtxTunnelingFeaturesTrueTable findOrCreateTunnelingFeaturesTrueTable(SootMethod sm) { - return m2ftt.computeIfAbsent(sm, k -> new CtxTunnelingFeaturesTrueTable(sm)); - } + private CtxTunnelingFeaturesTrueTable findOrCreateTunnelingFeaturesTrueTable(SootMethod sm) { + return m2ftt.computeIfAbsent(sm, k -> new CtxTunnelingFeaturesTrueTable(sm)); + } - public TunnelingConstructor(CtxConstructor ctxCons) { - this.ctxCons = ctxCons; - } + public TunnelingConstructor(CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + } - @Override - public Context constructCtx(MethodOrMethodContext caller, ContextAllocNode receiverNode, CallSite callSite, SootMethod target) { - CtxTunnelingFeaturesTrueTable ctftt1 = findOrCreateTunnelingFeaturesTrueTable(caller.method()); - CtxTunnelingFeaturesTrueTable ctftt2 = findOrCreateTunnelingFeaturesTrueTable(target); - if (ctxCons instanceof CallsiteCtxConstructor) { - if (ctftt1.cfaFormula1() || ctftt2.cfaFormula2()) { - return caller.context(); - } - } else if (ctxCons instanceof TypeCtxConstructor) { - if (ctftt1.typeFormula1() || ctftt2.typeFormula2()) { - return caller.context(); - } - } else if (ctxCons instanceof ObjCtxConstructor) { - if (ctftt1.objFormula1() || ctftt2.objFormula2()) { - return caller.context(); - } - } else if (ctxCons instanceof HybObjCtxConstructor) { - if (ctftt1.hybridFormula1() || ctftt2.hybridFormula2()) { - return caller.context(); - } - } else { - throw new RuntimeException("unsupported context constructor for tunneling: " + ctxCons.getClass()); - } - return ctxCons.constructCtx(caller, receiverNode, callSite, target); + @Override + public Context constructCtx( + MethodOrMethodContext caller, + ContextAllocNode receiverNode, + CallSite callSite, + SootMethod target) { + CtxTunnelingFeaturesTrueTable ctftt1 = findOrCreateTunnelingFeaturesTrueTable(caller.method()); + CtxTunnelingFeaturesTrueTable ctftt2 = findOrCreateTunnelingFeaturesTrueTable(target); + if (ctxCons instanceof CallsiteCtxConstructor) { + if (ctftt1.cfaFormula1() || ctftt2.cfaFormula2()) { + return caller.context(); + } + } else if (ctxCons instanceof TypeCtxConstructor) { + if (ctftt1.typeFormula1() || ctftt2.typeFormula2()) { + return caller.context(); + } + } else if (ctxCons instanceof ObjCtxConstructor) { + if (ctftt1.objFormula1() || ctftt2.objFormula2()) { + return caller.context(); + } + } else if (ctxCons instanceof HybObjCtxConstructor) { + if (ctftt1.hybridFormula1() || ctftt2.hybridFormula2()) { + return caller.context(); + } + } else { + throw new RuntimeException( + "unsupported context constructor for tunneling: " + ctxCons.getClass()); } + return ctxCons.constructCtx(caller, receiverNode, callSite, target); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java index 7a475c040cb..90de43e6700 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/CollectionHeuristic.java @@ -1,5 +1,11 @@ package qilin.pta.toolkits.debloaterx; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.pag.AllocNode; @@ -17,13 +23,6 @@ import sootup.core.types.ClassType; import sootup.core.types.Type; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - /* * This is a much simpler scheme for finding context-dependent objects. * This file does not belong to any part of DebloaterX. @@ -32,178 +31,180 @@ * (2) an object is context-dependent if it is of a container type. * */ public class CollectionHeuristic { - protected final PTA pta; - protected final PAG pag; - - protected final Map> t2Fields = new ConcurrentHashMap<>(); - - protected final Set containerType = ConcurrentHashMap.newKeySet(); - - protected final Set ctxDepHeaps = ConcurrentHashMap.newKeySet(); - - public Set getCtxDepHeaps() { - return ctxDepHeaps; + protected final PTA pta; + protected final PAG pag; + + protected final Map> t2Fields = new ConcurrentHashMap<>(); + + protected final Set containerType = ConcurrentHashMap.newKeySet(); + + protected final Set ctxDepHeaps = ConcurrentHashMap.newKeySet(); + + public Set getCtxDepHeaps() { + return ctxDepHeaps; + } + + public CollectionHeuristic(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + } + + private void buildHeapFieldsMappingIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + Set stores = new HashSet<>(); + Set loads = new HashSet<>(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof FieldRefNode frn) { + stores.add(frn); + } + } else if (from instanceof FieldRefNode frn) { + loads.add(frn); + } } - - public CollectionHeuristic(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - + // handle STORE + for (FieldRefNode frn : stores) { + LocalVarNode storeBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + } } - - private void buildHeapFieldsMappingIn(SootMethod method) { - MethodPAG srcmpag = pag.getMethodPAG(method); - Set stores = new HashSet<>(); - Set loads = new HashSet<>(); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof FieldRefNode frn) { - stores.add(frn); - } - } else if (from instanceof FieldRefNode frn) { - loads.add(frn); - } - } - // handle STORE - for (FieldRefNode frn : stores) { - LocalVarNode storeBase = (LocalVarNode) frn.getBase(); - SparkField field = frn.getField(); - for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { - t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); - } - } - // handle LOAD - for (FieldRefNode frn : loads) { - LocalVarNode loadBase = (LocalVarNode) frn.getBase(); - SparkField field = frn.getField(); - for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { - t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); - } - } + // handle LOAD + for (FieldRefNode frn : loads) { + LocalVarNode loadBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + } } - - private void buildHeapFieldsMapping() { - pta.getNakedReachableMethods().stream().filter(SootMethod::isConcrete).forEach(this::buildHeapFieldsMappingIn); + } + + private void buildHeapFieldsMapping() { + pta.getNakedReachableMethods().stream() + .filter(SootMethod::isConcrete) + .forEach(this::buildHeapFieldsMappingIn); + } + + private boolean isImplementingCollection(SootClass sc) { + Set allInterfaces = new HashSet<>(sc.getInterfaces()); + while (sc.hasSuperclass()) { + sc = (SootClass) sc.getSuperclass().get(); + allInterfaces.addAll(sc.getInterfaces()); } - - private boolean isImplementingCollection(SootClass sc) { - Set allInterfaces = new HashSet<>(sc.getInterfaces()); - while (sc.hasSuperclass()) { - sc = (SootClass) sc.getSuperclass().get(); - allInterfaces.addAll(sc.getInterfaces()); - } - // interface may also have super class - Set worklist = new HashSet<>(); - for (ClassType tmp : allInterfaces) { - SootClass msc = (SootClass) PTAScene.v().getView().getClass(tmp).get(); - worklist.add(msc); - while (msc.hasSuperclass() && ((SootClass) msc.getSuperclass().get()).isInterface()) { - SootClass superClazz = (SootClass) msc.getSuperclass().get(); - worklist.add(superClazz); - msc = superClazz; - } - } - boolean flag = false; - for (SootClass interf : worklist) { - if (interf.getType() == PTAUtils.getClassType("java.util.Collection") - // || interf.getType() == RefType.v("java.util.Map") - ) { - flag = true; - } - } - return flag; + // interface may also have super class + Set worklist = new HashSet<>(); + for (ClassType tmp : allInterfaces) { + SootClass msc = (SootClass) PTAScene.v().getView().getClass(tmp).get(); + worklist.add(msc); + while (msc.hasSuperclass() && ((SootClass) msc.getSuperclass().get()).isInterface()) { + SootClass superClazz = (SootClass) msc.getSuperclass().get(); + worklist.add(superClazz); + msc = superClazz; + } } - - private boolean isNestedInClassImplementCollection(SootClass sc) { - if (!sc.isInnerClass()) { - return false; - } - SootClass outer = (SootClass) sc.getOuterClass().get(); - if (isImplementingCollection(outer)) { - return true; - } - return isNestedInClassImplementCollection(outer); + boolean flag = false; + for (SootClass interf : worklist) { + if (interf.getType() == PTAUtils.getClassType("java.util.Collection") + // || interf.getType() == RefType.v("java.util.Map") + ) { + flag = true; + } } + return flag; + } - private void computeContainerTypes() { - for (Type type : t2Fields.keySet()) { - if (type instanceof ClassType refType) { - SootClass sc = (SootClass) PTAScene.v().getView().getClass(refType).get(); - if (isImplementingCollection(sc) || isNestedInClassImplementCollection(sc)) { - containerType.add(type); - } else { - for (SparkField sf : t2Fields.get(type)) { - if (sf.getType() == PTAUtils.getClassType("java.lang.Object")) { - containerType.add(type); - break; - } - } - } - } else if (type instanceof ArrayType at) { - if (at.getBaseType() == PTAUtils.getClassType("java.lang.Object")) { - containerType.add(at); - } - } else { - System.out.println(type); + private boolean isNestedInClassImplementCollection(SootClass sc) { + if (!sc.isInnerClass()) { + return false; + } + SootClass outer = (SootClass) sc.getOuterClass().get(); + if (isImplementingCollection(outer)) { + return true; + } + return isNestedInClassImplementCollection(outer); + } + + private void computeContainerTypes() { + for (Type type : t2Fields.keySet()) { + if (type instanceof ClassType refType) { + SootClass sc = (SootClass) PTAScene.v().getView().getClass(refType).get(); + if (isImplementingCollection(sc) || isNestedInClassImplementCollection(sc)) { + containerType.add(type); + } else { + for (SparkField sf : t2Fields.get(type)) { + if (sf.getType() == PTAUtils.getClassType("java.lang.Object")) { + containerType.add(type); + break; } + } } - // build a mapping from any field type to their containing type. - Map> ft2t = new HashMap<>(); - for (Type type : t2Fields.keySet()) { - if (type instanceof ClassType) { - for (SparkField sf : t2Fields.get(type)) { - Type sft = sf.getType(); - if (sft instanceof ArrayType at) { - sft = at.getBaseType(); - } - ft2t.computeIfAbsent(sft, k -> new HashSet<>()).add(type); - } - } else if (type instanceof ArrayType at) { - ft2t.computeIfAbsent(at.getBaseType(), k -> new HashSet<>()).add(type); - } + } else if (type instanceof ArrayType at) { + if (at.getBaseType() == PTAUtils.getClassType("java.lang.Object")) { + containerType.add(at); } - // find more container types by checking whether a type has a field of a container type. - Set newlyFound = new HashSet<>(); - containerType.addAll(ft2t.getOrDefault(PTAUtils.getClassType("java.lang.Object"), Collections.emptySet())); - for (Type t1 : containerType) { - for (Type t2 : ft2t.getOrDefault(t1, Collections.emptySet())) { - if (!containerType.contains(t2)) { - newlyFound.add(t2); - } - } + } else { + System.out.println(type); + } + } + // build a mapping from any field type to their containing type. + Map> ft2t = new HashMap<>(); + for (Type type : t2Fields.keySet()) { + if (type instanceof ClassType) { + for (SparkField sf : t2Fields.get(type)) { + Type sft = sf.getType(); + if (sft instanceof ArrayType at) { + sft = at.getBaseType(); + } + ft2t.computeIfAbsent(sft, k -> new HashSet<>()).add(type); } - while (!newlyFound.isEmpty()) { - containerType.addAll(newlyFound); - Set tmp = new HashSet<>(); - for (Type t1 : newlyFound) { - for (Type t2 : ft2t.getOrDefault(t1, Collections.emptySet())) { - if (!containerType.contains(t2)) { - tmp.add(t2); - } - } - } - newlyFound.clear(); - newlyFound.addAll(tmp); + } else if (type instanceof ArrayType at) { + ft2t.computeIfAbsent(at.getBaseType(), k -> new HashSet<>()).add(type); + } + } + // find more container types by checking whether a type has a field of a container type. + Set newlyFound = new HashSet<>(); + containerType.addAll( + ft2t.getOrDefault(PTAUtils.getClassType("java.lang.Object"), Collections.emptySet())); + for (Type t1 : containerType) { + for (Type t2 : ft2t.getOrDefault(t1, Collections.emptySet())) { + if (!containerType.contains(t2)) { + newlyFound.add(t2); } - System.out.println("#ContainerType:" + containerType.size()); + } } - - private void computeContextDependentObjects() { - for (AllocNode heap : pag.getAllocNodes()) { - if (containerType.contains(heap.getType())) { - ctxDepHeaps.add(heap); - } + while (!newlyFound.isEmpty()) { + containerType.addAll(newlyFound); + Set tmp = new HashSet<>(); + for (Type t1 : newlyFound) { + for (Type t2 : ft2t.getOrDefault(t1, Collections.emptySet())) { + if (!containerType.contains(t2)) { + tmp.add(t2); + } } - System.out.println("#OBJECTS:" + pag.getAllocNodes().size()); - System.out.println("#CS:" + ctxDepHeaps.size()); - System.out.println("#CI:" + (pag.getAllocNodes().size() - ctxDepHeaps.size())); + } + newlyFound.clear(); + newlyFound.addAll(tmp); } - - public void run() { - buildHeapFieldsMapping(); - computeContainerTypes(); - computeContextDependentObjects(); + System.out.println("#ContainerType:" + containerType.size()); + } + + private void computeContextDependentObjects() { + for (AllocNode heap : pag.getAllocNodes()) { + if (containerType.contains(heap.getType())) { + ctxDepHeaps.add(heap); + } } + System.out.println("#OBJECTS:" + pag.getAllocNodes().size()); + System.out.println("#CS:" + ctxDepHeaps.size()); + System.out.println("#CI:" + (pag.getAllocNodes().size() - ctxDepHeaps.size())); + } + + public void run() { + buildHeapFieldsMapping(); + computeContainerTypes(); + computeContextDependentObjects(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java index 6518bf69169..df24e5d688a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/ContainerFinder.java @@ -1,5 +1,8 @@ package qilin.pta.toolkits.debloaterx; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.ArrayElement; @@ -13,110 +16,122 @@ import sootup.core.types.ClassType; import sootup.core.types.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - /* * implementing rules for identifying container objects as shown in Figure 8 in the paper. * */ public class ContainerFinder { - protected final PTA pta; - protected final PAG pag; - private final Set notcontainers = ConcurrentHashMap.newKeySet(); - private final Map> containers = new ConcurrentHashMap<>(); + protected final PTA pta; + protected final PAG pag; + private final Set notcontainers = ConcurrentHashMap.newKeySet(); + private final Map> containers = new ConcurrentHashMap<>(); - private final XUtility utility; + private final XUtility utility; - public ContainerFinder(PTA pta, XUtility utility) { - this.pta = pta; - this.pag = pta.getPag(); - this.utility = utility; - } + public ContainerFinder(PTA pta, XUtility utility) { + this.pta = pta; + this.pag = pta.getPag(); + this.utility = utility; + } - /* - * classify objects into primitive containers, normal containers and notcontainers. - * */ - public void run() { - Stopwatch s1 = Stopwatch.newAndStart("pre-containerFinder"); - Set remainObjs = new HashSet<>(); - for (AllocNode heap : pag.getAllocNodes()) { - Type type = heap.getType(); - if (type instanceof ArrayType at) { - JNewArrayExpr nae = (JNewArrayExpr) heap.getNewExpr(); - Value vl = nae.getSize(); - if (utility.isCoarseType(at) && (!(vl instanceof IntConstant ic) || ic.getValue() != 0)) { - containers.computeIfAbsent(heap, k -> new HashSet<>()).add(ArrayElement.v()); - } else { - notcontainers.add(heap); - } - } else if (type instanceof ClassType refType) { - if (utility.isCoarseType(refType) && heap.getMethod() != null) { - remainObjs.add(heap); - } else { - notcontainers.add(heap); - } - } else { - throw new RuntimeException("invalid type for " + heap); - } + /* + * classify objects into primitive containers, normal containers and notcontainers. + * */ + public void run() { + Stopwatch s1 = Stopwatch.newAndStart("pre-containerFinder"); + Set remainObjs = new HashSet<>(); + for (AllocNode heap : pag.getAllocNodes()) { + Type type = heap.getType(); + if (type instanceof ArrayType at) { + JNewArrayExpr nae = (JNewArrayExpr) heap.getNewExpr(); + Value vl = nae.getSize(); + if (utility.isCoarseType(at) && (!(vl instanceof IntConstant ic) || ic.getValue() != 0)) { + containers.computeIfAbsent(heap, k -> new HashSet<>()).add(ArrayElement.v()); + } else { + notcontainers.add(heap); } - s1.stop(); - System.out.println(s1); - Stopwatch s2 = Stopwatch.newAndStart("mid-containerFinder"); - remainObjs.parallelStream().forEach(utility::getHCQ); - s2.stop(); - System.out.println(s2); - Stopwatch s3 = Stopwatch.newAndStart("remain-containerFinder"); - remainObjs.parallelStream().forEach(heap -> { - Set fields = utility.getFields(heap); - fields = fields.stream().filter(f -> utility.isCoarseType(f.getType())).collect(Collectors.toSet()); - HeapContainerQuery hcq = utility.getHCQ(heap); - for (SparkField field : fields) { + } else if (type instanceof ClassType refType) { + if (utility.isCoarseType(refType) && heap.getMethod() != null) { + remainObjs.add(heap); + } else { + notcontainers.add(heap); + } + } else { + throw new RuntimeException("invalid type for " + heap); + } + } + s1.stop(); + System.out.println(s1); + Stopwatch s2 = Stopwatch.newAndStart("mid-containerFinder"); + remainObjs.parallelStream().forEach(utility::getHCQ); + s2.stop(); + System.out.println(s2); + Stopwatch s3 = Stopwatch.newAndStart("remain-containerFinder"); + remainObjs.parallelStream() + .forEach( + heap -> { + Set fields = utility.getFields(heap); + fields = + fields.stream() + .filter(f -> utility.isCoarseType(f.getType())) + .collect(Collectors.toSet()); + HeapContainerQuery hcq = utility.getHCQ(heap); + for (SparkField field : fields) { // check in boolean hasIn = hasNonThisStoreOnField(heap, field, hcq); if (!hasIn) { - continue; + continue; } // check out boolean hasOut = hasNonThisLoadFromField(heap, field, hcq); if (hasOut) { - containers.computeIfAbsent(heap, k -> new HashSet<>()).add(field); + containers.computeIfAbsent(heap, k -> new HashSet<>()).add(field); } - } - if (!containers.containsKey(heap)) { + } + if (!containers.containsKey(heap)) { notcontainers.add(heap); - } - }); - s3.stop(); - System.out.println(s3); - System.out.println("#ObjectsNotAContainer:" + notcontainers.size()); - System.out.println("#Container:" + containers.size()); - } + } + }); + s3.stop(); + System.out.println(s3); + System.out.println("#ObjectsNotAContainer:" + notcontainers.size()); + System.out.println("#Container:" + containers.size()); + } - private boolean hasNonThisStoreOnField(AllocNode heap, SparkField field, HeapContainerQuery hcq) { - if (utility.hasNonThisStoreOnField(heap, field)) { - return true; - } - return hcq.hasParamsStoredInto(field); + private boolean hasNonThisStoreOnField(AllocNode heap, SparkField field, HeapContainerQuery hcq) { + if (utility.hasNonThisStoreOnField(heap, field)) { + return true; } + return hcq.hasParamsStoredInto(field); + } - private boolean hasNonThisLoadFromField(AllocNode heap, SparkField field, HeapContainerQuery hcq) { - if (utility.hasNonThisLoadFromField(heap, field)) { - return true; - } - return hcq.hasOutMethodsWithRetOrParamValueFrom(field); + private boolean hasNonThisLoadFromField( + AllocNode heap, SparkField field, HeapContainerQuery hcq) { + if (utility.hasNonThisLoadFromField(heap, field)) { + return true; } + return hcq.hasOutMethodsWithRetOrParamValueFrom(field); + } - public boolean isAContainer(AllocNode heap) { - if (this.containers.containsKey(heap)) { - return true; - } else if (heap.getMethod().getSignature().toString().startsWith("") - || heap.getMethod().getSignature().toString().startsWith("")) { - // We will remove such hacks in the future. The noise of [java.lang.String] types introduced by the resolving of reflection of - // Array.newInstance makes the whole analysis imprecise. Qilin's reflection mechanism causes this. One potential solution is - // not to resolve reflection for these two methods. - return true; - } - return false; + public boolean isAContainer(AllocNode heap) { + if (this.containers.containsKey(heap)) { + return true; + } else if (heap.getMethod() + .getSignature() + .toString() + .startsWith( + "") + || heap.getMethod() + .getSignature() + .toString() + .startsWith( + "")) { + // We will remove such hacks in the future. The noise of [java.lang.String] types introduced + // by the resolving of reflection of + // Array.newInstance makes the whole analysis imprecise. Qilin's reflection mechanism causes + // this. One potential solution is + // not to resolve reflection for these two methods. + return true; } + return false; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java index b8197867da5..9ac67d83008 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/DebloaterX.java @@ -1,6 +1,8 @@ package qilin.pta.toolkits.debloaterx; import com.google.common.collect.Sets; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import qilin.core.PTA; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; @@ -10,163 +12,198 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - /* * A container usage pattern-based approach to identifying context-independent objects for context debloating. * Corresponding to Algorithm 1 in the paper. * */ public class DebloaterX { - private final PTA pta; - private final PAG pag; - private final ContainerFinder containerFinder; - private final XUtility utility; + private final PTA pta; + private final PAG pag; + private final ContainerFinder containerFinder; + private final XUtility utility; - public DebloaterX(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - this.utility = new XUtility(pta); - this.containerFinder = new ContainerFinder(pta, utility); - this.containerFinder.run(); - } + public DebloaterX(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + this.utility = new XUtility(pta); + this.containerFinder = new ContainerFinder(pta, utility); + this.containerFinder.run(); + } - /* - * identifying factory-created containers (Fig 11 in the paper) - * */ - private boolean isAFactoryCreatedContainer(AllocNode heap, IntraFlowAnalysis mpag) { - SootMethod method = heap.getMethod(); - if (method.isStatic()) { - Type type = method.getReturnType(); - if (!(type instanceof ReferenceType)) { - return false; - } - MethodPAG methodPag = pag.getMethodPAG(method); - VarNode mRet = methodPag.nodeFactory().caseRet(); - if (pta.reachingObjects(mRet).toCIPointsToSet().toCollection().contains(heap)) { - return mpag.isDirectlyReturnedHeap(heap); - } - } + /* + * identifying factory-created containers (Fig 11 in the paper) + * */ + private boolean isAFactoryCreatedContainer(AllocNode heap, IntraFlowAnalysis mpag) { + SootMethod method = heap.getMethod(); + if (method.isStatic()) { + Type type = method.getReturnType(); + if (!(type instanceof ReferenceType)) { return false; + } + MethodPAG methodPag = pag.getMethodPAG(method); + VarNode mRet = methodPag.nodeFactory().caseRet(); + if (pta.reachingObjects(mRet).toCIPointsToSet().toCollection().contains(heap)) { + return mpag.isDirectlyReturnedHeap(heap); + } } + return false; + } - /* - * identifying container wrappers (Fig 12 in the paper) - * */ - private boolean isAContainerWrapper(AllocNode heap, IntraFlowAnalysis mpag) { - SootMethod method = heap.getMethod(); - if (method.isStatic()) { - return false; - } - Type type = method.getReturnType(); - if (!(type instanceof ReferenceType)) { - return false; - } - MethodPAG methodPag = pag.getMethodPAG(method); - VarNode mRet = methodPag.nodeFactory().caseRet(); - PointsToSet pts = pta.reachingObjects(mRet); - Collection ptsSet = pts.toCIPointsToSet().toCollection(); - if (ptsSet.contains(heap)) { - if (mpag.isDirectlyReturnedHeap(heap)) { - return mpag.isContentFromParam(heap); - } - } - return false; + /* + * identifying container wrappers (Fig 12 in the paper) + * */ + private boolean isAContainerWrapper(AllocNode heap, IntraFlowAnalysis mpag) { + SootMethod method = heap.getMethod(); + if (method.isStatic()) { + return false; + } + Type type = method.getReturnType(); + if (!(type instanceof ReferenceType)) { + return false; } + MethodPAG methodPag = pag.getMethodPAG(method); + VarNode mRet = methodPag.nodeFactory().caseRet(); + PointsToSet pts = pta.reachingObjects(mRet); + Collection ptsSet = pts.toCIPointsToSet().toCollection(); + if (ptsSet.contains(heap)) { + if (mpag.isDirectlyReturnedHeap(heap)) { + return mpag.isContentFromParam(heap); + } + } + return false; + } - /* - * identify inner containers (Fig 9 in the paper). - * */ - private boolean isAnInnerContainer(AllocNode heap, IntraFlowAnalysis mpag) { - SootMethod method = heap.getMethod(); - if (method.isStatic()) { - return false; - } - Set fields = mpag.retrieveStoreFields(heap); - if (fields.isEmpty()) { - return false; - } - Set objects = this.utility.getReceiverObjects(method); - for (AllocNode revobj : objects) { - if (revobj.getType() instanceof ClassType) { - HeapContainerQuery hcq = this.utility.getHCQ(revobj); - for (SparkField field : fields) { - if (hcq.isCSField(field)) { - return true; - } - } - } + /* + * identify inner containers (Fig 9 in the paper). + * */ + private boolean isAnInnerContainer(AllocNode heap, IntraFlowAnalysis mpag) { + SootMethod method = heap.getMethod(); + if (method.isStatic()) { + return false; + } + Set fields = mpag.retrieveStoreFields(heap); + if (fields.isEmpty()) { + return false; + } + Set objects = this.utility.getReceiverObjects(method); + for (AllocNode revobj : objects) { + if (revobj.getType() instanceof ClassType) { + HeapContainerQuery hcq = this.utility.getHCQ(revobj); + for (SparkField field : fields) { + if (hcq.isCSField(field)) { + return true; + } } - return false; + } } + return false; + } - protected final Set ctxDepHeaps = ConcurrentHashMap.newKeySet(); - protected final Set containerFactory = ConcurrentHashMap.newKeySet(); - protected final Set containerWrapper = ConcurrentHashMap.newKeySet(); - protected final Set innerContainer = ConcurrentHashMap.newKeySet(); + protected final Set ctxDepHeaps = ConcurrentHashMap.newKeySet(); + protected final Set containerFactory = ConcurrentHashMap.newKeySet(); + protected final Set containerWrapper = ConcurrentHashMap.newKeySet(); + protected final Set innerContainer = ConcurrentHashMap.newKeySet(); - /* - * Implementing Step 3 of Algorithm 1 (in the paper): finding context-dependent objects according to container-usage patterns - * */ - public void run() { - Map> m2o = new HashMap<>(); - for (AllocNode heap : pag.getAllocNodes()) { - SootMethod method = heap.getMethod(); - if (method == null || PTAUtils.isStaticInitializer(method)) { - continue; - } - m2o.computeIfAbsent(method, k -> new HashSet<>()).add(heap); - } - m2o.keySet().parallelStream().forEach(method -> { - IntraFlowAnalysis ifa = new IntraFlowAnalysis(utility, method); - for (AllocNode heap : m2o.get(method)) { + /* + * Implementing Step 3 of Algorithm 1 (in the paper): finding context-dependent objects according to container-usage patterns + * */ + public void run() { + Map> m2o = new HashMap<>(); + for (AllocNode heap : pag.getAllocNodes()) { + SootMethod method = heap.getMethod(); + if (method == null || PTAUtils.isStaticInitializer(method)) { + continue; + } + m2o.computeIfAbsent(method, k -> new HashSet<>()).add(heap); + } + m2o.keySet() + .parallelStream() + .forEach( + method -> { + IntraFlowAnalysis ifa = new IntraFlowAnalysis(utility, method); + for (AllocNode heap : m2o.get(method)) { if (!this.containerFinder.isAContainer(heap)) { - continue; + continue; } if (isAFactoryCreatedContainer(heap, ifa)) { - containerFactory.add(heap); - ctxDepHeaps.add(heap); + containerFactory.add(heap); + ctxDepHeaps.add(heap); } if (isAContainerWrapper(heap, ifa)) { - containerWrapper.add(heap); - ctxDepHeaps.add(heap); + containerWrapper.add(heap); + ctxDepHeaps.add(heap); } if (isAnInnerContainer(heap, ifa)) { - innerContainer.add(heap); - ctxDepHeaps.add(heap); + innerContainer.add(heap); + ctxDepHeaps.add(heap); } - } - }); - System.out.println("#OBJECTS:" + pag.getAllocNodes().size()); - System.out.println("#CS:" + ctxDepHeaps.size()); - System.out.println("#CI:" + (pag.getAllocNodes().size() - ctxDepHeaps.size())); - System.out.println("#ContainerFactory:" + containerFactory.size()); - System.out.println("#ContainerWrapper:" + containerWrapper.size()); - System.out.println("#InnerContainer:" + innerContainer.size()); - { - // for drawn venn3 figure. - int onlyInFactory = Sets.difference(Sets.difference(containerFactory, containerWrapper), innerContainer).size(); - int onlyInWrapper = Sets.difference(Sets.difference(containerWrapper, containerFactory), innerContainer).size(); - int onlyInInner = Sets.difference(Sets.difference(innerContainer, containerWrapper), containerFactory).size(); - int inAll = Sets.intersection(Sets.intersection(innerContainer, containerWrapper), containerFactory).size(); - int onlyInFactoryAndWrapper = Sets.difference(Sets.intersection(containerFactory, containerWrapper), innerContainer).size(); - int onlyInFactoryAndInner = Sets.difference(Sets.intersection(containerFactory, innerContainer), containerWrapper).size(); - int onlyInWrapperAndInner = Sets.difference(Sets.intersection(containerWrapper, innerContainer), containerFactory).size(); - System.out.println("#onlyInFactory:" + onlyInFactory); - System.out.println("#onlyInWrapper:" + onlyInWrapper); - System.out.println("#onlyInInner:" + onlyInInner); - System.out.println("#inAll:" + inAll); - System.out.println("#onlyInFactoryAndWrapper:" + onlyInFactoryAndWrapper); - System.out.println("#onlyInFactoryAndInner:" + onlyInFactoryAndInner); - System.out.println("#onlyInWrapperAndInner:" + onlyInWrapperAndInner); - System.out.println("#SUM:" + (onlyInFactory + onlyInWrapper + onlyInInner + inAll + onlyInFactoryAndWrapper + onlyInFactoryAndInner + onlyInWrapperAndInner)); - System.out.println("venn3(subsets = (" + onlyInFactory + "," + onlyInWrapper + "," + onlyInFactoryAndWrapper + "," + onlyInInner + "," - + onlyInFactoryAndInner + "," + onlyInWrapperAndInner + ", " + inAll + "))"); - } - } - - public Set getCtxDepHeaps() { - return ctxDepHeaps; + } + }); + System.out.println("#OBJECTS:" + pag.getAllocNodes().size()); + System.out.println("#CS:" + ctxDepHeaps.size()); + System.out.println("#CI:" + (pag.getAllocNodes().size() - ctxDepHeaps.size())); + System.out.println("#ContainerFactory:" + containerFactory.size()); + System.out.println("#ContainerWrapper:" + containerWrapper.size()); + System.out.println("#InnerContainer:" + innerContainer.size()); + { + // for drawn venn3 figure. + int onlyInFactory = + Sets.difference(Sets.difference(containerFactory, containerWrapper), innerContainer) + .size(); + int onlyInWrapper = + Sets.difference(Sets.difference(containerWrapper, containerFactory), innerContainer) + .size(); + int onlyInInner = + Sets.difference(Sets.difference(innerContainer, containerWrapper), containerFactory) + .size(); + int inAll = + Sets.intersection(Sets.intersection(innerContainer, containerWrapper), containerFactory) + .size(); + int onlyInFactoryAndWrapper = + Sets.difference(Sets.intersection(containerFactory, containerWrapper), innerContainer) + .size(); + int onlyInFactoryAndInner = + Sets.difference(Sets.intersection(containerFactory, innerContainer), containerWrapper) + .size(); + int onlyInWrapperAndInner = + Sets.difference(Sets.intersection(containerWrapper, innerContainer), containerFactory) + .size(); + System.out.println("#onlyInFactory:" + onlyInFactory); + System.out.println("#onlyInWrapper:" + onlyInWrapper); + System.out.println("#onlyInInner:" + onlyInInner); + System.out.println("#inAll:" + inAll); + System.out.println("#onlyInFactoryAndWrapper:" + onlyInFactoryAndWrapper); + System.out.println("#onlyInFactoryAndInner:" + onlyInFactoryAndInner); + System.out.println("#onlyInWrapperAndInner:" + onlyInWrapperAndInner); + System.out.println( + "#SUM:" + + (onlyInFactory + + onlyInWrapper + + onlyInInner + + inAll + + onlyInFactoryAndWrapper + + onlyInFactoryAndInner + + onlyInWrapperAndInner)); + System.out.println( + "venn3(subsets = (" + + onlyInFactory + + "," + + onlyInWrapper + + "," + + onlyInFactoryAndWrapper + + "," + + onlyInInner + + "," + + onlyInFactoryAndInner + + "," + + onlyInWrapperAndInner + + ", " + + inAll + + "))"); } + } + public Set getCtxDepHeaps() { + return ctxDepHeaps; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java index 3ad90a44fbe..e9bde4cf46e 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/Edge.java @@ -4,15 +4,15 @@ import qilin.core.pag.SparkField; public class Edge { - Node from; - Node to; - SparkField field; - EdgeKind kind; + Node from; + Node to; + SparkField field; + EdgeKind kind; - Edge(Node from, Node to, SparkField f, EdgeKind kind) { - this.from = from; - this.to = to; - this.field = f; - this.kind = kind; - } -} \ No newline at end of file + Edge(Node from, Node to, SparkField f, EdgeKind kind) { + this.from = from; + this.to = to; + this.field = f; + this.kind = kind; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java index 8b6cc07db9d..944943bef34 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/EdgeKind.java @@ -1,19 +1,27 @@ package qilin.pta.toolkits.debloaterx; public enum EdgeKind { - // "I" means inverse. - NEW, INEW, - // the following two used for normal assign, cast, and inter-procedural assign for invocations with "this" as the base variable. - // no global assignments are included. - ASSIGN, IASSIGN, - // the following four used only for normal Java store and load. - LOAD, ILOAD, - STORE, ISTORE, - // the following four model parameter passing for non-this invocation. - CLOAD, ICLOAD, - CSTORE, ICSTORE, - // the following three are self-loops. - THIS, ITHIS, - PARAM, - RETURN, -} \ No newline at end of file + // "I" means inverse. + NEW, + INEW, + // the following two used for normal assign, cast, and inter-procedural assign for invocations + // with "this" as the base variable. + // no global assignments are included. + ASSIGN, + IASSIGN, + // the following four used only for normal Java store and load. + LOAD, + ILOAD, + STORE, + ISTORE, + // the following four model parameter passing for non-this invocation. + CLOAD, + ICLOAD, + CSTORE, + ICSTORE, + // the following three are self-loops. + THIS, + ITHIS, + PARAM, + RETURN, +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java index 51d5413dd6f..bae42fe6c19 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/HeapContainerQuery.java @@ -1,77 +1,78 @@ package qilin.pta.toolkits.debloaterx; +import java.util.*; +import java.util.stream.Collectors; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.*; -import java.util.stream.Collectors; - public class HeapContainerQuery { - private final PAG pag; - private final XUtility utility; - private final Set invokedMs; - private final Set params; - private final InterFlowAnalysis interfa; - private final AllocNode heap; + private final PAG pag; + private final XUtility utility; + private final Set invokedMs; + private final Set params; + private final InterFlowAnalysis interfa; + private final AllocNode heap; + public HeapContainerQuery(XUtility utility, AllocNode heap) { + this.utility = utility; + this.pag = utility.getPta().getPag(); + this.heap = heap; + this.invokedMs = utility.getInvokedMethods(heap); + this.interfa = utility.getInterFlowAnalysis(); + this.params = getParameters(); + } - public HeapContainerQuery(XUtility utility, AllocNode heap) { - this.utility = utility; - this.pag = utility.getPta().getPag(); - this.heap = heap; - this.invokedMs = utility.getInvokedMethods(heap); - this.interfa = utility.getInterFlowAnalysis(); - this.params = getParameters(); - } - - /* computes input parameters for the class of refType */ - private Set getParameters() { - Set ret = new HashSet<>(); - for (SootMethod m : invokedMs) { - MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); - for (int i = 0; i < m.getParameterCount(); ++i) { - if (m.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(m.getParameterType(i))) { - LocalVarNode param = (LocalVarNode) mthdNF.caseParm(i); - ret.add(param); - } - } - ret.add((LocalVarNode) mthdNF.caseThis()); + /* computes input parameters for the class of refType */ + private Set getParameters() { + Set ret = new HashSet<>(); + for (SootMethod m : invokedMs) { + MethodNodeFactory mthdNF = pag.getMethodPAG(m).nodeFactory(); + for (int i = 0; i < m.getParameterCount(); ++i) { + if (m.getParameterType(i) instanceof ReferenceType + && !PTAUtils.isPrimitiveArrayType(m.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) mthdNF.caseParm(i); + ret.add(param); } - return ret; + } + ret.add((LocalVarNode) mthdNF.caseThis()); } + return ret; + } - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /* APIs for query */ - public boolean hasParamsStoredInto(SparkField field) { - Set tmp = interfa.getParamsStoredInto(field); - tmp = tmp.stream().filter(this.params::contains).collect(Collectors.toSet()); - return !tmp.isEmpty(); - } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* APIs for query */ + public boolean hasParamsStoredInto(SparkField field) { + Set tmp = interfa.getParamsStoredInto(field); + tmp = tmp.stream().filter(this.params::contains).collect(Collectors.toSet()); + return !tmp.isEmpty(); + } - public Set getInParamsToCSFields() { - Set fields = utility.getFields(heap); - Set ret = new HashSet<>(); - for (SparkField field : fields) { - if (isCSField(field)) { - ret.addAll(interfa.getParamsStoredInto(field)); - } - } - ret = ret.stream().filter(this.params::contains).collect(Collectors.toSet()); - return ret; + public Set getInParamsToCSFields() { + Set fields = utility.getFields(heap); + Set ret = new HashSet<>(); + for (SparkField field : fields) { + if (isCSField(field)) { + ret.addAll(interfa.getParamsStoredInto(field)); + } } + ret = ret.stream().filter(this.params::contains).collect(Collectors.toSet()); + return ret; + } - public boolean hasOutMethodsWithRetOrParamValueFrom(SparkField field) { - Set tmp = interfa.getOutMethodsWithRetOrParamValueFrom(field); - tmp = tmp.stream().filter(this.invokedMs::contains).collect(Collectors.toSet()); - return !tmp.isEmpty(); - } + public boolean hasOutMethodsWithRetOrParamValueFrom(SparkField field) { + Set tmp = interfa.getOutMethodsWithRetOrParamValueFrom(field); + tmp = tmp.stream().filter(this.invokedMs::contains).collect(Collectors.toSet()); + return !tmp.isEmpty(); + } - public boolean isCSField(SparkField field) { - boolean hasIn = utility.hasNonThisStoreOnField(this.heap, field) || hasParamsStoredInto(field); - boolean hasOut = utility.hasNonThisLoadFromField(this.heap, field) || hasOutMethodsWithRetOrParamValueFrom(field); - return hasIn && hasOut; - } + public boolean isCSField(SparkField field) { + boolean hasIn = utility.hasNonThisStoreOnField(this.heap, field) || hasParamsStoredInto(field); + boolean hasOut = + utility.hasNonThisLoadFromField(this.heap, field) + || hasOutMethodsWithRetOrParamValueFrom(field); + return hasIn && hasOut; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java index 7d4402ea114..277dbb18c45 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/InterFlowAnalysis.java @@ -1,12 +1,5 @@ package qilin.pta.toolkits.debloaterx; -import qilin.core.pag.LocalVarNode; -import qilin.core.pag.Node; -import qilin.core.pag.SparkField; -import qilin.util.Pair; -import qilin.util.queue.UniqueQueue; -import sootup.core.model.SootMethod; - import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -15,208 +8,229 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import qilin.core.pag.LocalVarNode; +import qilin.core.pag.Node; +import qilin.core.pag.SparkField; +import qilin.util.Pair; +import qilin.util.queue.UniqueQueue; +import sootup.core.model.SootMethod; public class InterFlowAnalysis { - protected final XUtility utility; - protected final XPAG xpag; - /* records the reachability info: given a field F, (1) which params could be saved into F - * (2) F could flows to which method's param or return node. - */ - protected final Map> field2InParams = new ConcurrentHashMap<>(); - protected final Map> field2OutParams = new ConcurrentHashMap<>(); + protected final XUtility utility; + protected final XPAG xpag; + /* records the reachability info: given a field F, (1) which params could be saved into F + * (2) F could flows to which method's param or return node. + */ + protected final Map> field2InParams = new ConcurrentHashMap<>(); + protected final Map> field2OutParams = new ConcurrentHashMap<>(); - public InterFlowAnalysis(XUtility utility) { - this.utility = utility; - this.xpag = utility.getXpag(); - reachabilityAnalysis(); - } + public InterFlowAnalysis(XUtility utility) { + this.utility = utility; + this.xpag = utility.getXpag(); + reachabilityAnalysis(); + } - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /* reachability analysis: fill content in field2InParams and field2Outs - * This is the implementation of Algorithm 2 in the paper. - * */ - public void reachabilityAnalysis() { - Set fields = utility.getFields(); - fields.parallelStream().forEach(field -> { - // compute the value of field could be loaded to which outmethods. - Set retOrParams = runDFAandCollect(field, false); - if (!retOrParams.isEmpty()) { - field2OutParams.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).addAll(retOrParams); - } - // compute the params could be stored into the specified field. - Set params = runDFAandCollect(field, true); - if (!params.isEmpty()) { - field2InParams.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).addAll(params); - } - }); - } + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* reachability analysis: fill content in field2InParams and field2Outs + * This is the implementation of Algorithm 2 in the paper. + * */ + public void reachabilityAnalysis() { + Set fields = utility.getFields(); + fields.parallelStream() + .forEach( + field -> { + // compute the value of field could be loaded to which outmethods. + Set retOrParams = runDFAandCollect(field, false); + if (!retOrParams.isEmpty()) { + field2OutParams + .computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()) + .addAll(retOrParams); + } + // compute the params could be stored into the specified field. + Set params = runDFAandCollect(field, true); + if (!params.isEmpty()) { + field2InParams + .computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()) + .addAll(params); + } + }); + } - /* - * When isInflow = true, check whether the value in param could be stored into field. - * Otherwise, check whether the value in field could be loaded to any method's return value or params. - * */ - private Set runDFAandCollect(SparkField field, boolean isInflow) { - Set ret = new HashSet<>(); - Map> state2nodes = new HashMap<>(); - Queue> queue = new UniqueQueue<>(); - queue.add(new Pair<>(xpag.getDummyThis(), State.THIS)); - while (!queue.isEmpty()) { - Pair front = queue.poll(); - if (front.getSecond() == State.End) { - if (front.getFirst() instanceof LocalVarNode lvn) { - ret.add(lvn); - } - } - // visit the node and state. - visit(front, state2nodes); - Set> nexts = getNextNodeStates(front, field, isInflow); - for (Pair nodeState : nexts) { - if (!isVisited(nodeState, state2nodes)) { - queue.add(nodeState); - } - } + /* + * When isInflow = true, check whether the value in param could be stored into field. + * Otherwise, check whether the value in field could be loaded to any method's return value or params. + * */ + private Set runDFAandCollect(SparkField field, boolean isInflow) { + Set ret = new HashSet<>(); + Map> state2nodes = new HashMap<>(); + Queue> queue = new UniqueQueue<>(); + queue.add(new Pair<>(xpag.getDummyThis(), State.THIS)); + while (!queue.isEmpty()) { + Pair front = queue.poll(); + if (front.getSecond() == State.End) { + if (front.getFirst() instanceof LocalVarNode lvn) { + ret.add(lvn); } - return ret; + } + // visit the node and state. + visit(front, state2nodes); + Set> nexts = getNextNodeStates(front, field, isInflow); + for (Pair nodeState : nexts) { + if (!isVisited(nodeState, state2nodes)) { + queue.add(nodeState); + } + } } + return ret; + } - private Set> getNextNodeStates(Pair nodeState, SparkField field, boolean in) { - Node node = nodeState.getFirst(); - State state = nodeState.getSecond(); - Set> ret = new HashSet<>(); - for (Edge edge : xpag.getOutEdges(node)) { - boolean mathched = edge.field != null && edge.field.equals(field); - State nextState; - if (in) { - nextState = nextStateForIn(state, edge.kind, mathched); - } else { - nextState = nextStateForOut(state, edge.kind, mathched); - } - if (nextState != State.Error) { - ret.add(new Pair<>(edge.to, nextState)); - } - } - return ret; + private Set> getNextNodeStates( + Pair nodeState, SparkField field, boolean in) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + Set> ret = new HashSet<>(); + for (Edge edge : xpag.getOutEdges(node)) { + boolean mathched = edge.field != null && edge.field.equals(field); + State nextState; + if (in) { + nextState = nextStateForIn(state, edge.kind, mathched); + } else { + nextState = nextStateForOut(state, edge.kind, mathched); + } + if (nextState != State.Error) { + ret.add(new Pair<>(edge.to, nextState)); + } } + return ret; + } - /* - * This method describes another automaton and its transition function for checking whether the field value could be - * loaded to any method's return. - * Correspoing to the automaton given in Fig 7c in the paper. - * */ - private State nextStateForOut(State currState, EdgeKind kind, boolean fieldMatch) { - switch (currState) { - case THIS -> { - if (kind == EdgeKind.ITHIS) { - return State.ThisAlias; - } - } - case ThisAlias -> { - if (kind == EdgeKind.ASSIGN) { - return State.ThisAlias; - } else if (kind == EdgeKind.LOAD && fieldMatch) { - return State.VPlus; - } - } - case VPlus -> { - if (kind == EdgeKind.ASSIGN || kind == EdgeKind.LOAD || kind == EdgeKind.CLOAD) { - return State.VPlus; - } else if (kind == EdgeKind.RETURN) { - return State.End; - } else if (kind == EdgeKind.CSTORE || kind == EdgeKind.STORE || kind == EdgeKind.ICSTORE || kind == EdgeKind.ISTORE) { - //kind == EdgeKind.ICSTORE || kind == EdgeKind.ISTORE can be removed. - return State.VMinus; - } - } - case VMinus -> { - if (kind == EdgeKind.IASSIGN || kind == EdgeKind.ILOAD || kind == EdgeKind.ICLOAD) { - return State.VMinus; - } else if (kind == EdgeKind.INEW) { - return State.O; - } else if (kind == EdgeKind.PARAM) { - return State.End; - } - } - case O -> { - if (kind == EdgeKind.NEW) { - return State.VPlus; - } - } + /* + * This method describes another automaton and its transition function for checking whether the field value could be + * loaded to any method's return. + * Correspoing to the automaton given in Fig 7c in the paper. + * */ + private State nextStateForOut(State currState, EdgeKind kind, boolean fieldMatch) { + switch (currState) { + case THIS -> { + if (kind == EdgeKind.ITHIS) { + return State.ThisAlias; + } + } + case ThisAlias -> { + if (kind == EdgeKind.ASSIGN) { + return State.ThisAlias; + } else if (kind == EdgeKind.LOAD && fieldMatch) { + return State.VPlus; + } + } + case VPlus -> { + if (kind == EdgeKind.ASSIGN || kind == EdgeKind.LOAD || kind == EdgeKind.CLOAD) { + return State.VPlus; + } else if (kind == EdgeKind.RETURN) { + return State.End; + } else if (kind == EdgeKind.CSTORE + || kind == EdgeKind.STORE + || kind == EdgeKind.ICSTORE + || kind == EdgeKind.ISTORE) { + // kind == EdgeKind.ICSTORE || kind == EdgeKind.ISTORE can be removed. + return State.VMinus; } - return State.Error; + } + case VMinus -> { + if (kind == EdgeKind.IASSIGN || kind == EdgeKind.ILOAD || kind == EdgeKind.ICLOAD) { + return State.VMinus; + } else if (kind == EdgeKind.INEW) { + return State.O; + } else if (kind == EdgeKind.PARAM) { + return State.End; + } + } + case O -> { + if (kind == EdgeKind.NEW) { + return State.VPlus; + } + } } + return State.Error; + } - private void visit(Pair nodeState, Map> state2nodes) { - Node node = nodeState.getFirst(); - State state = nodeState.getSecond(); - state2nodes.computeIfAbsent(state, k -> new HashSet<>()).add(node); - } + private void visit(Pair nodeState, Map> state2nodes) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + state2nodes.computeIfAbsent(state, k -> new HashSet<>()).add(node); + } - private boolean isVisited(Pair nodeState, Map> state2nodes) { - Node node = nodeState.getFirst(); - State state = nodeState.getSecond(); - Set nodes = state2nodes.getOrDefault(state, Collections.emptySet()); - return nodes.contains(node); - } + private boolean isVisited(Pair nodeState, Map> state2nodes) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + Set nodes = state2nodes.getOrDefault(state, Collections.emptySet()); + return nodes.contains(node); + } - /* - * This method describes an automaton and its transition function for checking whether the value could be stored - * into any field. - * Correspoing to the automaton given in Fig 7b in the paper. - * */ - private State nextStateForIn(State currState, EdgeKind kind, boolean fieldMatch) { - switch (currState) { - case O -> { - if (kind == EdgeKind.NEW) { - return State.VPlus; - } - } - case THIS -> { - if (kind == EdgeKind.ITHIS) { - return State.ThisAlias; - } - } - case VPlus -> { - if (kind == EdgeKind.ASSIGN || kind == EdgeKind.LOAD || kind == EdgeKind.CLOAD) { - return State.VPlus; - } else if (kind == EdgeKind.ISTORE || kind == EdgeKind.STORE || kind == EdgeKind.ICSTORE || kind == EdgeKind.CSTORE) { - // kind == EdgeKind.STORE || kind == EdgeKind.ICSTORE can be deleted due to not occured in the real world. - return State.VMinus; - } - } - case VMinus -> { - if (kind == EdgeKind.IASSIGN || kind == EdgeKind.ILOAD || kind == EdgeKind.ICLOAD) { - return State.VMinus; - } else if (kind == EdgeKind.INEW) { - return State.O; - } else if (kind == EdgeKind.PARAM) { - return State.End; - } - } - case ThisAlias -> { - if (kind == EdgeKind.ASSIGN) { - return State.ThisAlias; - } else if (kind == EdgeKind.ISTORE) { - if (fieldMatch) { - return State.VMinus; - } - } else if (kind == EdgeKind.LOAD) { - if (fieldMatch) { - return State.VPlus; - } - } - } + /* + * This method describes an automaton and its transition function for checking whether the value could be stored + * into any field. + * Correspoing to the automaton given in Fig 7b in the paper. + * */ + private State nextStateForIn(State currState, EdgeKind kind, boolean fieldMatch) { + switch (currState) { + case O -> { + if (kind == EdgeKind.NEW) { + return State.VPlus; } - return State.Error; - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /* APIs for query */ - public Set getParamsStoredInto(SparkField field) { - return this.field2InParams.getOrDefault(field, Collections.emptySet()); + } + case THIS -> { + if (kind == EdgeKind.ITHIS) { + return State.ThisAlias; + } + } + case VPlus -> { + if (kind == EdgeKind.ASSIGN || kind == EdgeKind.LOAD || kind == EdgeKind.CLOAD) { + return State.VPlus; + } else if (kind == EdgeKind.ISTORE + || kind == EdgeKind.STORE + || kind == EdgeKind.ICSTORE + || kind == EdgeKind.CSTORE) { + // kind == EdgeKind.STORE || kind == EdgeKind.ICSTORE can be deleted due to not occured in + // the real world. + return State.VMinus; + } + } + case VMinus -> { + if (kind == EdgeKind.IASSIGN || kind == EdgeKind.ILOAD || kind == EdgeKind.ICLOAD) { + return State.VMinus; + } else if (kind == EdgeKind.INEW) { + return State.O; + } else if (kind == EdgeKind.PARAM) { + return State.End; + } + } + case ThisAlias -> { + if (kind == EdgeKind.ASSIGN) { + return State.ThisAlias; + } else if (kind == EdgeKind.ISTORE) { + if (fieldMatch) { + return State.VMinus; + } + } else if (kind == EdgeKind.LOAD) { + if (fieldMatch) { + return State.VPlus; + } + } + } } + return State.Error; + } - public Set getOutMethodsWithRetOrParamValueFrom(SparkField field) { - return field2OutParams.getOrDefault(field, Collections.emptySet()).stream().map(LocalVarNode::getMethod).collect(Collectors.toSet()); - } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* APIs for query */ + public Set getParamsStoredInto(SparkField field) { + return this.field2InParams.getOrDefault(field, Collections.emptySet()); + } + public Set getOutMethodsWithRetOrParamValueFrom(SparkField field) { + return field2OutParams.getOrDefault(field, Collections.emptySet()).stream() + .map(LocalVarNode::getMethod) + .collect(Collectors.toSet()); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java index 9c8105252fa..3c785fece7d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/IntraFlowAnalysis.java @@ -1,5 +1,8 @@ package qilin.pta.toolkits.debloaterx; +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; import qilin.util.PTAUtils; @@ -18,284 +21,292 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.HashSet; -import java.util.Queue; -import java.util.Set; - /* * Implementation of Algorithm 3 and Fig 10 in the paper. * */ public class IntraFlowAnalysis { - private final PAG pag; - private final XUtility utility; - private final SootMethod method; - protected final XPAG xpag; - protected final Set params = new HashSet<>(); + private final PAG pag; + private final XUtility utility; + private final SootMethod method; + protected final XPAG xpag; + protected final Set params = new HashSet<>(); - public IntraFlowAnalysis(XUtility utility, SootMethod method) { - this.utility = utility; - this.pag = utility.getPta().getPag(); - this.method = method; - this.xpag = utility.getXpag(); - collectParams(); + public IntraFlowAnalysis(XUtility utility, SootMethod method) { + this.utility = utility; + this.pag = utility.getPta().getPag(); + this.method = method; + this.xpag = utility.getXpag(); + collectParams(); + } + + protected void collectParams() { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + VarNode thisNode = srcnf.caseThis(); + // handle parameters + for (int i = 0; i < method.getParameterCount(); ++i) { + if (method.getParameterType(i) instanceof ReferenceType + && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + this.params.add(param); + } } + this.params.add((LocalVarNode) thisNode); + } - protected void collectParams() { - MethodPAG srcmpag = pag.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - VarNode thisNode = srcnf.caseThis(); - // handle parameters - for (int i = 0; i < method.getParameterCount(); ++i) { - if (method.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { - LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); - this.params.add(param); - } + ////////////////////////////////////////////////////////////////////////////////// + /* + * x = y = z = ... = node; + * */ + Set epsilon(Node node) { + Queue queue = new UniqueQueue<>(); + for (Edge edge : xpag.getOutEdges(node)) { + queue.add(edge.to); + } + Set visit = new HashSet<>(); + while (!queue.isEmpty()) { + Node front = queue.poll(); + visit.add(front); + for (Edge edge : xpag.getOutEdges(front)) { + if (edge.kind == EdgeKind.ASSIGN && !visit.contains(edge.to)) { + queue.add(edge.to); } - this.params.add((LocalVarNode) thisNode); + } } + return visit; + } - ////////////////////////////////////////////////////////////////////////////////// - /* - * x = y = z = ... = node; - * */ - Set epsilon(Node node) { - Queue queue = new UniqueQueue<>(); - for (Edge edge : xpag.getOutEdges(node)) { - queue.add(edge.to); + /* + * t = new T; + * x = ... = t; + * return x; + * */ + public boolean isDirectlyReturnedHeap(AllocNode heap) { + Set visit = epsilon(heap); + boolean flag = false; + for (Node node : visit) { + if (node instanceof LocalVarNode lvn) { + if (lvn.isReturn()) { + flag = true; } - Set visit = new HashSet<>(); - while (!queue.isEmpty()) { - Node front = queue.poll(); - visit.add(front); - for (Edge edge : xpag.getOutEdges(front)) { - if (edge.kind == EdgeKind.ASSIGN && !visit.contains(edge.to)) { - queue.add(edge.to); - } - } - } - return visit; + } } + return flag; + } - /* - * t = new T; - * x = ... = t; - * return x; - * */ - public boolean isDirectlyReturnedHeap(AllocNode heap) { - Set visit = epsilon(heap); - boolean flag = false; - for (Node node : visit) { - if (node instanceof LocalVarNode lvn) { - if (lvn.isReturn()) { - flag = true; - } - } - } - return flag; + public boolean isContentFromParam(AllocNode heap) { + Type heapType = heap.getType(); + if (heapType instanceof ClassType) { + return isInstanceObjectContentFromParam(heap); + } else { + return isArrayContentFromParam(heap); } + } - public boolean isContentFromParam(AllocNode heap) { - Type heapType = heap.getType(); - if (heapType instanceof ClassType) { - return isInstanceObjectContentFromParam(heap); - } else { - return isArrayContentFromParam(heap); + /* + * return true iff heap.f comes from any parameter of heap.getMethod(). + * */ + private boolean isInstanceObjectContentFromParam(AllocNode heap) { + Set paramInArgs = collectParamInArguments(heap); + if (paramInArgs.isEmpty()) { + return false; + } + Queue queue = new UniqueQueue<>(); + Set visited = new HashSet<>(); + queue.addAll(params); + while (!queue.isEmpty()) { + Node front = queue.poll(); + if (paramInArgs.contains(front)) { + return true; + } + visited.add(front); + for (Edge edge : xpag.getOutEdges(front)) { + if (edge.kind == EdgeKind.ASSIGN + || edge.kind == EdgeKind.CLOAD + || edge.kind == EdgeKind.LOAD) { + if (!visited.contains(edge.to)) { + queue.add(edge.to); + } } + } } + return false; + } - /* - * return true iff heap.f comes from any parameter of heap.getMethod(). - * */ - private boolean isInstanceObjectContentFromParam(AllocNode heap) { - Set paramInArgs = collectParamInArguments(heap); - if (paramInArgs.isEmpty()) { - return false; + private Set collectParamInArguments(AllocNode heap) { + ClassType type = (ClassType) heap.getType(); + Set x = epsilon(heap); + Set ret = new HashSet<>(); + HeapContainerQuery hcq = this.utility.getHCQ(heap); + Set inParams = hcq.getInParamsToCSFields(); + MethodPAG srcmpag = pag.getMethodPAG(method); + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (!(ie instanceof AbstractInstanceInvokeExpr iie)) { + continue; + } + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + if (!x.contains(receiver)) { + continue; + } + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; } - Queue queue = new UniqueQueue<>(); - Set visited = new HashSet<>(); - queue.addAll(params); - while (!queue.isEmpty()) { - Node front = queue.poll(); - if (paramInArgs.contains(front)) { - return true; - } - visited.add(front); - for (Edge edge : xpag.getOutEdges(front)) { - if (edge.kind == EdgeKind.ASSIGN || edge.kind == EdgeKind.CLOAD || edge.kind == EdgeKind.LOAD) { - if (!visited.contains(edge.to)) { - queue.add(edge.to); - } - } - } + args[i] = arg; + } + MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); + VirtualCallSite virtualCallSite = + new VirtualCallSite( + receiver, + s, + new ContextMethod(method, utility.getPta().emptyContext()), + iie, + subSig, + soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); + QueueReader targets = PTAUtils.dispatch(type, virtualCallSite); + while (targets.hasNext()) { + SootMethod target = targets.next(); + MethodPAG tgtmpag = pag.getMethodPAG(target); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + int numParms = target.getParameterCount(); + if (numParms != numArgs) { + System.out.println(target); } - return false; - } - - private Set collectParamInArguments(AllocNode heap) { - ClassType type = (ClassType) heap.getType(); - Set x = epsilon(heap); - Set ret = new HashSet<>(); - HeapContainerQuery hcq = this.utility.getHCQ(heap); - Set inParams = hcq.getInParamsToCSFields(); - MethodPAG srcmpag = pag.getMethodPAG(method); - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (!(ie instanceof AbstractInstanceInvokeExpr iie)) { - continue; - } - LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); - if (!x.contains(receiver)) { - continue; - } - int numArgs = ie.getArgCount(); - Value[] args = new Value[numArgs]; - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { - continue; - } - args[i] = arg; - } - MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); - VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, new ContextMethod(method, utility.getPta().emptyContext()), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); - QueueReader targets = PTAUtils.dispatch(type, virtualCallSite); - while (targets.hasNext()) { - SootMethod target = targets.next(); - MethodPAG tgtmpag = pag.getMethodPAG(target); - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - int numParms = target.getParameterCount(); - if (numParms != numArgs) { - System.out.println(target); - } - for (int i = 0; i < numParms; i++) { - if (target.getParameterType(i) instanceof ReferenceType) { - if (args[i] != null) { - ValNode argNode = pag.findValNode(args[i]); - if (argNode instanceof LocalVarNode lvn) { - LocalVarNode param = (LocalVarNode) tgtnf.caseParm(i); - if (inParams.contains(param)) { - ret.add(lvn); - } - } - } - } + for (int i = 0; i < numParms; i++) { + if (target.getParameterType(i) instanceof ReferenceType) { + if (args[i] != null) { + ValNode argNode = pag.findValNode(args[i]); + if (argNode instanceof LocalVarNode lvn) { + LocalVarNode param = (LocalVarNode) tgtnf.caseParm(i); + if (inParams.contains(param)) { + ret.add(lvn); } + } } + } } - return ret; + } } + return ret; + } - /* - * x = new T[] - * x[i] = param.*; - * */ - private boolean isArrayContentFromParam(AllocNode heap) { - if (!(heap.getType() instanceof ArrayType)) { - return false; + /* + * x = new T[] + * x[i] = param.*; + * */ + private boolean isArrayContentFromParam(AllocNode heap) { + if (!(heap.getType() instanceof ArrayType)) { + return false; + } + Set x = epsilon(heap); + Queue queue = new UniqueQueue<>(); + Set visited = new HashSet<>(); + queue.addAll(params); + while (!queue.isEmpty()) { + Node front = queue.poll(); + visited.add(front); + for (Edge edge : xpag.getOutEdges(front)) { + if (edge.kind == EdgeKind.ASSIGN + || edge.kind == EdgeKind.CLOAD + || edge.kind == EdgeKind.LOAD) { + if (!visited.contains(edge.to)) { + queue.add(edge.to); + } } - Set x = epsilon(heap); - Queue queue = new UniqueQueue<>(); - Set visited = new HashSet<>(); - queue.addAll(params); - while (!queue.isEmpty()) { - Node front = queue.poll(); - visited.add(front); - for (Edge edge : xpag.getOutEdges(front)) { - if (edge.kind == EdgeKind.ASSIGN || edge.kind == EdgeKind.CLOAD || edge.kind == EdgeKind.LOAD) { - if (!visited.contains(edge.to)) { - queue.add(edge.to); - } - } - if (edge.kind == EdgeKind.STORE) { - if (x.contains(edge.to)) { - return true; - } - } - } + if (edge.kind == EdgeKind.STORE) { + if (x.contains(edge.to)) { + return true; + } } - return false; + } } + return false; + } - private State nextState(State currState, EdgeKind kind) { - switch (currState) { - case O -> { - if (kind == EdgeKind.NEW) { - return State.VPlus; - } - } - case VPlus -> { - if (kind == EdgeKind.ASSIGN) { - return State.VPlus; - } else if (kind == EdgeKind.STORE) { - return State.VMinus; - } - } - case VMinus -> { - if (kind == EdgeKind.IASSIGN) { - return State.VMinus; - } else if (kind == EdgeKind.ILOAD) { - return State.VMinus; - } else if (kind == EdgeKind.INEW) { - return State.O; - } - } + private State nextState(State currState, EdgeKind kind) { + switch (currState) { + case O -> { + if (kind == EdgeKind.NEW) { + return State.VPlus; + } + } + case VPlus -> { + if (kind == EdgeKind.ASSIGN) { + return State.VPlus; + } else if (kind == EdgeKind.STORE) { + return State.VMinus; + } + } + case VMinus -> { + if (kind == EdgeKind.IASSIGN) { + return State.VMinus; + } else if (kind == EdgeKind.ILOAD) { + return State.VMinus; + } else if (kind == EdgeKind.INEW) { + return State.O; } - return State.Error; + } } + return State.Error; + } - /* - * implementation of nextNodeStates in Algorithm 3 in the paper. It also encodes Fig 10 in the paper. - * */ - private Set> getNextNodeStates(Pair nodeState, Set thisAlias, Set stFields) { - Node node = nodeState.getFirst(); - State state = nodeState.getSecond(); - Set> ret = new HashSet<>(); - for (Edge edge : xpag.getOutEdges(node)) { - State nextState = nextState(state, edge.kind); - if (nextState != State.Error) { - if (edge.kind == EdgeKind.STORE && thisAlias.contains(edge.to)) { - Type type = edge.field.getType(); - if (!utility.isCoarseType(type)) { - continue; - } - stFields.add(edge.field); - } else if (edge.kind == EdgeKind.ILOAD && thisAlias.contains(edge.to)) { - Type type = edge.field.getType(); - if (!utility.isCoarseType(type)) { - continue; - } - stFields.add(edge.field); - } else { - ret.add(new Pair<>(edge.to, nextState)); - } - } + /* + * implementation of nextNodeStates in Algorithm 3 in the paper. It also encodes Fig 10 in the paper. + * */ + private Set> getNextNodeStates( + Pair nodeState, Set thisAlias, Set stFields) { + Node node = nodeState.getFirst(); + State state = nodeState.getSecond(); + Set> ret = new HashSet<>(); + for (Edge edge : xpag.getOutEdges(node)) { + State nextState = nextState(state, edge.kind); + if (nextState != State.Error) { + if (edge.kind == EdgeKind.STORE && thisAlias.contains(edge.to)) { + Type type = edge.field.getType(); + if (!utility.isCoarseType(type)) { + continue; + } + stFields.add(edge.field); + } else if (edge.kind == EdgeKind.ILOAD && thisAlias.contains(edge.to)) { + Type type = edge.field.getType(); + if (!utility.isCoarseType(type)) { + continue; + } + stFields.add(edge.field); + } else { + ret.add(new Pair<>(edge.to, nextState)); } - return ret; + } } + return ret; + } - /* - * Implementation of Algorithm 3 in the paper. - * */ - public Set retrieveStoreFields(AllocNode heap) { - Set ret = new HashSet<>(); - MethodPAG srcmpag = pag.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - VarNode thisNode = srcnf.caseThis(); - Set thisAlias = epsilon(thisNode); - Queue> queue = new UniqueQueue<>(); - Set> visited = new HashSet<>(); - queue.add(new Pair<>(heap, State.O)); - while (!queue.isEmpty()) { - Pair front = queue.poll(); - visited.add(front); - Set> nextStates = getNextNodeStates(front, thisAlias, ret); - for (Pair nextState : nextStates) { - if (!visited.contains(nextState)) { - queue.add(nextState); - } - } + /* + * Implementation of Algorithm 3 in the paper. + * */ + public Set retrieveStoreFields(AllocNode heap) { + Set ret = new HashSet<>(); + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + VarNode thisNode = srcnf.caseThis(); + Set thisAlias = epsilon(thisNode); + Queue> queue = new UniqueQueue<>(); + Set> visited = new HashSet<>(); + queue.add(new Pair<>(heap, State.O)); + while (!queue.isEmpty()) { + Pair front = queue.poll(); + visited.add(front); + Set> nextStates = getNextNodeStates(front, thisAlias, ret); + for (Pair nextState : nextStates) { + if (!visited.contains(nextState)) { + queue.add(nextState); } - return ret; + } } - + return ret; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java index 210c4c10294..15ee218a98d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/State.java @@ -1,5 +1,12 @@ package qilin.pta.toolkits.debloaterx; public enum State { - P, VPlus, VMinus, O, ThisAlias, THIS, End, Error + P, + VPlus, + VMinus, + O, + ThisAlias, + THIS, + End, + Error } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java index 3a6624a6b57..c045cbfaf61 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XPAG.java @@ -1,5 +1,7 @@ package qilin.pta.toolkits.debloaterx; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; @@ -17,254 +19,257 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - public class XPAG { - /* record nodes and edges in the graph */ - protected final Map> outEdges = new ConcurrentHashMap<>(); - protected final PTA pta; - protected final PAG pag; - private final LocalVarNode dummyThis; - protected final XUtility utility; + /* record nodes and edges in the graph */ + protected final Map> outEdges = new ConcurrentHashMap<>(); + protected final PTA pta; + protected final PAG pag; + private final LocalVarNode dummyThis; + protected final XUtility utility; - public XPAG(PTA pta, XUtility utility) { - this.pta = pta; - this.pag = pta.getPag(); - this.utility = utility; - this.dummyThis = new LocalVarNode("DUMMYTHIS", PTAUtils.getClassType("java.lang.Object"), null); - buildGraph(pta.getNakedReachableMethods()); - } + public XPAG(PTA pta, XUtility utility) { + this.pta = pta; + this.pag = pta.getPag(); + this.utility = utility; + this.dummyThis = new LocalVarNode("DUMMYTHIS", PTAUtils.getClassType("java.lang.Object"), null); + buildGraph(pta.getNakedReachableMethods()); + } - /* - * Constructing the XPAG for a program (Figure 5 in the paper) - * */ - protected void buildGraph(Collection reachables) { - // add edges in each method - reachables.parallelStream().forEach(this::buildInternal); - } + /* + * Constructing the XPAG for a program (Figure 5 in the paper) + * */ + protected void buildGraph(Collection reachables) { + // add edges in each method + reachables.parallelStream().forEach(this::buildInternal); + } - protected void buildInternal(SootMethod method) { - buildInternalWithInline(method); - } + protected void buildInternal(SootMethod method) { + buildInternalWithInline(method); + } - protected void buildInternalWithInline(SootMethod method) { - MethodPAG srcmpag = pag.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - VarNode thisNode = srcnf.caseThis(); - // add special ``this'' edge - addThisEdge((LocalVarNode) thisNode); - // add normal edges: NEW, ASSIGN, LOAD, STORE - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof LocalVarNode) { - this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); - } else if (to instanceof FieldRefNode fr) { - this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase(), fr.getField()); - } // local-global + protected void buildInternalWithInline(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + VarNode thisNode = srcnf.caseThis(); + // add special ``this'' edge + addThisEdge((LocalVarNode) thisNode); + // add normal edges: NEW, ASSIGN, LOAD, STORE + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + } else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase(), fr.getField()); + } // local-global - } else if (from instanceof AllocNode) { - if (to instanceof LocalVarNode) { - this.addNewEdge((AllocNode) from, (LocalVarNode) to); - } // GlobalVarNode - } else if (from instanceof FieldRefNode fr) { - this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to, fr.getField()); - } // global-local - } - // handle call statements. - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - Value[] args = new Value[numArgs]; - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) - continue; - args[i] = arg; - } - LocalVarNode retDest = null; - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - retDest = pag.findLocalVarNode(dest); - } - } - if (ie instanceof AbstractInstanceInvokeExpr iie) { - LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); - if (iie instanceof JSpecialInvokeExpr sie) { - SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(sie.getMethodSignature()).get(); - inline(s, target); - } else { - /* instance call with non-this base variable are modeled as in Eagle/Turner. */ - modelVirtualCall(numArgs, args, receiver, retDest); - } - } else { - if (ie instanceof JStaticInvokeExpr sie) { - SootMethod target = (SootMethod) PTAScene.v().getView().getMethod(sie.getMethodSignature()).get(); - inline(s, target); - } - } - } - // handle parameters. - for (int i = 0; i < method.getParameterCount(); ++i) { - if (method.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { - LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); - addParamEdge(param); - } + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to, fr.getField()); + } // global-local + } + // handle call statements. + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; + args[i] = arg; + } + LocalVarNode retDest = null; + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + retDest = pag.findLocalVarNode(dest); } - // treat this as a special parameter. - if (!method.isStatic()) { - addParamEdge((LocalVarNode) srcnf.caseThis()); + } + if (ie instanceof AbstractInstanceInvokeExpr iie) { + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + if (iie instanceof JSpecialInvokeExpr sie) { + SootMethod target = + (SootMethod) PTAScene.v().getView().getMethod(sie.getMethodSignature()).get(); + inline(s, target); + } else { + /* instance call with non-this base variable are modeled as in Eagle/Turner. */ + modelVirtualCall(numArgs, args, receiver, retDest); } - // handle returns - if (method.getReturnType() instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { - addReturnEdge((LocalVarNode) srcnf.caseRet()); + } else { + if (ie instanceof JStaticInvokeExpr sie) { + SootMethod target = + (SootMethod) PTAScene.v().getView().getMethod(sie.getMethodSignature()).get(); + inline(s, target); } + } } - - private void modelVirtualCall(int numArgs, Value[] args, LocalVarNode receiver, LocalVarNode retDest) { - for (int i = 0; i < numArgs; i++) { - if (args[i] == null) { - continue; - } - ValNode argNode = pag.findValNode(args[i]); - if (argNode instanceof LocalVarNode) { - addCStoreEdge((LocalVarNode) argNode, receiver); - } - } - if (retDest != null) { - addCLoadEdge(receiver, retDest); - } - addCStoreEdge(receiver, receiver); + // handle parameters. + for (int i = 0; i < method.getParameterCount(); ++i) { + if (method.getParameterType(i) instanceof ReferenceType + && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + addParamEdge(param); + } } - - private void inline(Stmt invokeStmt, SootMethod method) { - AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); - int numArgs = ie.getArgCount(); - Value[] args = new Value[numArgs]; - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) - continue; - args[i] = arg; - } - LocalVarNode retDest = null; - if (invokeStmt instanceof JAssignStmt) { - Value dest = ((JAssignStmt) invokeStmt).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - retDest = pag.findLocalVarNode(dest); - } - } - LocalVarNode receiver = null; - if (ie instanceof AbstractInstanceInvokeExpr iie) { - receiver = pag.findLocalVarNode(iie.getBase()); - } - MethodPAG mpag = pag.getMethodPAG(method); - MethodNodeFactory nodeFactory = mpag.nodeFactory(); - if (numArgs != method.getParameterCount()) { - return; - } - // handle parameters - for (int i = 0; i < method.getParameterCount(); ++i) { - if (args[i] != null && method.getParameterType(i) instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { - LocalVarNode param = (LocalVarNode) nodeFactory.caseParm(i); - ValNode argVal = pag.findValNode(args[i]); - if (argVal instanceof LocalVarNode argNode) { - addAssignEdge(argNode, param); - } - } - } - // handle return node - if (retDest != null && method.getReturnType() instanceof ReferenceType && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { - addAssignEdge((LocalVarNode) nodeFactory.caseRet(), retDest); - } - // handle this node - if (receiver != null) { - addAssignEdge(receiver, (LocalVarNode) nodeFactory.caseThis()); - } + // treat this as a special parameter. + if (!method.isStatic()) { + addParamEdge((LocalVarNode) srcnf.caseThis()); } + // handle returns + if (method.getReturnType() instanceof ReferenceType + && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { + addReturnEdge((LocalVarNode) srcnf.caseRet()); + } + } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - protected void addNormalEdge(Edge edge) { - outEdges.computeIfAbsent(edge.from, k -> ConcurrentHashMap.newKeySet()).add(edge); + private void modelVirtualCall( + int numArgs, Value[] args, LocalVarNode receiver, LocalVarNode retDest) { + for (int i = 0; i < numArgs; i++) { + if (args[i] == null) { + continue; + } + ValNode argNode = pag.findValNode(args[i]); + if (argNode instanceof LocalVarNode) { + addCStoreEdge((LocalVarNode) argNode, receiver); + } } + if (retDest != null) { + addCLoadEdge(receiver, retDest); + } + addCStoreEdge(receiver, receiver); + } - /* methods for adding normal edges: NEW, ASSIGN, STORE, LOAD. */ - protected void addNewEdge(AllocNode from, LocalVarNode to) { - // skip merged heaps. - if (from.getMethod() == null && !(from instanceof ConstantNode)) { - return; + private void inline(Stmt invokeStmt, SootMethod method) { + AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; + args[i] = arg; + } + LocalVarNode retDest = null; + if (invokeStmt instanceof JAssignStmt) { + Value dest = ((JAssignStmt) invokeStmt).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + retDest = pag.findLocalVarNode(dest); + } + } + LocalVarNode receiver = null; + if (ie instanceof AbstractInstanceInvokeExpr iie) { + receiver = pag.findLocalVarNode(iie.getBase()); + } + MethodPAG mpag = pag.getMethodPAG(method); + MethodNodeFactory nodeFactory = mpag.nodeFactory(); + if (numArgs != method.getParameterCount()) { + return; + } + // handle parameters + for (int i = 0; i < method.getParameterCount(); ++i) { + if (args[i] != null + && method.getParameterType(i) instanceof ReferenceType + && !PTAUtils.isPrimitiveArrayType(method.getParameterType(i))) { + LocalVarNode param = (LocalVarNode) nodeFactory.caseParm(i); + ValNode argVal = pag.findValNode(args[i]); + if (argVal instanceof LocalVarNode argNode) { + addAssignEdge(argNode, param); } - Edge newEdge = new Edge(from, to, null, EdgeKind.NEW); - addNormalEdge(newEdge); - Edge iNewEdge = new Edge(to, from, null, EdgeKind.INEW); - addNormalEdge(iNewEdge); + } } - - protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { - Edge assignEdge = new Edge(from, to, null, EdgeKind.ASSIGN); - addNormalEdge(assignEdge); - Edge iAssignEdge = new Edge(to, from, null, EdgeKind.IASSIGN); - addNormalEdge(iAssignEdge); + // handle return node + if (retDest != null + && method.getReturnType() instanceof ReferenceType + && !PTAUtils.isPrimitiveArrayType(method.getReturnType())) { + addAssignEdge((LocalVarNode) nodeFactory.caseRet(), retDest); } - - protected void addStoreEdge(LocalVarNode from, LocalVarNode base, SparkField field) { - Edge storeEdge = new Edge(from, base, field, EdgeKind.STORE); - addNormalEdge(storeEdge); - Edge iStoreEdge = new Edge(base, from, field, EdgeKind.ISTORE); - addNormalEdge(iStoreEdge); + // handle this node + if (receiver != null) { + addAssignEdge(receiver, (LocalVarNode) nodeFactory.caseThis()); } + } - protected void addLoadEdge(LocalVarNode base, LocalVarNode to, SparkField field) { - Edge loadEdge = new Edge(base, to, field, EdgeKind.LOAD); - addNormalEdge(loadEdge); - Edge iLoadEdge = new Edge(to, base, field, EdgeKind.ILOAD); - addNormalEdge(iLoadEdge); - } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /* methods for adding inter-procedural edges at non-this invocation site */ - protected void addCStoreEdge(LocalVarNode from, LocalVarNode base) { - Edge cstoreEdge = new Edge(from, base, null, EdgeKind.CSTORE); - addNormalEdge(cstoreEdge); - Edge iCstoreEdge = new Edge(base, from, null, EdgeKind.ICSTORE); - addNormalEdge(iCstoreEdge); - } + protected void addNormalEdge(Edge edge) { + outEdges.computeIfAbsent(edge.from, k -> ConcurrentHashMap.newKeySet()).add(edge); + } - protected void addCLoadEdge(LocalVarNode base, LocalVarNode to) { - Edge cLoadEdge = new Edge(base, to, null, EdgeKind.CLOAD); - addNormalEdge(cLoadEdge); - Edge iCloadEdge = new Edge(to, base, null, EdgeKind.ICLOAD); - addNormalEdge(iCloadEdge); + /* methods for adding normal edges: NEW, ASSIGN, STORE, LOAD. */ + protected void addNewEdge(AllocNode from, LocalVarNode to) { + // skip merged heaps. + if (from.getMethod() == null && !(from instanceof ConstantNode)) { + return; } + Edge newEdge = new Edge(from, to, null, EdgeKind.NEW); + addNormalEdge(newEdge); + Edge iNewEdge = new Edge(to, from, null, EdgeKind.INEW); + addNormalEdge(iNewEdge); + } - /* this is a special edge */ - protected void addThisEdge(LocalVarNode thisNode) { - Edge thisEdge = new Edge(thisNode, dummyThis, null, EdgeKind.THIS); - addNormalEdge(thisEdge); - Edge ithisEdge = new Edge(dummyThis, thisNode, null, EdgeKind.ITHIS); - addNormalEdge(ithisEdge); - } + protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { + Edge assignEdge = new Edge(from, to, null, EdgeKind.ASSIGN); + addNormalEdge(assignEdge); + Edge iAssignEdge = new Edge(to, from, null, EdgeKind.IASSIGN); + addNormalEdge(iAssignEdge); + } - /* methods for adding self-loop edges */ - protected void addParamEdge(LocalVarNode param) { - Edge paramEdge = new Edge(param, param, null, EdgeKind.PARAM); - addNormalEdge(paramEdge); - } + protected void addStoreEdge(LocalVarNode from, LocalVarNode base, SparkField field) { + Edge storeEdge = new Edge(from, base, field, EdgeKind.STORE); + addNormalEdge(storeEdge); + Edge iStoreEdge = new Edge(base, from, field, EdgeKind.ISTORE); + addNormalEdge(iStoreEdge); + } - protected void addReturnEdge(LocalVarNode ret) { - Edge retEdge = new Edge(ret, ret, null, EdgeKind.RETURN); - addNormalEdge(retEdge); - } + protected void addLoadEdge(LocalVarNode base, LocalVarNode to, SparkField field) { + Edge loadEdge = new Edge(base, to, field, EdgeKind.LOAD); + addNormalEdge(loadEdge); + Edge iLoadEdge = new Edge(to, base, field, EdgeKind.ILOAD); + addNormalEdge(iLoadEdge); + } - public Set getOutEdges(Node node) { - return this.outEdges.getOrDefault(node, Collections.emptySet()); - } + /* methods for adding inter-procedural edges at non-this invocation site */ + protected void addCStoreEdge(LocalVarNode from, LocalVarNode base) { + Edge cstoreEdge = new Edge(from, base, null, EdgeKind.CSTORE); + addNormalEdge(cstoreEdge); + Edge iCstoreEdge = new Edge(base, from, null, EdgeKind.ICSTORE); + addNormalEdge(iCstoreEdge); + } - public LocalVarNode getDummyThis() { - return dummyThis; - } + protected void addCLoadEdge(LocalVarNode base, LocalVarNode to) { + Edge cLoadEdge = new Edge(base, to, null, EdgeKind.CLOAD); + addNormalEdge(cLoadEdge); + Edge iCloadEdge = new Edge(to, base, null, EdgeKind.ICLOAD); + addNormalEdge(iCloadEdge); + } + + /* this is a special edge */ + protected void addThisEdge(LocalVarNode thisNode) { + Edge thisEdge = new Edge(thisNode, dummyThis, null, EdgeKind.THIS); + addNormalEdge(thisEdge); + Edge ithisEdge = new Edge(dummyThis, thisNode, null, EdgeKind.ITHIS); + addNormalEdge(ithisEdge); + } + + /* methods for adding self-loop edges */ + protected void addParamEdge(LocalVarNode param) { + Edge paramEdge = new Edge(param, param, null, EdgeKind.PARAM); + addNormalEdge(paramEdge); + } + + protected void addReturnEdge(LocalVarNode ret) { + Edge retEdge = new Edge(ret, ret, null, EdgeKind.RETURN); + addNormalEdge(retEdge); + } + + public Set getOutEdges(Node node) { + return this.outEdges.getOrDefault(node, Collections.emptySet()); + } + public LocalVarNode getDummyThis() { + return dummyThis; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java index 604fcaef8c4..40748547547 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/debloaterx/XUtility.java @@ -1,5 +1,8 @@ package qilin.pta.toolkits.debloaterx; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; @@ -20,294 +23,309 @@ import sootup.core.types.ClassType; import sootup.core.types.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - public class XUtility { - protected final PTA pta; - protected final PAG pag; + protected final PTA pta; + protected final PAG pag; - protected final Map o2HCQ = new ConcurrentHashMap<>(); - /* records objects and their instance fields */ - protected final Map> o2Fields = new ConcurrentHashMap<>(); - protected final Map> t2Fields = new ConcurrentHashMap<>(); - protected final Map>> o2nonThisFStores = new ConcurrentHashMap<>(); - protected final Map>> t2nonThisFStores = new ConcurrentHashMap<>(); - protected final Map>> o2nonThisFLoads = new ConcurrentHashMap<>(); - protected final Map>> t2nonThisFLoads = new ConcurrentHashMap<>(); + protected final Map o2HCQ = new ConcurrentHashMap<>(); + /* records objects and their instance fields */ + protected final Map> o2Fields = new ConcurrentHashMap<>(); + protected final Map> t2Fields = new ConcurrentHashMap<>(); + protected final Map>> o2nonThisFStores = + new ConcurrentHashMap<>(); + protected final Map>> t2nonThisFStores = + new ConcurrentHashMap<>(); + protected final Map>> o2nonThisFLoads = + new ConcurrentHashMap<>(); + protected final Map>> t2nonThisFLoads = + new ConcurrentHashMap<>(); - /* records the methods and their receiver objects and types */ - protected final Map> o2InvokedMethods = new HashMap<>(); - protected final Map> t2InvokedMethods = new HashMap<>(); - protected final Map> m2receiverObjects = new HashMap<>(); + /* records the methods and their receiver objects and types */ + protected final Map> o2InvokedMethods = new HashMap<>(); + protected final Map> t2InvokedMethods = new HashMap<>(); + protected final Map> m2receiverObjects = new HashMap<>(); - protected final Set rawOrPolyTypes = new HashSet<>(); - protected final XPAG xpag; - protected final InterFlowAnalysis interfa; + protected final Set rawOrPolyTypes = new HashSet<>(); + protected final XPAG xpag; + protected final InterFlowAnalysis interfa; - public XUtility(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - Stopwatch stopwatch = Stopwatch.newAndStart("HackUtility construction"); - buildHeapFieldsMapping(); - buildHeapMethodsMapping(); - computeRawOrPolyTypes(); - this.xpag = new XPAG(pta, this); - this.interfa = new InterFlowAnalysis(this); - stopwatch.stop(); - System.out.println(stopwatch); - } + public XUtility(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + Stopwatch stopwatch = Stopwatch.newAndStart("HackUtility construction"); + buildHeapFieldsMapping(); + buildHeapMethodsMapping(); + computeRawOrPolyTypes(); + this.xpag = new XPAG(pta, this); + this.interfa = new InterFlowAnalysis(this); + stopwatch.stop(); + System.out.println(stopwatch); + } - public PTA getPta() { - return pta; - } + public PTA getPta() { + return pta; + } - public XPAG getXpag() { - return xpag; - } + public XPAG getXpag() { + return xpag; + } - public InterFlowAnalysis getInterFlowAnalysis() { - return interfa; - } + public InterFlowAnalysis getInterFlowAnalysis() { + return interfa; + } - private boolean isImpreciseType(Type type) { - if (type == PTAUtils.getClassType("java.lang.Object")) { - return true; - } - if (type instanceof ClassType refType) { - SootClass sc = (SootClass) PTAScene.v().getView().getClass(refType).get(); - return sc.isAbstract() || sc.isInterface() || refType.getClassName().startsWith("Abstract"); - } - return false; + private boolean isImpreciseType(Type type) { + if (type == PTAUtils.getClassType("java.lang.Object")) { + return true; + } + if (type instanceof ClassType refType) { + SootClass sc = (SootClass) PTAScene.v().getView().getClass(refType).get(); + return sc.isAbstract() || sc.isInterface() || refType.getClassName().startsWith("Abstract"); } + return false; + } - /* Implemnting the rules for defining coarse types (Figure 6 in the paper) */ - public boolean isCoarseType(Type type) { - if (type instanceof ArrayType at) { - type = at.getArrayElementType(); - } - return isImpreciseType(type) || rawOrPolyTypes().contains(type); + /* Implemnting the rules for defining coarse types (Figure 6 in the paper) */ + public boolean isCoarseType(Type type) { + if (type instanceof ArrayType at) { + type = at.getArrayElementType(); } + return isImpreciseType(type) || rawOrPolyTypes().contains(type); + } - private void computeRawOrPolyTypes() { - Set types = new HashSet<>(); - for (AllocNode heap : pag.getAllocNodes()) { - Type type = heap.getType(); - if (type instanceof ArrayType at) { - Type et = at.getArrayElementType(); - if (isImpreciseType(et)) { - rawOrPolyTypes.add(et); - } else { - types.add(et); - } - } else { - for (SparkField field : getFields(heap)) { - Type ft = field.getType(); - if (ft instanceof ArrayType fat) { - ft = fat.getArrayElementType(); - } - if (isImpreciseType(ft)) { - rawOrPolyTypes.add(ft); - rawOrPolyTypes.add(type); - } else { - types.add(type); - types.add(ft); - } - } - } + private void computeRawOrPolyTypes() { + Set types = new HashSet<>(); + for (AllocNode heap : pag.getAllocNodes()) { + Type type = heap.getType(); + if (type instanceof ArrayType at) { + Type et = at.getArrayElementType(); + if (isImpreciseType(et)) { + rawOrPolyTypes.add(et); + } else { + types.add(et); } - boolean continueUpdating = true; - while (continueUpdating) { - continueUpdating = false; - for (Type type : types) { - for (SparkField field : getFields(type)) { - Type ft = field.getType(); - if (isCoarseType(ft)) { - if (rawOrPolyTypes.add(type)) { - continueUpdating = true; - } - } - } + } else { + for (SparkField field : getFields(heap)) { + Type ft = field.getType(); + if (ft instanceof ArrayType fat) { + ft = fat.getArrayElementType(); + } + if (isImpreciseType(ft)) { + rawOrPolyTypes.add(ft); + rawOrPolyTypes.add(type); + } else { + types.add(type); + types.add(ft); + } + } + } + } + boolean continueUpdating = true; + while (continueUpdating) { + continueUpdating = false; + for (Type type : types) { + for (SparkField field : getFields(type)) { + Type ft = field.getType(); + if (isCoarseType(ft)) { + if (rawOrPolyTypes.add(type)) { + continueUpdating = true; } + } } + } } + } - private Set rawOrPolyTypes() { - return rawOrPolyTypes; - } + private Set rawOrPolyTypes() { + return rawOrPolyTypes; + } - /* record objects and their fields */ - private void buildHeapFieldsMappingIn(SootMethod method) { - MethodPAG srcmpag = pag.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - Set stores = new HashSet<>(); - Set loads = new HashSet<>(); - Set thisAliases = new HashSet<>(); - thisAliases.add(thisRef); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof FieldRefNode frn) { - stores.add(frn); - } - if (thisAliases.contains(from) && to instanceof LocalVarNode) { - thisAliases.add(to); - } - } else if (from instanceof FieldRefNode frn) { - loads.add(frn); - } + /* record objects and their fields */ + private void buildHeapFieldsMappingIn(SootMethod method) { + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + Set stores = new HashSet<>(); + Set loads = new HashSet<>(); + Set thisAliases = new HashSet<>(); + thisAliases.add(thisRef); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof FieldRefNode frn) { + stores.add(frn); } - // handle STORE - for (FieldRefNode frn : stores) { - LocalVarNode storeBase = (LocalVarNode) frn.getBase(); - SparkField field = frn.getField(); - boolean isNonthisBase = !thisAliases.contains(storeBase); - for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { - o2Fields.computeIfAbsent(heap, k -> ConcurrentHashMap.newKeySet()).add(field); - t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); - if (isNonthisBase) { - Map> f2bs = o2nonThisFStores.computeIfAbsent(heap, k -> new ConcurrentHashMap<>()); - f2bs.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(storeBase); - Map> f2bsx = t2nonThisFStores.computeIfAbsent(heap.getType(), k -> new ConcurrentHashMap<>()); - f2bsx.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(storeBase); - } - } + if (thisAliases.contains(from) && to instanceof LocalVarNode) { + thisAliases.add(to); } - // handle LOAD - for (FieldRefNode frn : loads) { - LocalVarNode loadBase = (LocalVarNode) frn.getBase(); - SparkField field = frn.getField(); - boolean isNonthisBase = !thisAliases.contains(loadBase); - for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { - o2Fields.computeIfAbsent(heap, k -> ConcurrentHashMap.newKeySet()).add(field); - t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); - if (isNonthisBase) { - Map> f2bs = o2nonThisFLoads.computeIfAbsent(heap, k -> new ConcurrentHashMap<>()); - f2bs.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(loadBase); - Map> f2bsx = t2nonThisFLoads.computeIfAbsent(heap.getType(), k -> new ConcurrentHashMap<>()); - f2bsx.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(loadBase); - } - } + } else if (from instanceof FieldRefNode frn) { + loads.add(frn); + } + } + // handle STORE + for (FieldRefNode frn : stores) { + LocalVarNode storeBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + boolean isNonthisBase = !thisAliases.contains(storeBase); + for (AllocNode heap : pta.reachingObjects(storeBase).toCIPointsToSet().toCollection()) { + o2Fields.computeIfAbsent(heap, k -> ConcurrentHashMap.newKeySet()).add(field); + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + if (isNonthisBase) { + Map> f2bs = + o2nonThisFStores.computeIfAbsent(heap, k -> new ConcurrentHashMap<>()); + f2bs.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(storeBase); + Map> f2bsx = + t2nonThisFStores.computeIfAbsent(heap.getType(), k -> new ConcurrentHashMap<>()); + f2bsx.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(storeBase); } + } } - - private void buildHeapFieldsMapping() { - pta.getNakedReachableMethods().stream().filter(SootMethod::isConcrete).forEach(this::buildHeapFieldsMappingIn); + // handle LOAD + for (FieldRefNode frn : loads) { + LocalVarNode loadBase = (LocalVarNode) frn.getBase(); + SparkField field = frn.getField(); + boolean isNonthisBase = !thisAliases.contains(loadBase); + for (AllocNode heap : pta.reachingObjects(loadBase).toCIPointsToSet().toCollection()) { + o2Fields.computeIfAbsent(heap, k -> ConcurrentHashMap.newKeySet()).add(field); + t2Fields.computeIfAbsent(heap.getType(), k -> ConcurrentHashMap.newKeySet()).add(field); + if (isNonthisBase) { + Map> f2bs = + o2nonThisFLoads.computeIfAbsent(heap, k -> new ConcurrentHashMap<>()); + f2bs.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(loadBase); + Map> f2bsx = + t2nonThisFLoads.computeIfAbsent(heap.getType(), k -> new ConcurrentHashMap<>()); + f2bsx.computeIfAbsent(field, k -> ConcurrentHashMap.newKeySet()).add(loadBase); + } + } } + } - /* records objects (together with their types) and their invoked methods */ - private void buildHeapMethodsMapping() { - CallGraph callgraph = pta.getCallGraph(); - // collect virtual callsites. - Set vcallsites = new HashSet<>(); - for (Edge edge : callgraph) { - SootMethod tgtM = edge.tgt(); - if (tgtM.isStatic() || !tgtM.isConcrete()) { - continue; - } - final Stmt s = edge.srcStmt(); - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof AbstractInstanceInvokeExpr iie) { - LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); - MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); - VirtualCallSite virtualCallSite = new VirtualCallSite(receiver, s, new ContextMethod(edge.src(), pta.emptyContext()), iie, subSig, soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); - vcallsites.add(virtualCallSite); - } else { - throw new RuntimeException("ie could not be of " + ie.getClass()); - } - } - // foreach virtualcallsite, we build mapping from their receiver objects. - for (VirtualCallSite vcallsite : vcallsites) { - AbstractInstanceInvokeExpr iie = vcallsite.iie(); - LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); - for (AllocNode heap : pta.reachingObjects(receiver).toCIPointsToSet().toCollection()) { - QueueReader reader = PTAUtils.dispatch(heap.getType(), vcallsite); - while (reader.hasNext()) { - SootMethod tgtM = reader.next(); - m2receiverObjects.computeIfAbsent(tgtM, k -> new HashSet<>()).add(heap); - o2InvokedMethods.computeIfAbsent(heap, k -> new HashSet<>()).add(tgtM); - t2InvokedMethods.computeIfAbsent(heap.getType(), k -> new HashSet<>()).add(tgtM); - } - } + private void buildHeapFieldsMapping() { + pta.getNakedReachableMethods().stream() + .filter(SootMethod::isConcrete) + .forEach(this::buildHeapFieldsMappingIn); + } + + /* records objects (together with their types) and their invoked methods */ + private void buildHeapMethodsMapping() { + CallGraph callgraph = pta.getCallGraph(); + // collect virtual callsites. + Set vcallsites = new HashSet<>(); + for (Edge edge : callgraph) { + SootMethod tgtM = edge.tgt(); + if (tgtM.isStatic() || !tgtM.isConcrete()) { + continue; + } + final Stmt s = edge.srcStmt(); + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof AbstractInstanceInvokeExpr iie) { + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + MethodSubSignature subSig = iie.getMethodSignature().getSubSignature(); + VirtualCallSite virtualCallSite = + new VirtualCallSite( + receiver, + s, + new ContextMethod(edge.src(), pta.emptyContext()), + iie, + subSig, + soot.jimple.toolkits.callgraph.Edge.ieToKind(iie)); + vcallsites.add(virtualCallSite); + } else { + throw new RuntimeException("ie could not be of " + ie.getClass()); + } + } + // foreach virtualcallsite, we build mapping from their receiver objects. + for (VirtualCallSite vcallsite : vcallsites) { + AbstractInstanceInvokeExpr iie = vcallsite.iie(); + LocalVarNode receiver = pag.findLocalVarNode(iie.getBase()); + for (AllocNode heap : pta.reachingObjects(receiver).toCIPointsToSet().toCollection()) { + QueueReader reader = PTAUtils.dispatch(heap.getType(), vcallsite); + while (reader.hasNext()) { + SootMethod tgtM = reader.next(); + m2receiverObjects.computeIfAbsent(tgtM, k -> new HashSet<>()).add(heap); + o2InvokedMethods.computeIfAbsent(heap, k -> new HashSet<>()).add(tgtM); + t2InvokedMethods.computeIfAbsent(heap.getType(), k -> new HashSet<>()).add(tgtM); } + } } + } - // Below are public APIs for access. + // Below are public APIs for access. - public Set getReceiverObjects(SootMethod method) { - return m2receiverObjects.getOrDefault(method, Collections.emptySet()); - } + public Set getReceiverObjects(SootMethod method) { + return m2receiverObjects.getOrDefault(method, Collections.emptySet()); + } - public Set getInvokedMethods(AllocNode heap) { - return o2InvokedMethods.getOrDefault(heap, Collections.emptySet()); - } + public Set getInvokedMethods(AllocNode heap) { + return o2InvokedMethods.getOrDefault(heap, Collections.emptySet()); + } - /* get or create TPAG for a given type */ - public HeapContainerQuery getHCQ(AllocNode heap) { - HeapContainerQuery hcq = o2HCQ.get(heap); - if (hcq == null) { - hcq = new HeapContainerQuery(this, heap); - o2HCQ.put(heap, hcq); - } - return hcq; + /* get or create TPAG for a given type */ + public HeapContainerQuery getHCQ(AllocNode heap) { + HeapContainerQuery hcq = o2HCQ.get(heap); + if (hcq == null) { + hcq = new HeapContainerQuery(this, heap); + o2HCQ.put(heap, hcq); } + return hcq; + } - public Set getFields() { - Set tmp = this.o2Fields.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); - Set ret = new HashSet<>(); - for (SparkField field : tmp) { - Type type = field.getType(); - if (isCoarseType(type)) { - ret.add(field); - } - } - return ret; + public Set getFields() { + Set tmp = + this.o2Fields.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + Set ret = new HashSet<>(); + for (SparkField field : tmp) { + Type type = field.getType(); + if (isCoarseType(type)) { + ret.add(field); + } } + return ret; + } - public Set getFields(AllocNode heap) { - return this.o2Fields.getOrDefault(heap, Collections.emptySet()); - } + public Set getFields(AllocNode heap) { + return this.o2Fields.getOrDefault(heap, Collections.emptySet()); + } - public Set getFields(Type type) { - if (type instanceof ClassType refType) { - Set ret = this.t2Fields.get(refType); - if (ret != null) { - return ret; - } else { - ret = this.t2Fields.computeIfAbsent(refType, k -> new HashSet<>()); - for (AllocNode heap : this.o2Fields.keySet()) { - if (PTAScene.v().canStoreType(heap.getType(), refType)) { - for (SparkField sparkField : this.o2Fields.get(heap)) { - if (sparkField instanceof Field f) { - SootField sf = f.getField(); - Type declType = sf.getDeclaringClassType(); - if (PTAScene.v().canStoreType(type, declType)) { - ret.add(sparkField); - } - } else { - throw new RuntimeException(sparkField + ";" + sparkField.getClass()); - } - } - } + public Set getFields(Type type) { + if (type instanceof ClassType refType) { + Set ret = this.t2Fields.get(refType); + if (ret != null) { + return ret; + } else { + ret = this.t2Fields.computeIfAbsent(refType, k -> new HashSet<>()); + for (AllocNode heap : this.o2Fields.keySet()) { + if (PTAScene.v().canStoreType(heap.getType(), refType)) { + for (SparkField sparkField : this.o2Fields.get(heap)) { + if (sparkField instanceof Field f) { + SootField sf = f.getField(); + Type declType = sf.getDeclaringClassType(); + if (PTAScene.v().canStoreType(type, declType)) { + ret.add(sparkField); } - return ret; + } else { + throw new RuntimeException(sparkField + ";" + sparkField.getClass()); + } } - } else { - return Collections.emptySet(); + } } + return ret; + } + } else { + return Collections.emptySet(); } + } - public boolean hasNonThisStoreOnField(AllocNode heap, SparkField field) { - Map> field2bases = this.o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); - return field2bases.containsKey(field); - } - - public boolean hasNonThisLoadFromField(AllocNode heap, SparkField field) { - Map> field2bases = this.o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()); - return field2bases.containsKey(field); - } + public boolean hasNonThisStoreOnField(AllocNode heap, SparkField field) { + Map> field2bases = + this.o2nonThisFStores.getOrDefault(heap, Collections.emptyMap()); + return field2bases.containsKey(field); + } + public boolean hasNonThisLoadFromField(AllocNode heap, SparkField field) { + Map> field2bases = + this.o2nonThisFLoads.getOrDefault(heap, Collections.emptyMap()); + return field2bases.containsKey(field); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java index 54465868d11..fad5c4a71d3 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/BNode.java @@ -21,42 +21,39 @@ import qilin.core.pag.AllocNode; import qilin.util.PTAUtils; -/** - * Original Graph Node(sparkNode) expanded bidirectinally - */ +/** Original Graph Node(sparkNode) expanded bidirectinally */ public class BNode { - public Object sparkNode; - public Boolean forward; - public int level; - public Boolean cs; - - public boolean entryCS() { - if (this.cs) - return false; - return this.cs = true; - } - - public BNode(Object origin, Boolean forward) { - this.sparkNode = origin; - this.forward = forward; - this.cs = false; - this.level = 0; - } - - public Object getIR() { - return PTAUtils.getIR(sparkNode); - } - - boolean isHeapPlus() { - return sparkNode instanceof AllocNode && this.forward; - } - - boolean isHeapMinus() { - return sparkNode instanceof AllocNode && !this.forward; - } - - @Override - public String toString() { - return sparkNode + "," + forward; - } -} \ No newline at end of file + public Object sparkNode; + public Boolean forward; + public int level; + public Boolean cs; + + public boolean entryCS() { + if (this.cs) return false; + return this.cs = true; + } + + public BNode(Object origin, Boolean forward) { + this.sparkNode = origin; + this.forward = forward; + this.cs = false; + this.level = 0; + } + + public Object getIR() { + return PTAUtils.getIR(sparkNode); + } + + boolean isHeapPlus() { + return sparkNode instanceof AllocNode && this.forward; + } + + boolean isHeapMinus() { + return sparkNode instanceof AllocNode && !this.forward; + } + + @Override + public String toString() { + return sparkNode + "," + forward; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java index efb8fdef9c2..827de012539 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/eagle/Eagle.java @@ -18,6 +18,8 @@ package qilin.pta.toolkits.eagle; +import java.util.*; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; @@ -38,345 +40,360 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.*; -import java.util.stream.Collectors; - // implementation of Eagle (OOPSLA'19). public class Eagle { - protected Map> sparkNode2BNode = new HashMap<>(); - // fields for storage - public Set allocs = new HashSet<>(); - public Set allocIs = new HashSet<>(); - public Map> outEdges = new HashMap<>(); - protected Map> balancedOutEdges = new HashMap<>(); - - private int new_count = 0; - private int assign_count = 0; - protected int store_count = 0; - private int load_count = 0; - private int balance_count = 0; - private int hstore_count = 0; - private int hload_count = 0; - private int total_nodes_count = 0; - private int total_edges_count = 0; - - public void dumpCount() { - System.out.println("#NEW:" + new_count); - System.out.println("#ASSIGN:" + assign_count); - System.out.println("#STORE:" + store_count); - System.out.println("#LOAD:" + load_count); - System.out.println("#HSTORE:" + hstore_count); - System.out.println("#HLOAD:" + hload_count); - System.out.println("#BALANCE:" + balance_count); - } - - public Collection getNodes() { - return sparkNode2BNode.values().stream().flatMap(subMap -> subMap.values().stream()) - .collect(Collectors.toSet()); - } - - public Collection getSparkNodes() { - return sparkNode2BNode.values().stream().flatMap(subMap -> subMap.values().stream()).map(gn -> gn.sparkNode) - .collect(Collectors.toSet()); - } - - public BNode getBNode(Object origin, Boolean forward) { - Map subMap = sparkNode2BNode.computeIfAbsent(origin, k -> new HashMap<>()); - if (subMap.containsKey(forward)) { - return subMap.get(forward); - } else { - BNode ret = new BNode(origin, forward); - subMap.put(forward, ret); - total_nodes_count++; - return ret; - } - } - - protected void addNormalEdge(BNode from, BNode to) { - Set m = outEdges.computeIfAbsent(from, k -> new HashSet<>()); - m.add(to); - total_edges_count++; - } - - public boolean addBalancedEdge(BNode from, BNode to) { - boolean ret = Util.addToMap(balancedOutEdges, from, to); - balance_count++; - total_edges_count++; - return ret; - } - - public void addNewEdge(AllocNode from, LocalVarNode to) { - BNode fromE = getBNode(from, true), toE = getBNode(to, true); - addNormalEdge(fromE, toE); - BNode toEI = getBNode(to, false), fromEI = getBNode(from, false); - addNormalEdge(toEI, fromEI); - - new_count++; - allocs.add(fromE); - allocIs.add(fromEI); + protected Map> sparkNode2BNode = new HashMap<>(); + // fields for storage + public Set allocs = new HashSet<>(); + public Set allocIs = new HashSet<>(); + public Map> outEdges = new HashMap<>(); + protected Map> balancedOutEdges = new HashMap<>(); + + private int new_count = 0; + private int assign_count = 0; + protected int store_count = 0; + private int load_count = 0; + private int balance_count = 0; + private int hstore_count = 0; + private int hload_count = 0; + private int total_nodes_count = 0; + private int total_edges_count = 0; + + public void dumpCount() { + System.out.println("#NEW:" + new_count); + System.out.println("#ASSIGN:" + assign_count); + System.out.println("#STORE:" + store_count); + System.out.println("#LOAD:" + load_count); + System.out.println("#HSTORE:" + hstore_count); + System.out.println("#HLOAD:" + hload_count); + System.out.println("#BALANCE:" + balance_count); + } + + public Collection getNodes() { + return sparkNode2BNode.values().stream() + .flatMap(subMap -> subMap.values().stream()) + .collect(Collectors.toSet()); + } + + public Collection getSparkNodes() { + return sparkNode2BNode.values().stream() + .flatMap(subMap -> subMap.values().stream()) + .map(gn -> gn.sparkNode) + .collect(Collectors.toSet()); + } + + public BNode getBNode(Object origin, Boolean forward) { + Map subMap = sparkNode2BNode.computeIfAbsent(origin, k -> new HashMap<>()); + if (subMap.containsKey(forward)) { + return subMap.get(forward); + } else { + BNode ret = new BNode(origin, forward); + subMap.put(forward, ret); + total_nodes_count++; + return ret; } - - public void addAssignEdge(LocalVarNode from, LocalVarNode to) { - BNode fromE = getBNode(from, true), toE = getBNode(to, true); - addNormalEdge(fromE, toE); - BNode toEI = getBNode(to, false), fromEI = getBNode(from, false); - addNormalEdge(toEI, fromEI); - - assign_count++; - } - - public void addStoreEdge(LocalVarNode from, LocalVarNode base) { - BNode fromE = getBNode(from, true), baseEI = getBNode(base, false); - addNormalEdge(fromE, baseEI); - BNode baseE = getBNode(base, true), fromEI = getBNode(from, false); - addNormalEdge(baseE, fromEI); - - store_count++; - } - - public void addLoadEdge(LocalVarNode base, LocalVarNode to) { - BNode baseE = getBNode(base, true), toE = getBNode(to, true); - addNormalEdge(baseE, toE); - BNode toEI = getBNode(to, false), baseEI = getBNode(base, false); - addNormalEdge(toEI, baseEI); - - load_count++; - } - - public void addHstoreEdge(Object from, AllocNode baseObj) { - BNode fromE = getBNode(from, true), baseObjE = getBNode(baseObj, true); - addNormalEdge(fromE, baseObjE); - BNode baseObjEI = getBNode(baseObj, false), fromEI = getBNode(from, false); - addNormalEdge(baseObjEI, fromEI); - allocIs.add(baseObjEI); - allocs.add(baseObjE); - hstore_count++; + } + + protected void addNormalEdge(BNode from, BNode to) { + Set m = outEdges.computeIfAbsent(from, k -> new HashSet<>()); + m.add(to); + total_edges_count++; + } + + public boolean addBalancedEdge(BNode from, BNode to) { + boolean ret = Util.addToMap(balancedOutEdges, from, to); + balance_count++; + total_edges_count++; + return ret; + } + + public void addNewEdge(AllocNode from, LocalVarNode to) { + BNode fromE = getBNode(from, true), toE = getBNode(to, true); + addNormalEdge(fromE, toE); + BNode toEI = getBNode(to, false), fromEI = getBNode(from, false); + addNormalEdge(toEI, fromEI); + + new_count++; + allocs.add(fromE); + allocIs.add(fromEI); + } + + public void addAssignEdge(LocalVarNode from, LocalVarNode to) { + BNode fromE = getBNode(from, true), toE = getBNode(to, true); + addNormalEdge(fromE, toE); + BNode toEI = getBNode(to, false), fromEI = getBNode(from, false); + addNormalEdge(toEI, fromEI); + + assign_count++; + } + + public void addStoreEdge(LocalVarNode from, LocalVarNode base) { + BNode fromE = getBNode(from, true), baseEI = getBNode(base, false); + addNormalEdge(fromE, baseEI); + BNode baseE = getBNode(base, true), fromEI = getBNode(from, false); + addNormalEdge(baseE, fromEI); + + store_count++; + } + + public void addLoadEdge(LocalVarNode base, LocalVarNode to) { + BNode baseE = getBNode(base, true), toE = getBNode(to, true); + addNormalEdge(baseE, toE); + BNode toEI = getBNode(to, false), baseEI = getBNode(base, false); + addNormalEdge(toEI, baseEI); + + load_count++; + } + + public void addHstoreEdge(Object from, AllocNode baseObj) { + BNode fromE = getBNode(from, true), baseObjE = getBNode(baseObj, true); + addNormalEdge(fromE, baseObjE); + BNode baseObjEI = getBNode(baseObj, false), fromEI = getBNode(from, false); + addNormalEdge(baseObjEI, fromEI); + allocIs.add(baseObjEI); + allocs.add(baseObjE); + hstore_count++; + } + + public void addHloadEdge(AllocNode baseObj, Object to) { + BNode baseObjEI = getBNode(baseObj, false), toE = getBNode(to, true); + addNormalEdge(baseObjEI, toE); + BNode toEI = getBNode(to, false), baseObjE = getBNode(baseObj, true); + addNormalEdge(toEI, baseObjE); + allocIs.add(baseObjEI); + allocs.add(baseObjE); + hload_count++; + } + + public int totalEdgesCount() { + return total_edges_count; + } + + public int totalNodesCount() { + return total_nodes_count; + } + + public Set getAllOutEdges(BNode node) { + Set ret = new HashSet<>(getOutEdges(node)); + if (balancedOutEdges.containsKey(node)) { + ret.addAll(balancedOutEdges.get(node)); } + return ret; + } - public void addHloadEdge(AllocNode baseObj, Object to) { - BNode baseObjEI = getBNode(baseObj, false), toE = getBNode(to, true); - addNormalEdge(baseObjEI, toE); - BNode toEI = getBNode(to, false), baseObjE = getBNode(baseObj, true); - addNormalEdge(toEI, baseObjE); - allocIs.add(baseObjEI); - allocs.add(baseObjE); - hload_count++; - } + public Collection getOutEdges(BNode node) { + return outEdges.getOrDefault(node, Collections.emptySet()); + } - public int totalEdgesCount() { - return total_edges_count; + public boolean reachValidReceiverObject(BNode from, BNode to) { + BNode fromEI = getBNode(to.sparkNode, false); + if (from.sparkNode instanceof Field || from.sparkNode instanceof ArrayElement) { + return getOutEdges(fromEI).contains(from); } - - public int totalNodesCount() { - return total_nodes_count; + return true; + } + + // eagle propagate + protected boolean enterCS(BNode node) { + return node.entryCS(); + } + + public Map contxtLengthAnalysis() { + Queue workList = new UniqueQueue<>(); + Set matchedObjects = new HashSet<>(); + // start from all "parameter/field" node + for (BNode heapNode : allocIs) { + for (BNode dst : getOutEdges(heapNode)) { + dst.cs = true; + workList.add(dst); + } } - - public Set getAllOutEdges(BNode node) { - Set ret = new HashSet<>(getOutEdges(node)); - if (balancedOutEdges.containsKey(node)) { - ret.addAll(balancedOutEdges.get(node)); + while (!workList.isEmpty()) { + BNode node = workList.poll(); + for (BNode dst : getAllOutEdges(node)) { + if (dst.isHeapPlus() && !node.isHeapMinus()) { + if (reachValidReceiverObject(node, dst)) { + if (matchedObjects.add(dst.sparkNode)) { // add balanced edges + BNode fromEI = getBNode(dst.sparkNode, false); + addBalancedEdge(fromEI, dst, workList); + } + } + } else { + if (enterCS(dst)) { + workList.add(dst); + } } - return ret; + } } - - public Collection getOutEdges(BNode node) { - return outEdges.getOrDefault(node, Collections.emptySet()); + Map ret = new HashMap<>(); + getSparkNodes() + .forEach( + sparkNode -> { + BNode node = getBNode(sparkNode, true); + BNode nodeInv = getBNode(sparkNode, false); + ret.put(sparkNode, node.cs && nodeInv.cs ? 1 : 0); + }); + return ret; + } + + protected void addBalancedEdge(BNode from, BNode to, Queue workList) { + if (addBalancedEdge(from, to)) { + if (from.cs) { + workList.add(from); // add src of the balanced edges to worklist + } } - - public boolean reachValidReceiverObject(BNode from, BNode to) { - BNode fromEI = getBNode(to.sparkNode, false); - if (from.sparkNode instanceof Field || from.sparkNode instanceof ArrayElement) { - return getOutEdges(fromEI).contains(from); - } - return true; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + + protected void addParamEdges( + AllocNode o, + LocalVarNode thisRef, + LocalVarNode[] parms, + LocalVarNode mret, + LocalVarNode mThrow) { + this.addHloadEdge(o, thisRef); + for (VarNode parm : parms) { + if (parm != null) { + this.addHloadEdge(o, parm); + } } - - // eagle propagate - protected boolean enterCS(BNode node) { - return node.entryCS(); + if (mret != null) { + this.addHstoreEdge(mret, o); } - - public Map contxtLengthAnalysis() { - Queue workList = new UniqueQueue<>(); - Set matchedObjects = new HashSet<>(); - // start from all "parameter/field" node - for (BNode heapNode : allocIs) { - for (BNode dst : getOutEdges(heapNode)) { - dst.cs = true; - workList.add(dst); - } - } - while (!workList.isEmpty()) { - BNode node = workList.poll(); - for (BNode dst : getAllOutEdges(node)) { - if (dst.isHeapPlus() && !node.isHeapMinus()) { - if (reachValidReceiverObject(node, dst)) { - if (matchedObjects.add(dst.sparkNode)) { // add balanced edges - BNode fromEI = getBNode(dst.sparkNode, false); - addBalancedEdge(fromEI, dst, workList); - } - } - } else { - if (enterCS(dst)) { - workList.add(dst); - } + if (mThrow != null) { + this.addHstoreEdge(mThrow, o); + } + } + + public void buildGraph(PTA prePTA) { + PAG prePAG = prePTA.getPag(); + // calculate points-to set for "This" pointer in each static method. + Map> pts = PTAUtils.calcStaticThisPTS(prePTA); + + CallGraph callGraph = prePTA.getCallGraph(); + for (SootMethod method : prePTA.getNakedReachableMethods()) { + if (!method.isConcrete()) { + continue; + } + MethodPAG srcmpag = prePAG.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + // add local edges + if (PTAUtils.isFakeMainMethod(method)) { + // special treatment for fake main + this.addNewEdge(prePTA.getRootNode(), thisRef); + } + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + } // local-global + + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + } // global-local + } + // add exception edges that added dynamically during the pre-analysis. + srcmpag + .getExceptionEdges() + .forEach( + (k, vs) -> { + for (Node v : vs) { + this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); } - } + }); + // add para edges + int numParms = method.getParameterCount(); + LocalVarNode[] parms = new LocalVarNode[numParms]; + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof ReferenceType) { + parms[i] = (LocalVarNode) srcnf.caseParm(i); } - Map ret = new HashMap<>(); - getSparkNodes().forEach(sparkNode -> { - BNode node = getBNode(sparkNode, true); - BNode nodeInv = getBNode(sparkNode, false); - ret.put(sparkNode, node.cs && nodeInv.cs ? 1 : 0); - }); - return ret; - } - - protected void addBalancedEdge(BNode from, BNode to, Queue workList) { - if (addBalancedEdge(from, to)) { - if (from.cs) { - workList.add(from);// add src of the balanced edges to worklist - } + } + LocalVarNode mret = + method.getReturnType() instanceof ReferenceType ? (LocalVarNode) srcnf.caseRet() : null; + LocalVarNode throwFinal = + prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); + if (method.isStatic()) { + pts.getOrDefault(thisRef, Collections.emptySet()) + .forEach( + a -> { + addParamEdges(a, thisRef, parms, mret, throwFinal); + }); + } else { + PointsToSet thisPts = prePTA.reachingObjects(thisRef).toCIPointsToSet(); + for (Iterator it = thisPts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + addParamEdges(n, thisRef, parms, mret, throwFinal); } - } - - ////////////////////////////////////////////////////////////////////////////////////////// - - protected void addParamEdges(AllocNode o, LocalVarNode thisRef, LocalVarNode[] parms, LocalVarNode mret, LocalVarNode mThrow) { - this.addHloadEdge(o, thisRef); - for (VarNode parm : parms) { - if (parm != null) { - this.addHloadEdge(o, parm); - } + } + + // add invoke edges + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; + args[i] = arg; } - if (mret != null) { - this.addHstoreEdge(mret, o); + LocalVarNode retDest = null; + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + retDest = prePAG.findLocalVarNode(dest); + } } - if (mThrow != null) { - this.addHstoreEdge(mThrow, o); + LocalVarNode receiver; + if (ie instanceof AbstractInstanceInvokeExpr iie) { + receiver = prePAG.findLocalVarNode(iie.getBase()); + } else { + // static call + receiver = thisRef; } - } - - public void buildGraph(PTA prePTA) { - PAG prePAG = prePTA.getPag(); - // calculate points-to set for "This" pointer in each static method. - Map> pts = PTAUtils.calcStaticThisPTS(prePTA); - - CallGraph callGraph = prePTA.getCallGraph(); - for (SootMethod method : prePTA.getNakedReachableMethods()) { - if (!method.isConcrete()) { - continue; - } - MethodPAG srcmpag = prePAG.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - // add local edges - if (PTAUtils.isFakeMainMethod(method)) { - // special treatment for fake main - this.addNewEdge(prePTA.getRootNode(), thisRef); - } - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof LocalVarNode) - this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); - else if (to instanceof FieldRefNode fr) { - this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); - } // local-global - - } else if (from instanceof AllocNode) { - if (to instanceof LocalVarNode) { - this.addNewEdge((AllocNode) from, (LocalVarNode) to); - } // GlobalVarNode - } else if (from instanceof FieldRefNode fr) { - this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); - } // global-local - } - // add exception edges that added dynamically during the pre-analysis. - srcmpag.getExceptionEdges().forEach((k, vs) -> { - for (Node v : vs) { - this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); - } - }); - // add para edges - int numParms = method.getParameterCount(); - LocalVarNode[] parms = new LocalVarNode[numParms]; - for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { - parms[i] = (LocalVarNode) srcnf.caseParm(i); - } - } - LocalVarNode mret = method.getReturnType() instanceof ReferenceType ? (LocalVarNode) srcnf.caseRet() : null; - LocalVarNode throwFinal = prePAG.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); - if (method.isStatic()) { - pts.getOrDefault(thisRef, Collections.emptySet()).forEach(a -> { - addParamEdges(a, thisRef, parms, mret, throwFinal); - }); - } else { - PointsToSet thisPts = prePTA.reachingObjects(thisRef).toCIPointsToSet(); - for (Iterator it = thisPts.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - addParamEdges(n, thisRef, parms, mret, throwFinal); - } - } - - // add invoke edges - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - Value[] args = new Value[numArgs]; - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) - continue; - args[i] = arg; - } - LocalVarNode retDest = null; - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - retDest = prePAG.findLocalVarNode(dest); - } - } - LocalVarNode receiver; - if (ie instanceof AbstractInstanceInvokeExpr iie) { - receiver = prePAG.findLocalVarNode(iie.getBase()); - } else { - // static call - receiver = thisRef; - } - for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { - Edge e = it.next(); - SootMethod tgtmtd = e.tgt(); - for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) - continue; - ValNode argNode = prePAG.findValNode(args[i]); - if (argNode instanceof LocalVarNode) { - this.addStoreEdge((LocalVarNode) argNode, receiver); - } - } - if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { - this.addLoadEdge(receiver, retDest); - } - LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); - this.addLoadEdge(receiver, stmtThrowNode); - this.addStoreEdge(receiver, receiver);// do not move this out of loop - } + for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + for (int i = 0; i < numArgs; i++) { + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) continue; + ValNode argNode = prePAG.findValNode(args[i]); + if (argNode instanceof LocalVarNode) { + this.addStoreEdge((LocalVarNode) argNode, receiver); } + } + if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { + this.addLoadEdge(receiver, retDest); + } + LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); + this.addLoadEdge(receiver, stmtThrowNode); + this.addStoreEdge(receiver, receiver); // do not move this out of loop } + } + } - // add field edges - prePAG.getContextFields().forEach(contextField -> { - AllocNode base = contextField.getBase(); - SparkField field = contextField.getField(); - if (!prePAG.simpleInvLookup(contextField).isEmpty()) { + // add field edges + prePAG + .getContextFields() + .forEach( + contextField -> { + AllocNode base = contextField.getBase(); + SparkField field = contextField.getField(); + if (!prePAG.simpleInvLookup(contextField).isEmpty()) { this.addHloadEdge(base, field); - } - if (!prePAG.simpleLookup(contextField).isEmpty()) { + } + if (!prePAG.simpleLookup(contextField).isEmpty()) { this.addHstoreEdge(field, base); - } - }); - } + } + }); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java index 35e4830c93d..402e6ec22ba 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/HeapAbstraction.java @@ -1,136 +1,136 @@ package qilin.pta.toolkits.mahjong; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import qilin.core.pag.AllocNode; import qilin.core.pag.Node; +import qilin.pta.toolkits.common.FieldPointstoGraph; import qilin.pta.toolkits.mahjong.automata.DFA; import qilin.pta.toolkits.mahjong.automata.DFAEquivalenceChecker; import qilin.pta.toolkits.mahjong.automata.DFAFactory; import qilin.pta.toolkits.mahjong.automata.DFAState; -import qilin.pta.toolkits.common.FieldPointstoGraph; import qilin.util.UnionFindSet; import sootup.core.types.Type; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - /** * @author Tian Tan - * @author Yue Li - * refactered by Dongjie He. + * @author Yue Li refactered by Dongjie He. */ public class HeapAbstraction { - private final FieldPointstoGraph fpg; - private final DFAFactory dfaFactory; - private final DFAEquivalenceChecker dfaEqChecker; + private final FieldPointstoGraph fpg; + private final DFAFactory dfaFactory; + private final DFAEquivalenceChecker dfaEqChecker; - /** - * This map would be manipulated by multiple threads - * thus it should be concurrent hashmap. - */ - private Map canMerged; + /** This map would be manipulated by multiple threads thus it should be concurrent hashmap. */ + private Map canMerged; - public HeapAbstraction(FieldPointstoGraph fpg) { - this.fpg = fpg; - this.dfaFactory = new DFAFactory(fpg); - this.dfaEqChecker = new DFAEquivalenceChecker(); - } + public HeapAbstraction(FieldPointstoGraph fpg) { + this.fpg = fpg; + this.dfaFactory = new DFAFactory(fpg); + this.dfaEqChecker = new DFAEquivalenceChecker(); + } - public Map computeMergedObjectMap() { - UnionFindSet uf = modelHeap(); - return convertToMap(uf.getDisjointSets()); - } + public Map computeMergedObjectMap() { + UnionFindSet uf = modelHeap(); + return convertToMap(uf.getDisjointSets()); + } - /** - * Modeling the heap by checking the equivalence of automata. - */ - private UnionFindSet modelHeap() { - canMerged = new ConcurrentHashMap<>(); - Set allObjs = fpg.getAllObjs(); - UnionFindSet uf = new UnionFindSet<>(allObjs); - // group the objects by their types - Map> groupedObjs = allObjs.stream() - .collect(Collectors.groupingBy(Node::getType, Collectors.toSet())); - groupedObjs.entrySet().parallelStream().forEach(entry -> { - DFAMap dfaMap = new DFAMap(); - Set objs = entry.getValue().stream().filter(o -> canBeMerged(o, dfaMap)).collect(Collectors.toSet()); - for (AllocNode o1 : objs) { + /** Modeling the heap by checking the equivalence of automata. */ + private UnionFindSet modelHeap() { + canMerged = new ConcurrentHashMap<>(); + Set allObjs = fpg.getAllObjs(); + UnionFindSet uf = new UnionFindSet<>(allObjs); + // group the objects by their types + Map> groupedObjs = + allObjs.stream().collect(Collectors.groupingBy(Node::getType, Collectors.toSet())); + groupedObjs + .entrySet() + .parallelStream() + .forEach( + entry -> { + DFAMap dfaMap = new DFAMap(); + Set objs = + entry.getValue().stream() + .filter(o -> canBeMerged(o, dfaMap)) + .collect(Collectors.toSet()); + for (AllocNode o1 : objs) { for (AllocNode o2 : objs) { - if (o1.getNumber() <= o2.getNumber() && !uf.isConnected(o1, o2)) { - if (canBeMerged(o1, o2, dfaMap)) { - uf.union(o1, o2); - } + if (o1.getNumber() <= o2.getNumber() && !uf.isConnected(o1, o2)) { + if (canBeMerged(o1, o2, dfaMap)) { + uf.union(o1, o2); } + } } - } - }); - return uf; - } + } + }); + return uf; + } - /** - * @param o1 - * @param o2 - * @return whether o1 and o2 can be merged. - */ - private boolean canBeMerged(AllocNode o1, AllocNode o2, DFAMap dfaMap) { - if (o1 == o2) { - return true; - } - DFA dfa1 = dfaMap.retrieveDFA(o1); - DFA dfa2 = dfaMap.retrieveDFA(o2); - return dfaEqChecker.isEquivalent(dfa1, dfa2); + /** + * @param o1 + * @param o2 + * @return whether o1 and o2 can be merged. + */ + private boolean canBeMerged(AllocNode o1, AllocNode o2, DFAMap dfaMap) { + if (o1 == o2) { + return true; } + DFA dfa1 = dfaMap.retrieveDFA(o1); + DFA dfa2 = dfaMap.retrieveDFA(o2); + return dfaEqChecker.isEquivalent(dfa1, dfa2); + } - /** - * @param o - * @return whether o can be merged with other objects. - */ - private boolean canBeMerged(AllocNode o, DFAMap dfaMap) { - if (!canMerged.containsKey(o)) { - boolean result = true; - // Check whether the types of objects pointed (directly/indirectly) - // by o are unique. - DFA dfa = dfaMap.retrieveDFA(o); - for (DFAState s : dfa.getStates()) { - if (dfa.outputOf(s).size() > 1) { - // Types pointed (directly/indirectly) by o are not unique. - result = false; - break; - } - } - canMerged.put(o, result); + /** + * @param o + * @return whether o can be merged with other objects. + */ + private boolean canBeMerged(AllocNode o, DFAMap dfaMap) { + if (!canMerged.containsKey(o)) { + boolean result = true; + // Check whether the types of objects pointed (directly/indirectly) + // by o are unique. + DFA dfa = dfaMap.retrieveDFA(o); + for (DFAState s : dfa.getStates()) { + if (dfa.outputOf(s).size() > 1) { + // Types pointed (directly/indirectly) by o are not unique. + result = false; + break; } - return canMerged.get(o); + } + canMerged.put(o, result); } + return canMerged.get(o); + } - private static Map convertToMap(Collection> objModel) { - Map map = new HashMap<>(); - objModel.forEach(objs -> { - AllocNode rep = selectRepresentative(objs); - objs.forEach(obj -> map.put(obj, rep)); + private static Map convertToMap(Collection> objModel) { + Map map = new HashMap<>(); + objModel.forEach( + objs -> { + AllocNode rep = selectRepresentative(objs); + objs.forEach(obj -> map.put(obj, rep)); }); - return map; - } + return map; + } - private static AllocNode selectRepresentative(Set objs) { - return objs.stream().findFirst().get(); - } + private static AllocNode selectRepresentative(Set objs) { + return objs.stream().findFirst().get(); + } - /** - * During equivalence check, each thread holds a DFAMap which contains - * the DFA of the objects of the type. After comparison, the DFAMap - * and its containing DFA will be released to save memory space. - */ - private class DFAMap { - private final Map dfaMap = new HashMap<>(); + /** + * During equivalence check, each thread holds a DFAMap which contains the DFA of the objects of + * the type. After comparison, the DFAMap and its containing DFA will be released to save memory + * space. + */ + private class DFAMap { + private final Map dfaMap = new HashMap<>(); - private DFA retrieveDFA(AllocNode o) { - return dfaMap.computeIfAbsent(o, k -> dfaFactory.getDFA(o)); - } + private DFA retrieveDFA(AllocNode o) { + return dfaMap.computeIfAbsent(o, k -> dfaFactory.getDFA(o)); } - + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java index 4e1eedbf247..e86901e57e4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/Mahjong.java @@ -1,68 +1,74 @@ package qilin.pta.toolkits.mahjong; +import java.util.Collection; +import java.util.Map; import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.pta.toolkits.common.FieldPointstoGraph; import qilin.util.Stopwatch; -import java.util.Collection; -import java.util.Map; - /** * @author Tian Tan * @author Yue Li */ public class Mahjong { - public static void run(PTA pta, Map heapModelMap) { - FieldPointstoGraph fpg = buildFPG(pta); - System.out.print("Creating heap abstraction ... "); - Stopwatch mahjongTimer = Stopwatch.newAndStart("Mahjong"); - HeapAbstraction heapAbs = new HeapAbstraction(fpg); - Map mom = heapAbs.computeMergedObjectMap(); - mahjongTimer.stop(); - System.out.println(mahjongTimer); - outputStatistics(fpg, mom); + public static void run(PTA pta, Map heapModelMap) { + FieldPointstoGraph fpg = buildFPG(pta); + System.out.print("Creating heap abstraction ... "); + Stopwatch mahjongTimer = Stopwatch.newAndStart("Mahjong"); + HeapAbstraction heapAbs = new HeapAbstraction(fpg); + Map mom = heapAbs.computeMergedObjectMap(); + mahjongTimer.stop(); + System.out.println(mahjongTimer); + outputStatistics(fpg, mom); - System.out.print("Writing Mahjong heap abstraction ...\n"); - writeMergedObjectMap(mom, heapModelMap); - } + System.out.print("Writing Mahjong heap abstraction ...\n"); + writeMergedObjectMap(mom, heapModelMap); + } - public static FieldPointstoGraph buildFPG(PTA pta) { - System.out.print("Building FPG (Field Points-to Graph) ... "); - Stopwatch fpgTimer = Stopwatch.newAndStart("FPG Construction"); - FieldPointstoGraph fpg = new FieldPointstoGraph(pta); - fpgTimer.stop(); - System.out.println(fpgTimer); - return fpg; - } + public static FieldPointstoGraph buildFPG(PTA pta) { + System.out.print("Building FPG (Field Points-to Graph) ... "); + Stopwatch fpgTimer = Stopwatch.newAndStart("FPG Construction"); + FieldPointstoGraph fpg = new FieldPointstoGraph(pta); + fpgTimer.stop(); + System.out.println(fpgTimer); + return fpg; + } - public static void outputStatistics(FieldPointstoGraph fpg, Map mom) { - int nObj = (int) mom.keySet().stream().distinct().count(); - int nObjMahjong = (int) mom.values().stream().distinct().count(); - System.out.println("-----------------------------------------------------------"); - System.out.printf("%d objects in the allocation-site heap abstraction.\n", nObj); - System.out.printf("%d objects in the Mahjong heap abstraction.\n", nObjMahjong); - System.out.println("-----------------------------------------------------------"); + public static void outputStatistics(FieldPointstoGraph fpg, Map mom) { + int nObj = (int) mom.keySet().stream().distinct().count(); + int nObjMahjong = (int) mom.values().stream().distinct().count(); + System.out.println("-----------------------------------------------------------"); + System.out.printf("%d objects in the allocation-site heap abstraction.\n", nObj); + System.out.printf("%d objects in the Mahjong heap abstraction.\n", nObjMahjong); + System.out.println("-----------------------------------------------------------"); - int nType = (int) fpg.getAllObjs().stream().map(AllocNode::getType).distinct().count(); - int nField = (int) fpg.getAllObjs().stream().map(fpg::outFieldsOf).flatMap(Collection::stream).distinct().count(); - int nObj2 = fpg.getAllObjs().size(); - // int nObjMahjong = model.size(); + int nType = (int) fpg.getAllObjs().stream().map(AllocNode::getType).distinct().count(); + int nField = + (int) + fpg.getAllObjs().stream() + .map(fpg::outFieldsOf) + .flatMap(Collection::stream) + .distinct() + .count(); + int nObj2 = fpg.getAllObjs().size(); + // int nObjMahjong = model.size(); - System.out.println("-----------------------------------------------------------"); - System.out.println("In the FPG (allocation-site heap abstraction), there are:"); - System.out.printf("%10d types\n", nType); - System.out.printf("%10d fields\n", nField); - System.out.printf("%10d objects\n", nObj2); - System.out.println("In the Mahjong heap abstraction, there are:"); - System.out.printf("%10d objects\n", nObjMahjong); - System.out.println("-----------------------------------------------------------"); - } + System.out.println("-----------------------------------------------------------"); + System.out.println("In the FPG (allocation-site heap abstraction), there are:"); + System.out.printf("%10d types\n", nType); + System.out.printf("%10d fields\n", nField); + System.out.printf("%10d objects\n", nObj2); + System.out.println("In the Mahjong heap abstraction, there are:"); + System.out.printf("%10d objects\n", nObjMahjong); + System.out.println("-----------------------------------------------------------"); + } - private static void writeMergedObjectMap(Map mom, Map heapModelMap) { - mom.forEach((heap, mergedHeap) -> { - heapModelMap.put(heap.getNewExpr(), mergedHeap.getNewExpr()); + private static void writeMergedObjectMap( + Map mom, Map heapModelMap) { + mom.forEach( + (heap, mergedHeap) -> { + heapModelMap.put(heap.getNewExpr(), mergedHeap.getNewExpr()); }); - } - + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java index a62de6109c7..2e1076fd55d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFA.java @@ -1,74 +1,67 @@ package qilin.pta.toolkits.mahjong.automata; -import sootup.core.types.Type; - import java.util.HashSet; import java.util.LinkedList; import java.util.Queue; import java.util.Set; +import sootup.core.types.Type; /** * @author Tian Tan * @author Yue Li - *

- * refactered by Dongjie He. + *

refactered by Dongjie He. */ public class DFA { - private Set states, allStates; - private final DFAState q0; - - static final DFAState deadState = new DFAState(); + private Set states, allStates; + private final DFAState q0; - public DFA(DFAState q0) { - this.q0 = q0; - } + static final DFAState deadState = new DFAState(); - /** - * @return Set of states. Does not contains dead state. - */ - public Set getStates() { - if (states == null) { - computeStates(); - } - return states; - } + public DFA(DFAState q0) { + this.q0 = q0; + } - /** - * @return Set of all states including dead state. - */ - public Set getAllStates() { - if (allStates == null) { - computeStates(); - } - return allStates; + /** @return Set of states. Does not contains dead state. */ + public Set getStates() { + if (states == null) { + computeStates(); } + return states; + } - private void computeStates() { - Queue queue = new LinkedList<>(); - queue.add(q0); - states = new HashSet<>(); - while (!queue.isEmpty()) { - DFAState s = queue.poll(); - if (!states.contains(s)) { - states.add(s); - queue.addAll(s.getNextMap().values()); - } - } - allStates = new HashSet<>(states); - allStates.add(deadState); + /** @return Set of all states including dead state. */ + public Set getAllStates() { + if (allStates == null) { + computeStates(); } + return allStates; + } - public DFAState getStartState() { - return q0; + private void computeStates() { + Queue queue = new LinkedList<>(); + queue.add(q0); + states = new HashSet<>(); + while (!queue.isEmpty()) { + DFAState s = queue.poll(); + if (!states.contains(s)) { + states.add(s); + queue.addAll(s.getNextMap().values()); + } } + allStates = new HashSet<>(states); + allStates.add(deadState); + } - public static DFAState getDeadState() { - return deadState; - } + public DFAState getStartState() { + return q0; + } - public Set outputOf(DFAState s) { - return s.getOutput(); - } + public static DFAState getDeadState() { + return deadState; + } + public Set outputOf(DFAState s) { + return s.getOutput(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java index e038c8605fa..bc7861327c4 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAEquivalenceChecker.java @@ -1,15 +1,14 @@ package qilin.pta.toolkits.mahjong.automata; -import qilin.core.pag.SparkField; -import qilin.util.Pair; -import qilin.util.UnionFindSet; -import sootup.core.types.Type; - import java.util.Collection; import java.util.Set; import java.util.Stack; import java.util.stream.Collectors; import java.util.stream.Stream; +import qilin.core.pag.SparkField; +import qilin.util.Pair; +import qilin.util.UnionFindSet; +import sootup.core.types.Type; /** * @author Tian Tan @@ -17,89 +16,78 @@ */ public class DFAEquivalenceChecker { - /** - * Check the equivalence of input automata by Hopcroft-Karp algorithm - * with minor modifications. - * - * @param dfa1 - * @param dfa2 - * @return whether dfa1 and dfa2 are equivalent - */ - public boolean isEquivalent(DFA dfa1, DFA dfa2) { - CombinedDFA dfa = new CombinedDFA(dfa1, dfa2); - Set combinedStates = dfa.getStates(); - UnionFindSet uf = new UnionFindSet<>(combinedStates); - Stack> stack = new Stack<>(); - - DFAState s1 = dfa1.getStartState(); - DFAState s2 = dfa2.getStartState(); - uf.union(s1, s2); - stack.push(new Pair<>(s1, s2)); - while (!stack.isEmpty()) { - Pair pair = stack.pop(); - DFAState q1 = pair.getFirst(); - DFAState q2 = pair.getSecond(); - Stream.concat(dfa.outEdgesOf(q1).stream(), dfa.outEdgesOf(q2).stream()).forEach(field -> { + /** + * Check the equivalence of input automata by Hopcroft-Karp algorithm with minor modifications. + * + * @param dfa1 + * @param dfa2 + * @return whether dfa1 and dfa2 are equivalent + */ + public boolean isEquivalent(DFA dfa1, DFA dfa2) { + CombinedDFA dfa = new CombinedDFA(dfa1, dfa2); + Set combinedStates = dfa.getStates(); + UnionFindSet uf = new UnionFindSet<>(combinedStates); + Stack> stack = new Stack<>(); + + DFAState s1 = dfa1.getStartState(); + DFAState s2 = dfa2.getStartState(); + uf.union(s1, s2); + stack.push(new Pair<>(s1, s2)); + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + DFAState q1 = pair.getFirst(); + DFAState q2 = pair.getSecond(); + Stream.concat(dfa.outEdgesOf(q1).stream(), dfa.outEdgesOf(q2).stream()) + .forEach( + field -> { DFAState r1 = uf.find(q1.nextState(field)); DFAState r2 = uf.find(q2.nextState(field)); if (r1 != r2) { - uf.union(r1, r2); - stack.push(new Pair<>(r1, r2)); + uf.union(r1, r2); + stack.push(new Pair<>(r1, r2)); } - }); - } - Collection> mergedStateSets = uf.getDisjointSets(); - return validate(dfa, mergedStateSets); + }); } - - - /** - * @param dfa - * @param mergedStateSets - * @return true if every state set contains no different output - * (i.e., types) - */ - private boolean validate(CombinedDFA dfa, Collection> mergedStateSets) { - for (Set set : mergedStateSets) { - int minSize = set.stream() - .mapToInt(s -> dfa.outputOf(s).size()) - .min() - .getAsInt(); - long unionSize = set.stream() - .flatMap(s -> dfa.outputOf(s).stream()) - .distinct() - .count(); - if (unionSize > minSize) { - return false; - } - } - return true; + Collection> mergedStateSets = uf.getDisjointSets(); + return validate(dfa, mergedStateSets); + } + + /** + * @param dfa + * @param mergedStateSets + * @return true if every state set contains no different output (i.e., types) + */ + private boolean validate(CombinedDFA dfa, Collection> mergedStateSets) { + for (Set set : mergedStateSets) { + int minSize = set.stream().mapToInt(s -> dfa.outputOf(s).size()).min().getAsInt(); + long unionSize = set.stream().flatMap(s -> dfa.outputOf(s).stream()).distinct().count(); + if (unionSize > minSize) { + return false; + } } + return true; + } + private static class CombinedDFA { - private static class CombinedDFA { - - DFA dfa1, dfa2; - - private CombinedDFA(DFA dfa1, DFA dfa2) { - this.dfa1 = dfa1; - this.dfa2 = dfa2; - } + DFA dfa1, dfa2; - private Set getStates() { - return Stream - .concat(dfa1.getAllStates().stream(), dfa2.getAllStates().stream()) - .collect(Collectors.toSet()); - } - - private Set outEdgesOf(DFAState s) { - return s.outEdges(); - } + private CombinedDFA(DFA dfa1, DFA dfa2) { + this.dfa1 = dfa1; + this.dfa2 = dfa2; + } - private Set outputOf(DFAState s) { - return s.getOutput(); - } + private Set getStates() { + return Stream.concat(dfa1.getAllStates().stream(), dfa2.getAllStates().stream()) + .collect(Collectors.toSet()); + } + private Set outEdgesOf(DFAState s) { + return s.outEdges(); } + private Set outputOf(DFAState s) { + return s.getOutput(); + } + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java index 69ec2ad74fd..e419a21c769 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAFactory.java @@ -1,102 +1,98 @@ package qilin.pta.toolkits.mahjong.automata; +import java.util.*; +import java.util.stream.Collectors; import qilin.core.pag.AllocNode; import qilin.core.pag.SparkField; import qilin.pta.toolkits.common.FieldPointstoGraph; import sootup.core.types.Type; -import java.util.*; -import java.util.stream.Collectors; - /** * @author Tian Tan * @author Yue Li */ public class DFAFactory { - private final FieldPointstoGraph fpg; + private final FieldPointstoGraph fpg; - private Map, DFAState> stateMap; - private Set states, visited; + private Map, DFAState> stateMap; + private Set states, visited; - public DFAFactory(FieldPointstoGraph fpg) { - this.fpg = fpg; - buildAllDFA(); - } + public DFAFactory(FieldPointstoGraph fpg) { + this.fpg = fpg; + buildAllDFA(); + } - public DFA getDFA(AllocNode obj) { - DFAState q0 = stateMap.get(Collections.singleton(obj)); - return new DFA(q0); - } + public DFA getDFA(AllocNode obj) { + DFAState q0 = stateMap.get(Collections.singleton(obj)); + return new DFA(q0); + } - private void buildAllDFA() { - stateMap = new HashMap<>(); - states = new HashSet<>(); - visited = new HashSet<>(); - fpg.getAllObjs().forEach(this::buildDFA); - } + private void buildAllDFA() { + stateMap = new HashMap<>(); + states = new HashSet<>(); + visited = new HashSet<>(); + fpg.getAllObjs().forEach(this::buildDFA); + } - /** - * Perform subset construction algorithm to convert an NFA - * to a DFA. If a set of NFA states are merged to an existing - * DFA state, then reused the existing DFA state instead of creating - * an equivalent new one. - * - * @param obj the start state (object) of the DFA - */ - private void buildDFA(AllocNode obj) { - Set q0Set = Collections.singleton(obj); - if (!stateMap.containsKey(q0Set)) { - NFA nfa = new NFA(obj, fpg); - DFAState startState = getDFAState(q0Set, nfa); - Queue worklist = new LinkedList<>(); - states.add(startState); - worklist.add(startState); - while (!worklist.isEmpty()) { - DFAState s = worklist.poll(); - if (!visited.contains(s)) { - visited.add(s); - Set fields = fields(nfa, s.getObjects()); - fields.forEach(f -> { - Set nextNFAStates = move(nfa, s.getObjects(), f); - DFAState nextState = getDFAState(nextNFAStates, nfa); - if (!states.contains(nextState)) { - states.add(nextState); - worklist.add(nextState); - } - addTransition(s, f, nextState); - }); + /** + * Perform subset construction algorithm to convert an NFA to a DFA. If a set of NFA states are + * merged to an existing DFA state, then reused the existing DFA state instead of creating an + * equivalent new one. + * + * @param obj the start state (object) of the DFA + */ + private void buildDFA(AllocNode obj) { + Set q0Set = Collections.singleton(obj); + if (!stateMap.containsKey(q0Set)) { + NFA nfa = new NFA(obj, fpg); + DFAState startState = getDFAState(q0Set, nfa); + Queue worklist = new LinkedList<>(); + states.add(startState); + worklist.add(startState); + while (!worklist.isEmpty()) { + DFAState s = worklist.poll(); + if (!visited.contains(s)) { + visited.add(s); + Set fields = fields(nfa, s.getObjects()); + fields.forEach( + f -> { + Set nextNFAStates = move(nfa, s.getObjects(), f); + DFAState nextState = getDFAState(nextNFAStates, nfa); + if (!states.contains(nextState)) { + states.add(nextState); + worklist.add(nextState); } - } - } - } - - private DFAState getDFAState(Set objs, NFA nfa) { - if (!stateMap.containsKey(objs)) { - Set output = objs.stream() - .map(nfa::outputOf) - .collect(Collectors.toSet()); - stateMap.put(objs, new DFAState(objs, output)); + addTransition(s, f, nextState); + }); } - return stateMap.get(objs); + } } + } - private Set move(NFA nfa, Set objs, SparkField f) { - return objs.stream() - .map(obj -> nfa.nextStates(obj, f)) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); + private DFAState getDFAState(Set objs, NFA nfa) { + if (!stateMap.containsKey(objs)) { + Set output = objs.stream().map(nfa::outputOf).collect(Collectors.toSet()); + stateMap.put(objs, new DFAState(objs, output)); } + return stateMap.get(objs); + } - private Set fields(NFA nfa, Set objs) { - return objs.stream() - .map(nfa::outEdgesOf) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); - } + private Set move(NFA nfa, Set objs, SparkField f) { + return objs.stream() + .map(obj -> nfa.nextStates(obj, f)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } - private void addTransition(DFAState s, SparkField f, DFAState nextState) { - s.addTransition(f, nextState); - } + private Set fields(NFA nfa, Set objs) { + return objs.stream() + .map(nfa::outEdgesOf) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } + private void addTransition(DFAState s, SparkField f, DFAState nextState) { + s.addTransition(f, nextState); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java index 02e70604a48..0456622a337 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/DFAState.java @@ -1,91 +1,87 @@ package qilin.pta.toolkits.mahjong.automata; +import java.util.*; +import java.util.stream.Collectors; import qilin.core.pag.AllocNode; import qilin.core.pag.SparkField; import sootup.core.types.Type; -import java.util.*; -import java.util.stream.Collectors; - /** * @author Tian Tan * @author Yue Li */ public class DFAState { - private final Set objs; - private final Set output; - private final Map nextMap; - - private boolean hasHashCode = false; - private int hashCode; - - public DFAState() { - this.objs = Collections.emptySet(); - this.output = Collections.emptySet(); - this.nextMap = new HashMap<>(); + private final Set objs; + private final Set output; + private final Map nextMap; + + private boolean hasHashCode = false; + private int hashCode; + + public DFAState() { + this.objs = Collections.emptySet(); + this.output = Collections.emptySet(); + this.nextMap = new HashMap<>(); + } + + public DFAState(Set objs, Set output) { + this.objs = objs; + this.output = output; + this.nextMap = new HashMap<>(); + } + + public Set getObjects() { + return objs; + } + + public Set getOutput() { + return output; + } + + void addTransition(SparkField f, DFAState nextState) { + nextMap.put(f, nextState); + } + + Map getNextMap() { + return nextMap; + } + + DFAState nextState(SparkField f) { + return nextMap.getOrDefault(f, DFA.getDeadState()); + } + + Set outEdges() { + return nextMap.keySet(); + } + + /** Cache hash code. */ + @Override + public int hashCode() { + if (!hasHashCode) { + hashCode = objs.hashCode(); + hasHashCode = true; } + return hashCode; + } - public DFAState(Set objs, Set output) { - this.objs = objs; - this.output = output; - this.nextMap = new HashMap<>(); + @Override + public boolean equals(Object other) { + if (this == other) { + return true; } - - public Set getObjects() { - return objs; - } - - public Set getOutput() { - return output; + if (!(other instanceof DFAState anoDFAState)) { + return false; } - - void addTransition(SparkField f, DFAState nextState) { - nextMap.put(f, nextState); - } - - Map getNextMap() { - return nextMap; - } - - DFAState nextState(SparkField f) { - return nextMap.getOrDefault(f, DFA.getDeadState()); - } - - Set outEdges() { - return nextMap.keySet(); - } - - /** - * Cache hash code. - */ - @Override - public int hashCode() { - if (!hasHashCode) { - hashCode = objs.hashCode(); - hasHashCode = true; - } - return hashCode; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof DFAState anoDFAState)) { - return false; - } - return getObjects().equals(anoDFAState.getObjects()); - } - - @Override - public String toString() { - return getObjects().stream() - .map(obj -> obj == null ? "null" : String.valueOf(obj.getNumber())) - .sorted() - .collect(Collectors.toCollection(LinkedHashSet::new)) - .toString(); - } - + return getObjects().equals(anoDFAState.getObjects()); + } + + @Override + public String toString() { + return getObjects().stream() + .map(obj -> obj == null ? "null" : String.valueOf(obj.getNumber())) + .sorted() + .collect(Collectors.toCollection(LinkedHashSet::new)) + .toString(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java index 067208c53a9..ce95a8adf7c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/mahjong/automata/NFA.java @@ -1,14 +1,13 @@ package qilin.pta.toolkits.mahjong.automata; -import qilin.core.pag.AllocNode; -import qilin.core.pag.SparkField; -import qilin.pta.toolkits.common.FieldPointstoGraph; -import sootup.core.types.Type; - import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.Stack; +import qilin.core.pag.AllocNode; +import qilin.core.pag.SparkField; +import qilin.pta.toolkits.common.FieldPointstoGraph; +import sootup.core.types.Type; /** * @author Tian Tan @@ -16,73 +15,74 @@ */ public class NFA { - private static final AllocNode deadState = null; + private static final AllocNode deadState = null; - private final AllocNode q0; - private final FieldPointstoGraph fpg; + private final AllocNode q0; + private final FieldPointstoGraph fpg; - public NFA(AllocNode q0, FieldPointstoGraph fpg) { - this.q0 = q0; - this.fpg = fpg; - } + public NFA(AllocNode q0, FieldPointstoGraph fpg) { + this.q0 = q0; + this.fpg = fpg; + } - /** - * This method on-the-fly computes set of states. - * - * @return Set of states. Does not contains dead state. - */ - public Set getStates() { - Set states = new HashSet<>(); - Stack stack = new Stack<>(); - stack.push(q0); - while (!stack.isEmpty()) { - AllocNode s = stack.pop(); - if (!states.contains(s)) { - states.add(s); - outEdgesOf(s).forEach(field -> { - nextStates(s, field).stream() - .filter(obj -> !states.contains(obj)) - .forEach(stack::push); + /** + * This method on-the-fly computes set of states. + * + * @return Set of states. Does not contains dead state. + */ + public Set getStates() { + Set states = new HashSet<>(); + Stack stack = new Stack<>(); + stack.push(q0); + while (!stack.isEmpty()) { + AllocNode s = stack.pop(); + if (!states.contains(s)) { + states.add(s); + outEdgesOf(s) + .forEach( + field -> { + nextStates(s, field).stream() + .filter(obj -> !states.contains(obj)) + .forEach(stack::push); }); - } - } - return states; + } } + return states; + } - public AllocNode getStartState() { - return q0; - } + public AllocNode getStartState() { + return q0; + } - public AllocNode getDeadState() { - return deadState; - } + public AllocNode getDeadState() { + return deadState; + } - public Set nextStates(AllocNode obj, SparkField f) { - if (isDeadState(obj) || !fpg.hasFieldPointer(obj, f)) { - return Collections.singleton(deadState); - } else { - return fpg.pointsTo(obj, f); - } + public Set nextStates(AllocNode obj, SparkField f) { + if (isDeadState(obj) || !fpg.hasFieldPointer(obj, f)) { + return Collections.singleton(deadState); + } else { + return fpg.pointsTo(obj, f); } + } - public boolean isDeadState(AllocNode obj) { - return obj == deadState; - } + public boolean isDeadState(AllocNode obj) { + return obj == deadState; + } - public Set outEdgesOf(AllocNode obj) { - if (isDeadState(obj)) { - return Collections.emptySet(); - } else { - return fpg.outFieldsOf(obj); - } + public Set outEdgesOf(AllocNode obj) { + if (isDeadState(obj)) { + return Collections.emptySet(); + } else { + return fpg.outFieldsOf(obj); } + } - public Type outputOf(AllocNode obj) { - if (isDeadState(obj)) { - return null; - } else { - return obj.getType(); - } + public Type outputOf(AllocNode obj) { + if (isDeadState(obj)) { + return null; + } else { + return obj.getType(); } - + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java index 11a34a16313..2cf66d80bbb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/BNode.java @@ -18,43 +18,41 @@ package qilin.pta.toolkits.selectx; -import qilin.core.pag.Node; - -import java.util.Set; import java.util.stream.Stream; +import qilin.core.pag.Node; public abstract class BNode { - public Node sparkNode; - /** - * visited is not overrided by para: this represents value flows in *any* contexts, - * this can avoid unmatched exit without missing exit from inner alloc or global - */ - private boolean visited = false; - - BNode(Node origin) { - this.sparkNode = origin; - } - - public void reset() { - visited = false; - } - - public boolean isVisited() { - return this.visited; - } - - public boolean setVisited() { - if (visited) - return false; - return visited = true; - } - - public abstract boolean addOutEdge(BNode to); - - public abstract Stream forwardTargets(); - - @Override - public String toString() { - return this.getClass().toString() + " : " + sparkNode.toString(); - } + public Node sparkNode; + + /** + * visited is not overrided by para: this represents value flows in *any* contexts, this can avoid + * unmatched exit without missing exit from inner alloc or global + */ + private boolean visited = false; + + BNode(Node origin) { + this.sparkNode = origin; + } + + public void reset() { + visited = false; + } + + public boolean isVisited() { + return this.visited; + } + + public boolean setVisited() { + if (visited) return false; + return visited = true; + } + + public abstract boolean addOutEdge(BNode to); + + public abstract Stream forwardTargets(); + + @Override + public String toString() { + return this.getClass().toString() + " : " + sparkNode.toString(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java index 69e13466309..f54be2fc501 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/G.java @@ -20,40 +20,39 @@ import java.util.*; import java.util.stream.Stream; - import qilin.core.pag.GlobalVarNode; public class G extends BNode { - public static Map g2GN = new HashMap<>(); - public static Map g2GP = new HashMap<>(); - - public static G v(GlobalVarNode origin, boolean positive) { - if (positive) { - return g2GP.computeIfAbsent(origin, k -> new G(origin, true)); - } else { - return g2GN.computeIfAbsent(origin, k -> new G(origin, false)); - } + public static Map g2GN = new HashMap<>(); + public static Map g2GP = new HashMap<>(); + + public static G v(GlobalVarNode origin, boolean positive) { + if (positive) { + return g2GP.computeIfAbsent(origin, k -> new G(origin, true)); + } else { + return g2GN.computeIfAbsent(origin, k -> new G(origin, false)); } + } - private final Set outLs = new HashSet<>(); - private final boolean positive; + private final Set outLs = new HashSet<>(); + private final boolean positive; - G(GlobalVarNode origin, boolean positive) { - super(origin); - this.positive = positive; - } + G(GlobalVarNode origin, boolean positive) { + super(origin); + this.positive = positive; + } - public boolean addOutEdge(L toE) { - return outLs.add(toE); - } + public boolean addOutEdge(L toE) { + return outLs.add(toE); + } - @Override - public boolean addOutEdge(BNode toE) { - return addOutEdge((L) toE); - } + @Override + public boolean addOutEdge(BNode toE) { + return addOutEdge((L) toE); + } - @Override - public Stream forwardTargets() { - return outLs.stream(); - } + @Override + public Stream forwardTargets() { + return outLs.stream(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java index 784a198b99e..a7b278c5447 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/I.java @@ -18,47 +18,43 @@ package qilin.pta.toolkits.selectx; -import qilin.core.pag.Node; - import java.util.HashSet; import java.util.Set; import java.util.stream.Stream; +import qilin.core.pag.Node; - -/** - * local nodes - */ +/** local nodes */ public abstract class I extends BNode { - private final Set outIs = new HashSet<>(); - protected Set paras = new HashSet<>(); - - I(Node origin) { - super(origin); - } - - public void clearParas() { - this.paras.clear(); - } - - boolean update(I another) { - return this.paras.addAll(another.paras); - } - - public boolean addOutEdge(I to) { - return outIs.add(to); - } - - @Override - public boolean addOutEdge(BNode toE) { - return addOutEdge((I) toE); - } - - @Override - public Stream forwardTargets() { - return outIs.stream(); - } - - public Set getOutTargets() { - return this.outIs; - } + private final Set outIs = new HashSet<>(); + protected Set paras = new HashSet<>(); + + I(Node origin) { + super(origin); + } + + public void clearParas() { + this.paras.clear(); + } + + boolean update(I another) { + return this.paras.addAll(another.paras); + } + + public boolean addOutEdge(I to) { + return outIs.add(to); + } + + @Override + public boolean addOutEdge(BNode toE) { + return addOutEdge((I) toE); + } + + @Override + public Stream forwardTargets() { + return outIs.stream(); + } + + public Set getOutTargets() { + return this.outIs; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java index 4998e5885c7..e5fa38d4fa7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/L.java @@ -18,90 +18,85 @@ package qilin.pta.toolkits.selectx; -import qilin.core.pag.LocalVarNode; -import qilin.util.Util; - import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import qilin.core.pag.LocalVarNode; +import qilin.util.Util; - -/** - * locals - */ +/** locals */ public class L extends I { - public static Map l2LN = new HashMap<>(); - public static Map l2LP = new HashMap<>(); - - public static L v(LocalVarNode origin, boolean positive) { - if (positive) { - return l2LP.computeIfAbsent(origin, k -> new L(origin, positive)); - } else { - return l2LN.computeIfAbsent(origin, k -> new L(origin, positive)); - } - } - - private final Set outGs = new HashSet<>(); - private final boolean positive; - private final Map> outEntryEdges = new HashMap<>(); - private final Map> outExitEdges = new HashMap<>(); - private final Map> inEntryEdges = new HashMap<>(); - - L(LocalVarNode origin, boolean positive) { - super(origin); - this.positive = positive; - } - - public boolean addOutEdge(G to) { - return outGs.add(to); - } - - public Stream getOutGs() { - return outGs.stream(); - } - - @Override - public boolean addOutEdge(BNode toE) { - if (toE instanceof G) - return addOutEdge((G) toE); - return super.addOutEdge(toE); - } - - public boolean addOutEntryEdge(int i, L toE) { - return Util.addToMap(outEntryEdges, i, toE); - } - - public boolean addOutExitEdge(int i, L toE) { - return Util.addToMap(outExitEdges, i, toE); - } - - public Set getOutEntryEdges() { - return outEntryEdges.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); - } - - public Set>> getOutExitEdges() { - return outExitEdges.entrySet(); - } - - public boolean addInEntryEdge(int i, L fromE) { - return Util.addToMap(inEntryEdges, i, fromE); - } - - public Set getInEntryEdges(int i) { - return inEntryEdges.getOrDefault(i, Collections.emptySet()); - } - - @Override - public Stream forwardTargets() { - Stream exits = outExitEdges.values().stream().flatMap(Collection::stream); - Stream outs = Stream.concat(exits, outGs.stream()); - return Stream.concat(outs, super.forwardTargets()); - } - - /* - * inverse operation: inv(l-) = l+ and inv(l+) = l-. - * */ - public L inv() { - return L.v((LocalVarNode) sparkNode, !positive); + public static Map l2LN = new HashMap<>(); + public static Map l2LP = new HashMap<>(); + + public static L v(LocalVarNode origin, boolean positive) { + if (positive) { + return l2LP.computeIfAbsent(origin, k -> new L(origin, positive)); + } else { + return l2LN.computeIfAbsent(origin, k -> new L(origin, positive)); } + } + + private final Set outGs = new HashSet<>(); + private final boolean positive; + private final Map> outEntryEdges = new HashMap<>(); + private final Map> outExitEdges = new HashMap<>(); + private final Map> inEntryEdges = new HashMap<>(); + + L(LocalVarNode origin, boolean positive) { + super(origin); + this.positive = positive; + } + + public boolean addOutEdge(G to) { + return outGs.add(to); + } + + public Stream getOutGs() { + return outGs.stream(); + } + + @Override + public boolean addOutEdge(BNode toE) { + if (toE instanceof G) return addOutEdge((G) toE); + return super.addOutEdge(toE); + } + + public boolean addOutEntryEdge(int i, L toE) { + return Util.addToMap(outEntryEdges, i, toE); + } + + public boolean addOutExitEdge(int i, L toE) { + return Util.addToMap(outExitEdges, i, toE); + } + + public Set getOutEntryEdges() { + return outEntryEdges.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + } + + public Set>> getOutExitEdges() { + return outExitEdges.entrySet(); + } + + public boolean addInEntryEdge(int i, L fromE) { + return Util.addToMap(inEntryEdges, i, fromE); + } + + public Set getInEntryEdges(int i) { + return inEntryEdges.getOrDefault(i, Collections.emptySet()); + } + + @Override + public Stream forwardTargets() { + Stream exits = outExitEdges.values().stream().flatMap(Collection::stream); + Stream outs = Stream.concat(exits, outGs.stream()); + return Stream.concat(outs, super.forwardTargets()); + } + + /* + * inverse operation: inv(l-) = l+ and inv(l+) = l-. + * */ + public L inv() { + return L.v((LocalVarNode) sparkNode, !positive); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java index dd77fd99ff5..38fd570c397 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/O.java @@ -18,19 +18,18 @@ package qilin.pta.toolkits.selectx; -import qilin.core.pag.AllocNode; - import java.util.HashMap; import java.util.Map; +import qilin.core.pag.AllocNode; public class O extends I { - public static Map o2O = new HashMap<>(); + public static Map o2O = new HashMap<>(); - public static O v(AllocNode origin) { - return o2O.computeIfAbsent(origin, k -> new O(origin)); - } + public static O v(AllocNode origin) { + return o2O.computeIfAbsent(origin, k -> new O(origin)); + } - public O(AllocNode origin) { - super(origin); - } + public O(AllocNode origin) { + super(origin); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java index 0f3fa83dc3f..7271a57f6d5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/selectx/Selectx.java @@ -21,7 +21,6 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; - import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; @@ -38,287 +37,309 @@ import sootup.core.types.ReferenceType; public class Selectx { - private final PTA prePTA; - private final PAG prePAG; - private final Set sparkFields = new HashSet<>(); + private final PTA prePTA; + private final PAG prePAG; + private final Set sparkFields = new HashSet<>(); - public Selectx(PTA pta) { - this.prePTA = pta; - this.prePAG = pta.getPag(); - buildGraph(); - } + public Selectx(PTA pta) { + this.prePTA = pta; + this.prePAG = pta.getPag(); + buildGraph(); + } - public void addNewEdge(AllocNode from, LocalVarNode to) { - O fromE = O.v(from); - L toE = L.v(to, true); - fromE.addOutEdge(toE); - L toEI = L.v(to, false); - toEI.addOutEdge(fromE); - } + public void addNewEdge(AllocNode from, LocalVarNode to) { + O fromE = O.v(from); + L toE = L.v(to, true); + fromE.addOutEdge(toE); + L toEI = L.v(to, false); + toEI.addOutEdge(fromE); + } - public void addAssignEdge(LocalVarNode from, LocalVarNode to) { - L fromE = L.v(from, true), toE = L.v(to, true); - fromE.addOutEdge(toE); - L fromEI = L.v(from, false), toEI = L.v(to, false); - toEI.addOutEdge(fromEI); - } + public void addAssignEdge(LocalVarNode from, LocalVarNode to) { + L fromE = L.v(from, true), toE = L.v(to, true); + fromE.addOutEdge(toE); + L fromEI = L.v(from, false), toEI = L.v(to, false); + toEI.addOutEdge(fromEI); + } - public void addEntryEdge(LocalVarNode from, LocalVarNode to, CallSite callSite) { - int i = getCallSiteNumber(callSite); + public void addEntryEdge(LocalVarNode from, LocalVarNode to, CallSite callSite) { + int i = getCallSiteNumber(callSite); - L fromE = L.v(from, true), toE = L.v(to, true); - if (fromE.addOutEntryEdge(i, toE)) { - toE.addInEntryEdge(i, fromE); - L fromEI = L.v(from, false), toEI = L.v(to, false); - toEI.addOutExitEdge(i, fromEI); - } + L fromE = L.v(from, true), toE = L.v(to, true); + if (fromE.addOutEntryEdge(i, toE)) { + toE.addInEntryEdge(i, fromE); + L fromEI = L.v(from, false), toEI = L.v(to, false); + toEI.addOutExitEdge(i, fromEI); } + } - public void addExitEdge(LocalVarNode from, LocalVarNode to, CallSite callSite) { - int i = getCallSiteNumber(callSite); + public void addExitEdge(LocalVarNode from, LocalVarNode to, CallSite callSite) { + int i = getCallSiteNumber(callSite); - L fromE = L.v(from, true), toE = L.v(to, true); - if (fromE.addOutExitEdge(i, toE)) { - L fromEI = L.v(from, false), toEI = L.v(to, false); - toEI.addOutEntryEdge(i, fromEI); - fromEI.addInEntryEdge(i, toEI); - } + L fromE = L.v(from, true), toE = L.v(to, true); + if (fromE.addOutExitEdge(i, toE)) { + L fromEI = L.v(from, false), toEI = L.v(to, false); + toEI.addOutEntryEdge(i, fromEI); + fromEI.addInEntryEdge(i, toEI); } + } - public void addStoreEdge(LocalVarNode from, LocalVarNode base) { - L fromE = L.v(from, true), baseE = L.v(base, true); - L fromEI = L.v(from, false), baseEI = L.v(base, false); - fromE.addOutEdge(baseEI); - baseE.addOutEdge(fromEI); - } + public void addStoreEdge(LocalVarNode from, LocalVarNode base) { + L fromE = L.v(from, true), baseE = L.v(base, true); + L fromEI = L.v(from, false), baseEI = L.v(base, false); + fromE.addOutEdge(baseEI); + baseE.addOutEdge(fromEI); + } - public void addStaticStoreEdge(LocalVarNode from, GlobalVarNode to) { - L fromE = L.v(from, true); - G toE = G.v(to, true); - fromE.addOutEdge(toE); - L fromEI = L.v(from, false); - G toEI = G.v(to, false); - toEI.addOutEdge(fromEI); - } + public void addStaticStoreEdge(LocalVarNode from, GlobalVarNode to) { + L fromE = L.v(from, true); + G toE = G.v(to, true); + fromE.addOutEdge(toE); + L fromEI = L.v(from, false); + G toEI = G.v(to, false); + toEI.addOutEdge(fromEI); + } - public void addStaticLoadEdge(GlobalVarNode from, LocalVarNode to) { - G fromE = G.v(from, true); - L toE = L.v(to, true); - fromE.addOutEdge(toE); - G fromEI = G.v(from, false); - L toEI = L.v(to, false); - toEI.addOutEdge(fromEI); - } + public void addStaticLoadEdge(GlobalVarNode from, LocalVarNode to) { + G fromE = G.v(from, true); + L toE = L.v(to, true); + fromE.addOutEdge(toE); + G fromEI = G.v(from, false); + L toEI = L.v(to, false); + toEI.addOutEdge(fromEI); + } - private void propagate(Set workList, Set paraWorkList) { - while (!workList.isEmpty() || !paraWorkList.isEmpty()) { - while (!workList.isEmpty()) { - BNode node = workList.iterator().next(); - workList.remove(node); - node.forwardTargets().filter(BNode::setVisited).forEach(workList::add); - if (node instanceof L l) { - l.getOutEntryEdges().stream().filter(tgt -> tgt.paras.add(tgt)).forEach(paraWorkList::add); - } - } - while (!paraWorkList.isEmpty()) { - I node = paraWorkList.iterator().next(); - paraWorkList.remove(node); - // para propagation. - node.getOutTargets().stream().filter(i -> i.update(node)).forEach(paraWorkList::add); - if (node instanceof L l) { - l.getOutGs().filter(BNode::setVisited).forEach(workList::add); - l.getOutEntryEdges().stream().filter(tgt -> tgt.paras.add(tgt)).forEach(paraWorkList::add); - for (Map.Entry> entry : l.getOutExitEdges()) { - Integer i = entry.getKey(); - Set tgts = entry.getValue(); - l.paras.stream().flatMap(para -> para.getInEntryEdges(i).stream()).forEach(arg -> { - tgts.forEach(tgt -> { - if (arg.addOutEdge(tgt)) { //add match edge - if (arg.isVisited() && tgt.setVisited()) { - workList.add(tgt); - } - if (tgt.update(arg)) { - paraWorkList.add(tgt); - } - } - }); - }); - } - } - } // para while - } // outer while - } + private void propagate(Set workList, Set paraWorkList) { + while (!workList.isEmpty() || !paraWorkList.isEmpty()) { + while (!workList.isEmpty()) { + BNode node = workList.iterator().next(); + workList.remove(node); + node.forwardTargets().filter(BNode::setVisited).forEach(workList::add); + if (node instanceof L l) { + l.getOutEntryEdges().stream() + .filter(tgt -> tgt.paras.add(tgt)) + .forEach(paraWorkList::add); + } + } + while (!paraWorkList.isEmpty()) { + I node = paraWorkList.iterator().next(); + paraWorkList.remove(node); + // para propagation. + node.getOutTargets().stream().filter(i -> i.update(node)).forEach(paraWorkList::add); + if (node instanceof L l) { + l.getOutGs().filter(BNode::setVisited).forEach(workList::add); + l.getOutEntryEdges().stream() + .filter(tgt -> tgt.paras.add(tgt)) + .forEach(paraWorkList::add); + for (Map.Entry> entry : l.getOutExitEdges()) { + Integer i = entry.getKey(); + Set tgts = entry.getValue(); + l.paras.stream() + .flatMap(para -> para.getInEntryEdges(i).stream()) + .forEach( + arg -> { + tgts.forEach( + tgt -> { + if (arg.addOutEdge(tgt)) { // add match edge + if (arg.isVisited() && tgt.setVisited()) { + workList.add(tgt); + } + if (tgt.update(arg)) { + paraWorkList.add(tgt); + } + } + }); + }); + } + } + } // para while + } // outer while + } - private void resetNodes() { - // reset nodes' visited state - G.g2GN.values().forEach(BNode::reset); - G.g2GP.values().forEach(BNode::reset); - L.l2LN.values().forEach(BNode::reset); - L.l2LP.values().forEach(BNode::reset); - O.o2O.values().forEach(BNode::reset); - // clear paras - L.l2LN.values().forEach(I::clearParas); - L.l2LP.values().forEach(I::clearParas); - O.o2O.values().forEach(I::clearParas); - } + private void resetNodes() { + // reset nodes' visited state + G.g2GN.values().forEach(BNode::reset); + G.g2GP.values().forEach(BNode::reset); + L.l2LN.values().forEach(BNode::reset); + L.l2LP.values().forEach(BNode::reset); + O.o2O.values().forEach(BNode::reset); + // clear paras + L.l2LN.values().forEach(I::clearParas); + L.l2LP.values().forEach(I::clearParas); + O.o2O.values().forEach(I::clearParas); + } - public Map process() { - System.out.print("cs2 propogating ..."); - long time = System.currentTimeMillis(); + public Map process() { + System.out.print("cs2 propogating ..."); + long time = System.currentTimeMillis(); - Set workList = new HashSet<>(); - Set paraWorkList = new HashSet<>(); + Set workList = new HashSet<>(); + Set paraWorkList = new HashSet<>(); - //forward processing... - O.o2O.values().forEach(o -> { - o.setVisited(); - workList.add(o); - }); - propagate(workList, paraWorkList); + // forward processing... + O.o2O + .values() + .forEach( + o -> { + o.setVisited(); + workList.add(o); + }); + propagate(workList, paraWorkList); - //record and reset... - Set entryO = O.o2O.values().stream().filter(o -> !o.paras.isEmpty()).collect(Collectors.toSet()); - Set entryL = Stream.concat(L.l2LP.values().stream(), L.l2LN.values().stream()) - .filter(l -> !l.paras.isEmpty()).collect(Collectors.toSet()); - resetNodes(); + // record and reset... + Set entryO = + O.o2O.values().stream().filter(o -> !o.paras.isEmpty()).collect(Collectors.toSet()); + Set entryL = + Stream.concat(L.l2LP.values().stream(), L.l2LN.values().stream()) + .filter(l -> !l.paras.isEmpty()) + .collect(Collectors.toSet()); + resetNodes(); - //backward processing... - L.l2LN.values().forEach(ln -> { - ln.setVisited(); - workList.add(ln); - }); - propagate(workList, paraWorkList); + // backward processing... + L.l2LN + .values() + .forEach( + ln -> { + ln.setVisited(); + workList.add(ln); + }); + propagate(workList, paraWorkList); - System.out.println((System.currentTimeMillis() - time) / 1000 + "s"); + System.out.println((System.currentTimeMillis() - time) / 1000 + "s"); - Map ret = new HashMap<>(); - entryO.forEach(o -> { - if (!o.paras.isEmpty()) { - ret.put(o.sparkNode, 1); - } else { - ret.put(o.sparkNode, 0); - } + Map ret = new HashMap<>(); + entryO.forEach( + o -> { + if (!o.paras.isEmpty()) { + ret.put(o.sparkNode, 1); + } else { + ret.put(o.sparkNode, 0); + } }); - entryL.forEach(l -> { - if (!l.inv().paras.isEmpty()) { - ret.put(l.sparkNode, 1); - } else { - ret.put(l.sparkNode, 0); - } + entryL.forEach( + l -> { + if (!l.inv().paras.isEmpty()) { + ret.put(l.sparkNode, 1); + } else { + ret.put(l.sparkNode, 0); + } }); - this.sparkFields.forEach(f -> { - ret.put(f, 1); + this.sparkFields.forEach( + f -> { + ret.put(f, 1); }); - return ret; - } + return ret; + } + Map call2Number = new HashMap<>(); + int totalCallsites = 0; - Map call2Number = new HashMap<>(); - int totalCallsites = 0; - - int getCallSiteNumber(CallSite callsite) { - Integer oldNumber = call2Number.get(callsite); - if (oldNumber != null) { - return oldNumber; - } - totalCallsites++; - call2Number.put(callsite, totalCallsites); - return totalCallsites; + int getCallSiteNumber(CallSite callsite) { + Integer oldNumber = call2Number.get(callsite); + if (oldNumber != null) { + return oldNumber; } + totalCallsites++; + call2Number.put(callsite, totalCallsites); + return totalCallsites; + } + private void buildGraph() { + for (SootMethod method : prePTA.getNakedReachableMethods()) { + if (!method.isConcrete()) { + continue; + } + MethodPAG srcmpag = prePAG.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + } else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + this.sparkFields.add(fr.getField()); + } else { // local-global + assert to instanceof GlobalVarNode; + this.addStaticStoreEdge((LocalVarNode) from, (GlobalVarNode) to); + } + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + // load edge is treated as assign. + this.addAssignEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + this.sparkFields.add(fr.getField()); + } else { + assert (from instanceof GlobalVarNode); + this.addStaticLoadEdge((GlobalVarNode) from, (LocalVarNode) to); + } + } - private void buildGraph() { - for (SootMethod method : prePTA.getNakedReachableMethods()) { - if (!method.isConcrete()) { - continue; - } - MethodPAG srcmpag = prePAG.getMethodPAG(method); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof LocalVarNode) { - this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); - } else if (to instanceof FieldRefNode fr) { - this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); - this.sparkFields.add(fr.getField()); - } else { // local-global - assert to instanceof GlobalVarNode; - this.addStaticStoreEdge((LocalVarNode) from, (GlobalVarNode) to); - } - } else if (from instanceof AllocNode) { - if (to instanceof LocalVarNode) { - this.addNewEdge((AllocNode) from, (LocalVarNode) to); - } // GlobalVarNode - } else if (from instanceof FieldRefNode fr) { - // load edge is treated as assign. - this.addAssignEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); - this.sparkFields.add(fr.getField()); - } else { - assert (from instanceof GlobalVarNode); - this.addStaticLoadEdge((GlobalVarNode) from, (LocalVarNode) to); - } - } - - // add exception edges that added dynamically during the pre-analysis. - srcmpag.getExceptionEdges().forEach((k, vs) -> { + // add exception edges that added dynamically during the pre-analysis. + srcmpag + .getExceptionEdges() + .forEach( + (k, vs) -> { for (Node v : vs) { - this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); + this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); } - }); + }); - // add invoke edges - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - for (final Stmt s : srcmpag.getInvokeStmts()) { - CallSite callSite = new CallSite(s); - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - Value[] args = new Value[numArgs]; - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { - continue; - } - args[i] = arg; - } - LocalVarNode retDest = null; - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - retDest = prePAG.findLocalVarNode(dest); - } - } - LocalVarNode receiver = null; - if (ie instanceof AbstractInstanceInvokeExpr iie) { - receiver = prePAG.findLocalVarNode(iie.getBase()); - } - for (Iterator it = prePTA.getCallGraph().edgesOutOf(s); it.hasNext(); ) { - Edge e = it.next(); - SootMethod tgtmtd = e.tgt(); - MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - for (int i = 0; i < numArgs; i++) { - if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) { - continue; - } - LocalVarNode parm = (LocalVarNode) tgtnf.caseParm(i); - this.addEntryEdge((LocalVarNode) srcnf.getNode(args[i]), parm, callSite); - } - if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { - LocalVarNode ret = (LocalVarNode) tgtnf.caseRet(); - this.addExitEdge(ret, retDest, callSite); - } - LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); - LocalVarNode throwFinal = prePAG.findLocalVarNode(new Parm(tgtmtd, PointsToAnalysis.THROW_NODE)); - if (throwFinal != null) { - this.addExitEdge(throwFinal, stmtThrowNode, callSite); - } - if (receiver != null) { - LocalVarNode thisRef = (LocalVarNode) tgtnf.caseThis(); - this.addEntryEdge(receiver, thisRef, callSite); - } - } + // add invoke edges + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + for (final Stmt s : srcmpag.getInvokeStmts()) { + CallSite callSite = new CallSite(s); + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + args[i] = arg; + } + LocalVarNode retDest = null; + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + retDest = prePAG.findLocalVarNode(dest); + } + } + LocalVarNode receiver = null; + if (ie instanceof AbstractInstanceInvokeExpr iie) { + receiver = prePAG.findLocalVarNode(iie.getBase()); + } + for (Iterator it = prePTA.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + MethodPAG tgtmpag = prePAG.getMethodPAG(tgtmtd); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + for (int i = 0; i < numArgs; i++) { + if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) { + continue; } - } // reachable methods. - } -} \ No newline at end of file + LocalVarNode parm = (LocalVarNode) tgtnf.caseParm(i); + this.addEntryEdge((LocalVarNode) srcnf.getNode(args[i]), parm, callSite); + } + if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) { + LocalVarNode ret = (LocalVarNode) tgtnf.caseRet(); + this.addExitEdge(ret, retDest, callSite); + } + LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); + LocalVarNode throwFinal = + prePAG.findLocalVarNode(new Parm(tgtmtd, PointsToAnalysis.THROW_NODE)); + if (throwFinal != null) { + this.addExitEdge(throwFinal, stmtThrowNode, callSite); + } + if (receiver != null) { + LocalVarNode thisRef = (LocalVarNode) tgtnf.caseThis(); + this.addEntryEdge(receiver, thisRef, callSite); + } + } + } + } // reachable methods. + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java index 1bd305e8e7c..46686f56d72 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/AbstractMVFG.java @@ -18,6 +18,7 @@ package qilin.pta.toolkits.turner; +import java.util.*; import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; @@ -36,261 +37,258 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.*; - public abstract class AbstractMVFG { - public static Map method2VFG = new HashMap<>(); - protected final PTA prePTA; - protected final OCG hg; - protected final SootMethod method; - protected final Set sparkNodes = new HashSet<>(); - protected final Set csNodes = new HashSet<>(); - protected final Map> outEdges = new HashMap<>(); - protected final Map> inEdges = new HashMap<>(); - - protected int total_edge_count = 0; + public static Map method2VFG = new HashMap<>(); + protected final PTA prePTA; + protected final OCG hg; + protected final SootMethod method; + protected final Set sparkNodes = new HashSet<>(); + protected final Set csNodes = new HashSet<>(); + protected final Map> outEdges = new HashMap<>(); + protected final Map> inEdges = new HashMap<>(); - public static AbstractMVFG findMethodVFG(SootMethod method) { - return method2VFG.getOrDefault(method, null); - } + protected int total_edge_count = 0; - public AbstractMVFG(PTA prePTA, OCG hg, SootMethod method) { - this.prePTA = prePTA; - this.hg = hg; - this.method = method; - } + public static AbstractMVFG findMethodVFG(SootMethod method) { + return method2VFG.getOrDefault(method, null); + } - public Collection getAllNodes() { - return sparkNodes; - } + public AbstractMVFG(PTA prePTA, OCG hg, SootMethod method) { + this.prePTA = prePTA; + this.hg = hg; + this.method = method; + } - public int getTotalNodeCount() { - return sparkNodes.size(); - } + public Collection getAllNodes() { + return sparkNodes; + } - public int getTotalEdgeCount() { - return total_edge_count; - } + public int getTotalNodeCount() { + return sparkNodes.size(); + } - public Collection getCSNodes() { - return csNodes; - } + public int getTotalEdgeCount() { + return total_edge_count; + } - protected void addNormalEdge(TranEdge edge) { - sparkNodes.add(edge.getSource()); - sparkNodes.add(edge.getTarget()); - total_edge_count++; - outEdges.computeIfAbsent(edge.getSource(), k -> new HashSet<>()).add(edge); - inEdges.computeIfAbsent(edge.getTarget(), k -> new HashSet<>()).add(edge); - } + public Collection getCSNodes() { + return csNodes; + } - protected void addNewEdge(AllocNode from, LocalVarNode to) { - TranEdge newEdge = new TranEdge(from, to, DFA.TranCond.NEW); - addNormalEdge(newEdge); - TranEdge newInvEdge = new TranEdge(to, from, DFA.TranCond.INEW); - addNormalEdge(newInvEdge); - } + protected void addNormalEdge(TranEdge edge) { + sparkNodes.add(edge.getSource()); + sparkNodes.add(edge.getTarget()); + total_edge_count++; + outEdges.computeIfAbsent(edge.getSource(), k -> new HashSet<>()).add(edge); + inEdges.computeIfAbsent(edge.getTarget(), k -> new HashSet<>()).add(edge); + } - protected void addCSLikelyEdge(AllocNode heap) { - TranEdge csLikelyEdge = new TranEdge(heap, heap, DFA.TranCond.CSLIKELY); - addNormalEdge(csLikelyEdge); - } + protected void addNewEdge(AllocNode from, LocalVarNode to) { + TranEdge newEdge = new TranEdge(from, to, DFA.TranCond.NEW); + addNormalEdge(newEdge); + TranEdge newInvEdge = new TranEdge(to, from, DFA.TranCond.INEW); + addNormalEdge(newInvEdge); + } - protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { - TranEdge assignEdge = new TranEdge(from, to, DFA.TranCond.ASSIGN); - addNormalEdge(assignEdge); - TranEdge assignInvEdge = new TranEdge(to, from, DFA.TranCond.IASSIGN); - addNormalEdge(assignInvEdge); - } + protected void addCSLikelyEdge(AllocNode heap) { + TranEdge csLikelyEdge = new TranEdge(heap, heap, DFA.TranCond.CSLIKELY); + addNormalEdge(csLikelyEdge); + } - protected void addStoreEdge(LocalVarNode from, LocalVarNode base) { - TranEdge storeEdge = new TranEdge(from, base, DFA.TranCond.STORE); - addNormalEdge(storeEdge); - TranEdge storeInvEdge = new TranEdge(base, from, DFA.TranCond.ISTORE); - addNormalEdge(storeInvEdge); - } + protected void addAssignEdge(LocalVarNode from, LocalVarNode to) { + TranEdge assignEdge = new TranEdge(from, to, DFA.TranCond.ASSIGN); + addNormalEdge(assignEdge); + TranEdge assignInvEdge = new TranEdge(to, from, DFA.TranCond.IASSIGN); + addNormalEdge(assignInvEdge); + } - protected void addLoadEdge(LocalVarNode base, LocalVarNode to) { - TranEdge loadEdge = new TranEdge(base, to, DFA.TranCond.LOAD); - addNormalEdge(loadEdge); - TranEdge loadInvEdge = new TranEdge(to, base, DFA.TranCond.ILOAD); - addNormalEdge(loadInvEdge); - } + protected void addStoreEdge(LocalVarNode from, LocalVarNode base) { + TranEdge storeEdge = new TranEdge(from, base, DFA.TranCond.STORE); + addNormalEdge(storeEdge); + TranEdge storeInvEdge = new TranEdge(base, from, DFA.TranCond.ISTORE); + addNormalEdge(storeInvEdge); + } - protected void buildVFG() { - CallGraph callGraph = prePTA.getCallGraph(); - PAG pag = prePTA.getPag(); - MethodPAG srcmpag = pag.getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof LocalVarNode) - this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); - else if (to instanceof FieldRefNode fr) { - this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); - } // local-global + protected void addLoadEdge(LocalVarNode base, LocalVarNode to) { + TranEdge loadEdge = new TranEdge(base, to, DFA.TranCond.LOAD); + addNormalEdge(loadEdge); + TranEdge loadInvEdge = new TranEdge(to, base, DFA.TranCond.ILOAD); + addNormalEdge(loadInvEdge); + } - } else if (from instanceof AllocNode) { - if (to instanceof LocalVarNode) { - this.addNewEdge((AllocNode) from, (LocalVarNode) to); - if (hg.isCSLikely((AllocNode) from)) { - this.addCSLikelyEdge((AllocNode) from); - } - } // GlobalVarNode - } else if (from instanceof FieldRefNode fr) { - this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); - } // global-local + protected void buildVFG() { + CallGraph callGraph = prePTA.getCallGraph(); + PAG pag = prePTA.getPag(); + MethodPAG srcmpag = pag.getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to); + else if (to instanceof FieldRefNode fr) { + this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase()); + } // local-global - } - // add exception edges that added dynamically during the pre-analysis. - srcmpag.getExceptionEdges().forEach((k, vs) -> { - for (Node v : vs) { + } else if (from instanceof AllocNode) { + if (to instanceof LocalVarNode) { + this.addNewEdge((AllocNode) from, (LocalVarNode) to); + if (hg.isCSLikely((AllocNode) from)) { + this.addCSLikelyEdge((AllocNode) from); + } + } // GlobalVarNode + } else if (from instanceof FieldRefNode fr) { + this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to); + } // global-local + } + // add exception edges that added dynamically during the pre-analysis. + srcmpag + .getExceptionEdges() + .forEach( + (k, vs) -> { + for (Node v : vs) { this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v); - } - }); + } + }); - // add invoke edges - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - Value[] args = new Value[numArgs]; - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) - continue; - args[i] = arg; - } - LocalVarNode retDest = null; - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - retDest = pag.findLocalVarNode(dest); - } - } - LocalVarNode receiver; - if (ie instanceof AbstractInstanceInvokeExpr iie) { - receiver = pag.findLocalVarNode(iie.getBase()); - } else { - // static call - receiver = thisRef; - } - - Set targets = new HashSet<>(); - for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { - Edge e = it.next(); - SootMethod tgtmtd = e.tgt(); - targets.add(tgtmtd); - } - if (!targets.isEmpty()) { - for (int i = 0; i < numArgs; i++) { - if (args[i] == null) - continue; - ValNode argNode = pag.findValNode(args[i]); - if (argNode instanceof LocalVarNode && satisfyAddingStoreCondition(i, targets)) { - this.addStoreEdge((LocalVarNode) argNode, receiver); - } - } - if (retDest != null && retDest.getType() instanceof ReferenceType) { - if (statisfyAddingLoadCondition(targets)) { - this.addLoadEdge(receiver, retDest); - } - } - if (statisfyAddingLoadCondition(targets)) { - LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); - this.addLoadEdge(receiver, stmtThrowNode); - } - if (satisfyAddingStoreCondition(PointsToAnalysis.THIS_NODE, targets)) { - this.addStoreEdge(receiver, receiver); - } - } + // add invoke edges + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + Value[] args = new Value[numArgs]; + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue; + args[i] = arg; + } + LocalVarNode retDest = null; + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + retDest = pag.findLocalVarNode(dest); } + } + LocalVarNode receiver; + if (ie instanceof AbstractInstanceInvokeExpr iie) { + receiver = pag.findLocalVarNode(iie.getBase()); + } else { + // static call + receiver = thisRef; + } - // add param and return edges - addNormalEdge(new TranEdge(thisRef, thisRef, DFA.TranCond.PARAM)); - addNormalEdge(new TranEdge(thisRef, thisRef, DFA.TranCond.IPARAM)); - - int numParms = method.getParameterCount(); - for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { - LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); - addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); - addNormalEdge(new TranEdge(param, param, DFA.TranCond.IPARAM)); - } + Set targets = new HashSet<>(); + for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + targets.add(tgtmtd); + } + if (!targets.isEmpty()) { + for (int i = 0; i < numArgs; i++) { + if (args[i] == null) continue; + ValNode argNode = pag.findValNode(args[i]); + if (argNode instanceof LocalVarNode && satisfyAddingStoreCondition(i, targets)) { + this.addStoreEdge((LocalVarNode) argNode, receiver); + } } - if (method.getReturnType() instanceof ReferenceType) { - LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); - addStoreEdge(mret, thisRef); + if (retDest != null && retDest.getType() instanceof ReferenceType) { + if (statisfyAddingLoadCondition(targets)) { + this.addLoadEdge(receiver, retDest); + } } - LocalVarNode mThrow = pag.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); - if (mThrow != null) { - addStoreEdge(mThrow, thisRef); + if (statisfyAddingLoadCondition(targets)) { + LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method); + this.addLoadEdge(receiver, stmtThrowNode); } + if (satisfyAddingStoreCondition(PointsToAnalysis.THIS_NODE, targets)) { + this.addStoreEdge(receiver, receiver); + } + } + } + + // add param and return edges + addNormalEdge(new TranEdge(thisRef, thisRef, DFA.TranCond.PARAM)); + addNormalEdge(new TranEdge(thisRef, thisRef, DFA.TranCond.IPARAM)); + + int numParms = method.getParameterCount(); + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof ReferenceType) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + addNormalEdge(new TranEdge(param, param, DFA.TranCond.PARAM)); + addNormalEdge(new TranEdge(param, param, DFA.TranCond.IPARAM)); + } } + if (method.getReturnType() instanceof ReferenceType) { + LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); + addStoreEdge(mret, thisRef); + } + LocalVarNode mThrow = pag.findLocalVarNode(new Parm(method, PointsToAnalysis.THROW_NODE)); + if (mThrow != null) { + addStoreEdge(mThrow, thisRef); + } + } - protected abstract boolean statisfyAddingLoadCondition(Set targets); + protected abstract boolean statisfyAddingLoadCondition(Set targets); - protected abstract boolean satisfyAddingStoreCondition(int paramIndex, Set targets); + protected abstract boolean satisfyAddingStoreCondition(int paramIndex, Set targets); - /* - * Algorithm1: x \in R(flow) \cap R(iflow). - * more efficient. - * */ - public void computeNodesInPrecisionLossPatterns() { - Queue> workList = new UniqueQueue<>(); - Map> state2nodes = new HashMap<>(); - MethodPAG srcmpag = prePTA.getPag().getMethodPAG(method); - MethodNodeFactory srcnf = srcmpag.nodeFactory(); + /* + * Algorithm1: x \in R(flow) \cap R(iflow). + * more efficient. + * */ + public void computeNodesInPrecisionLossPatterns() { + Queue> workList = new UniqueQueue<>(); + Map> state2nodes = new HashMap<>(); + MethodPAG srcmpag = prePTA.getPag().getMethodPAG(method); + MethodNodeFactory srcnf = srcmpag.nodeFactory(); - // initialize worklist - int numParms = method.getParameterCount(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - Set startState = state2nodes.computeIfAbsent(DFA.State.S, k -> new HashSet<>()); - startState.add(thisRef); - workList.add(new Pair<>(thisRef, DFA.State.S)); + // initialize worklist + int numParms = method.getParameterCount(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + Set startState = state2nodes.computeIfAbsent(DFA.State.S, k -> new HashSet<>()); + startState.add(thisRef); + workList.add(new Pair<>(thisRef, DFA.State.S)); - for (int i = 0; i < numParms; i++) { - if (method.getParameterType(i) instanceof ReferenceType) { - LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); - startState.add(param); - workList.add(new Pair<>(param, DFA.State.S)); - } - } - if (method.getReturnType() instanceof ReferenceType) { - LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); - startState.add(mret); - workList.add(new Pair<>(mret, DFA.State.S)); - } - LocalVarNode mThrow = (LocalVarNode) srcnf.caseMethodThrow(); - startState.add(mThrow); - workList.add(new Pair<>(mThrow, DFA.State.S)); + for (int i = 0; i < numParms; i++) { + if (method.getParameterType(i) instanceof ReferenceType) { + LocalVarNode param = (LocalVarNode) srcnf.caseParm(i); + startState.add(param); + workList.add(new Pair<>(param, DFA.State.S)); + } + } + if (method.getReturnType() instanceof ReferenceType) { + LocalVarNode mret = (LocalVarNode) srcnf.caseRet(); + startState.add(mret); + workList.add(new Pair<>(mret, DFA.State.S)); + } + LocalVarNode mThrow = (LocalVarNode) srcnf.caseMethodThrow(); + startState.add(mThrow); + workList.add(new Pair<>(mThrow, DFA.State.S)); - // propagate - while (!workList.isEmpty()) { - Pair pair = workList.poll(); - Object currNode = pair.getFirst(); - DFA.State currState = pair.getSecond(); - for (TranEdge e : outEdges.getOrDefault(currNode, Collections.emptySet())) { - Object target = e.getTarget(); - DFA.TranCond tranCond = e.getTranCond(); - DFA.State nextState = DFA.nextState(currState, tranCond); - if (nextState != DFA.State.ERROR) { - Set stateNodes = state2nodes.computeIfAbsent(nextState, k -> new HashSet<>()); - if (stateNodes.add(target)) { - workList.add(new Pair<>(target, nextState)); - } - } - } - } - // collect cs nodes. - Set flowNodes = state2nodes.getOrDefault(DFA.State.FLOW, Collections.emptySet()); - Set iflowNodes = state2nodes.getOrDefault(DFA.State.IFLOW, Collections.emptySet()); - for (Object sparkNode : sparkNodes) { - if (flowNodes.contains(sparkNode) && iflowNodes.contains(sparkNode)) { - csNodes.add(sparkNode); - } + // propagate + while (!workList.isEmpty()) { + Pair pair = workList.poll(); + Object currNode = pair.getFirst(); + DFA.State currState = pair.getSecond(); + for (TranEdge e : outEdges.getOrDefault(currNode, Collections.emptySet())) { + Object target = e.getTarget(); + DFA.TranCond tranCond = e.getTranCond(); + DFA.State nextState = DFA.nextState(currState, tranCond); + if (nextState != DFA.State.ERROR) { + Set stateNodes = state2nodes.computeIfAbsent(nextState, k -> new HashSet<>()); + if (stateNodes.add(target)) { + workList.add(new Pair<>(target, nextState)); + } } + } + } + // collect cs nodes. + Set flowNodes = state2nodes.getOrDefault(DFA.State.FLOW, Collections.emptySet()); + Set iflowNodes = state2nodes.getOrDefault(DFA.State.IFLOW, Collections.emptySet()); + for (Object sparkNode : sparkNodes) { + if (flowNodes.contains(sparkNode) && iflowNodes.contains(sparkNode)) { + csNodes.add(sparkNode); + } } + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java index d4145828d00..6681998ec59 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/DFA.java @@ -23,36 +23,52 @@ import java.util.Map; public class DFA { - public enum State { - S, FLOW, IFLOW, E, ERROR; - } - - public enum TranCond { - PARAM, IPARAM, ASSIGN, IASSIGN, LOAD, ILOAD, STORE, ISTORE, NEW, INEW, CSLIKELY; - } - - private static final Map> transitionFunc = new HashMap<>(); - - static { - Map mS = transitionFunc.computeIfAbsent(State.S, k -> new HashMap<>()); - mS.put(TranCond.PARAM, State.FLOW); - - Map mFlow = transitionFunc.computeIfAbsent(State.FLOW, k -> new HashMap<>()); - mFlow.put(TranCond.ASSIGN, State.FLOW); - mFlow.put(TranCond.LOAD, State.FLOW); - mFlow.put(TranCond.STORE, State.IFLOW); - mFlow.put(TranCond.ISTORE, State.IFLOW); - mFlow.put(TranCond.NEW, State.FLOW); - - Map mIFlow = transitionFunc.computeIfAbsent(State.IFLOW, k -> new HashMap<>()); - mIFlow.put(TranCond.IASSIGN, State.IFLOW); - mIFlow.put(TranCond.ILOAD, State.IFLOW); - mIFlow.put(TranCond.IPARAM, State.E); - mIFlow.put(TranCond.INEW, State.IFLOW); - mIFlow.put(TranCond.CSLIKELY, State.FLOW); - } - - public static State nextState(State curr, TranCond tranCond) { - return transitionFunc.getOrDefault(curr, Collections.emptyMap()).getOrDefault(tranCond, State.ERROR); - } -} \ No newline at end of file + public enum State { + S, + FLOW, + IFLOW, + E, + ERROR; + } + + public enum TranCond { + PARAM, + IPARAM, + ASSIGN, + IASSIGN, + LOAD, + ILOAD, + STORE, + ISTORE, + NEW, + INEW, + CSLIKELY; + } + + private static final Map> transitionFunc = new HashMap<>(); + + static { + Map mS = transitionFunc.computeIfAbsent(State.S, k -> new HashMap<>()); + mS.put(TranCond.PARAM, State.FLOW); + + Map mFlow = transitionFunc.computeIfAbsent(State.FLOW, k -> new HashMap<>()); + mFlow.put(TranCond.ASSIGN, State.FLOW); + mFlow.put(TranCond.LOAD, State.FLOW); + mFlow.put(TranCond.STORE, State.IFLOW); + mFlow.put(TranCond.ISTORE, State.IFLOW); + mFlow.put(TranCond.NEW, State.FLOW); + + Map mIFlow = transitionFunc.computeIfAbsent(State.IFLOW, k -> new HashMap<>()); + mIFlow.put(TranCond.IASSIGN, State.IFLOW); + mIFlow.put(TranCond.ILOAD, State.IFLOW); + mIFlow.put(TranCond.IPARAM, State.E); + mIFlow.put(TranCond.INEW, State.IFLOW); + mIFlow.put(TranCond.CSLIKELY, State.FLOW); + } + + public static State nextState(State curr, TranCond tranCond) { + return transitionFunc + .getOrDefault(curr, Collections.emptyMap()) + .getOrDefault(tranCond, State.ERROR); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java index e91354a5dd9..29257fc1f98 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodLevelCallGraph.java @@ -18,52 +18,54 @@ package qilin.pta.toolkits.turner; +import java.util.Collection; import qilin.util.graph.DirectedGraph; import qilin.util.graph.DirectedGraphImpl; import soot.jimple.toolkits.callgraph.CallGraph; import sootup.core.model.SootMethod; -import java.util.Collection; - public class MethodLevelCallGraph implements DirectedGraph { - private final CallGraph callGraph; - private final DirectedGraphImpl mcg; + private final CallGraph callGraph; + private final DirectedGraphImpl mcg; - public MethodLevelCallGraph(CallGraph callGraph) { - this.callGraph = callGraph; - this.mcg = new DirectedGraphImpl<>(); - init(); - } + public MethodLevelCallGraph(CallGraph callGraph) { + this.callGraph = callGraph; + this.mcg = new DirectedGraphImpl<>(); + init(); + } - private void init() { - callGraph.iterator().forEachRemaining(edge -> { - SootMethod src = edge.getSrc().method(); - SootMethod tgt = edge.getTgt().method(); - if (src != null && tgt != null) { + private void init() { + callGraph + .iterator() + .forEachRemaining( + edge -> { + SootMethod src = edge.getSrc().method(); + SootMethod tgt = edge.getTgt().method(); + if (src != null && tgt != null) { mcg.addEdge(src, tgt); - } else { + } else { if (src != null) { - mcg.addNode(src); + mcg.addNode(src); } if (tgt != null) { - mcg.addNode(tgt); + mcg.addNode(tgt); } - } - }); - } + } + }); + } - @Override - public Collection allNodes() { - return mcg.allNodes(); - } + @Override + public Collection allNodes() { + return mcg.allNodes(); + } - @Override - public Collection predsOf(SootMethod n) { - return mcg.predsOf(n); - } + @Override + public Collection predsOf(SootMethod n) { + return mcg.predsOf(n); + } - @Override - public Collection succsOf(final SootMethod n) { - return mcg.succsOf(n); - } + @Override + public Collection succsOf(final SootMethod n) { + return mcg.succsOf(n); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java index b92a9ceb6b0..b5c7816b310 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/MethodVFG.java @@ -18,28 +18,27 @@ package qilin.pta.toolkits.turner; +import java.util.Set; import qilin.core.PTA; import sootup.core.model.SootMethod; -import java.util.Set; - public class MethodVFG extends AbstractMVFG { - public static AbstractMVFG findOrCreateMethodVFG(PTA prePTA, SootMethod method, OCG hg) { - return method2VFG.computeIfAbsent(method, k -> new MethodVFG(prePTA, method, hg)); - } + public static AbstractMVFG findOrCreateMethodVFG(PTA prePTA, SootMethod method, OCG hg) { + return method2VFG.computeIfAbsent(method, k -> new MethodVFG(prePTA, method, hg)); + } - public MethodVFG(PTA prePTA, SootMethod method, OCG hg) { - super(prePTA, hg, method); - buildVFG(); - } + public MethodVFG(PTA prePTA, SootMethod method, OCG hg) { + super(prePTA, hg, method); + buildVFG(); + } - @Override - protected boolean statisfyAddingLoadCondition(Set targets) { - return true; - } + @Override + protected boolean statisfyAddingLoadCondition(Set targets) { + return true; + } - @Override - protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { - return true; - } -} \ No newline at end of file + @Override + protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { + return true; + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java index 7f2750fe093..a8628efa1fa 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/ModularMVFG.java @@ -18,6 +18,7 @@ package qilin.pta.toolkits.turner; +import java.util.Set; import qilin.core.PTA; import qilin.core.PointsToAnalysis; import qilin.core.builder.MethodNodeFactory; @@ -28,69 +29,66 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.Set; - public class ModularMVFG extends AbstractMVFG { - public static AbstractMVFG findOrCreateMethodVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode sccNode) { - return method2VFG.computeIfAbsent(method, k -> new ModularMVFG(prePTA, method, hg, sccNode)); - } + public static AbstractMVFG findOrCreateMethodVFG( + PTA prePTA, SootMethod method, OCG hg, MergedNode sccNode) { + return method2VFG.computeIfAbsent(method, k -> new ModularMVFG(prePTA, method, hg, sccNode)); + } - private final MergedNode sccNode; + private final MergedNode sccNode; - public ModularMVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode sccNode) { - super(prePTA, hg, method); - this.sccNode = sccNode; - buildVFG(); - } + public ModularMVFG(PTA prePTA, SootMethod method, OCG hg, MergedNode sccNode) { + super(prePTA, hg, method); + this.sccNode = sccNode; + buildVFG(); + } - @Override - protected boolean statisfyAddingLoadCondition(Set targets) { - for (SootMethod tgtmtd : targets) { - // the target method is in the same scc with current method. - if (!tgtmtd.isConcrete() || sccNode.getContent().contains(tgtmtd)) { - return true; - } - if (!(tgtmtd.getReturnType() instanceof ReferenceType)) { - continue; - } - MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); - AbstractMVFG tgtVfg = method2VFG.get(tgtmtd); - assert tgtVfg != null; - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - Node ret = tgtnf.caseRet(); - if (tgtVfg.getCSNodes().contains(ret)) { - return true; - } - } - return false; + @Override + protected boolean statisfyAddingLoadCondition(Set targets) { + for (SootMethod tgtmtd : targets) { + // the target method is in the same scc with current method. + if (!tgtmtd.isConcrete() || sccNode.getContent().contains(tgtmtd)) { + return true; + } + if (!(tgtmtd.getReturnType() instanceof ReferenceType)) { + continue; + } + MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); + AbstractMVFG tgtVfg = method2VFG.get(tgtmtd); + assert tgtVfg != null; + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + Node ret = tgtnf.caseRet(); + if (tgtVfg.getCSNodes().contains(ret)) { + return true; + } } + return false; + } - - protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { - for (SootMethod tgtmtd : targets) { - // the target method is in the same scc with current method. - if (!tgtmtd.isConcrete() || sccNode.getContent().contains(tgtmtd)) { - return true; - } - MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); - AbstractMVFG tgtVfg = method2VFG.get(tgtmtd); - assert tgtVfg != null; - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - LocalVarNode parm; - if (paramIndex == PointsToAnalysis.THIS_NODE) { - parm = (LocalVarNode) tgtnf.caseThis(); - } else { - if (tgtmtd.getParameterType(paramIndex) instanceof ReferenceType) { - parm = (LocalVarNode) tgtnf.caseParm(paramIndex); - } else { - continue; - } - } - if (tgtVfg.getCSNodes().contains(parm)) { - return true; - } + protected boolean satisfyAddingStoreCondition(int paramIndex, Set targets) { + for (SootMethod tgtmtd : targets) { + // the target method is in the same scc with current method. + if (!tgtmtd.isConcrete() || sccNode.getContent().contains(tgtmtd)) { + return true; + } + MethodPAG tgtmpag = prePTA.getPag().getMethodPAG(tgtmtd); + AbstractMVFG tgtVfg = method2VFG.get(tgtmtd); + assert tgtVfg != null; + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + LocalVarNode parm; + if (paramIndex == PointsToAnalysis.THIS_NODE) { + parm = (LocalVarNode) tgtnf.caseThis(); + } else { + if (tgtmtd.getParameterType(paramIndex) instanceof ReferenceType) { + parm = (LocalVarNode) tgtnf.caseParm(paramIndex); + } else { + continue; } - return false; + } + if (tgtVfg.getCSNodes().contains(parm)) { + return true; + } } - + return false; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java index 8f7f4e3388a..02fb93057d6 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/OCG.java @@ -18,6 +18,7 @@ package qilin.pta.toolkits.turner; +import java.util.*; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; @@ -30,235 +31,229 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.*; - // Object Containment Graph public class OCG { - public final PTA pta; - protected final Map> pts; - public Map nodes; - private int total_node_count = 0; - private int total_edge_count = 0; + public final PTA pta; + protected final Map> pts; + public Map nodes; + private int total_node_count = 0; + private int total_edge_count = 0; - public OCG(PTA pta) { - this.pta = pta; - this.pts = PTAUtils.calcStaticThisPTS(pta); - this.nodes = new HashMap<>(); - buildGraph(); - } + public OCG(PTA pta) { + this.pta = pta; + this.pts = PTAUtils.calcStaticThisPTS(pta); + this.nodes = new HashMap<>(); + buildGraph(); + } - protected void buildGraph() { - PAG pag = pta.getPag(); - pag.getAllocNodes().forEach(this::findOrCreate); - pag.getContextFields().forEach(contextField -> { - AllocNode base = contextField.getBase(); - if (base instanceof ConstantNode) { + protected void buildGraph() { + PAG pag = pta.getPag(); + pag.getAllocNodes().forEach(this::findOrCreate); + pag.getContextFields() + .forEach( + contextField -> { + AllocNode base = contextField.getBase(); + if (base instanceof ConstantNode) { return; - } + } - SparkField f = contextField.getField(); - if (f.getType() instanceof ArrayType at) { + SparkField f = contextField.getField(); + if (f.getType() instanceof ArrayType at) { if (at.getBaseType() instanceof PrimitiveType) { - return; + return; } - } - PointsToSet pts = pta.reachingObjects(contextField).toCIPointsToSet(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { + } + PointsToSet pts = pta.reachingObjects(contextField).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { AllocNode n = it.next(); if (n instanceof ConstantNode) { - continue; + continue; } addEdge(findOrCreate(base), findOrCreate(n)); - } - }); - } + } + }); + } - public Collection allNodes() { - return nodes.values(); - } + public Collection allNodes() { + return nodes.values(); + } - public int getTotalNodeCount() { - return total_node_count; - } + public int getTotalNodeCount() { + return total_node_count; + } - public int getTotalEdgeCount() { - return total_edge_count; - } + public int getTotalEdgeCount() { + return total_edge_count; + } - /** - * (1) case1: objects on OCG have successors but does not have predecessors. - * (1-1) factorys - * (1-2) normal uses. - * (2) case2: objects on OCG does not have successors. - * (2-1) no predecessors. - * (2-2) have predecessors. - * (3) othercase: objects on OCG have successors and predecessors. - */ - public void stat() { - int case1 = 0; - int total_factory = 0; - int case1_factory = 0; - int case1_normal = 0; - int case2 = 0; - int case2_noPred = 0; - int case2_hasPred = 0; - int otherCase = 0; - for (OCGNode node : nodes.values()) { - if (node.successors.size() == 0) { - case2++; - if (node.predecessors.size() == 0) { - case2_noPred++; - } else { - case2_hasPred++; - } - if (isFactoryObject(node.ir)) { - total_factory++; - } - } else if (node.predecessors.size() == 0) { - case1++; - if (isFactoryObject(node.ir)) { - case1_factory++; - // System.out.println(((AllocNode) node.ir).toString2()); - } else { - case1_normal++; - } - } else { - if (isFactoryObject(node.ir)) { - total_factory++; - } - otherCase++; - } + /** + * (1) case1: objects on OCG have successors but does not have predecessors. (1-1) factorys (1-2) + * normal uses. (2) case2: objects on OCG does not have successors. (2-1) no predecessors. (2-2) + * have predecessors. (3) othercase: objects on OCG have successors and predecessors. + */ + public void stat() { + int case1 = 0; + int total_factory = 0; + int case1_factory = 0; + int case1_normal = 0; + int case2 = 0; + int case2_noPred = 0; + int case2_hasPred = 0; + int otherCase = 0; + for (OCGNode node : nodes.values()) { + if (node.successors.size() == 0) { + case2++; + if (node.predecessors.size() == 0) { + case2_noPred++; + } else { + case2_hasPred++; } - - System.out.println("#case1:" + case1); - System.out.println("#total_factory:" + total_factory); - System.out.println("#case1_factory:" + case1_factory); - System.out.println("#case1_normal:" + case1_normal); - System.out.println("#case2:" + case2); - System.out.println("#case2_noPred:" + case2_noPred); - System.out.println("#case2_hasPred:" + case2_hasPred); - System.out.println("#othercase:" + otherCase); - } - - private OCGNode findOrCreate(AllocNode ir) { - if (nodes.containsKey(ir)) { - return nodes.get(ir); + if (isFactoryObject(node.ir)) { + total_factory++; + } + } else if (node.predecessors.size() == 0) { + case1++; + if (isFactoryObject(node.ir)) { + case1_factory++; + // System.out.println(((AllocNode) node.ir).toString2()); } else { - total_node_count++; - OCGNode ret = new OCGNode(ir); - nodes.put(ir, ret); - return ret; + case1_normal++; + } + } else { + if (isFactoryObject(node.ir)) { + total_factory++; } + otherCase++; + } } - private boolean isNewTop(OCGNode node) { - return node.predecessors.isEmpty() && !isFactoryObject(node.ir); - } + System.out.println("#case1:" + case1); + System.out.println("#total_factory:" + total_factory); + System.out.println("#case1_factory:" + case1_factory); + System.out.println("#case1_normal:" + case1_normal); + System.out.println("#case2:" + case2); + System.out.println("#case2_noPred:" + case2_noPred); + System.out.println("#case2_hasPred:" + case2_hasPred); + System.out.println("#othercase:" + otherCase); + } - private boolean isNewBottom(OCGNode node) { - return node.successors.isEmpty(); + private OCGNode findOrCreate(AllocNode ir) { + if (nodes.containsKey(ir)) { + return nodes.get(ir); + } else { + total_node_count++; + OCGNode ret = new OCGNode(ir); + nodes.put(ir, ret); + return ret; } + } - public boolean isTop(AllocNode heap) { - return !nodes.containsKey(heap) || isNewTop(findOrCreate(heap)); - } + private boolean isNewTop(OCGNode node) { + return node.predecessors.isEmpty() && !isFactoryObject(node.ir); + } - public boolean isBottom(AllocNode heap) { - return !nodes.containsKey(heap) || isNewBottom(findOrCreate(heap)); - } + private boolean isNewBottom(OCGNode node) { + return node.successors.isEmpty(); + } - private boolean isNotTopAndBottom(OCGNode node) { - return !isNewBottom(node) && !isNewTop(node); - } + public boolean isTop(AllocNode heap) { + return !nodes.containsKey(heap) || isNewTop(findOrCreate(heap)); + } - public boolean isCSLikely(AllocNode allocNode) { - OCGNode node = this.nodes.getOrDefault(allocNode, null); - if (node == null) { - return false; - } else { - return node.cslikely; - } - } + public boolean isBottom(AllocNode heap) { + return !nodes.containsKey(heap) || isNewBottom(findOrCreate(heap)); + } - public void run() { - int[] a = new int[2]; - System.out.println(PTAConfig.v().turnerConfig); - for (OCGNode node : nodes.values()) { - PTAConfig.TurnerConfig hgConfig = PTAConfig.v().turnerConfig; - if (hgConfig == PTAConfig.TurnerConfig.PHASE_TWO) { - node.cslikely = true; - } else { - node.cslikely = isNotTopAndBottom(node); - } - if (node.cslikely) { - a[1]++; - } else { - a[0]++; - } + private boolean isNotTopAndBottom(OCGNode node) { + return !isNewBottom(node) && !isNewTop(node); + } - } - for (int i = 0; i < 2; ++i) { - System.out.println("#level " + i + ": " + a[i]); - } - stat(); + public boolean isCSLikely(AllocNode allocNode) { + OCGNode node = this.nodes.getOrDefault(allocNode, null); + if (node == null) { + return false; + } else { + return node.cslikely; } + } - protected void addEdge(OCGNode pre, OCGNode succ) { - total_edge_count++; - pre.addSucc(succ); - succ.addPred(pre); + public void run() { + int[] a = new int[2]; + System.out.println(PTAConfig.v().turnerConfig); + for (OCGNode node : nodes.values()) { + PTAConfig.TurnerConfig hgConfig = PTAConfig.v().turnerConfig; + if (hgConfig == PTAConfig.TurnerConfig.PHASE_TWO) { + node.cslikely = true; + } else { + node.cslikely = isNotTopAndBottom(node); + } + if (node.cslikely) { + a[1]++; + } else { + a[0]++; + } + } + for (int i = 0; i < 2; ++i) { + System.out.println("#level " + i + ": " + a[i]); } + stat(); + } - public static class OCGNode { - public final AllocNode ir; - public Set successors; - public Set predecessors; - public boolean cslikely; + protected void addEdge(OCGNode pre, OCGNode succ) { + total_edge_count++; + pre.addSucc(succ); + succ.addPred(pre); + } - public OCGNode(AllocNode ir) { - this.ir = ir; - this.cslikely = false; - this.successors = new HashSet<>(); - this.predecessors = new HashSet<>(); - } + public static class OCGNode { + public final AllocNode ir; + public Set successors; + public Set predecessors; + public boolean cslikely; - @Override - public String toString() { - return ir.toString(); - } + public OCGNode(AllocNode ir) { + this.ir = ir; + this.cslikely = false; + this.successors = new HashSet<>(); + this.predecessors = new HashSet<>(); + } - public void addSucc(OCGNode node) { - this.successors.add(node); - } + @Override + public String toString() { + return ir.toString(); + } - public void addPred(OCGNode node) { - this.predecessors.add(node); - } + public void addSucc(OCGNode node) { + this.successors.add(node); } - /** - * patterns in case1: (1) create one object and never return out of the method. - * (2) create one object and then return out (factory). - */ - boolean isFactoryObject(AllocNode heap) { - SootMethod method = heap.getMethod(); - if (method == null) { - return false; - } - Type retType = method.getReturnType(); - if (!(retType instanceof ReferenceType)) { - return false; - } - if (retType instanceof ArrayType at) { - if (at.getBaseType() instanceof PrimitiveType) { - return false; - } - } - MethodPAG methodPAG = pta.getPag().getMethodPAG(method); - MethodNodeFactory factory = methodPAG.nodeFactory(); - Node retNode = factory.caseRet(); - PointsToSet pts = pta.reachingObjects(retNode).toCIPointsToSet(); - return pts.contains(heap); + public void addPred(OCGNode node) { + this.predecessors.add(node); } + } + /** + * patterns in case1: (1) create one object and never return out of the method. (2) create one + * object and then return out (factory). + */ + boolean isFactoryObject(AllocNode heap) { + SootMethod method = heap.getMethod(); + if (method == null) { + return false; + } + Type retType = method.getReturnType(); + if (!(retType instanceof ReferenceType)) { + return false; + } + if (retType instanceof ArrayType at) { + if (at.getBaseType() instanceof PrimitiveType) { + return false; + } + } + MethodPAG methodPAG = pta.getPag().getMethodPAG(method); + MethodNodeFactory factory = methodPAG.nodeFactory(); + Node retNode = factory.caseRet(); + PointsToSet pts = pta.reachingObjects(retNode).toCIPointsToSet(); + return pts.contains(heap); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java index f1a8ebb41e7..4d28c25e990 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/TranEdge.java @@ -21,40 +21,40 @@ import java.util.Objects; public class TranEdge { - private final Object src; - private final Object dst; - private final DFA.TranCond tranCond; - - public TranEdge(Object s, Object d, DFA.TranCond tran) { - this.src = s; - this.dst = d; - this.tranCond = tran; - } - - public Object getSource() { - return src; - } - - public Object getTarget() { - return dst; - } - - public DFA.TranCond getTranCond() { - return tranCond; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TranEdge tranEdge = (TranEdge) o; - return Objects.equals(src, tranEdge.src) && - Objects.equals(dst, tranEdge.dst) && - tranCond == tranEdge.tranCond; - } - - @Override - public int hashCode() { - return Objects.hash(src, dst, tranCond); - } -} \ No newline at end of file + private final Object src; + private final Object dst; + private final DFA.TranCond tranCond; + + public TranEdge(Object s, Object d, DFA.TranCond tran) { + this.src = s; + this.dst = d; + this.tranCond = tran; + } + + public Object getSource() { + return src; + } + + public Object getTarget() { + return dst; + } + + public DFA.TranCond getTranCond() { + return tranCond; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TranEdge tranEdge = (TranEdge) o; + return Objects.equals(src, tranEdge.src) + && Objects.equals(dst, tranEdge.dst) + && tranCond == tranEdge.tranCond; + } + + @Override + public int hashCode() { + return Objects.hash(src, dst, tranCond); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java index 856d2c1a927..5a88f80f940 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/turner/Turner.java @@ -18,6 +18,8 @@ package qilin.pta.toolkits.turner; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import qilin.core.PTA; import qilin.core.pag.AllocNode; import qilin.core.pag.PAG; @@ -28,205 +30,211 @@ import qilin.util.graph.TopologicalSorter; import sootup.core.model.SootMethod; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - public class Turner { - protected OCG ocg; - private int total_node_count = 0; - private int total_edge_count = 0; - private final PTA prePTA; - private final int k; - private final int hk; - public static boolean isModular = false; + protected OCG ocg; + private int total_node_count = 0; + private int total_edge_count = 0; + private final PTA prePTA; + private final int k; + private final int hk; + public static boolean isModular = false; - public Turner(int k, PTA pta) { - this.k = k; - this.hk = k - 1; - this.prePTA = pta; - if (isModular) { - System.out.println("Turner with modularization ..."); - } else { - System.out.println("Turner ..."); - } + public Turner(int k, PTA pta) { + this.k = k; + this.hk = k - 1; + this.prePTA = pta; + if (isModular) { + System.out.println("Turner with modularization ..."); + } else { + System.out.println("Turner ..."); } + } - //////////////////////////////////////////////////////////////////////// - public Map contxtLengthAnalysis() { - this.ocg = new OCG(prePTA); - ocg.run(); - mergeNodeAndEdgeCount(ocg.getTotalNodeCount(), ocg.getTotalEdgeCount()); - // compute level for variables in methods - Set nodes = ConcurrentHashMap.newKeySet(); - Collection reachables = prePTA.getNakedReachableMethods(); - if (isModular) { - MethodLevelCallGraph mcg = new MethodLevelCallGraph(prePTA.getCallGraph()); - final SCCMergedGraph mg = new SCCMergedGraph<>(mcg); - mystat(mg); - final TopologicalSorter> topoSorter = new TopologicalSorter<>(); - topoSorter.sort(mg, true).forEach(node -> { + //////////////////////////////////////////////////////////////////////// + public Map contxtLengthAnalysis() { + this.ocg = new OCG(prePTA); + ocg.run(); + mergeNodeAndEdgeCount(ocg.getTotalNodeCount(), ocg.getTotalEdgeCount()); + // compute level for variables in methods + Set nodes = ConcurrentHashMap.newKeySet(); + Collection reachables = prePTA.getNakedReachableMethods(); + if (isModular) { + MethodLevelCallGraph mcg = new MethodLevelCallGraph(prePTA.getCallGraph()); + final SCCMergedGraph mg = new SCCMergedGraph<>(mcg); + mystat(mg); + final TopologicalSorter> topoSorter = new TopologicalSorter<>(); + topoSorter + .sort(mg, true) + .forEach( + node -> { for (SootMethod method : node.getContent()) { - nodes.addAll(computeCtxLevelForVariables(method, node)); - } - }); - } else { - reachables.forEach(method -> { - nodes.addAll(computeCtxLevelForVariables(method)); - }); - } - // collect nodes and their level - Map ret1 = new HashMap<>(); - // compute level for variables/objects - reachables.forEach(method -> { - AbstractMVFG mvfg = MethodVFG.findMethodVFG(method); - if (mvfg != null) { - for (Object obj : mvfg.getAllNodes()) { - if (nodes.contains(obj)) { - ret1.put(obj, obj instanceof AllocNode ? hk : k); - } else { - ret1.put(obj, 0); - } + nodes.addAll(computeCtxLevelForVariables(method, node)); } + }); + } else { + reachables.forEach( + method -> { + nodes.addAll(computeCtxLevelForVariables(method)); + }); + } + // collect nodes and their level + Map ret1 = new HashMap<>(); + // compute level for variables/objects + reachables.forEach( + method -> { + AbstractMVFG mvfg = MethodVFG.findMethodVFG(method); + if (mvfg != null) { + for (Object obj : mvfg.getAllNodes()) { + if (nodes.contains(obj)) { + ret1.put(obj, obj instanceof AllocNode ? hk : k); + } else { + ret1.put(obj, 0); + } } + } }); - // compute level for fields, In our paper, we do not mention this part - // as it does not hurt too much efficiency. - PAG pag = prePTA.getPag(); - Set fields = new HashSet<>(); - Set readSet = new HashSet<>(); - Set writeSet = new HashSet<>(); + // compute level for fields, In our paper, we do not mention this part + // as it does not hurt too much efficiency. + PAG pag = prePTA.getPag(); + Set fields = new HashSet<>(); + Set readSet = new HashSet<>(); + Set writeSet = new HashSet<>(); - pag.getContextFields().forEach(contextField -> { - SparkField field = contextField.getField(); - fields.add(field); - if (!pag.simpleInvLookup(contextField).isEmpty()) { + pag.getContextFields() + .forEach( + contextField -> { + SparkField field = contextField.getField(); + fields.add(field); + if (!pag.simpleInvLookup(contextField).isEmpty()) { writeSet.add(field); - } - if (!pag.simpleLookup(contextField).isEmpty()) { + } + if (!pag.simpleLookup(contextField).isEmpty()) { readSet.add(field); - } - }); - - for (SparkField f : fields) { - int x = 0; - this.total_node_count += 1; - if (writeSet.contains(f) && readSet.contains(f)) { - x = k; - } - ret1.put(f, x); - } - Map ret = new HashMap<>(ret1); - if (PTAConfig.v().turnerConfig == PTAConfig.TurnerConfig.PHASE_ONE) { - Map ret2 = new HashMap<>(); - ret1.forEach((w, v) -> { - if (w instanceof AllocNode) { - ret2.put(w, ocg.isCSLikely((AllocNode) w) ? hk : 0); - } else { - ret2.put(w, k); - } + } }); - ret = ret2; - } - System.out.println("#Node:" + this.total_node_count); - System.out.println("#Edge:" + this.total_edge_count); - statObjInOCG(ret); - return ret; - } - private void statObjInOCG(Map ret) { - int cibyocg = 0; - int cibydfa = 0; - int csobj = 0; - int tops = 0; - int bottoms = 0; - int topandbottoms = 0; - for (AllocNode o : prePTA.getPag().getAllocNodes()) { - if (!this.ocg.isCSLikely(o)) { - cibyocg++; - } else if (ret.containsKey(o) && ret.get(o) > 0) { - csobj++; + for (SparkField f : fields) { + int x = 0; + this.total_node_count += 1; + if (writeSet.contains(f) && readSet.contains(f)) { + x = k; + } + ret1.put(f, x); + } + Map ret = new HashMap<>(ret1); + if (PTAConfig.v().turnerConfig == PTAConfig.TurnerConfig.PHASE_ONE) { + Map ret2 = new HashMap<>(); + ret1.forEach( + (w, v) -> { + if (w instanceof AllocNode) { + ret2.put(w, ocg.isCSLikely((AllocNode) w) ? hk : 0); } else { - cibydfa++; - } - if (this.ocg.isTop(o)) { - tops++; - } - if (this.ocg.isBottom(o)) { - bottoms++; - } - if (this.ocg.isTop(o) && this.ocg.isBottom(o)) { - topandbottoms++; + ret2.put(w, k); } - } - System.out.println("#CIByOCG:" + cibyocg); - System.out.println("#CIByDFA:" + cibydfa); - System.out.println("#CSOBJ:" + csobj); - System.out.println("#CITOP:" + tops); - System.out.println("#CIBOT:" + bottoms); - System.out.println("#CITOPBOT:" + topandbottoms); + }); + ret = ret2; } + System.out.println("#Node:" + this.total_node_count); + System.out.println("#Edge:" + this.total_edge_count); + statObjInOCG(ret); + return ret; + } - private Collection computeCtxLevelForVariables(SootMethod method) { - if (!method.isConcrete()) { - return Collections.emptySet(); - } else { - AbstractMVFG mvfg = MethodVFG.findOrCreateMethodVFG(prePTA, method, ocg); - mvfg.computeNodesInPrecisionLossPatterns(); - mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); - return mvfg.getCSNodes(); - } + private void statObjInOCG(Map ret) { + int cibyocg = 0; + int cibydfa = 0; + int csobj = 0; + int tops = 0; + int bottoms = 0; + int topandbottoms = 0; + for (AllocNode o : prePTA.getPag().getAllocNodes()) { + if (!this.ocg.isCSLikely(o)) { + cibyocg++; + } else if (ret.containsKey(o) && ret.get(o) > 0) { + csobj++; + } else { + cibydfa++; + } + if (this.ocg.isTop(o)) { + tops++; + } + if (this.ocg.isBottom(o)) { + bottoms++; + } + if (this.ocg.isTop(o) && this.ocg.isBottom(o)) { + topandbottoms++; + } } + System.out.println("#CIByOCG:" + cibyocg); + System.out.println("#CIByDFA:" + cibydfa); + System.out.println("#CSOBJ:" + csobj); + System.out.println("#CITOP:" + tops); + System.out.println("#CIBOT:" + bottoms); + System.out.println("#CITOPBOT:" + topandbottoms); + } - private Collection computeCtxLevelForVariables(SootMethod method, MergedNode sccNode) { - if (!method.isConcrete()) { - return Collections.emptySet(); - } else { - AbstractMVFG mvfg = ModularMVFG.findOrCreateMethodVFG(prePTA, method, ocg, sccNode); - mvfg.computeNodesInPrecisionLossPatterns(); - mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); - return mvfg.getCSNodes(); - } + private Collection computeCtxLevelForVariables(SootMethod method) { + if (!method.isConcrete()) { + return Collections.emptySet(); + } else { + AbstractMVFG mvfg = MethodVFG.findOrCreateMethodVFG(prePTA, method, ocg); + mvfg.computeNodesInPrecisionLossPatterns(); + mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); + return mvfg.getCSNodes(); } + } - private void mergeNodeAndEdgeCount(int nodeCnt, int edgeCnt) { - this.total_node_count += nodeCnt; - this.total_edge_count += edgeCnt; + private Collection computeCtxLevelForVariables( + SootMethod method, MergedNode sccNode) { + if (!method.isConcrete()) { + return Collections.emptySet(); + } else { + AbstractMVFG mvfg = ModularMVFG.findOrCreateMethodVFG(prePTA, method, ocg, sccNode); + mvfg.computeNodesInPrecisionLossPatterns(); + mergeNodeAndEdgeCount(mvfg.getTotalNodeCount(), mvfg.getTotalEdgeCount()); + return mvfg.getCSNodes(); } + } - private void mystat(SCCMergedGraph scccg) { - int sccCnt = scccg.allNodes().size(); - int sccCntGtW = 0; - int maxScc = 0; - double avgScc = 0.0; - double avgSccGtW = 0.0; - for (MergedNode scc : scccg.allNodes()) { - int sccSize = scc.getContent().size(); - if (sccSize > maxScc) { - maxScc = sccSize; - } - avgScc += sccSize; - if (sccSize > 1) { - ++sccCntGtW; - avgSccGtW += sccSize; - } - } - avgScc /= sccCnt; - avgSccGtW /= sccCntGtW; - int[] dist = new int[maxScc + 1]; - for (MergedNode scc : scccg.allNodes()) { - int sccSize = scc.getContent().size(); - dist[sccSize]++; - } - System.out.println("#scc count:" + sccCnt); - System.out.println("#scc count (exclude singleton):" + sccCntGtW); - System.out.println("Average scc size:" + avgScc); - System.out.println("Average scc size(exclude singleton):" + avgSccGtW); - System.out.println("Maximum scc size:" + maxScc); - System.out.println("Scc size distribution (size, count):"); - for (int i = 0; i <= maxScc; ++i) { - if (dist[i] > 0) { - System.out.println(i + "," + dist[i]); - } - } + private void mergeNodeAndEdgeCount(int nodeCnt, int edgeCnt) { + this.total_node_count += nodeCnt; + this.total_edge_count += edgeCnt; + } + + private void mystat(SCCMergedGraph scccg) { + int sccCnt = scccg.allNodes().size(); + int sccCntGtW = 0; + int maxScc = 0; + double avgScc = 0.0; + double avgSccGtW = 0.0; + for (MergedNode scc : scccg.allNodes()) { + int sccSize = scc.getContent().size(); + if (sccSize > maxScc) { + maxScc = sccSize; + } + avgScc += sccSize; + if (sccSize > 1) { + ++sccCntGtW; + avgSccGtW += sccSize; + } + } + avgScc /= sccCnt; + avgSccGtW /= sccCntGtW; + int[] dist = new int[maxScc + 1]; + for (MergedNode scc : scccg.allNodes()) { + int sccSize = scc.getContent().size(); + dist[sccSize]++; + } + System.out.println("#scc count:" + sccCnt); + System.out.println("#scc count (exclude singleton):" + sccCntGtW); + System.out.println("Average scc size:" + avgScc); + System.out.println("Average scc size(exclude singleton):" + avgSccGtW); + System.out.println("Maximum scc size:" + maxScc); + System.out.println("Scc size distribution (size, count):"); + for (int i = 0; i <= maxScc; ++i) { + if (dist[i] > 0) { + System.out.println(i + "," + dist[i]); + } } + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java index 2434032e006..04081e05328 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Global.java @@ -1,87 +1,87 @@ package qilin.pta.toolkits.zipper; public class Global { - private static boolean debug = false; - private static String flow = null; - private static boolean enableWrappedFlow = true; - private static boolean enableUnwrappedFlow = true; - private static boolean isExpress = false; - public static final int UNDEFINE = -1; - private static int tst = UNDEFINE; - private static int thread = UNDEFINE; - private static float expressThreshold = 0.05f; - - public static void setDebug(final boolean debug) { - Global.debug = debug; - } - - public static boolean isDebug() { - return Global.debug; - } - - public static String getFlow() { - return Global.flow; - } - - public static void setFlow(String flow) { - Global.flow = flow; - } - - public static boolean isEnableWrappedFlow() { - return Global.enableWrappedFlow; - } - - public static void setEnableWrappedFlow(boolean enableWrappedFlow) { - Global.enableWrappedFlow = enableWrappedFlow; - } - - public static boolean isEnableUnwrappedFlow() { - return Global.enableUnwrappedFlow; - } - - public static void setEnableUnwrappedFlow(boolean enableUnwrappedFlow) { - Global.enableUnwrappedFlow = enableUnwrappedFlow; - } - - public static boolean isExpress() { - return Global.isExpress; - } - - public static void setExpress(final boolean isExpress) { - Global.isExpress = isExpress; - } - - public static int getTST() { - return Global.tst; - } - - public static void setTST(int tst) { - Global.tst = tst; - } - - public static int getThread() { - return thread; - } - - public static void setThread(int thread) { - Global.thread = thread; - } - - public static float getExpressThreshold() { - return expressThreshold; - } - - public static void setExpressThreshold(float expressThreshold) { - Global.expressThreshold = expressThreshold; - } - - private static boolean listContext = false; - - public static boolean isListContext() { - return listContext; - } - - public static void setListContext(boolean listContext) { - Global.listContext = listContext; - } + private static boolean debug = false; + private static String flow = null; + private static boolean enableWrappedFlow = true; + private static boolean enableUnwrappedFlow = true; + private static boolean isExpress = false; + public static final int UNDEFINE = -1; + private static int tst = UNDEFINE; + private static int thread = UNDEFINE; + private static float expressThreshold = 0.05f; + + public static void setDebug(final boolean debug) { + Global.debug = debug; + } + + public static boolean isDebug() { + return Global.debug; + } + + public static String getFlow() { + return Global.flow; + } + + public static void setFlow(String flow) { + Global.flow = flow; + } + + public static boolean isEnableWrappedFlow() { + return Global.enableWrappedFlow; + } + + public static void setEnableWrappedFlow(boolean enableWrappedFlow) { + Global.enableWrappedFlow = enableWrappedFlow; + } + + public static boolean isEnableUnwrappedFlow() { + return Global.enableUnwrappedFlow; + } + + public static void setEnableUnwrappedFlow(boolean enableUnwrappedFlow) { + Global.enableUnwrappedFlow = enableUnwrappedFlow; + } + + public static boolean isExpress() { + return Global.isExpress; + } + + public static void setExpress(final boolean isExpress) { + Global.isExpress = isExpress; + } + + public static int getTST() { + return Global.tst; + } + + public static void setTST(int tst) { + Global.tst = tst; + } + + public static int getThread() { + return thread; + } + + public static void setThread(int thread) { + Global.thread = thread; + } + + public static float getExpressThreshold() { + return expressThreshold; + } + + public static void setExpressThreshold(float expressThreshold) { + Global.expressThreshold = expressThreshold; + } + + private static boolean listContext = false; + + public static boolean isListContext() { + return listContext; + } + + public static void setListContext(boolean listContext) { + Global.listContext = listContext; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java index 33cb0d39f99..92b8d244ae7 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/Main.java @@ -18,42 +18,48 @@ package qilin.pta.toolkits.zipper; +import java.util.Comparator; +import java.util.Set; import qilin.core.PTA; import qilin.pta.toolkits.zipper.analysis.Zipper; import qilin.util.ANSIColor; import qilin.util.Stopwatch; import sootup.core.model.SootMethod; -import java.util.Comparator; -import java.util.Set; - public class Main { - public static void run(PTA pta, Set zipperPCMOutput) { - int numThreads = Runtime.getRuntime().availableProcessors(); - Global.setThread(numThreads); - Global.setExpress(false); - String zipperStr = Global.isExpress() ? "Zipper-e" : "Zipper"; - System.out.println(ANSIColor.BOLD + ANSIColor.YELLOW + zipperStr + " starts ..." + ANSIColor.RESET); - String flows = Global.getFlow() != null ? Global.getFlow() : "Direct+Wrapped+Unwrapped"; - System.out.println("Precision loss patterns: " + ANSIColor.BOLD + ANSIColor.GREEN + flows + ANSIColor.RESET); - Zipper.outputNumberOfClasses(pta); - Stopwatch zipperTimer = Stopwatch.newAndStart("Zipper Timer"); - Zipper zipper = new Zipper(pta); - Set pcm = zipper.analyze(); - zipperTimer.stop(); - System.out.print(ANSIColor.BOLD + ANSIColor.YELLOW + zipperStr + " finishes, analysis time: " + ANSIColor.RESET); - System.out.print(ANSIColor.BOLD + ANSIColor.GREEN); - System.out.printf("%.2fs", zipperTimer.elapsed()); - System.out.println(ANSIColor.RESET); - - System.out.println("Writing Zipper precision-critical methods ...\n"); - System.out.println(); - writeZipperResults(pcm, zipperPCMOutput); - } + public static void run(PTA pta, Set zipperPCMOutput) { + int numThreads = Runtime.getRuntime().availableProcessors(); + Global.setThread(numThreads); + Global.setExpress(false); + String zipperStr = Global.isExpress() ? "Zipper-e" : "Zipper"; + System.out.println( + ANSIColor.BOLD + ANSIColor.YELLOW + zipperStr + " starts ..." + ANSIColor.RESET); + String flows = Global.getFlow() != null ? Global.getFlow() : "Direct+Wrapped+Unwrapped"; + System.out.println( + "Precision loss patterns: " + ANSIColor.BOLD + ANSIColor.GREEN + flows + ANSIColor.RESET); + Zipper.outputNumberOfClasses(pta); + Stopwatch zipperTimer = Stopwatch.newAndStart("Zipper Timer"); + Zipper zipper = new Zipper(pta); + Set pcm = zipper.analyze(); + zipperTimer.stop(); + System.out.print( + ANSIColor.BOLD + + ANSIColor.YELLOW + + zipperStr + + " finishes, analysis time: " + + ANSIColor.RESET); + System.out.print(ANSIColor.BOLD + ANSIColor.GREEN); + System.out.printf("%.2fs", zipperTimer.elapsed()); + System.out.println(ANSIColor.RESET); - private static void writeZipperResults(final Set results, final Set outputSet) { - results.stream().sorted(Comparator.comparing(Object::toString)).forEach(outputSet::add); - } + System.out.println("Writing Zipper precision-critical methods ...\n"); + System.out.println(); + writeZipperResults(pcm, zipperPCMOutput); + } + private static void writeZipperResults( + final Set results, final Set outputSet) { + results.stream().sorted(Comparator.comparing(Object::toString)).forEach(outputSet::add); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java index c8936ade446..ba5863de396 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/PotentialContextElement.java @@ -1,5 +1,7 @@ package qilin.pta.toolkits.zipper.analysis; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.AllocNode; @@ -15,171 +17,192 @@ import sootup.core.model.SootMethod; import sootup.core.types.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - /** - * For each object o, this class compute the set of methods - * which o could potentially be their context element. - *

- * Conversely, for each method m, this class compute the - * set of objects which could potentially be its context element. + * For each object o, this class compute the set of methods which o could potentially be their + * context element. + * + *

Conversely, for each method m, this class compute the set of objects which could potentially + * be its context element. */ public class PotentialContextElement { - private final PTA pta; - // This map maps each object to the methods invoked on it. - // For instance methods, they are the methods whose receiver is the object. - // For static methods, they are the methods reachable from instance methods. - private Map> invokedMethods; - private Map> obj2invokedMethods; - private final Map> typePCEMethods; - private final Map> pceOfMap; - - private final OAG oag; - private final Map> typeAllocatees; - private final Map> allocateeMap; - - PotentialContextElement(final PTA pta, final OAG oag) { - this.pta = pta; - this.oag = oag; - this.typePCEMethods = new ConcurrentHashMap<>(); - this.obj2invokedMethods = new ConcurrentHashMap<>(); - this.pceOfMap = new ConcurrentHashMap<>(); - this.typeAllocatees = new ConcurrentHashMap<>(); - this.allocateeMap = new ConcurrentHashMap<>(); - this.init(oag); - } - - public Set PCEMethodsOf(final AllocNode obj) { - return this.pceOfMap.getOrDefault(obj, Collections.emptySet()); + private final PTA pta; + // This map maps each object to the methods invoked on it. + // For instance methods, they are the methods whose receiver is the object. + // For static methods, they are the methods reachable from instance methods. + private Map> invokedMethods; + private Map> obj2invokedMethods; + private final Map> typePCEMethods; + private final Map> pceOfMap; + + private final OAG oag; + private final Map> typeAllocatees; + private final Map> allocateeMap; + + PotentialContextElement(final PTA pta, final OAG oag) { + this.pta = pta; + this.oag = oag; + this.typePCEMethods = new ConcurrentHashMap<>(); + this.obj2invokedMethods = new ConcurrentHashMap<>(); + this.pceOfMap = new ConcurrentHashMap<>(); + this.typeAllocatees = new ConcurrentHashMap<>(); + this.allocateeMap = new ConcurrentHashMap<>(); + this.init(oag); + } + + public Set PCEMethodsOf(final AllocNode obj) { + return this.pceOfMap.getOrDefault(obj, Collections.emptySet()); + } + + /** + * @param type + * @return PCE methods of the objects of given type. + */ + public Set PCEMethodsOf(final Type type) { + if (!this.typePCEMethods.containsKey(type)) { + final Set methods = ConcurrentHashMap.newKeySet(); + pta.getPag().getAllocNodes().stream() + .filter(o -> o.getType().equals(type)) + .forEach(obj -> methods.addAll(this.PCEMethodsOf(obj))); + this.typePCEMethods.put(type, methods); } - - /** - * @param type - * @return PCE methods of the objects of given type. - */ - public Set PCEMethodsOf(final Type type) { - if (!this.typePCEMethods.containsKey(type)) { - final Set methods = ConcurrentHashMap.newKeySet(); - pta.getPag().getAllocNodes().stream(). - filter(o -> o.getType().equals(type)). - forEach(obj -> methods.addAll(this.PCEMethodsOf(obj))); - this.typePCEMethods.put(type, methods); - } - return this.typePCEMethods.getOrDefault(type, Collections.emptySet()); - } - - /** - * Compute PCE methods for each objects. - */ - private void init(final OAG oag) { - final SCCMergedGraph mg = new SCCMergedGraph<>(oag); - final TopologicalSorter> topoSorter = new TopologicalSorter<>(); - final SetFactory setFactory = new SetFactory<>(); - final SetFactory setFactory2 = new SetFactory<>(); - this.buildMethodsInvokedOnObjects(); - this.invokedMethods = new HashMap<>(); - topoSorter.sort(mg, true).forEach(node -> { - final Set methods = ConcurrentHashMap.newKeySet(); - methods.addAll(setFactory.get(this.getPCEMethods(node, mg))); - final Set allocatees = ConcurrentHashMap.newKeySet(); - allocatees.addAll(setFactory2.get(this.getAllocatees(node, mg))); - node.getContent().forEach(obj -> { - pceOfMap.put(obj, methods); - allocateeMap.put(obj, allocatees); + return this.typePCEMethods.getOrDefault(type, Collections.emptySet()); + } + + /** Compute PCE methods for each objects. */ + private void init(final OAG oag) { + final SCCMergedGraph mg = new SCCMergedGraph<>(oag); + final TopologicalSorter> topoSorter = new TopologicalSorter<>(); + final SetFactory setFactory = new SetFactory<>(); + final SetFactory setFactory2 = new SetFactory<>(); + this.buildMethodsInvokedOnObjects(); + this.invokedMethods = new HashMap<>(); + topoSorter + .sort(mg, true) + .forEach( + node -> { + final Set methods = ConcurrentHashMap.newKeySet(); + methods.addAll(setFactory.get(this.getPCEMethods(node, mg))); + final Set allocatees = ConcurrentHashMap.newKeySet(); + allocatees.addAll(setFactory2.get(this.getAllocatees(node, mg))); + node.getContent() + .forEach( + obj -> { + pceOfMap.put(obj, methods); + allocateeMap.put(obj, allocatees); + }); }); - }); - this.invokedMethods = null; - if (Global.isDebug()) { - this.computePCEObjects(); - } - - oag.allNodes().forEach(obj -> { - final Type type = obj.getType(); - this.typeAllocatees.putIfAbsent(type, new HashSet<>()); - this.typeAllocatees.get(type).addAll(this.allocateesOf(obj)); - }); - } - - private Set getAllocatees(final MergedNode node, final SCCMergedGraph mg) { - final Set allocatees = new HashSet<>(); - mg.succsOf(node).forEach(n -> { - // direct allocatees - allocatees.addAll(n.getContent()); - // indirect allocatees, here, it does not require to traverse all heaps in n.getContent() - // because of lines 104-107. - final AllocNode o = n.getContent().iterator().next(); - allocatees.addAll(this.allocateesOf(o)); - }); - final AllocNode obj = node.getContent().iterator().next(); - if (node.getContent().size() > 1 || oag.succsOf(obj).contains(obj)) { - // The merged node is a true SCC - allocatees.addAll(node.getContent()); - } - return allocatees; - } - - private Set allocateesOf(final AllocNode obj) { - return this.allocateeMap.getOrDefault(obj, Collections.emptySet()); + this.invokedMethods = null; + if (Global.isDebug()) { + this.computePCEObjects(); } - public Set allocateesOf(final Type type) { - return this.typeAllocatees.getOrDefault(type, Collections.emptySet()); - } - - private Set getPCEMethods(final MergedNode node, final SCCMergedGraph mg) { - final Set methods = new HashSet<>(); - mg.succsOf(node).forEach(n -> { - final AllocNode o2 = n.getContent().iterator().next(); - methods.addAll(this.PCEMethodsOf(o2)); - }); - node.getContent().forEach(o -> methods.addAll(this.invokedMethodsOf(o))); - return methods; - } - - public Set methodsInvokedOn(final AllocNode obj) { - return this.obj2invokedMethods.getOrDefault(obj, Collections.emptySet()); + oag.allNodes() + .forEach( + obj -> { + final Type type = obj.getType(); + this.typeAllocatees.putIfAbsent(type, new HashSet<>()); + this.typeAllocatees.get(type).addAll(this.allocateesOf(obj)); + }); + } + + private Set getAllocatees( + final MergedNode node, final SCCMergedGraph mg) { + final Set allocatees = new HashSet<>(); + mg.succsOf(node) + .forEach( + n -> { + // direct allocatees + allocatees.addAll(n.getContent()); + // indirect allocatees, here, it does not require to traverse all heaps in + // n.getContent() + // because of lines 104-107. + final AllocNode o = n.getContent().iterator().next(); + allocatees.addAll(this.allocateesOf(o)); + }); + final AllocNode obj = node.getContent().iterator().next(); + if (node.getContent().size() > 1 || oag.succsOf(obj).contains(obj)) { + // The merged node is a true SCC + allocatees.addAll(node.getContent()); } - - private void buildMethodsInvokedOnObjects() { - this.obj2invokedMethods = new HashMap<>(); - pta.getNakedReachableMethods().stream().filter(m -> !m.isStatic()).forEach(instMtd -> { - MethodNodeFactory mthdNF = pta.getPag().getMethodPAG(instMtd).nodeFactory(); - VarNode thisVar = mthdNF.caseThis(); - PointsToSet pts = pta.reachingObjects(thisVar).toCIPointsToSet(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { + return allocatees; + } + + private Set allocateesOf(final AllocNode obj) { + return this.allocateeMap.getOrDefault(obj, Collections.emptySet()); + } + + public Set allocateesOf(final Type type) { + return this.typeAllocatees.getOrDefault(type, Collections.emptySet()); + } + + private Set getPCEMethods( + final MergedNode node, final SCCMergedGraph mg) { + final Set methods = new HashSet<>(); + mg.succsOf(node) + .forEach( + n -> { + final AllocNode o2 = n.getContent().iterator().next(); + methods.addAll(this.PCEMethodsOf(o2)); + }); + node.getContent().forEach(o -> methods.addAll(this.invokedMethodsOf(o))); + return methods; + } + + public Set methodsInvokedOn(final AllocNode obj) { + return this.obj2invokedMethods.getOrDefault(obj, Collections.emptySet()); + } + + private void buildMethodsInvokedOnObjects() { + this.obj2invokedMethods = new HashMap<>(); + pta.getNakedReachableMethods().stream() + .filter(m -> !m.isStatic()) + .forEach( + instMtd -> { + MethodNodeFactory mthdNF = pta.getPag().getMethodPAG(instMtd).nodeFactory(); + VarNode thisVar = mthdNF.caseThis(); + PointsToSet pts = pta.reachingObjects(thisVar).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { AllocNode obj = it.next(); obj2invokedMethods.computeIfAbsent(obj, k -> new HashSet<>()).add(instMtd); - } - }); - } - - private Set invokedMethodsOf(final AllocNode obj) { - if (!this.invokedMethods.containsKey(obj)) { - final Set methods = new HashSet<>(); - final Queue queue = new LinkedList<>(this.methodsInvokedOn(obj)); - while (!queue.isEmpty()) { - final SootMethod method = queue.poll(); - methods.add(method); - pta.getCallGraph().edgesOutOf(new ContextMethod(method, pta.emptyContext())).forEachRemaining(edge -> { - SootMethod callee = edge.getTgt().method(); - if (callee.isStatic() && !methods.contains(callee)) { - queue.offer(callee); - } + } + }); + } + + private Set invokedMethodsOf(final AllocNode obj) { + if (!this.invokedMethods.containsKey(obj)) { + final Set methods = new HashSet<>(); + final Queue queue = new LinkedList<>(this.methodsInvokedOn(obj)); + while (!queue.isEmpty()) { + final SootMethod method = queue.poll(); + methods.add(method); + pta.getCallGraph() + .edgesOutOf(new ContextMethod(method, pta.emptyContext())) + .forEachRemaining( + edge -> { + SootMethod callee = edge.getTgt().method(); + if (callee.isStatic() && !methods.contains(callee)) { + queue.offer(callee); + } }); - } - this.invokedMethods.put(obj, methods); - } - return this.invokedMethods.get(obj); - } - - private void computePCEObjects() { - final Map> pceObjs = new HashMap<>(); - pta.getPag().getAllocNodes().forEach(obj -> this.PCEMethodsOf(obj).forEach(method -> { - if (!pceObjs.containsKey(method)) { - pceObjs.put(method, new HashSet<>()); - } - pceObjs.get(method).add(obj); - })); + } + this.invokedMethods.put(obj, methods); } + return this.invokedMethods.get(obj); + } + + private void computePCEObjects() { + final Map> pceObjs = new HashMap<>(); + pta.getPag() + .getAllocNodes() + .forEach( + obj -> + this.PCEMethodsOf(obj) + .forEach( + method -> { + if (!pceObjs.containsKey(method)) { + pceObjs.put(method, new HashSet<>()); + } + pceObjs.get(method).add(obj); + })); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java index 067dfff3acd..20694cae444 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/analysis/Zipper.java @@ -1,5 +1,14 @@ package qilin.pta.toolkits.zipper.analysis; +import static qilin.util.ANSIColor.color; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.pag.*; import qilin.pta.toolkits.common.OAG; @@ -14,299 +23,310 @@ import sootup.core.types.ClassType; import sootup.core.types.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import static qilin.util.ANSIColor.color; - /** - * Main class of Zipper, which computes precision-critical methods - * in the program being analyzed. + * Main class of Zipper, which computes precision-critical methods in the program being analyzed. */ public class Zipper { - private final PTA pta; - private final PotentialContextElement pce; - private final ObjectFlowGraph ofg; - private final AtomicInteger analyzedClasses = new AtomicInteger(0); - private final AtomicInteger totalPFGNodes = new AtomicInteger(0); - private final AtomicInteger totalPFGEdges = new AtomicInteger(0); - private final ConcurrentDirectedGraphImpl overallPFG = new ConcurrentDirectedGraphImpl<>(); - private final Map methodPts; - private final Map> pcmMap = new ConcurrentHashMap<>(1024); + private final PTA pta; + private final PotentialContextElement pce; + private final ObjectFlowGraph ofg; + private final AtomicInteger analyzedClasses = new AtomicInteger(0); + private final AtomicInteger totalPFGNodes = new AtomicInteger(0); + private final AtomicInteger totalPFGEdges = new AtomicInteger(0); + private final ConcurrentDirectedGraphImpl overallPFG = new ConcurrentDirectedGraphImpl<>(); + private final Map methodPts; + private final Map> pcmMap = new ConcurrentHashMap<>(1024); - public Zipper(PTA pta) { - this.pta = pta; - OAG oag = new OAG(pta); - oag.build(); - System.out.println("#OAG:" + oag.allNodes().size()); - this.pce = new PotentialContextElement(pta, oag); - this.ofg = buildObjectFlowGraph(); - this.methodPts = getMethodPointsToSize(); - } + public Zipper(PTA pta) { + this.pta = pta; + OAG oag = new OAG(pta); + oag.build(); + System.out.println("#OAG:" + oag.allNodes().size()); + this.pce = new PotentialContextElement(pta, oag); + this.ofg = buildObjectFlowGraph(); + this.methodPts = getMethodPointsToSize(); + } - public static void outputNumberOfClasses(PTA pta) { - int nrClasses = (int) pta.getPag().getAllocNodes().stream() - .map(AllocNode::getType) - .distinct() - .count(); - System.out.println("#classes: " + ANSIColor.BOLD + ANSIColor.GREEN + nrClasses + ANSIColor.RESET); - System.out.println(); - } + public static void outputNumberOfClasses(PTA pta) { + int nrClasses = + (int) pta.getPag().getAllocNodes().stream().map(AllocNode::getType).distinct().count(); + System.out.println( + "#classes: " + ANSIColor.BOLD + ANSIColor.GREEN + nrClasses + ANSIColor.RESET); + System.out.println(); + } - public int numberOfOverallPFGNodes() { - return overallPFG.allNodes().size(); - } + public int numberOfOverallPFGNodes() { + return overallPFG.allNodes().size(); + } - public int numberOfOverallPFGEdges() { - int nrEdges = 0; - for (Node node : overallPFG.allNodes()) { - nrEdges += overallPFG.succsOf(node).size(); - } - return nrEdges; + public int numberOfOverallPFGEdges() { + int nrEdges = 0; + for (Node node : overallPFG.allNodes()) { + nrEdges += overallPFG.succsOf(node).size(); } + return nrEdges; + } - public ObjectFlowGraph buildObjectFlowGraph() { - Stopwatch ofgTimer = Stopwatch.newAndStart("Object Flow Graph Timer"); - System.out.println("Building OFG (Object Flow Graph) ... "); - ObjectFlowGraph ofg = new ObjectFlowGraph(pta); - ofgTimer.stop(); - System.out.println(ofgTimer); - outputObjectFlowGraphSize(ofg); - return ofg; - } + public ObjectFlowGraph buildObjectFlowGraph() { + Stopwatch ofgTimer = Stopwatch.newAndStart("Object Flow Graph Timer"); + System.out.println("Building OFG (Object Flow Graph) ... "); + ObjectFlowGraph ofg = new ObjectFlowGraph(pta); + ofgTimer.stop(); + System.out.println(ofgTimer); + outputObjectFlowGraphSize(ofg); + return ofg; + } - public static void outputObjectFlowGraphSize(ObjectFlowGraph ofg) { - int nrNodes = ofg.allNodes().size(); - int nrEdges = 0; - for (Node node : ofg.allNodes()) { - nrEdges += ofg.outEdgesOf(node).size(); - } - - System.out.println("#nodes in OFG: " + ANSIColor.BOLD + ANSIColor.GREEN + nrNodes + ANSIColor.RESET); - System.out.println("#edges in OFG: " + ANSIColor.BOLD + ANSIColor.GREEN + nrEdges + ANSIColor.RESET); - System.out.println(); + public static void outputObjectFlowGraphSize(ObjectFlowGraph ofg) { + int nrNodes = ofg.allNodes().size(); + int nrEdges = 0; + for (Node node : ofg.allNodes()) { + nrEdges += ofg.outEdgesOf(node).size(); } - /** - * @return set of precision-critical methods in the program - */ - public Set analyze() { - reset(); - System.out.println("Building PFGs (Pollution Flow Graphs) and computing precision-critical methods ..."); - List types = pta.getPag().getAllocNodes().stream() - .map(AllocNode::getType) - .distinct() - .sorted(Comparator.comparing(Type::toString)) - .filter(t -> t instanceof ClassType) - .map(t -> (ClassType) t) - .collect(Collectors.toList()); - if (Global.getThread() == Global.UNDEFINE) { - computePCM(types); - } else { - computePCMConcurrent(types, Global.getThread()); - } - System.out.println("#avg. nodes in PFG: " + ANSIColor.BOLD + ANSIColor.GREEN + - Math.round(totalPFGNodes.floatValue() / analyzedClasses.get()) + ANSIColor.RESET); - System.out.println("#avg. edges in PFG: " + ANSIColor.BOLD + ANSIColor.GREEN + - Math.round(totalPFGEdges.floatValue() / analyzedClasses.get()) + ANSIColor.RESET); - System.out.println("#Node:" + totalPFGNodes.intValue()); - System.out.println("#Edge:" + totalPFGEdges.intValue()); - System.out.println("#Node2:" + numberOfOverallPFGNodes()); - System.out.println("#Edge2:" + numberOfOverallPFGEdges()); - System.out.println(); + System.out.println( + "#nodes in OFG: " + ANSIColor.BOLD + ANSIColor.GREEN + nrNodes + ANSIColor.RESET); + System.out.println( + "#edges in OFG: " + ANSIColor.BOLD + ANSIColor.GREEN + nrEdges + ANSIColor.RESET); + System.out.println(); + } - Set pcm = collectAllPrecisionCriticalMethods(pcmMap, - computePCMThreshold()); - System.out.println("#Precision-critical methods: " + ANSIColor.BOLD + ANSIColor.GREEN + pcm.size() + ANSIColor.RESET); - return pcm; + /** + * @return set of precision-critical methods in the program + */ + public Set analyze() { + reset(); + System.out.println( + "Building PFGs (Pollution Flow Graphs) and computing precision-critical methods ..."); + List types = + pta.getPag().getAllocNodes().stream() + .map(AllocNode::getType) + .distinct() + .sorted(Comparator.comparing(Type::toString)) + .filter(t -> t instanceof ClassType) + .map(t -> (ClassType) t) + .collect(Collectors.toList()); + if (Global.getThread() == Global.UNDEFINE) { + computePCM(types); + } else { + computePCMConcurrent(types, Global.getThread()); } + System.out.println( + "#avg. nodes in PFG: " + + ANSIColor.BOLD + + ANSIColor.GREEN + + Math.round(totalPFGNodes.floatValue() / analyzedClasses.get()) + + ANSIColor.RESET); + System.out.println( + "#avg. edges in PFG: " + + ANSIColor.BOLD + + ANSIColor.GREEN + + Math.round(totalPFGEdges.floatValue() / analyzedClasses.get()) + + ANSIColor.RESET); + System.out.println("#Node:" + totalPFGNodes.intValue()); + System.out.println("#Edge:" + totalPFGEdges.intValue()); + System.out.println("#Node2:" + numberOfOverallPFGNodes()); + System.out.println("#Edge2:" + numberOfOverallPFGEdges()); + System.out.println(); - private void computePCM(List types) { - FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); - types.forEach(type -> analyze(type, fa)); - } + Set pcm = collectAllPrecisionCriticalMethods(pcmMap, computePCMThreshold()); + System.out.println( + "#Precision-critical methods: " + + ANSIColor.BOLD + + ANSIColor.GREEN + + pcm.size() + + ANSIColor.RESET); + return pcm; + } - private void computePCMConcurrent(List types, int nThread) { - ExecutorService executorService = Executors.newFixedThreadPool(nThread); - types.forEach(type -> - executorService.execute(() -> { - FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); - analyze(type, fa); + private void computePCM(List types) { + FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); + types.forEach(type -> analyze(type, fa)); + } + + private void computePCMConcurrent(List types, int nThread) { + ExecutorService executorService = Executors.newFixedThreadPool(nThread); + types.forEach( + type -> + executorService.execute( + () -> { + FlowAnalysis fa = new FlowAnalysis(pta, pce, ofg); + analyze(type, fa); })); - executorService.shutdown(); - try { - executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + executorService.shutdown(); + try { + executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); } + } - /** - * @param type - * @param fa Compute the set of precision-critical methods for a class/type and add these methods - * to the pcm collection. - */ - private void analyze(ClassType type, FlowAnalysis fa) { - if (Global.isDebug()) { - System.out.println("----------------------------------------"); - } - // System.out.println(color(YELLOW, "Zipper: analyzing ") + type); - - // Obtain all methods of type (including inherited methods) - Set ms = pta.getPag().getAllocNodes().stream(). - filter(o -> o.getType().equals(type)) - .map(pce::methodsInvokedOn) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); - if (type.toString().equals("java.util.HashMap")) { - System.out.println("ssssss"); - } - // Obtain IN methods - Set inms = ms.stream() - .filter(m -> !m.isPrivate()) - .filter(m -> ToolUtil.getParameters(pta.getPag(), m).stream() - .anyMatch(p -> !pta.reachingObjects(p).toCIPointsToSet().isEmpty())) - .collect(Collectors.toSet()); + /** + * @param type + * @param fa Compute the set of precision-critical methods for a class/type and add these methods + * to the pcm collection. + */ + private void analyze(ClassType type, FlowAnalysis fa) { + if (Global.isDebug()) { + System.out.println("----------------------------------------"); + } + // System.out.println(color(YELLOW, "Zipper: analyzing ") + type); - // Obtain OUT methods - Set outms = new HashSet<>(); + // Obtain all methods of type (including inherited methods) + Set ms = + pta.getPag().getAllocNodes().stream() + .filter(o -> o.getType().equals(type)) + .map(pce::methodsInvokedOn) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + if (type.toString().equals("java.util.HashMap")) { + System.out.println("ssssss"); + } + // Obtain IN methods + Set inms = ms.stream() - .filter(m -> !m.isPrivate()) - .filter(m -> ToolUtil.getRetVars(pta.getPag(), m).stream() - .anyMatch(r -> !pta.reachingObjects(r).toCIPointsToSet().isEmpty())) - .forEach(outms::add); + .filter(m -> !m.isPrivate()) + .filter( + m -> + ToolUtil.getParameters(pta.getPag(), m).stream() + .anyMatch(p -> !pta.reachingObjects(p).toCIPointsToSet().isEmpty())) + .collect(Collectors.toSet()); - // OUT methods of inner classes and special access$ methods - // are also considered as the OUT methods of current type - pce.PCEMethodsOf(type).stream() - .filter(m -> !m.isPrivate() && !m.isStatic()) - .filter(m -> ToolUtil.isInnerType( - m.getDeclaringClassType(), type)) - .forEach(outms::add); - pce.PCEMethodsOf(type).stream() - .filter(m -> !m.isPrivate() && !m.isStatic()) - .filter(m -> m.getDeclaringClassType().equals(type) - && m.toString().contains("access$")) - .forEach(outms::add); + // Obtain OUT methods + Set outms = new HashSet<>(); + ms.stream() + .filter(m -> !m.isPrivate()) + .filter( + m -> + ToolUtil.getRetVars(pta.getPag(), m).stream() + .anyMatch(r -> !pta.reachingObjects(r).toCIPointsToSet().isEmpty())) + .forEach(outms::add); - if (Global.isDebug()) { - System.out.println(color(ANSIColor.YELLOW, "In methods:")); - inms.stream() - .sorted(Comparator.comparing(SootMethod::toString)) - .forEach(m -> System.out.println(" " + m)); - System.out.println(color(ANSIColor.YELLOW, "Out methods:")); - outms.stream() - .sorted(Comparator.comparing(SootMethod::toString)) - .forEach(m -> System.out.println(" " + m)); - } + // OUT methods of inner classes and special access$ methods + // are also considered as the OUT methods of current type + pce.PCEMethodsOf(type).stream() + .filter(m -> !m.isPrivate() && !m.isStatic()) + .filter(m -> ToolUtil.isInnerType(m.getDeclaringClassType(), type)) + .forEach(outms::add); + pce.PCEMethodsOf(type).stream() + .filter(m -> !m.isPrivate() && !m.isStatic()) + .filter(m -> m.getDeclaringClassType().equals(type) && m.toString().contains("access$")) + .forEach(outms::add); - fa.initialize(type, inms, outms); - inms.forEach(fa::analyze); - Set flowNodes = fa.getFlowNodes(); - Set precisionCriticalMethods = getPrecisionCriticalMethods(type, flowNodes); - if (Global.isDebug()) { - if (!precisionCriticalMethods.isEmpty()) { - System.out.println(color(ANSIColor.BLUE, "Flow found: ") + type); - } - } - mergeAnalysisResults(type, fa.numberOfPFGNodes(), fa.numberOfPFGEdges(), precisionCriticalMethods); - mergeSinglePFG(fa.getPFG()); - fa.clear(); + if (Global.isDebug()) { + System.out.println(color(ANSIColor.YELLOW, "In methods:")); + inms.stream() + .sorted(Comparator.comparing(SootMethod::toString)) + .forEach(m -> System.out.println(" " + m)); + System.out.println(color(ANSIColor.YELLOW, "Out methods:")); + outms.stream() + .sorted(Comparator.comparing(SootMethod::toString)) + .forEach(m -> System.out.println(" " + m)); } - private void mergeSinglePFG(ConcurrentDirectedGraphImpl pfg) { - for (Node node : pfg.allNodes()) { - this.overallPFG.addNode(node); - for (Node succ : pfg.succsOf(node)) { - this.overallPFG.addEdge(node, succ); - } - } + fa.initialize(type, inms, outms); + inms.forEach(fa::analyze); + Set flowNodes = fa.getFlowNodes(); + Set precisionCriticalMethods = getPrecisionCriticalMethods(type, flowNodes); + if (Global.isDebug()) { + if (!precisionCriticalMethods.isEmpty()) { + System.out.println(color(ANSIColor.BLUE, "Flow found: ") + type); + } } + mergeAnalysisResults( + type, fa.numberOfPFGNodes(), fa.numberOfPFGEdges(), precisionCriticalMethods); + mergeSinglePFG(fa.getPFG()); + fa.clear(); + } - private void mergeAnalysisResults(Type type, int nrPFGNodes, int nrPFGEdges, Set precisionCriticalMethods) { - analyzedClasses.incrementAndGet(); - totalPFGNodes.addAndGet(nrPFGNodes); - totalPFGEdges.addAndGet(nrPFGEdges); - pcmMap.put(type, new ArrayList<>(precisionCriticalMethods)); + private void mergeSinglePFG(ConcurrentDirectedGraphImpl pfg) { + for (Node node : pfg.allNodes()) { + this.overallPFG.addNode(node); + for (Node succ : pfg.succsOf(node)) { + this.overallPFG.addEdge(node, succ); + } } + } + + private void mergeAnalysisResults( + Type type, int nrPFGNodes, int nrPFGEdges, Set precisionCriticalMethods) { + analyzedClasses.incrementAndGet(); + totalPFGNodes.addAndGet(nrPFGNodes); + totalPFGEdges.addAndGet(nrPFGEdges); + pcmMap.put(type, new ArrayList<>(precisionCriticalMethods)); + } - private Set collectAllPrecisionCriticalMethods( - Map> pcmMap, int pcmThreshold) { - System.out.println("PCM Threshold:" + pcmThreshold); - Set pcm = new HashSet<>(); - pcmMap.forEach((type, pcms) -> { - if (Global.isExpress() && - getAccumulativePointsToSetSize(pcms) > pcmThreshold) { - System.out.println("type: " + type + ", accumulativePTSize: " + getAccumulativePointsToSetSize(pcms)); - return; - } - pcm.addAll(pcms); + private Set collectAllPrecisionCriticalMethods( + Map> pcmMap, int pcmThreshold) { + System.out.println("PCM Threshold:" + pcmThreshold); + Set pcm = new HashSet<>(); + pcmMap.forEach( + (type, pcms) -> { + if (Global.isExpress() && getAccumulativePointsToSetSize(pcms) > pcmThreshold) { + System.out.println( + "type: " + type + ", accumulativePTSize: " + getAccumulativePointsToSetSize(pcms)); + return; + } + pcm.addAll(pcms); }); - return pcm; - } + return pcm; + } - private int computePCMThreshold() { - // Use points-to size of whole program as denominator - int totalPTSSize = 0; - for (ValNode var : pta.getPag().getValNodes()) { - if (var instanceof VarNode varNode) { -// Collection pts = ToolUtil.pointsToSetOf(pta, varNode); - totalPTSSize += pta.reachingObjects(varNode).toCIPointsToSet().size(); - } - } - return (int) (Global.getExpressThreshold() * totalPTSSize); + private int computePCMThreshold() { + // Use points-to size of whole program as denominator + int totalPTSSize = 0; + for (ValNode var : pta.getPag().getValNodes()) { + if (var instanceof VarNode varNode) { + // Collection pts = ToolUtil.pointsToSetOf(pta, varNode); + totalPTSSize += pta.reachingObjects(varNode).toCIPointsToSet().size(); + } } + return (int) (Global.getExpressThreshold() * totalPTSSize); + } - private Set getPrecisionCriticalMethods(Type type, Set nodes) { - return nodes.stream() - .map(this::node2ContainingMethod) - .filter(Objects::nonNull) - .filter(pce.PCEMethodsOf(type)::contains) - .collect(Collectors.toSet()); - } + private Set getPrecisionCriticalMethods(Type type, Set nodes) { + return nodes.stream() + .map(this::node2ContainingMethod) + .filter(Objects::nonNull) + .filter(pce.PCEMethodsOf(type)::contains) + .collect(Collectors.toSet()); + } - private SootMethod node2ContainingMethod(Node node) { - if (node instanceof LocalVarNode lvn) { - return lvn.getMethod(); - } else { - ContextField ctxField = (ContextField) node; - return ctxField.getBase().getMethod(); - } + private SootMethod node2ContainingMethod(Node node) { + if (node instanceof LocalVarNode lvn) { + return lvn.getMethod(); + } else { + ContextField ctxField = (ContextField) node; + return ctxField.getBase().getMethod(); } + } - private void reset() { - analyzedClasses.set(0); - totalPFGNodes.set(0); - totalPFGEdges.set(0); - pcmMap.clear(); - } + private void reset() { + analyzedClasses.set(0); + totalPFGNodes.set(0); + totalPFGEdges.set(0); + pcmMap.clear(); + } - private Map getMethodPointsToSize() { - Map results = new HashMap<>(); - for (ValNode valnode : pta.getPag().getValNodes()) { - if (!(valnode instanceof LocalVarNode lvn)) { - continue; - } - SootMethod inMethod = lvn.getMethod(); - int ptSize = ToolUtil.pointsToSetSizeOf(pta, lvn); - if (results.containsKey(inMethod)) { - int oldValue = results.get(inMethod); - results.replace(inMethod, oldValue, oldValue + ptSize); - } else { - results.put(inMethod, ptSize); - } - } - return results; + private Map getMethodPointsToSize() { + Map results = new HashMap<>(); + for (ValNode valnode : pta.getPag().getValNodes()) { + if (!(valnode instanceof LocalVarNode lvn)) { + continue; + } + SootMethod inMethod = lvn.getMethod(); + int ptSize = ToolUtil.pointsToSetSizeOf(pta, lvn); + if (results.containsKey(inMethod)) { + int oldValue = results.get(inMethod); + results.replace(inMethod, oldValue, oldValue + ptSize); + } else { + results.put(inMethod, ptSize); + } } + return results; + } - private long getAccumulativePointsToSetSize(Collection methods) { - return methods.stream() - .mapToInt(methodPts::get) - .sum(); - } -} \ No newline at end of file + private long getAccumulativePointsToSetSize(Collection methods) { + return methods.stream().mapToInt(methodPts::get).sum(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java index 2f1b0262ca3..68fb22135c0 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseA.java @@ -2,18 +2,18 @@ // NO IN , NO OUT, CASE 4. public class CaseA { - static class A { - Object f; - } + static class A { + Object f; + } - A create() { - return new A(); - } + A create() { + return new A(); + } - void foo() { - Object o = new Object(); - A a = create(); - a.f = o; - o = a.f; - } + void foo() { + Object o = new Object(); + A a = create(); + a.f = o; + o = a.f; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java index 0d3084bb9ad..301fa7d0d63 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseB.java @@ -2,24 +2,24 @@ // No Out, case 2 public class CaseB { - static class A { - Object f; + static class A { + Object f; - void bar(Object q) { - this.f = q; - } + void bar(Object q) { + this.f = q; } + } - void foo() { - Object oy = new Object(); - Object oz = new Object(); + void foo() { + Object oy = new Object(); + Object oz = new Object(); - A a = new A(); - a.bar(oy); - Object o = a.f; + A a = new A(); + a.bar(oy); + Object o = a.f; -// A a1 = new A(); -// a1.bar(oz); -// Object o1 = a1.f; - } + // A a1 = new A(); + // a1.bar(oz); + // Object o1 = a1.f; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java index 9a8eb9a75a8..5e1e4e5fbdb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseC.java @@ -1,35 +1,35 @@ package qilin.pta.toolkits.zipper.cases; public class CaseC { - static class A { - Object f; - } + static class A { + Object f; + } - A f; + A f; - // case 2; - CaseC() { - A a = new A(); - this.f = a; - } + // case 2; + CaseC() { + A a = new A(); + this.f = a; + } - // does not consider this_variable. - A getF() { - A r = this.f; - return r; - } + // does not consider this_variable. + A getF() { + A r = this.f; + return r; + } - void foo() { - Object o1 = new Object(); - CaseC c1 = new CaseC(); - A a1 = c1.getF(); - a1.f = o1; - Object o1x = a1.f; + void foo() { + Object o1 = new Object(); + CaseC c1 = new CaseC(); + A a1 = c1.getF(); + a1.f = o1; + Object o1x = a1.f; -// Object o2 = new Object(); -// CaseC c2 = new CaseC(); -// A a2 = c2.getF(); -// a2.f = o2; -// Object o2x = a2.f; - } + // Object o2 = new Object(); + // CaseC c2 = new CaseC(); + // A a2 = c2.getF(); + // a2.f = o2; + // Object o2x = a2.f; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java index f799dccea5c..db452344624 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/cases/CaseD.java @@ -1,21 +1,21 @@ package qilin.pta.toolkits.zipper.cases; public class CaseD { - static class A { - Object f, g; - } + static class A { + Object f, g; + } - Object id(Object p) { - A a = new A(); - a.f = p; - Object r = a.f; - return r; - } + Object id(Object p) { + A a = new A(); + a.f = p; + Object r = a.f; + return r; + } - Object fakeId(Object p) { - A a = new A(); - a.f = p; - a.g = new Object(); - return a.g; - } + Object fakeId(Object p) { + A a = new A(); + a.f = p; + a.g = new Object(); + return a.g; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java index 4bad0783246..baf76ae0e0d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Edge.java @@ -1,59 +1,60 @@ package qilin.pta.toolkits.zipper.flowgraph; -import qilin.core.pag.Node; - import java.util.Objects; +import qilin.core.pag.Node; public class Edge { - private final Kind kind; - private final Node source; - private final Node target; - private final int hashCode; - - public Edge(final Kind kind, final Node source, final Node target) { - this.kind = kind; - this.source = source; - this.target = target; - this.hashCode = Objects.hash(kind, source, target); - } - - public Kind getKind() { - return this.kind; - } - - public Node getSource() { - return this.source; - } - - public Node getTarget() { - return this.target; - } - - @Override - public String toString() { - return this.kind + ": " + this.source + " --> " + this.target; - } - - @Override - public int hashCode() { - return this.hashCode; - } - - @Override - public boolean equals(final Object other) { - if (this.isOFGEdge()) { - return this == other; - } - if (this == other) { - return true; - } - if (!(other instanceof final Edge otherEdge)) { - return false; - } - return this.kind.equals(otherEdge.kind) && this.source.equals(otherEdge.source) && this.target.equals(otherEdge.target); - } - - private boolean isOFGEdge() { - return this.kind != Kind.WRAPPED_FLOW && this.kind != Kind.UNWRAPPED_FLOW; - } + private final Kind kind; + private final Node source; + private final Node target; + private final int hashCode; + + public Edge(final Kind kind, final Node source, final Node target) { + this.kind = kind; + this.source = source; + this.target = target; + this.hashCode = Objects.hash(kind, source, target); + } + + public Kind getKind() { + return this.kind; + } + + public Node getSource() { + return this.source; + } + + public Node getTarget() { + return this.target; + } + + @Override + public String toString() { + return this.kind + ": " + this.source + " --> " + this.target; + } + + @Override + public int hashCode() { + return this.hashCode; + } + + @Override + public boolean equals(final Object other) { + if (this.isOFGEdge()) { + return this == other; + } + if (this == other) { + return true; + } + if (!(other instanceof final Edge otherEdge)) { + return false; + } + return this.kind.equals(otherEdge.kind) + && this.source.equals(otherEdge.source) + && this.target.equals(otherEdge.target); + } + + private boolean isOFGEdge() { + return this.kind != Kind.WRAPPED_FLOW && this.kind != Kind.UNWRAPPED_FLOW; + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java index 39b29874e4a..9fd53125991 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/FlowAnalysis.java @@ -1,5 +1,9 @@ package qilin.pta.toolkits.zipper.flowgraph; +import static qilin.util.ANSIColor.color; + +import java.util.*; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.pag.*; import qilin.pta.toolkits.common.ToolUtil; @@ -17,256 +21,262 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.*; -import java.util.stream.Collectors; - -import static qilin.util.ANSIColor.color; - public class FlowAnalysis { - private final PTA pta; - private final PotentialContextElement pce; - private final ObjectFlowGraph objectFlowGraph; - - private Type currentType; - private Set inVars; - private Set outNodes; - private Set visitedNodes; - private Map> wuEdges; - private ConcurrentDirectedGraphImpl pollutionFlowGraph; - private Reachability reachability; + private final PTA pta; + private final PotentialContextElement pce; + private final ObjectFlowGraph objectFlowGraph; - public FlowAnalysis(PTA pta, - PotentialContextElement pce, - ObjectFlowGraph ofg) { - this.pta = pta; - this.pce = pce; - this.objectFlowGraph = ofg; - } + private Type currentType; + private Set inVars; + private Set outNodes; + private Set visitedNodes; + private Map> wuEdges; + private ConcurrentDirectedGraphImpl pollutionFlowGraph; + private Reachability reachability; - public void initialize(Type type, Set inms, Set outms) { - currentType = type; - inVars = inms.stream() - .map(m -> ToolUtil.getParameters(pta.getPag(), m)) - .flatMap(Collection::stream) - .collect(Collectors.toSet()); - outNodes = outms.stream() - .map(m -> ToolUtil.getRetVars(pta.getPag(), m)) - .flatMap(Collection::stream) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); - visitedNodes = new HashSet<>(); - wuEdges = new HashMap<>(); - pollutionFlowGraph = new ConcurrentDirectedGraphImpl<>(); - reachability = new Reachability<>(pollutionFlowGraph); - } + public FlowAnalysis(PTA pta, PotentialContextElement pce, ObjectFlowGraph ofg) { + this.pta = pta; + this.pce = pce; + this.objectFlowGraph = ofg; + } - public void analyze(SootMethod startMethod) { - for (VarNode param : ToolUtil.getParameters(pta.getPag(), startMethod)) { - if (param != null) { - dfs(param); - } else { - if (Global.isDebug()) { - System.out.println(param + " is absent in the flow graph."); - } - } - } + public void initialize(Type type, Set inms, Set outms) { + currentType = type; + inVars = + inms.stream() + .map(m -> ToolUtil.getParameters(pta.getPag(), m)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + outNodes = + outms.stream() + .map(m -> ToolUtil.getRetVars(pta.getPag(), m)) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + visitedNodes = new HashSet<>(); + wuEdges = new HashMap<>(); + pollutionFlowGraph = new ConcurrentDirectedGraphImpl<>(); + reachability = new Reachability<>(pollutionFlowGraph); + } + public void analyze(SootMethod startMethod) { + for (VarNode param : ToolUtil.getParameters(pta.getPag(), startMethod)) { + if (param != null) { + dfs(param); + } else { if (Global.isDebug()) { - Set outMethods = new HashSet<>(); - for (VarNode param : ToolUtil.getParameters(pta.getPag(), startMethod)) { - if (param != null) { - for (Node outNode : outNodes) { - if (reachability.reachableNodesFrom(param).contains(outNode)) { - LocalVarNode outVarNode = (LocalVarNode) outNode; - outMethods.add(outVarNode.getMethod()); - } - } - } - } - System.out.println(color(ANSIColor.GREEN, "In method: ") + startMethod); - System.out.println(color(ANSIColor.GREEN, "Out methods: ") + outMethods); + System.out.println(param + " is absent in the flow graph."); } + } } - public Set getFlowNodes() { - Set results = new HashSet<>(); - for (Node outNode : outNodes) { - if (pollutionFlowGraph.allNodes().contains(outNode)) { - results.addAll(reachability.nodesReach(outNode)); + if (Global.isDebug()) { + Set outMethods = new HashSet<>(); + for (VarNode param : ToolUtil.getParameters(pta.getPag(), startMethod)) { + if (param != null) { + for (Node outNode : outNodes) { + if (reachability.reachableNodesFrom(param).contains(outNode)) { + LocalVarNode outVarNode = (LocalVarNode) outNode; + outMethods.add(outVarNode.getMethod()); } + } } - return results; + } + System.out.println(color(ANSIColor.GREEN, "In method: ") + startMethod); + System.out.println(color(ANSIColor.GREEN, "Out methods: ") + outMethods); } + } - public int numberOfPFGNodes() { - return pollutionFlowGraph.allNodes().size(); + public Set getFlowNodes() { + Set results = new HashSet<>(); + for (Node outNode : outNodes) { + if (pollutionFlowGraph.allNodes().contains(outNode)) { + results.addAll(reachability.nodesReach(outNode)); + } } + return results; + } - public int numberOfPFGEdges() { - int nrEdges = 0; - for (Node node : pollutionFlowGraph.allNodes()) { - nrEdges += pollutionFlowGraph.succsOf(node).size(); - } - return nrEdges; - } + public int numberOfPFGNodes() { + return pollutionFlowGraph.allNodes().size(); + } - public ConcurrentDirectedGraphImpl getPFG() { - return pollutionFlowGraph; + public int numberOfPFGEdges() { + int nrEdges = 0; + for (Node node : pollutionFlowGraph.allNodes()) { + nrEdges += pollutionFlowGraph.succsOf(node).size(); } + return nrEdges; + } - public void clear() { - currentType = null; - inVars = null; - outNodes = null; - visitedNodes = null; - wuEdges = null; - pollutionFlowGraph = null; - reachability = null; - } + public ConcurrentDirectedGraphImpl getPFG() { + return pollutionFlowGraph; + } - // a bit more complicated than the algorithm in TOPLAS'20 - private void dfs(Node node) { - if (Global.isDebug()) { - System.out.println(color(ANSIColor.BLUE, "Node ") + node); - } - if (visitedNodes.contains(node)) { // node has been visited - if (Global.isDebug()) { - System.out.println(color(ANSIColor.RED, "Visited node: ") + node); - } - } else { - visitedNodes.add(node); - pollutionFlowGraph.addNode(node); - // add unwrapped flow edges - if (Global.isEnableUnwrappedFlow()) { - if (node instanceof VarNode var) { - Collection varPts = pta.reachingObjects(var).toCIPointsToSet().toCollection(); - // Optimization: approximate unwrapped flows to make - // Zipper and pointer analysis run faster - pta.getCgb().getReceiverToSitesMap() - .getOrDefault(var, Collections.emptySet()) - .forEach(vcs -> { - Stmt callsiteStmt = vcs.getUnit(); - AbstractInvokeExpr invo = callsiteStmt.getInvokeExpr(); - if (!(invo instanceof AbstractInstanceInvokeExpr)) { - return; - } - if (callsiteStmt instanceof JAssignStmt assignStmt) { - Value lv = assignStmt.getLeftOp(); - if (!(lv.getType() instanceof ReferenceType)) { - return; - } - final VarNode to = (VarNode) pta.getPag().findValNode(lv); - if (outNodes.contains(to)) { - for (VarNode inVar : inVars) { - if (!Collections.disjoint(pta.reachingObjects(inVar).toCIPointsToSet().toCollection(), varPts)) { - Edge unwrappedEdge = new Edge(Kind.UNWRAPPED_FLOW, node, to); - addWUEdge(node, unwrappedEdge); - break; - } - } - } - } - }); - } - } - List nextEdges = new ArrayList<>(); - for (Edge edge : outEdgesOf(node)) { - switch (edge.getKind()) { - case LOCAL_ASSIGN, UNWRAPPED_FLOW -> { - nextEdges.add(edge); + public void clear() { + currentType = null; + inVars = null; + outNodes = null; + visitedNodes = null; + wuEdges = null; + pollutionFlowGraph = null; + reachability = null; + } + + // a bit more complicated than the algorithm in TOPLAS'20 + private void dfs(Node node) { + if (Global.isDebug()) { + System.out.println(color(ANSIColor.BLUE, "Node ") + node); + } + if (visitedNodes.contains(node)) { // node has been visited + if (Global.isDebug()) { + System.out.println(color(ANSIColor.RED, "Visited node: ") + node); + } + } else { + visitedNodes.add(node); + pollutionFlowGraph.addNode(node); + // add unwrapped flow edges + if (Global.isEnableUnwrappedFlow()) { + if (node instanceof VarNode var) { + Collection varPts = pta.reachingObjects(var).toCIPointsToSet().toCollection(); + // Optimization: approximate unwrapped flows to make + // Zipper and pointer analysis run faster + pta.getCgb() + .getReceiverToSitesMap() + .getOrDefault(var, Collections.emptySet()) + .forEach( + vcs -> { + Stmt callsiteStmt = vcs.getUnit(); + AbstractInvokeExpr invo = callsiteStmt.getInvokeExpr(); + if (!(invo instanceof AbstractInstanceInvokeExpr)) { + return; } - case INTERPROCEDURAL_ASSIGN, INSTANCE_LOAD, WRAPPED_FLOW -> { - // next must be a variable - LocalVarNode next = (LocalVarNode) edge.getTarget(); - SootMethod inMethod = next.getMethod(); - // Optimization: filter out some potential spurious flows due to - // the imprecision of context-insensitive pre-analysis, which - // helps improve the performance of Zipper and pointer analysis. - if (pce.PCEMethodsOf(currentType).contains(inMethod)) { - nextEdges.add(edge); + if (callsiteStmt instanceof JAssignStmt assignStmt) { + Value lv = assignStmt.getLeftOp(); + if (!(lv.getType() instanceof ReferenceType)) { + return; + } + final VarNode to = (VarNode) pta.getPag().findValNode(lv); + if (outNodes.contains(to)) { + for (VarNode inVar : inVars) { + if (!Collections.disjoint( + pta.reachingObjects(inVar).toCIPointsToSet().toCollection(), + varPts)) { + Edge unwrappedEdge = new Edge(Kind.UNWRAPPED_FLOW, node, to); + addWUEdge(node, unwrappedEdge); + break; + } } + } } - case INSTANCE_STORE -> { - ContextField next = (ContextField) edge.getTarget(); - AllocNode base = next.getBase(); - if (base.getType().equals(currentType)) { - // add wrapped flow edges to this variable - if (Global.isEnableWrappedFlow()) { - methodsInvokedOn(currentType).stream() - .map(m -> ToolUtil.getThis(pta.getPag(), m)) // filter this variable of native methods - .map(n -> new Edge(Kind.WRAPPED_FLOW, next, n)) - .forEach(e -> addWUEdge(next, e)); - } - nextEdges.add(edge); - } else if (pce.allocateesOf(currentType).contains(base)) { - // Optimization, similar as above. - if (Global.isEnableWrappedFlow()) { - Set r = new HashSet<>(); - AllocNode mBase = (AllocNode) pta.parameterize(base, pta.emptyContext()); - pta.getPag().allocLookup(mBase).forEach(v -> { - if (v instanceof ContextVarNode cvn) { - if (cvn.base() instanceof LocalVarNode lvn) { - if (!lvn.isThis()) { - r.add(lvn); - } - } - } - }); - Iterator it = r.iterator(); - if (it.hasNext()) { - Node assigned = r.iterator().next(); - if (assigned != null) { - Edge e = new Edge(Kind.WRAPPED_FLOW, next, assigned); - addWUEdge(next, e); - } - } + }); + } + } + List nextEdges = new ArrayList<>(); + for (Edge edge : outEdgesOf(node)) { + switch (edge.getKind()) { + case LOCAL_ASSIGN, UNWRAPPED_FLOW -> { + nextEdges.add(edge); + } + case INTERPROCEDURAL_ASSIGN, INSTANCE_LOAD, WRAPPED_FLOW -> { + // next must be a variable + LocalVarNode next = (LocalVarNode) edge.getTarget(); + SootMethod inMethod = next.getMethod(); + // Optimization: filter out some potential spurious flows due to + // the imprecision of context-insensitive pre-analysis, which + // helps improve the performance of Zipper and pointer analysis. + if (pce.PCEMethodsOf(currentType).contains(inMethod)) { + nextEdges.add(edge); + } + } + case INSTANCE_STORE -> { + ContextField next = (ContextField) edge.getTarget(); + AllocNode base = next.getBase(); + if (base.getType().equals(currentType)) { + // add wrapped flow edges to this variable + if (Global.isEnableWrappedFlow()) { + methodsInvokedOn(currentType).stream() + .map( + m -> + ToolUtil.getThis( + pta.getPag(), m)) // filter this variable of native methods + .map(n -> new Edge(Kind.WRAPPED_FLOW, next, n)) + .forEach(e -> addWUEdge(next, e)); + } + nextEdges.add(edge); + } else if (pce.allocateesOf(currentType).contains(base)) { + // Optimization, similar as above. + if (Global.isEnableWrappedFlow()) { + Set r = new HashSet<>(); + AllocNode mBase = (AllocNode) pta.parameterize(base, pta.emptyContext()); + pta.getPag() + .allocLookup(mBase) + .forEach( + v -> { + if (v instanceof ContextVarNode cvn) { + if (cvn.base() instanceof LocalVarNode lvn) { + if (!lvn.isThis()) { + r.add(lvn); + } } - nextEdges.add(edge); - } - } - default -> { - throw new RuntimeException("Unknown edge: " + edge); - } + } + }); + Iterator it = r.iterator(); + if (it.hasNext()) { + Node assigned = r.iterator().next(); + if (assigned != null) { + Edge e = new Edge(Kind.WRAPPED_FLOW, next, assigned); + addWUEdge(next, e); + } } + } + nextEdges.add(edge); } - for (Edge nextEdge : nextEdges) { - Node nextNode = nextEdge.getTarget(); - pollutionFlowGraph.addEdge(node, nextNode); - dfs(nextNode); - } + } + default -> { + throw new RuntimeException("Unknown edge: " + edge); + } } + } + for (Edge nextEdge : nextEdges) { + Node nextNode = nextEdge.getTarget(); + pollutionFlowGraph.addEdge(node, nextNode); + dfs(nextNode); + } } + } - private void addWUEdge(Node sourceNode, Edge edge) { - wuEdges.computeIfAbsent(sourceNode, k -> new HashSet<>()).add(edge); - } + private void addWUEdge(Node sourceNode, Edge edge) { + wuEdges.computeIfAbsent(sourceNode, k -> new HashSet<>()).add(edge); + } - private Collection methodsInvokedOn(Type type) { - return pta.getPag().getAllocNodes() - .stream().filter(o -> o.getType().equals(type)) - .map(pce::methodsInvokedOn).flatMap(Collection::stream) - .collect(Collectors.toSet()); - } + private Collection methodsInvokedOn(Type type) { + return pta.getPag().getAllocNodes().stream() + .filter(o -> o.getType().equals(type)) + .map(pce::methodsInvokedOn) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } - /** - * @param node - * @return out edges of node from OFG, and wuEdges, if present - */ - private Set outEdgesOf(Node node) { - Set outEdges = objectFlowGraph.outEdgesOf(node); - if (wuEdges.containsKey(node)) { - outEdges = new HashSet<>(outEdges); - outEdges.addAll(wuEdges.get(node)); - } - return outEdges; + /** + * @param node + * @return out edges of node from OFG, and wuEdges, if present + */ + private Set outEdgesOf(Node node) { + Set outEdges = objectFlowGraph.outEdgesOf(node); + if (wuEdges.containsKey(node)) { + outEdges = new HashSet<>(outEdges); + outEdges.addAll(wuEdges.get(node)); } + return outEdges; + } - private void outputPollutionFlowGraphSize() { - int nrNodes = pollutionFlowGraph.allNodes().size(); - int nrEdges = 0; - for (Node node : pollutionFlowGraph.allNodes()) { - nrEdges += pollutionFlowGraph.succsOf(node).size(); - } - System.out.printf("#Size of PFG of %s: %d nodes, %d edges.\n", currentType, nrNodes, nrEdges); + private void outputPollutionFlowGraphSize() { + int nrNodes = pollutionFlowGraph.allNodes().size(); + int nrEdges = 0; + for (Node node : pollutionFlowGraph.allNodes()) { + nrEdges += pollutionFlowGraph.succsOf(node).size(); } + System.out.printf("#Size of PFG of %s: %d nodes, %d edges.\n", currentType, nrNodes, nrEdges); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java index 753f7cd9bae..777dc55a603 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/IObjectFlowGraph.java @@ -1,11 +1,10 @@ package qilin.pta.toolkits.zipper.flowgraph; -import qilin.core.pag.Node; - import java.util.Set; +import qilin.core.pag.Node; public interface IObjectFlowGraph { - Set outEdgesOf(final Node p0); + Set outEdgesOf(final Node p0); - Set allNodes(); + Set allNodes(); } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java index 1acca6aabc7..a7df60b694f 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/Kind.java @@ -1,10 +1,10 @@ package qilin.pta.toolkits.zipper.flowgraph; public enum Kind { - LOCAL_ASSIGN, - INTERPROCEDURAL_ASSIGN, - INSTANCE_LOAD, - INSTANCE_STORE, - WRAPPED_FLOW, - UNWRAPPED_FLOW; + LOCAL_ASSIGN, + INTERPROCEDURAL_ASSIGN, + INSTANCE_LOAD, + INSTANCE_STORE, + WRAPPED_FLOW, + UNWRAPPED_FLOW; } diff --git a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java index 3d9a2b47d30..71442dadee5 100644 --- a/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java +++ b/sootup.qilin/src/main/java/qilin/pta/toolkits/zipper/flowgraph/ObjectFlowGraph.java @@ -1,5 +1,6 @@ package qilin.pta.toolkits.zipper.flowgraph; +import java.util.*; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; import qilin.core.pag.*; @@ -10,117 +11,122 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; -import java.util.*; - public class ObjectFlowGraph implements IObjectFlowGraph { - private final PTA pta; - private Map> outEdges; + private final PTA pta; + private Map> outEdges; - public ObjectFlowGraph(PTA pta) { - this.pta = pta; - init(); - } + public ObjectFlowGraph(PTA pta) { + this.pta = pta; + init(); + } - @Override - public Set outEdgesOf(Node node) { - return outEdges.getOrDefault(node, Collections.emptySet()); - } + @Override + public Set outEdgesOf(Node node) { + return outEdges.getOrDefault(node, Collections.emptySet()); + } - @Override - public Set allNodes() { - return outEdges.keySet(); - } + @Override + public Set allNodes() { + return outEdges.keySet(); + } - private boolean localVarBase(ValNode valNode) { - if (valNode instanceof ContextVarNode cvn) { - return cvn.base() instanceof LocalVarNode; - } else { - return valNode instanceof LocalVarNode; - } + private boolean localVarBase(ValNode valNode) { + if (valNode instanceof ContextVarNode cvn) { + return cvn.base() instanceof LocalVarNode; + } else { + return valNode instanceof LocalVarNode; } + } - private LocalVarNode fetchLocalVar(ValNode valNode) { - if (valNode instanceof ContextVarNode cvn) { - if (cvn.base() instanceof LocalVarNode) { - return (LocalVarNode) cvn.base(); - } - } else if (valNode instanceof LocalVarNode) { - return (LocalVarNode) valNode; - } - return null; + private LocalVarNode fetchLocalVar(ValNode valNode) { + if (valNode instanceof ContextVarNode cvn) { + if (cvn.base() instanceof LocalVarNode) { + return (LocalVarNode) cvn.base(); + } + } else if (valNode instanceof LocalVarNode) { + return (LocalVarNode) valNode; } + return null; + } - private LocalVarNode fetchVar(ValNode valNode) { - if (valNode instanceof ContextVarNode cvn) { - VarNode base = cvn.base(); - if (base instanceof LocalVarNode lvn) { - return lvn; - } - } else if (valNode instanceof LocalVarNode lvn) { - return lvn; - } - return null; + private LocalVarNode fetchVar(ValNode valNode) { + if (valNode instanceof ContextVarNode cvn) { + VarNode base = cvn.base(); + if (base instanceof LocalVarNode lvn) { + return lvn; + } + } else if (valNode instanceof LocalVarNode lvn) { + return lvn; } + return null; + } - public void addOutEdge(final Edge e) { - outEdges.computeIfAbsent(e.getSource(), k -> new HashSet<>()).add(e); - } + public void addOutEdge(final Edge e) { + outEdges.computeIfAbsent(e.getSource(), k -> new HashSet<>()).add(e); + } - private void init() { - outEdges = new HashMap<>(); + private void init() { + outEdges = new HashMap<>(); - pta.getPag().getSimple().forEach((s, ts) -> { - if (localVarBase(s)) { - ts.forEach(t -> { - if (localVarBase(t)) { + pta.getPag() + .getSimple() + .forEach( + (s, ts) -> { + if (localVarBase(s)) { + ts.forEach( + t -> { + if (localVarBase(t)) { LocalVarNode toNode = fetchVar(t); LocalVarNode fromNode = fetchVar(s); if (fetchLocalVar(s).isInterProcSource()) { - addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, toNode)); + addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, toNode)); } else { - if (fetchLocalVar(t).isInterProcTarget()) { - if (!fetchLocalVar(t).isThis()) { - addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, toNode)); - } - } else { - addOutEdge(new Edge(Kind.LOCAL_ASSIGN, fromNode, toNode)); + if (fetchLocalVar(t).isInterProcTarget()) { + if (!fetchLocalVar(t).isThis()) { + addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, toNode)); } + } else { + addOutEdge(new Edge(Kind.LOCAL_ASSIGN, fromNode, toNode)); + } } - } else if (t instanceof ContextField ctxField) { + } else if (t instanceof ContextField ctxField) { LocalVarNode varNode = fetchVar(s); addOutEdge(new Edge(Kind.INSTANCE_STORE, varNode, ctxField)); - } - }); - } else if (s instanceof ContextField ctxField) { - ts.forEach(t -> { - assert localVarBase(t); - LocalVarNode varNode = fetchVar(t); - addOutEdge(new Edge(Kind.INSTANCE_LOAD, ctxField, varNode)); - }); - } - }); + } + }); + } else if (s instanceof ContextField ctxField) { + ts.forEach( + t -> { + assert localVarBase(t); + LocalVarNode varNode = fetchVar(t); + addOutEdge(new Edge(Kind.INSTANCE_LOAD, ctxField, varNode)); + }); + } + }); - pta.getCallGraph().forEach(e -> { - Stmt callsite = e.srcStmt(); - SootMethod caller = e.src(); - if (caller != null) { + pta.getCallGraph() + .forEach( + e -> { + Stmt callsite = e.srcStmt(); + SootMethod caller = e.src(); + if (caller != null) { SootMethod callee = e.tgt(); if (!callee.isStatic()) { - MethodNodeFactory calleeNF = pta.getPag().getMethodPAG(callee).nodeFactory(); - LocalVarNode thisVar = (LocalVarNode) calleeNF.caseThis(); - AbstractInvokeExpr ie = callsite.getInvokeExpr(); - Value base = null; - if (ie instanceof AbstractInstanceInvokeExpr iie) { - base = iie.getBase(); - } - if (base != null) { - LocalVarNode fromNode = (LocalVarNode) pta.getPag().findValNode(base); - addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, thisVar)); - } + MethodNodeFactory calleeNF = pta.getPag().getMethodPAG(callee).nodeFactory(); + LocalVarNode thisVar = (LocalVarNode) calleeNF.caseThis(); + AbstractInvokeExpr ie = callsite.getInvokeExpr(); + Value base = null; + if (ie instanceof AbstractInstanceInvokeExpr iie) { + base = iie.getBase(); + } + if (base != null) { + LocalVarNode fromNode = (LocalVarNode) pta.getPag().findValNode(base); + addOutEdge(new Edge(Kind.INTERPROCEDURAL_ASSIGN, fromNode, thisVar)); + } } - } else if (Global.isDebug()) { + } else if (Global.isDebug()) { System.out.println("Null caller of: " + callsite); - } - }); - } + } + }); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java index af437b68ae4..e9c8579c097 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BasePTA.java @@ -25,59 +25,59 @@ import qilin.core.solver.Propagator; import qilin.core.solver.Solver; import qilin.stat.IEvaluator; -import qilin.stat.PTAEvaluator; import qilin.stat.SimplifiedEvaluator; import qilin.util.PTAUtils; public abstract class BasePTA extends CorePTA { - protected IEvaluator evaluator; + protected IEvaluator evaluator; - public BasePTA() { -// this.evaluator = new PTAEvaluator(this); - this.evaluator = new SimplifiedEvaluator(this); - } + public BasePTA() { + // this.evaluator = new PTAEvaluator(this); + this.evaluator = new SimplifiedEvaluator(this); + } - public IEvaluator evaluator() { - return this.evaluator; - } + public IEvaluator evaluator() { + return this.evaluator; + } - @Override - protected PAG createPAG() { - return new PAG(this); - } + @Override + protected PAG createPAG() { + return new PAG(this); + } - @Override - protected CallGraphBuilder createCallGraphBuilder() { - return new CallGraphBuilder(this); - } + @Override + protected CallGraphBuilder createCallGraphBuilder() { + return new CallGraphBuilder(this); + } - @Override - public Propagator getPropagator() { - return new Solver(this); - } + @Override + public Propagator getPropagator() { + return new Solver(this); + } - @Override - public void run() { - evaluator.begin(); - pureRun(); - evaluator.end(); - dumpStats(); - System.out.println(evaluator()); - } + @Override + public void run() { + evaluator.begin(); + pureRun(); + evaluator.end(); + dumpStats(); + System.out.println(evaluator()); + } - protected void dumpStats() { - if (CoreConfig.v().getOutConfig().dumppts) { - PTAUtils.dumpPts(this, !CoreConfig.v().getOutConfig().dumplibpts); - } - if (CoreConfig.v().getOutConfig().dumpCallGraph) { - PTAUtils.dumpCallGraph(getCallGraph(), false); -// PTAUtils.dumpSlicedCallGraph(getCallGraph(), -// parameterize(PTAScene.v().getMethod(""), emptyContext())); - } - if (CoreConfig.v().getOutConfig().dumppag) { - PTAUtils.dumpPAG(pag, "pag"); -// PTAUtils.dumpMPAGs(this, "mpags"); - PTAUtils.dumpNodeNames("nodeNames"); - } + protected void dumpStats() { + if (CoreConfig.v().getOutConfig().dumppts) { + PTAUtils.dumpPts(this, !CoreConfig.v().getOutConfig().dumplibpts); + } + if (CoreConfig.v().getOutConfig().dumpCallGraph) { + PTAUtils.dumpCallGraph(getCallGraph(), false); + // PTAUtils.dumpSlicedCallGraph(getCallGraph(), + // parameterize(PTAScene.v().getMethod(""), emptyContext())); + } + if (CoreConfig.v().getOutConfig().dumppag) { + PTAUtils.dumpPAG(pag, "pag"); + // PTAUtils.dumpMPAGs(this, "mpags"); + PTAUtils.dumpNodeNames("nodeNames"); } + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java index 86be816e2f9..9600fb9179d 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/BeanPTA.java @@ -18,6 +18,8 @@ package qilin.pta.tools; +import java.util.HashMap; +import java.util.Map; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.AllocSiteAbstractor; import qilin.parm.heapabst.HeuristicAbstractor; @@ -29,43 +31,40 @@ import qilin.pta.toolkits.bean.Bean; import qilin.util.Stopwatch; -import java.util.HashMap; -import java.util.Map; - /* * refer to "Making k-Object-Sensitive Pointer Analysis More Precise with Still k-Limiting" (SAS'16) * */ public class BeanPTA extends StagedPTA { - // currently, we only support k = 2 and hk = 1; - // [current heap, [allocator heap, [heap ctx, new ctx]]] only for B-2obj; - Map>> beanNexCtxMap = new HashMap<>(); + // currently, we only support k = 2 and hk = 1; + // [current heap, [allocator heap, [heap ctx, new ctx]]] only for B-2obj; + Map>> beanNexCtxMap = new HashMap<>(); - public BeanPTA(CtxConstructor ctxCons) { - this.ctxCons = ctxCons; - CtxSelector us = new BeanSelector(pag, beanNexCtxMap); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - prePTA = new Spark(); - System.out.println("bean ..."); + public BeanPTA(CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new BeanSelector(pag, beanNexCtxMap); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } - - @Override - protected void preAnalysis() { - Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); - prePTA.pureRun(); - sparkTimer.stop(); - System.out.println(sparkTimer); - Stopwatch beanTimer = Stopwatch.newAndStart("Bean"); - Bean.run(prePTA, beanNexCtxMap); - beanTimer.stop(); - System.out.println(beanTimer); + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); } + prePTA = new Spark(); + System.out.println("bean ..."); + } + + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + Stopwatch beanTimer = Stopwatch.newAndStart("Bean"); + Bean.run(prePTA, beanNexCtxMap); + beanTimer.stop(); + System.out.println(beanTimer); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java index 1bdf094bb70..6831f2c9a74 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/CallSiteSensPTA.java @@ -33,19 +33,19 @@ public class CallSiteSensPTA extends BasePTA { - public CallSiteSensPTA(int k, int hk) { - this.ctxCons = new CallsiteCtxConstructor(); - CtxSelector us = new UniformSelector(k, hk); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("k-callsite PTA ..."); + public CallSiteSensPTA(int k, int hk) { + this.ctxCons = new CallsiteCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("k-callsite PTA ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java index b43824e9783..e063d239fad 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DataDrivenPTA.java @@ -26,6 +26,7 @@ import qilin.parm.select.PipelineSelector; import qilin.pta.PTAConfig; import qilin.pta.toolkits.dd.DataDrivenSelector; + /* * Support Data-driven context-sensitivity for Points-to Analysis (OOPSLA 2017): * https://doi.org/10.1145/3133924 @@ -38,19 +39,19 @@ public class DataDrivenPTA extends BasePTA { - public DataDrivenPTA(CtxConstructor ctxCons) { - this.ctxCons = ctxCons; - CtxSelector us = new DataDrivenSelector(ctxCons.getClass()); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("data-driven ..."); + public DataDrivenPTA(CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new DataDrivenSelector(ctxCons.getClass()); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); } + System.out.println("data-driven ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java index a7b1ee37aa0..fcab060b654 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/DebloatedPTA.java @@ -18,6 +18,7 @@ package qilin.pta.tools; +import java.util.*; import qilin.core.pag.*; import qilin.core.sets.PointsToSet; import qilin.core.solver.Propagator; @@ -27,9 +28,9 @@ import qilin.pta.PTAConfig; import qilin.pta.toolkits.common.DebloatedOAG; import qilin.pta.toolkits.common.OAG; +import qilin.pta.toolkits.conch.Conch; import qilin.pta.toolkits.debloaterx.CollectionHeuristic; import qilin.pta.toolkits.debloaterx.DebloaterX; -import qilin.pta.toolkits.conch.Conch; import qilin.stat.IEvaluator; import qilin.util.Stopwatch; import soot.Context; @@ -38,167 +39,169 @@ import sootup.core.model.SootField; import sootup.core.model.SootMethod; -import java.util.*; - /* * refer to "Context Debloating for Object-Sensitive Pointer Analysis" (ASE'21) * */ public class DebloatedPTA extends StagedPTA { - public enum DebloatApproach { - CONCH, DEBLOATERX, COLLECTION - } - - protected BasePTA basePTA; - protected Set ctxDepHeaps = new HashSet<>(); - protected DebloatApproach debloatApproach = DebloatApproach.CONCH; - - /* - * The debloating approach is currently for object-sensitive PTA only. - * Thus the base PTA should be k-OBJ, Zipper-OBJ or Eagle-OBJ. - * */ - public DebloatedPTA(BasePTA basePTA) { - this.basePTA = basePTA; - CtxSelector debloatingSelector = new DebloatingSelector(ctxDepHeaps); - basePTA.setContextSelector(new PipelineSelector(basePTA.ctxSelector(), debloatingSelector)); - if (basePTA instanceof StagedPTA stagedPTA) { - this.prePTA = stagedPTA.getPrePTA(); - } else { - this.prePTA = new Spark(); - } - System.out.println("debloating ...."); - } - - /* this constructor is used to specify the debloating approach. */ - public DebloatedPTA(BasePTA basePTA, DebloatApproach approach) { - this(basePTA); - this.debloatApproach = approach; - } - - @Override - protected void preAnalysis() { - Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); - prePTA.pureRun(); - sparkTimer.stop(); - System.out.println(sparkTimer); - if (debloatApproach == DebloatApproach.CONCH) { - Stopwatch conchTimer = Stopwatch.newAndStart("Conch"); - Conch hc = new Conch(prePTA); - hc.runClassifier(); - this.ctxDepHeaps.addAll(hc.ctxDependentHeaps()); - System.out.println(); - conchTimer.stop(); - System.out.println(conchTimer); - } else if (debloatApproach == DebloatApproach.DEBLOATERX) { - Stopwatch debloaterXTimer = Stopwatch.newAndStart("DebloaterX"); - DebloaterX debloaterX = new DebloaterX(prePTA); - debloaterX.run(); - Set mCtxDepHeaps = debloaterX.getCtxDepHeaps(); - for (AllocNode obj : mCtxDepHeaps) { - this.ctxDepHeaps.add(obj.getNewExpr()); - } - System.out.println(); - debloaterXTimer.stop(); - System.out.println(debloaterXTimer); - // stat OAG reductions - OAG oag = new OAG(prePTA); - oag.build(); - OAG doag1 = new DebloatedOAG(prePTA, mCtxDepHeaps); - doag1.build(); - System.out.println("OAG #node:" + oag.nodeSize() + "; #edge:" + oag.edgeSize()); - System.out.println("DebloaterX OAG #node:" + doag1.nodeSize() + "; #edge:" + doag1.edgeSize()); - } else { - assert (debloatApproach == DebloatApproach.COLLECTION); - Stopwatch collectionHeuristic = Stopwatch.newAndStart("COLLECTION"); - CollectionHeuristic ch = new CollectionHeuristic(prePTA); - ch.run(); - collectionHeuristic.stop(); - System.out.println(collectionHeuristic); - for (AllocNode obj : ch.getCtxDepHeaps()) { - this.ctxDepHeaps.add(obj.getNewExpr()); - } - } - } - - @Override - protected void mainAnalysis() { - if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { - System.out.println("selective pta starts!"); - basePTA.run(); - } - } - - @Override - public Propagator getPropagator() { - return basePTA.getPropagator(); - } - - @Override - public Node parameterize(Node n, Context context) { - return basePTA.parameterize(n, context); - } - - @Override - public MethodOrMethodContext parameterize(SootMethod method, Context context) { - return basePTA.parameterize(method, context); - } - - @Override - public AllocNode getRootNode() { - return basePTA.getRootNode(); - } - - @Override - public IEvaluator evaluator() { - return basePTA.evaluator(); - } - - @Override - public Context emptyContext() { - return basePTA.emptyContext(); - } - - @Override - public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { - return basePTA.createCalleeCtx(caller, receiverNode, callSite, target); - } - - @Override - public PointsToSet reachingObjects(Local l) { - return basePTA.reachingObjects(l); - } - - @Override - public PointsToSet reachingObjects(Node n) { - return basePTA.reachingObjects(n); - } - - @Override - public PointsToSet reachingObjects(Context c, Local l) { - return basePTA.reachingObjects(c, l); - } - - @Override - public PointsToSet reachingObjects(SootField f) { - return basePTA.reachingObjects(f); - } - - @Override - public PointsToSet reachingObjects(PointsToSet s, SootField f) { - return basePTA.reachingObjects(s, f); - } - - @Override - public PointsToSet reachingObjects(Local l, SootField f) { - return basePTA.reachingObjects(l, f); - } - - @Override - public PointsToSet reachingObjects(Context c, Local l, SootField f) { - return basePTA.reachingObjects(c, l, f); - } - - @Override - public PointsToSet reachingObjectsOfArrayElement(PointsToSet s) { - return basePTA.reachingObjectsOfArrayElement(s); - } + public enum DebloatApproach { + CONCH, + DEBLOATERX, + COLLECTION + } + + protected BasePTA basePTA; + protected Set ctxDepHeaps = new HashSet<>(); + protected DebloatApproach debloatApproach = DebloatApproach.CONCH; + + /* + * The debloating approach is currently for object-sensitive PTA only. + * Thus the base PTA should be k-OBJ, Zipper-OBJ or Eagle-OBJ. + * */ + public DebloatedPTA(BasePTA basePTA) { + this.basePTA = basePTA; + CtxSelector debloatingSelector = new DebloatingSelector(ctxDepHeaps); + basePTA.setContextSelector(new PipelineSelector(basePTA.ctxSelector(), debloatingSelector)); + if (basePTA instanceof StagedPTA stagedPTA) { + this.prePTA = stagedPTA.getPrePTA(); + } else { + this.prePTA = new Spark(); + } + System.out.println("debloating ...."); + } + + /* this constructor is used to specify the debloating approach. */ + public DebloatedPTA(BasePTA basePTA, DebloatApproach approach) { + this(basePTA); + this.debloatApproach = approach; + } + + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + if (debloatApproach == DebloatApproach.CONCH) { + Stopwatch conchTimer = Stopwatch.newAndStart("Conch"); + Conch hc = new Conch(prePTA); + hc.runClassifier(); + this.ctxDepHeaps.addAll(hc.ctxDependentHeaps()); + System.out.println(); + conchTimer.stop(); + System.out.println(conchTimer); + } else if (debloatApproach == DebloatApproach.DEBLOATERX) { + Stopwatch debloaterXTimer = Stopwatch.newAndStart("DebloaterX"); + DebloaterX debloaterX = new DebloaterX(prePTA); + debloaterX.run(); + Set mCtxDepHeaps = debloaterX.getCtxDepHeaps(); + for (AllocNode obj : mCtxDepHeaps) { + this.ctxDepHeaps.add(obj.getNewExpr()); + } + System.out.println(); + debloaterXTimer.stop(); + System.out.println(debloaterXTimer); + // stat OAG reductions + OAG oag = new OAG(prePTA); + oag.build(); + OAG doag1 = new DebloatedOAG(prePTA, mCtxDepHeaps); + doag1.build(); + System.out.println("OAG #node:" + oag.nodeSize() + "; #edge:" + oag.edgeSize()); + System.out.println( + "DebloaterX OAG #node:" + doag1.nodeSize() + "; #edge:" + doag1.edgeSize()); + } else { + assert (debloatApproach == DebloatApproach.COLLECTION); + Stopwatch collectionHeuristic = Stopwatch.newAndStart("COLLECTION"); + CollectionHeuristic ch = new CollectionHeuristic(prePTA); + ch.run(); + collectionHeuristic.stop(); + System.out.println(collectionHeuristic); + for (AllocNode obj : ch.getCtxDepHeaps()) { + this.ctxDepHeaps.add(obj.getNewExpr()); + } + } + } + + @Override + protected void mainAnalysis() { + if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { + System.out.println("selective pta starts!"); + basePTA.run(); + } + } + + @Override + public Propagator getPropagator() { + return basePTA.getPropagator(); + } + + @Override + public Node parameterize(Node n, Context context) { + return basePTA.parameterize(n, context); + } + + @Override + public MethodOrMethodContext parameterize(SootMethod method, Context context) { + return basePTA.parameterize(method, context); + } + + @Override + public AllocNode getRootNode() { + return basePTA.getRootNode(); + } + + @Override + public IEvaluator evaluator() { + return basePTA.evaluator(); + } + + @Override + public Context emptyContext() { + return basePTA.emptyContext(); + } + + @Override + public Context createCalleeCtx( + MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { + return basePTA.createCalleeCtx(caller, receiverNode, callSite, target); + } + + @Override + public PointsToSet reachingObjects(Local l) { + return basePTA.reachingObjects(l); + } + + @Override + public PointsToSet reachingObjects(Node n) { + return basePTA.reachingObjects(n); + } + + @Override + public PointsToSet reachingObjects(Context c, Local l) { + return basePTA.reachingObjects(c, l); + } + + @Override + public PointsToSet reachingObjects(SootField f) { + return basePTA.reachingObjects(f); + } + + @Override + public PointsToSet reachingObjects(PointsToSet s, SootField f) { + return basePTA.reachingObjects(s, f); + } + + @Override + public PointsToSet reachingObjects(Local l, SootField f) { + return basePTA.reachingObjects(l, f); + } + + @Override + public PointsToSet reachingObjects(Context c, Local l, SootField f) { + return basePTA.reachingObjects(c, l, f); + } + + @Override + public PointsToSet reachingObjectsOfArrayElement(PointsToSet s) { + return basePTA.reachingObjectsOfArrayElement(s); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java index 69006afea65..4fb3865c9eb 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/EaglePTA.java @@ -18,6 +18,9 @@ package qilin.pta.tools; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.Map; import qilin.core.pag.AllocNode; import qilin.core.pag.LocalVarNode; import qilin.core.pag.Parm; @@ -29,94 +32,92 @@ import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.stmt.Stmt; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.util.Map; - /* * refer to "Precision-Preserving Yet Fast Object-Sensitive Pointer Analysis with Partial Context Sensitivity" (OOPSLA'19) * and "Eagle: CFL-Reachability-based Precision-Preserving Acceleration of Object-Sensitive Pointer Analysis with Partial Context Sensitivity" * (TOSEM'21) * */ public class EaglePTA extends PartialObjSensPTA { - public EaglePTA(int ctxLen) { - super(ctxLen); - System.out.println("Eagle ...."); - } + public EaglePTA(int ctxLen) { + super(ctxLen); + System.out.println("Eagle ...."); + } - @Override - protected Map calculatingNode2Length() { - Stopwatch timer = Stopwatch.newAndStart("TransGraph Construction"); - Eagle eagle = new Eagle(); - eagle.buildGraph(prePTA); - timer.stop(); - System.out.println(timer); - Stopwatch eagleTimer = Stopwatch.newAndStart("Eagle Selection"); - Map ret = eagle.contxtLengthAnalysis(); - eagleTimer.stop(); - System.out.println(eagleTimer); - eagle.dumpCount(); -// try { -// writeToFile(ret); -// } catch (FileNotFoundException e) { -// System.out.println("no file exists for dumping eagle selected partial heaps/variables."); -// } - System.out.println("#Node:" + eagle.totalNodesCount()); - System.out.println("#Edge:" + eagle.totalEdgesCount()); - return ret; - } + @Override + protected Map calculatingNode2Length() { + Stopwatch timer = Stopwatch.newAndStart("TransGraph Construction"); + Eagle eagle = new Eagle(); + eagle.buildGraph(prePTA); + timer.stop(); + System.out.println(timer); + Stopwatch eagleTimer = Stopwatch.newAndStart("Eagle Selection"); + Map ret = eagle.contxtLengthAnalysis(); + eagleTimer.stop(); + System.out.println(eagleTimer); + eagle.dumpCount(); + // try { + // writeToFile(ret); + // } catch (FileNotFoundException e) { + // System.out.println("no file exists for dumping eagle selected partial + // heaps/variables."); + // } + System.out.println("#Node:" + eagle.totalNodesCount()); + System.out.println("#Edge:" + eagle.totalEdgesCount()); + return ret; + } - protected void writeToFile(Map partialResults) throws FileNotFoundException { - final char EOL = '\n'; - String insensVarFile = "InsensitiveVar.facts"; - String insensHeapFile = "InsensitiveHeap.facts"; - PrintWriter varWriter = new PrintWriter(insensVarFile); - PrintWriter heapWriter = new PrintWriter(insensHeapFile); - partialResults.forEach((k, v) -> { - if (v > 0) { - return; + protected void writeToFile(Map partialResults) throws FileNotFoundException { + final char EOL = '\n'; + String insensVarFile = "InsensitiveVar.facts"; + String insensHeapFile = "InsensitiveHeap.facts"; + PrintWriter varWriter = new PrintWriter(insensVarFile); + PrintWriter heapWriter = new PrintWriter(insensHeapFile); + partialResults.forEach( + (k, v) -> { + if (v > 0) { + return; + } + if (k instanceof AllocNode heap) { + if (heap.getMethod() == null) { + return; + } + String newExpr = heap.getNewExpr().toString(); + if (heap.getNewExpr() instanceof JNewArrayExpr nae) { + newExpr = "new " + nae.getBaseType() + "[]"; } - if (k instanceof AllocNode heap) { - if (heap.getMethod() == null) { - return; - } - String newExpr = heap.getNewExpr().toString(); - if (heap.getNewExpr() instanceof JNewArrayExpr nae) { - newExpr = "new " + nae.getBaseType() + "[]"; - } - String heapSig = heap.getMethod().toString() + "/" + newExpr; - heapWriter.write(heapSig); - heapWriter.write(EOL); - } else if (k instanceof LocalVarNode lvn) { - Object variable = lvn.getVariable(); - String varName = variable.toString(); - if (variable instanceof Parm parm) { - if (parm.isThis()) { - varName = "@this"; - } else if (parm.isReturn()) { - return; - } else if (parm.isThrowRet()) { - return; - } else { - varName = "@parameter" + parm.getIndex(); - } - } else if (variable instanceof Local) { + String heapSig = heap.getMethod().toString() + "/" + newExpr; + heapWriter.write(heapSig); + heapWriter.write(EOL); + } else if (k instanceof LocalVarNode lvn) { + Object variable = lvn.getVariable(); + String varName = variable.toString(); + if (variable instanceof Parm parm) { + if (parm.isThis()) { + varName = "@this"; + } else if (parm.isReturn()) { + return; + } else if (parm.isThrowRet()) { + return; + } else { + varName = "@parameter" + parm.getIndex(); + } + } else if (variable instanceof Local) { - } else if (variable instanceof Stmt) { - return; - } else if (variable instanceof Expr) { - return; - } else if (variable instanceof Pair) { - return; - } else { - return; - } - String varSig = lvn.getMethod().toString() + "/" + varName; - varWriter.write(varSig); - varWriter.write(EOL); + } else if (variable instanceof Stmt) { + return; + } else if (variable instanceof Expr) { + return; + } else if (variable instanceof Pair) { + return; + } else { + return; } + String varSig = lvn.getMethod().toString() + "/" + varName; + varWriter.write(varSig); + varWriter.write(EOL); + } }); - varWriter.close(); - heapWriter.close(); - } + varWriter.close(); + heapWriter.close(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java index 1ef7cef9008..7fdb4d78281 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridObjectSensPTA.java @@ -27,25 +27,22 @@ import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -/** - * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) - */ +/** refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) */ public class HybridObjectSensPTA extends BasePTA { - public HybridObjectSensPTA(int k, int hk) { - this.ctxCons = new HybObjCtxConstructor(); - CtxSelector us = new UniformSelector(k + 1, hk); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("Hybrid k-OBJ ..."); + public HybridObjectSensPTA(int k, int hk) { + this.ctxCons = new HybObjCtxConstructor(); + CtxSelector us = new UniformSelector(k + 1, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } - + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("Hybrid k-OBJ ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java index 34db6856bde..12e017ec03a 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/HybridTypeSensPTA.java @@ -27,25 +27,22 @@ import qilin.parm.select.UniformSelector; import qilin.pta.PTAConfig; -/** - * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) - */ - +/** refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) */ public class HybridTypeSensPTA extends BasePTA { - public HybridTypeSensPTA(int k, int hk) { - this.ctxCons = new HybTypeCtxConstructor(); - CtxSelector us = new UniformSelector(k, hk); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("Hybrid k-type ..."); + public HybridTypeSensPTA(int k, int hk) { + this.ctxCons = new HybTypeCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; + } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); } + System.out.println("Hybrid k-type ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java index 5dfbf69bab4..5285487713b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/MahjongPTA.java @@ -18,6 +18,10 @@ package qilin.pta.tools; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.MahjongAbstractor; import qilin.parm.select.CtxSelector; @@ -27,50 +31,46 @@ import qilin.pta.PTAConfig; import qilin.pta.toolkits.mahjong.Mahjong; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - /* * refer to "Efficient and Precise Points-to Analysis: Modeling the Heap by Merging Equivalent Automata" (PLDI'17) * */ public class MahjongPTA extends StagedPTA { - protected final Map heapModelMap = new HashMap<>(); - public Set mergedHeap = new HashSet<>(); - public Set csHeap = new HashSet<>(); + protected final Map heapModelMap = new HashMap<>(); + public Set mergedHeap = new HashSet<>(); + public Set csHeap = new HashSet<>(); - public MahjongPTA(int k, int hk, CtxConstructor ctxCons) { - this.ctxCons = ctxCons; - CtxSelector us = new UniformSelector(k, hk); - CtxSelector ds = new DebloatingSelector(csHeap); - this.ctxSel = new PipelineSelector(us, ds); - this.heapAbst = new MahjongAbstractor(pag, mergedHeap, heapModelMap); - System.out.println("Mahjong ..."); - } + public MahjongPTA(int k, int hk, CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new UniformSelector(k, hk); + CtxSelector ds = new DebloatingSelector(csHeap); + this.ctxSel = new PipelineSelector(us, ds); + this.heapAbst = new MahjongAbstractor(pag, mergedHeap, heapModelMap); + System.out.println("Mahjong ..."); + } - @Override - protected void preAnalysis() { - PTAConfig.v().getPtaConfig().mergeHeap = false; - prePTA.pureRun(); + @Override + protected void preAnalysis() { + PTAConfig.v().getPtaConfig().mergeHeap = false; + prePTA.pureRun(); - Mahjong.run(prePTA, heapModelMap); - heapModelMap.forEach((origin, merged) -> { - if (pag.findAllocNode(origin) == null || pag.findAllocNode(merged) == null) { - return; - } - if (pag.findAllocNode(origin).getType() != pag.findAllocNode(merged).getType()) { - return; - } - if (!csHeap.add(merged)) { - mergedHeap.add(merged); - } + Mahjong.run(prePTA, heapModelMap); + heapModelMap.forEach( + (origin, merged) -> { + if (pag.findAllocNode(origin) == null || pag.findAllocNode(merged) == null) { + return; + } + if (pag.findAllocNode(origin).getType() != pag.findAllocNode(merged).getType()) { + return; + } + if (!csHeap.add(merged)) { + mergedHeap.add(merged); + } }); - csHeap.removeAll(mergedHeap); - System.out.println("#MERGE HEAP (not-single):" + mergedHeap.size()); - System.out.println("#NON-MERGED HEAP (single):" + csHeap.size()); - for (Object mh : mergedHeap) { - System.out.println(mh); - } + csHeap.removeAll(mergedHeap); + System.out.println("#MERGE HEAP (not-single):" + mergedHeap.size()); + System.out.println("#NON-MERGED HEAP (single):" + csHeap.size()); + for (Object mh : mergedHeap) { + System.out.println(mh); } + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java index aaa9010bd48..55b05030bb9 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ObjectSensPTA.java @@ -31,20 +31,20 @@ * refer to "Parameterized object sensitivity for points-to analysis for Java" (TSE'05) * */ public class ObjectSensPTA extends BasePTA { - public ObjectSensPTA(int k, int hk) { - this.ctxCons = new ObjCtxConstructor(); - CtxSelector us = new UniformSelector(k, hk); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - System.out.println(".... Heuristic..."); - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("k-OBJ ..."); + public ObjectSensPTA(int k, int hk) { + this.ctxCons = new ObjCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + System.out.println(".... Heuristic..."); + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("k-OBJ ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java index 2721a6ff7ed..92f785cf813 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -18,6 +18,9 @@ package qilin.pta.tools; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import qilin.core.CorePTA; import qilin.core.pag.*; import qilin.parm.ctxcons.CallsiteCtxConstructor; @@ -39,157 +42,154 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - public abstract class PartialCallSiteSensPTA extends StagedPTA { - protected Set csnodes = new HashSet<>(); - protected Set csmethods = new HashSet<>(); - protected CorePTA prePTA; - protected PAG prePAG; + protected Set csnodes = new HashSet<>(); + protected Set csmethods = new HashSet<>(); + protected CorePTA prePTA; + protected PAG prePAG; - // just for stats - Set PCSM = new HashSet<>(); - Set CSM = new HashSet<>(); + // just for stats + Set PCSM = new HashSet<>(); + Set CSM = new HashSet<>(); - public PartialCallSiteSensPTA(int ctxLen) { - this.ctxCons = new CallsiteCtxConstructor(); - CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - this.prePTA = new Spark(); - this.prePAG = prePTA.getPag(); + public PartialCallSiteSensPTA(int ctxLen) { + this.ctxCons = new CallsiteCtxConstructor(); + CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } - - @Override - protected void preAnalysis() { - Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); - prePTA.pureRun(); - sparkTimer.stop(); - System.out.println(sparkTimer); - select(); - extraStats(); + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); } + this.prePTA = new Spark(); + this.prePAG = prePTA.getPag(); + } - protected abstract Map calculatingNode2Length(); + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + select(); + extraStats(); + } - // =========context selector============= - protected void select() { - Stopwatch preTimer = Stopwatch.newAndStart("pre-analysis"); - Map ret = calculatingNode2Length(); - ret.forEach((sparkNode, l) -> { - if (l > 0) { - csnodes.add(PTAUtils.getIR(sparkNode)); - } - SootMethod method = null; - if (sparkNode instanceof LocalVarNode) { - method = ((LocalVarNode) sparkNode).getMethod(); - } else if (sparkNode instanceof AllocNode allocNode) { - method = allocNode.getMethod(); - } + protected abstract Map calculatingNode2Length(); - if (method != null) { - if (l == 0) { - PCSM.add(method); - } else { - CSM.add(method); - } + // =========context selector============= + protected void select() { + Stopwatch preTimer = Stopwatch.newAndStart("pre-analysis"); + Map ret = calculatingNode2Length(); + ret.forEach( + (sparkNode, l) -> { + if (l > 0) { + csnodes.add(PTAUtils.getIR(sparkNode)); + } + SootMethod method = null; + if (sparkNode instanceof LocalVarNode) { + method = ((LocalVarNode) sparkNode).getMethod(); + } else if (sparkNode instanceof AllocNode allocNode) { + method = allocNode.getMethod(); + } + + if (method != null) { + if (l == 0) { + PCSM.add(method); + } else { + CSM.add(method); } + } }); - PCSM.retainAll(CSM); - CSM.removeAll(PCSM); - csmethods.addAll(CSM); - csmethods.addAll(PCSM); - System.out.println("#CSNODES:" + csnodes.size()); - System.out.println("#CSMETHODS:" + csmethods.size()); - preTimer.stop(); - System.out.println(preTimer); - } + PCSM.retainAll(CSM); + CSM.removeAll(PCSM); + csmethods.addAll(CSM); + csmethods.addAll(PCSM); + System.out.println("#CSNODES:" + csnodes.size()); + System.out.println("#CSMETHODS:" + csmethods.size()); + preTimer.stop(); + System.out.println(preTimer); + } - protected void extraStats() { - int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { - SootMethod method = momc.method(); - Set nodes = new HashSet<>(); - if (!method.isConcrete()) { - return; - } - MethodPAG srcmpag = pag.getMethodPAG(method); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - nodes.add(((VarNode) from).getVariable()); - } else if (from instanceof AllocNode) { - nodes.add(((AllocNode) from).getNewExpr()); - } else if (from instanceof FieldRefNode fr) { - VarNode base = fr.getBase(); - if (base instanceof LocalVarNode) { - nodes.add(base.getVariable()); - } - } + protected void extraStats() { + int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + SootMethod method = momc.method(); + Set nodes = new HashSet<>(); + if (!method.isConcrete()) { + return; + } + MethodPAG srcmpag = pag.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + nodes.add(((VarNode) from).getVariable()); + } else if (from instanceof AllocNode) { + nodes.add(((AllocNode) from).getNewExpr()); + } else if (from instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } - if (to instanceof LocalVarNode) { - nodes.add(((VarNode) to).getVariable()); - } else if (to instanceof FieldRefNode fr) { - VarNode base = fr.getBase(); - if (base instanceof LocalVarNode) { - nodes.add(base.getVariable()); - } - } - } - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { - continue; - } - nodes.add(arg); - } + if (to instanceof LocalVarNode) { + nodes.add(((VarNode) to).getVariable()); + } else if (to instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + } + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + nodes.add(arg); + } - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - nodes.add(dest); - } - } - if (ie instanceof AbstractInstanceInvokeExpr iie) { - Local base = iie.getBase(); - nodes.add(base); - } - } - for (Object o : nodes) { - int index = 0; - if (csnodes.contains(o)) { - index = 1; - } - if (index != 0) { - PCN[0]++; - } else { - NPCN[0]++; - } - totalN[0]++; - } - RM[0]++; + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + nodes.add(dest); + } + } + if (ie instanceof AbstractInstanceInvokeExpr iie) { + Local base = iie.getBase(); + nodes.add(base); + } + } + for (Object o : nodes) { + int index = 0; + if (csnodes.contains(o)) { + index = 1; + } + if (index != 0) { + PCN[0]++; + } else { + NPCN[0]++; } - RM[0]--; // For the FakeMain method. - System.out.println("#ReachableMethod:" + RM[0]); - System.out.println("#FCSM:" + CSM.size()); - System.out.println("#PCSM:" + PCSM.size()); - System.out.println("#CIM:" + (RM[0] - PCSM.size() - CSM.size())); - System.out.println("#CIN: " + NPCN[0]); - System.out.println("#CSN: " + PCN[0]); - System.out.println("totalN: " + totalN[0]); + totalN[0]++; + } + RM[0]++; } + RM[0]--; // For the FakeMain method. + System.out.println("#ReachableMethod:" + RM[0]); + System.out.println("#FCSM:" + CSM.size()); + System.out.println("#PCSM:" + PCSM.size()); + System.out.println("#CIM:" + (RM[0] - PCSM.size() - CSM.size())); + System.out.println("#CIN: " + NPCN[0]); + System.out.println("#CSN: " + PCN[0]); + System.out.println("totalN: " + totalN[0]); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java index 87282a87ae5..2e908512e31 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/PartialObjSensPTA.java @@ -18,6 +18,9 @@ package qilin.pta.tools; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import qilin.core.pag.*; import qilin.parm.ctxcons.ObjCtxConstructor; import qilin.parm.heapabst.AllocSiteAbstractor; @@ -41,157 +44,154 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - public abstract class PartialObjSensPTA extends StagedPTA { - protected Set csnodes = new HashSet<>(); - protected Set csmethods = new HashSet<>(); - protected PAG prePAG; + protected Set csnodes = new HashSet<>(); + protected Set csmethods = new HashSet<>(); + protected PAG prePAG; - // just for stats - Set PCSM = new HashSet<>(); - Set CSM = new HashSet<>(); + // just for stats + Set PCSM = new HashSet<>(); + Set CSM = new HashSet<>(); - public PartialObjSensPTA(int ctxLen) { - this.ctxCons = new ObjCtxConstructor(); - CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - this.prePTA = new Spark(); - this.prePAG = prePTA.getPag(); + public PartialObjSensPTA(int ctxLen) { + this.ctxCons = new ObjCtxConstructor(); + CtxSelector us = new PartialVarSelector(ctxLen, ctxLen - 1, csnodes, csmethods); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } - - @Override - protected void preAnalysis() { - Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); - prePTA.pureRun(); - sparkTimer.stop(); - System.out.println(sparkTimer); - select(); - extraStats(); + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); } + this.prePTA = new Spark(); + this.prePAG = prePTA.getPag(); + } - protected abstract Map calculatingNode2Length(); + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + select(); + extraStats(); + } - // =========context selector============= - protected void select() { - Stopwatch preTimer = Stopwatch.newAndStart("pre-analysis"); - Map ret = calculatingNode2Length(); - ret.forEach((sparkNode, l) -> { - if (l > 0) { - csnodes.add(PTAUtils.getIR(sparkNode)); - } - SootMethod method = null; - if (sparkNode instanceof LocalVarNode) { - method = ((LocalVarNode) sparkNode).getMethod(); - } else if (sparkNode instanceof AllocNode allocNode) { - method = allocNode.getMethod(); - } + protected abstract Map calculatingNode2Length(); - if (method != null) { - if (l == 0) { - PCSM.add(method); - } else { - CSM.add(method); - } + // =========context selector============= + protected void select() { + Stopwatch preTimer = Stopwatch.newAndStart("pre-analysis"); + Map ret = calculatingNode2Length(); + ret.forEach( + (sparkNode, l) -> { + if (l > 0) { + csnodes.add(PTAUtils.getIR(sparkNode)); + } + SootMethod method = null; + if (sparkNode instanceof LocalVarNode) { + method = ((LocalVarNode) sparkNode).getMethod(); + } else if (sparkNode instanceof AllocNode allocNode) { + method = allocNode.getMethod(); + } + + if (method != null) { + if (l == 0) { + PCSM.add(method); + } else { + CSM.add(method); } + } }); - PCSM.retainAll(CSM); - CSM.removeAll(PCSM); - csmethods.addAll(CSM); - csmethods.addAll(PCSM); - System.out.println("#CSNODES:" + csnodes.size()); - System.out.println("#CSMETHODS:" + csmethods.size()); - preTimer.stop(); - System.out.println(preTimer); - } + PCSM.retainAll(CSM); + CSM.removeAll(PCSM); + csmethods.addAll(CSM); + csmethods.addAll(PCSM); + System.out.println("#CSNODES:" + csnodes.size()); + System.out.println("#CSMETHODS:" + csmethods.size()); + preTimer.stop(); + System.out.println(preTimer); + } - protected void extraStats() { - int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { - SootMethod method = momc.method(); - Set nodes = new HashSet<>(); - if (!method.isConcrete()) { - return; - } - MethodPAG srcmpag = pag.getMethodPAG(method); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - nodes.add(((VarNode) from).getVariable()); - } else if (from instanceof AllocNode) { - nodes.add(((AllocNode) from).getNewExpr()); - } else if (from instanceof FieldRefNode fr) { - VarNode base = fr.getBase(); - if (base instanceof LocalVarNode) { - nodes.add(base.getVariable()); - } - } + protected void extraStats() { + int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + SootMethod method = momc.method(); + Set nodes = new HashSet<>(); + if (!method.isConcrete()) { + return; + } + MethodPAG srcmpag = pag.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + nodes.add(((VarNode) from).getVariable()); + } else if (from instanceof AllocNode) { + nodes.add(((AllocNode) from).getNewExpr()); + } else if (from instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } - if (to instanceof LocalVarNode) { - nodes.add(((VarNode) to).getVariable()); - } else if (to instanceof FieldRefNode fr) { - VarNode base = fr.getBase(); - if (base instanceof LocalVarNode) { - nodes.add(base.getVariable()); - } - } - } - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { - continue; - } - nodes.add(arg); - } + if (to instanceof LocalVarNode) { + nodes.add(((VarNode) to).getVariable()); + } else if (to instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + } + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + nodes.add(arg); + } - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - nodes.add(dest); - } - } - if (ie instanceof AbstractInstanceInvokeExpr iie) { - Local base = iie.getBase(); - nodes.add(base); - } - } - for (Object o : nodes) { - int index = 0; - if (csnodes.contains(o)) { - index = 1; - } - if (index != 0) { - PCN[0]++; - } else { - NPCN[0]++; - } - totalN[0]++; - } -// System.out.println(method); - RM[0]++; + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + nodes.add(dest); + } + } + if (ie instanceof AbstractInstanceInvokeExpr iie) { + Local base = iie.getBase(); + nodes.add(base); + } + } + for (Object o : nodes) { + int index = 0; + if (csnodes.contains(o)) { + index = 1; + } + if (index != 0) { + PCN[0]++; + } else { + NPCN[0]++; } - RM[0]--; // For the FakeMain method. - System.out.println("#ReachableMethod:" + RM[0]); - System.out.println("#FCSM:" + CSM.size()); - System.out.println("#PCSM:" + PCSM.size()); - System.out.println("#CIM:" + (RM[0] - PCSM.size() - CSM.size())); - System.out.println("#CIN: " + NPCN[0]); - System.out.println("#CSN: " + PCN[0]); - System.out.println("totalN: " + totalN[0]); + totalN[0]++; + } + // System.out.println(method); + RM[0]++; } + RM[0]--; // For the FakeMain method. + System.out.println("#ReachableMethod:" + RM[0]); + System.out.println("#FCSM:" + CSM.size()); + System.out.println("#PCSM:" + PCSM.size()); + System.out.println("#CIM:" + (RM[0] - PCSM.size() - CSM.size())); + System.out.println("#CIN: " + NPCN[0]); + System.out.println("#CSN: " + PCN[0]); + System.out.println("totalN: " + totalN[0]); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java index 3640b614914..52c23a34a5c 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/SelectxPTA.java @@ -18,31 +18,29 @@ package qilin.pta.tools; -import qilin.pta.toolkits.selectx.Selectx; - import java.util.Map; +import qilin.pta.toolkits.selectx.Selectx; public class SelectxPTA extends PartialCallSiteSensPTA { - public SelectxPTA(int ctxLen) { - super(ctxLen); - System.out.println("selectx ... "); - } - - //=========context selector============= + public SelectxPTA(int ctxLen) { + super(ctxLen); + System.out.println("selectx ... "); + } - @Override - protected Map calculatingNode2Length() { - System.out.print("Construct transPAG..."); - long time = System.currentTimeMillis(); + // =========context selector============= - prePAG = prePTA.getPag(); - Selectx selectx = new Selectx(prePTA); + @Override + protected Map calculatingNode2Length() { + System.out.print("Construct transPAG..."); + long time = System.currentTimeMillis(); - System.out.println((System.currentTimeMillis() - time) / 1000 + "s"); + prePAG = prePTA.getPag(); + Selectx selectx = new Selectx(prePTA); - System.out.println("Propagate.."); - return selectx.process(); - } + System.out.println((System.currentTimeMillis() - time) / 1000 + "s"); + System.out.println("Propagate.."); + return selectx.process(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java index da0a21fb2fb..a03abd7f0c2 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/Spark.java @@ -28,14 +28,14 @@ * refer to "Scaling Java Points-To Analysis using SPARK" (CC'03) * */ public class Spark extends BasePTA { - public Spark() { - this.ctxCons = new InsensCtxConstructor(); - this.ctxSel = new InsenSelector(); - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("Context-Insensitive ..."); + public Spark() { + this.ctxCons = new InsensCtxConstructor(); + this.ctxSel = new InsenSelector(); + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); } + System.out.println("Context-Insensitive ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java index 11788894772..9481625276b 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/StagedPTA.java @@ -25,25 +25,25 @@ * This class gives a structure for such kinds of analyses. * */ public abstract class StagedPTA extends BasePTA { - protected BasePTA prePTA; + protected BasePTA prePTA; - public BasePTA getPrePTA() { - return this.prePTA; - } + public BasePTA getPrePTA() { + return this.prePTA; + } - protected abstract void preAnalysis(); + protected abstract void preAnalysis(); - protected void mainAnalysis() { - if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { - System.out.println("selective pta starts!"); - super.run(); - } + protected void mainAnalysis() { + if (!PTAConfig.v().getPtaConfig().preAnalysisOnly) { + System.out.println("selective pta starts!"); + super.run(); } + } - @Override - public void run() { - preAnalysis(); - prePTA.getPag().resetPointsToSet(); - mainAnalysis(); - } + @Override + public void run() { + preAnalysis(); + prePTA.getPag().resetPointsToSet(); + mainAnalysis(); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java index dc02e2a5f15..55ed417c476 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TunnelingPTA.java @@ -34,19 +34,19 @@ * not show the claimed effectiveness. Maybe we should train the benchmarks to get new formulas? * */ public class TunnelingPTA extends BasePTA { - public TunnelingPTA(CtxConstructor ctxCons, int k, int hk) { - this.ctxCons = new TunnelingConstructor(ctxCons); - CtxSelector us = new UniformSelector(k, hk); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("context-tunneling ..."); + public TunnelingPTA(CtxConstructor ctxCons, int k, int hk) { + this.ctxCons = new TunnelingConstructor(ctxCons); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("context-tunneling ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java index cb159f3397c..4d4e9115982 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TurnerPTA.java @@ -18,25 +18,24 @@ package qilin.pta.tools; -import qilin.pta.toolkits.turner.Turner; - import java.util.Map; +import qilin.pta.toolkits.turner.Turner; /* * refer to "Accelerating Object-Sensitive Pointer Analysis by Exploiting Object Containment and Reachability" (ECOOP'21) * */ public class TurnerPTA extends PartialObjSensPTA { - private final int k; + private final int k; - public TurnerPTA(int k) { - super(k); - this.k = k; - System.out.println("Turner ..."); - } + public TurnerPTA(int k) { + super(k); + this.k = k; + System.out.println("Turner ..."); + } - @Override - protected Map calculatingNode2Length() { - Turner turner = new Turner(k, prePTA); - return turner.contxtLengthAnalysis(); - } -} \ No newline at end of file + @Override + protected Map calculatingNode2Length() { + Turner turner = new Turner(k, prePTA); + return turner.contxtLengthAnalysis(); + } +} diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java index 022996b4743..125a3e8a1db 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/TypeSensPTA.java @@ -32,19 +32,19 @@ * */ public class TypeSensPTA extends BasePTA { - public TypeSensPTA(int k, int hk) { - this.ctxCons = new TypeCtxConstructor(); - CtxSelector us = new UniformSelector(k, hk); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - System.out.println("k-type ..."); + public TypeSensPTA(int k, int hk) { + this.ctxCons = new TypeCtxConstructor(); + CtxSelector us = new UniformSelector(k, hk); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); + } + System.out.println("k-type ..."); + } } diff --git a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java index 883eccca646..91195f15e9e 100644 --- a/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java +++ b/sootup.qilin/src/main/java/qilin/pta/tools/ZipperPTA.java @@ -18,6 +18,8 @@ package qilin.pta.tools; +import java.util.HashSet; +import java.util.Set; import qilin.core.pag.*; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.AllocSiteAbstractor; @@ -41,122 +43,119 @@ import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; -import java.util.HashSet; -import java.util.Set; - /* * refer to "Precision-Guided Context Sensitivity for Pointer Analysis" (OOPSLA'18) * and "A Principled Approach to Selective Context Sensitivity for Pointer Analysis" (TOPLAS'20) * */ public class ZipperPTA extends StagedPTA { - private final Set PCMs = new HashSet<>(); + private final Set PCMs = new HashSet<>(); - /* - * Zipper support object-sensitivity, callsite-sensitivity by using corresponding - * context-constructor. - * */ - public ZipperPTA(int k, int hk, CtxConstructor ctxCons) { - this.ctxCons = ctxCons; - CtxSelector us = new PartialMethodLvSelector(k, hk, PCMs); - if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { - this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); - } else { - this.ctxSel = us; - } - if (PTAConfig.v().getPtaConfig().mergeHeap) { - this.heapAbst = new HeuristicAbstractor(pag); - } else { - this.heapAbst = new AllocSiteAbstractor(); - } - this.prePTA = new Spark(); + /* + * Zipper support object-sensitivity, callsite-sensitivity by using corresponding + * context-constructor. + * */ + public ZipperPTA(int k, int hk, CtxConstructor ctxCons) { + this.ctxCons = ctxCons; + CtxSelector us = new PartialMethodLvSelector(k, hk, PCMs); + if (PTAConfig.v().getPtaConfig().enforceEmptyCtxForIgnoreTypes) { + this.ctxSel = new PipelineSelector(new HeuristicSelector(), us); + } else { + this.ctxSel = us; } - - @Override - protected void preAnalysis() { - Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); - prePTA.pureRun(); - sparkTimer.stop(); - System.out.println(sparkTimer); - Stopwatch zipperTimer = Stopwatch.newAndStart("Zipper"); - Main.run(prePTA, PCMs); - zipperTimer.stop(); - System.out.println(zipperTimer); - extraStats(); + if (PTAConfig.v().getPtaConfig().mergeHeap) { + this.heapAbst = new HeuristicAbstractor(pag); + } else { + this.heapAbst = new AllocSiteAbstractor(); } + this.prePTA = new Spark(); + } - protected void extraStats() { - int[] RM = new int[1], PCN = new int[1], NPCN = new int[1]; - int[] totalN = new int[1]; - for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { - SootMethod method = momc.method(); - Set nodes = new HashSet<>(); + @Override + protected void preAnalysis() { + Stopwatch sparkTimer = Stopwatch.newAndStart("Spark"); + prePTA.pureRun(); + sparkTimer.stop(); + System.out.println(sparkTimer); + Stopwatch zipperTimer = Stopwatch.newAndStart("Zipper"); + Main.run(prePTA, PCMs); + zipperTimer.stop(); + System.out.println(zipperTimer); + extraStats(); + } - if (!method.isConcrete()) { - return; - } - MethodPAG srcmpag = pag.getMethodPAG(method); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - nodes.add(((VarNode) from).getVariable()); - } else if (from instanceof AllocNode) { - nodes.add(((AllocNode) from).getNewExpr()); - } else if (from instanceof FieldRefNode fr) { - VarNode base = fr.getBase(); - if (base instanceof LocalVarNode) { - nodes.add(base.getVariable()); - } - } + protected void extraStats() { + int[] RM = new int[1], PCN = new int[1], NPCN = new int[1]; + int[] totalN = new int[1]; + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { + SootMethod method = momc.method(); + Set nodes = new HashSet<>(); - if (to instanceof LocalVarNode) { - nodes.add(((VarNode) to).getVariable()); - } else if (to instanceof FieldRefNode fr) { - VarNode base = fr.getBase(); - if (base instanceof LocalVarNode) { - nodes.add(base.getVariable()); - } - } - } - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - int numArgs = ie.getArgCount(); - for (int i = 0; i < numArgs; i++) { - Value arg = ie.getArg(i); - if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { - continue; - } - nodes.add(arg); - } - - if (s instanceof JAssignStmt) { - Value dest = ((JAssignStmt) s).getLeftOp(); - if (dest.getType() instanceof ReferenceType) { - nodes.add(dest); - } - } - if (ie instanceof AbstractInstanceInvokeExpr iie) { - Local base = iie.getBase(); - nodes.add(base); - } - } + if (!method.isConcrete()) { + return; + } + MethodPAG srcmpag = pag.getMethodPAG(method); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + nodes.add(((VarNode) from).getVariable()); + } else if (from instanceof AllocNode) { + nodes.add(((AllocNode) from).getNewExpr()); + } else if (from instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } - if (PCMs.contains(method)) { - PCN[0] += nodes.size(); - } else { - NPCN[0] += nodes.size(); - } - RM[0]++; + if (to instanceof LocalVarNode) { + nodes.add(((VarNode) to).getVariable()); + } else if (to instanceof FieldRefNode fr) { + VarNode base = fr.getBase(); + if (base instanceof LocalVarNode) { + nodes.add(base.getVariable()); + } + } + } + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + int numArgs = ie.getArgCount(); + for (int i = 0; i < numArgs; i++) { + Value arg = ie.getArg(i); + if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) { + continue; + } + nodes.add(arg); + } - totalN[0] += nodes.size(); + if (s instanceof JAssignStmt) { + Value dest = ((JAssignStmt) s).getLeftOp(); + if (dest.getType() instanceof ReferenceType) { + nodes.add(dest); + } } - RM[0]--; // For the FakeMain method. - System.out.println("#ReachableMethod:" + RM[0]); - System.out.println("#FCSM:" + PCMs.size()); - System.out.println("#PCSM:0"); - System.out.println("#CIM:" + (RM[0] - PCMs.size())); - System.out.println("#CIN: " + NPCN[0]); - System.out.println("#CSN: " + PCN[0]); - System.out.println("totalN: " + totalN[0]); + if (ie instanceof AbstractInstanceInvokeExpr iie) { + Local base = iie.getBase(); + nodes.add(base); + } + } + + if (PCMs.contains(method)) { + PCN[0] += nodes.size(); + } else { + NPCN[0] += nodes.size(); + } + RM[0]++; + + totalN[0] += nodes.size(); } + RM[0]--; // For the FakeMain method. + System.out.println("#ReachableMethod:" + RM[0]); + System.out.println("#FCSM:" + PCMs.size()); + System.out.println("#PCSM:0"); + System.out.println("#CIM:" + (RM[0] - PCMs.size())); + System.out.println("#CIN: " + NPCN[0]); + System.out.println("#CSN: " + PCN[0]); + System.out.println("totalN: " + totalN[0]); + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/AbstractStat.java b/sootup.qilin/src/main/java/qilin/stat/AbstractStat.java index bafb994e668..351c21f345b 100644 --- a/sootup.qilin/src/main/java/qilin/stat/AbstractStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/AbstractStat.java @@ -19,5 +19,5 @@ package qilin.stat; public interface AbstractStat { - void export(Exporter exporter); + void export(Exporter exporter); } diff --git a/sootup.qilin/src/main/java/qilin/stat/AliasStat.java b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java index 430385299f9..c99ddac0b19 100644 --- a/sootup.qilin/src/main/java/qilin/stat/AliasStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/AliasStat.java @@ -18,6 +18,12 @@ package qilin.stat; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import qilin.core.PTA; import qilin.core.pag.FieldRefNode; import qilin.core.pag.LocalVarNode; @@ -33,146 +39,151 @@ import sootup.core.jimple.basic.Local; import sootup.core.model.SootMethod; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - public class AliasStat implements AbstractStat { - private final PTA pta; - Map> assignMap = new HashMap<>(); - Map>> globalMap = new HashMap<>(); - private int intraAlias = 0, intraAlias_incstst = 0, globalAlias = 0, globalAlias_incstst = 0; - private int intraAlias_app = 0, intraAlias_incstst_app = 0, globalAlias_app = 0, globalAlias_incstst_app = 0; + private final PTA pta; + Map> assignMap = new HashMap<>(); + Map>> globalMap = new HashMap<>(); + private int intraAlias = 0, intraAlias_incstst = 0, globalAlias = 0, globalAlias_incstst = 0; + private int intraAlias_app = 0, + intraAlias_incstst_app = 0, + globalAlias_app = 0, + globalAlias_incstst_app = 0; - public AliasStat(PTA pta) { - this.pta = pta; - } + public AliasStat(PTA pta) { + this.pta = pta; + } - private Pair recordAndComputeIntraAliases(Set reachableMethods) { - int intraAlias = 0; - int intraAlias_incstst = 0; - for (SootMethod m : reachableMethods) { - Map>> localMap = new HashMap<>(); - MethodPAG srcmpag = pta.getPag().getMethodPAG(m); - QueueReader reader = srcmpag.getInternalReader().clone(); - while (reader.hasNext()) { - Node from = reader.next(), to = reader.next(); - if (from instanceof LocalVarNode) { - if (to instanceof LocalVarNode) { - if (!(((VarNode) from).getVariable() instanceof Local)) - continue; - if (!(((VarNode) to).getVariable() instanceof Local)) - continue; - Util.addToMap(assignMap, (LocalVarNode) from, (LocalVarNode) to); - Util.addToMap(assignMap, (LocalVarNode) to, (LocalVarNode) from); - } else if (to instanceof FieldRefNode fr) { - LocalVarNode base = (LocalVarNode) fr.getBase(); - if (!(base.getVariable() instanceof Local)) - continue; - addToMap(globalMap, fr.getField(), true, base); - addToMap(localMap, fr.getField(), true, base); - }//else//local-global - } else if (from instanceof FieldRefNode fr) { - LocalVarNode base = (LocalVarNode) fr.getBase(); - if (!(base.getVariable() instanceof Local)) - continue; - addToMap(globalMap, fr.getField(), false, base); - addToMap(localMap, fr.getField(), false, base); - }//else//global-local or new - } + private Pair recordAndComputeIntraAliases(Set reachableMethods) { + int intraAlias = 0; + int intraAlias_incstst = 0; + for (SootMethod m : reachableMethods) { + Map>> localMap = new HashMap<>(); + MethodPAG srcmpag = pta.getPag().getMethodPAG(m); + QueueReader reader = srcmpag.getInternalReader().clone(); + while (reader.hasNext()) { + Node from = reader.next(), to = reader.next(); + if (from instanceof LocalVarNode) { + if (to instanceof LocalVarNode) { + if (!(((VarNode) from).getVariable() instanceof Local)) continue; + if (!(((VarNode) to).getVariable() instanceof Local)) continue; + Util.addToMap(assignMap, (LocalVarNode) from, (LocalVarNode) to); + Util.addToMap(assignMap, (LocalVarNode) to, (LocalVarNode) from); + } else if (to instanceof FieldRefNode fr) { + LocalVarNode base = (LocalVarNode) fr.getBase(); + if (!(base.getVariable() instanceof Local)) continue; + addToMap(globalMap, fr.getField(), true, base); + addToMap(localMap, fr.getField(), true, base); + } // else//local-global + } else if (from instanceof FieldRefNode fr) { + LocalVarNode base = (LocalVarNode) fr.getBase(); + if (!(base.getVariable() instanceof Local)) continue; + addToMap(globalMap, fr.getField(), false, base); + addToMap(localMap, fr.getField(), false, base); + } // else//global-local or new + } - int methodAlias = 0, methodAlias_incstst = 0; - for (Map> subMap : localMap.values()) { - Set storeSet = subMap.getOrDefault(true, Collections.emptySet()); - Set loadSet = subMap.getOrDefault(false, Collections.emptySet()); - int stld = checkAlias(storeSet, loadSet, assignMap) + checkAlias(loadSet, storeSet, assignMap); - int stst = checkAlias(storeSet, storeSet, assignMap); - methodAlias += stld; - methodAlias_incstst += stld + stst; - } + int methodAlias = 0, methodAlias_incstst = 0; + for (Map> subMap : localMap.values()) { + Set storeSet = subMap.getOrDefault(true, Collections.emptySet()); + Set loadSet = subMap.getOrDefault(false, Collections.emptySet()); + int stld = + checkAlias(storeSet, loadSet, assignMap) + checkAlias(loadSet, storeSet, assignMap); + int stst = checkAlias(storeSet, storeSet, assignMap); + methodAlias += stld; + methodAlias_incstst += stld + stst; + } - intraAlias += methodAlias; - intraAlias_incstst += methodAlias_incstst; - } - return new Pair<>(intraAlias, intraAlias_incstst); + intraAlias += methodAlias; + intraAlias_incstst += methodAlias_incstst; } + return new Pair<>(intraAlias, intraAlias_incstst); + } - private Pair computeInterAliases() { - int globalAlias = 0; - int globalAlias_incstst = 0; - for (Map> subMap : globalMap.values()) { - Set storeSet = subMap.getOrDefault(true, Collections.emptySet()); - Set loadSet = subMap.getOrDefault(false, Collections.emptySet()); - int stld = checkAlias(storeSet, loadSet, assignMap) + checkAlias(loadSet, storeSet, assignMap); - int stst = checkAlias(storeSet, storeSet, assignMap); - globalAlias += stld; - globalAlias_incstst += stld + stst; - } - return new Pair<>(globalAlias, globalAlias_incstst); + private Pair computeInterAliases() { + int globalAlias = 0; + int globalAlias_incstst = 0; + for (Map> subMap : globalMap.values()) { + Set storeSet = subMap.getOrDefault(true, Collections.emptySet()); + Set loadSet = subMap.getOrDefault(false, Collections.emptySet()); + int stld = + checkAlias(storeSet, loadSet, assignMap) + checkAlias(loadSet, storeSet, assignMap); + int stst = checkAlias(storeSet, storeSet, assignMap); + globalAlias += stld; + globalAlias_incstst += stld + stst; } + return new Pair<>(globalAlias, globalAlias_incstst); + } - private int checkAlias(Set set1, Set set2, Map> exclMap) { - int num = 0; - for (LocalVarNode l1 : set1) { - Set exclSet = exclMap.getOrDefault(l1, Collections.emptySet()); - int l1Hashcode = l1.hashCode(); - for (LocalVarNode l2 : set2) { - int l2Hashcode = l2.hashCode(); - if (l2Hashcode <= l1Hashcode || exclSet.contains(l2)) { - continue; - } - if (checkAlias(l1, l2)) { - num++; - } - } + private int checkAlias( + Set set1, + Set set2, + Map> exclMap) { + int num = 0; + for (LocalVarNode l1 : set1) { + Set exclSet = exclMap.getOrDefault(l1, Collections.emptySet()); + int l1Hashcode = l1.hashCode(); + for (LocalVarNode l2 : set2) { + int l2Hashcode = l2.hashCode(); + if (l2Hashcode <= l1Hashcode || exclSet.contains(l2)) { + continue; + } + if (checkAlias(l1, l2)) { + num++; } - return num; + } } + return num; + } - private boolean checkAlias(LocalVarNode l1, LocalVarNode l2) { - PointsToSet pts1 = pta.reachingObjects((Local) l1.getVariable()); - PointsToSet pts2 = pta.reachingObjects((Local) l2.getVariable()); - return pts1.hasNonEmptyIntersection(pts2); - } + private boolean checkAlias(LocalVarNode l1, LocalVarNode l2) { + PointsToSet pts1 = pta.reachingObjects((Local) l1.getVariable()); + PointsToSet pts2 = pta.reachingObjects((Local) l2.getVariable()); + return pts1.hasNonEmptyIntersection(pts2); + } - public static boolean addToMap(Map>> m, K key1, T key2, V value) { - Map> subMap = m.computeIfAbsent(key1, k -> new HashMap<>()); - return Util.addToMap(subMap, key2, value); - } + public static boolean addToMap(Map>> m, K key1, T key2, V value) { + Map> subMap = m.computeIfAbsent(key1, k -> new HashMap<>()); + return Util.addToMap(subMap, key2, value); + } - public void aliasesProcessing() { - Collection reachableMethods = pta.getNakedReachableMethods(); - Pair r1 = recordAndComputeIntraAliases(reachableMethods.stream().filter(PTAUtils::isApplicationMethod).collect(Collectors.toSet())); - this.intraAlias_app = r1.getFirst(); - this.intraAlias_incstst_app = r1.getSecond(); - Pair r2 = computeInterAliases(); - this.globalAlias_app = r2.getFirst(); - this.globalAlias_incstst_app = r2.getSecond(); - Pair r3 = recordAndComputeIntraAliases(reachableMethods.stream().filter(m -> !PTAUtils.isApplicationMethod(m)).collect(Collectors.toSet())); - this.intraAlias = this.intraAlias_app + r3.getFirst(); - this.intraAlias_incstst = this.intraAlias_incstst_app + r3.getSecond(); - Pair r4 = computeInterAliases(); - this.globalAlias = r4.getFirst(); - this.globalAlias_incstst = r4.getSecond(); - } + public void aliasesProcessing() { + Collection reachableMethods = pta.getNakedReachableMethods(); + Pair r1 = + recordAndComputeIntraAliases( + reachableMethods.stream() + .filter(PTAUtils::isApplicationMethod) + .collect(Collectors.toSet())); + this.intraAlias_app = r1.getFirst(); + this.intraAlias_incstst_app = r1.getSecond(); + Pair r2 = computeInterAliases(); + this.globalAlias_app = r2.getFirst(); + this.globalAlias_incstst_app = r2.getSecond(); + Pair r3 = + recordAndComputeIntraAliases( + reachableMethods.stream() + .filter(m -> !PTAUtils.isApplicationMethod(m)) + .collect(Collectors.toSet())); + this.intraAlias = this.intraAlias_app + r3.getFirst(); + this.intraAlias_incstst = this.intraAlias_incstst_app + r3.getSecond(); + Pair r4 = computeInterAliases(); + this.globalAlias = r4.getFirst(); + this.globalAlias_incstst = r4.getSecond(); + } - public int getGlobalAliasesIncludingStSt() { - return globalAlias_incstst; - } + public int getGlobalAliasesIncludingStSt() { + return globalAlias_incstst; + } - @Override - public void export(Exporter exporter) { - aliasesProcessing(); - exporter.collectMetric("#intraAlias(App):", String.valueOf(intraAlias_app)); - exporter.collectMetric("#intraAlias_incstst(App):", String.valueOf(intraAlias_incstst_app)); - exporter.collectMetric("#globalAlias(App):", String.valueOf(globalAlias_app)); - exporter.collectMetric("#globalAlias_incstst(App):", String.valueOf(globalAlias_incstst_app)); - exporter.collectMetric("#intraAlias:", String.valueOf(intraAlias)); - exporter.collectMetric("#intraAlias_incstst:", String.valueOf(intraAlias_incstst)); - exporter.collectMetric("#globalAlias:", String.valueOf(globalAlias)); - exporter.collectMetric("#globalAlias_incstst:", String.valueOf(globalAlias_incstst)); - } + @Override + public void export(Exporter exporter) { + aliasesProcessing(); + exporter.collectMetric("#intraAlias(App):", String.valueOf(intraAlias_app)); + exporter.collectMetric("#intraAlias_incstst(App):", String.valueOf(intraAlias_incstst_app)); + exporter.collectMetric("#globalAlias(App):", String.valueOf(globalAlias_app)); + exporter.collectMetric("#globalAlias_incstst(App):", String.valueOf(globalAlias_incstst_app)); + exporter.collectMetric("#intraAlias:", String.valueOf(intraAlias)); + exporter.collectMetric("#intraAlias_incstst:", String.valueOf(intraAlias_incstst)); + exporter.collectMetric("#globalAlias:", String.valueOf(globalAlias)); + exporter.collectMetric("#globalAlias_incstst:", String.valueOf(globalAlias_incstst)); + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java index b53dc025961..ae1b43cb075 100644 --- a/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/BenchmarkStat.java @@ -18,58 +18,61 @@ package qilin.stat; +import java.util.Set; +import java.util.stream.Collectors; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; import sootup.core.model.SootClass; import sootup.core.types.ClassType; -import java.util.Set; -import java.util.stream.Collectors; - public class BenchmarkStat implements AbstractStat { - private final PTA pta; + private final PTA pta; - private int classes = 0; - private int appClasses = 0; - private int phantomClasses = 0; - private int libClasses = 0; - private Set reachableClasses; - private Set reachableAppClasses; - int libReachableClasses = 0; + private int classes = 0; + private int appClasses = 0; + private int phantomClasses = 0; + private int libClasses = 0; + private Set reachableClasses; + private Set reachableAppClasses; + int libReachableClasses = 0; - public BenchmarkStat(PTA pta) { - this.pta = pta; - init(); - } + public BenchmarkStat(PTA pta) { + this.pta = pta; + init(); + } - private void init() { - reachableClasses = pta.getNakedReachableMethods().stream().map(m -> { - ClassType classType = m.getDeclaringClassType(); - return (SootClass) PTAScene.v().getView().getClass(classType).get(); - }).collect(Collectors.toSet()); - reachableAppClasses = reachableClasses.stream().filter(SootClass::isApplicationClass) - .collect(Collectors.toSet()); + private void init() { + reachableClasses = + pta.getNakedReachableMethods().stream() + .map( + m -> { + ClassType classType = m.getDeclaringClassType(); + return (SootClass) PTAScene.v().getView().getClass(classType).get(); + }) + .collect(Collectors.toSet()); + reachableAppClasses = + reachableClasses.stream().filter(SootClass::isApplicationClass).collect(Collectors.toSet()); - classes = PTAScene.v().getClasses().size(); - appClasses = PTAScene.v().getApplicationClasses().size(); - phantomClasses = PTAScene.v().getPhantomClasses().size(); - libClasses = classes - appClasses - phantomClasses; - libReachableClasses = (reachableClasses.size() - reachableAppClasses.size() - 1); // -FakeMain - } + classes = PTAScene.v().getClasses().size(); + appClasses = PTAScene.v().getApplicationClasses().size(); + phantomClasses = PTAScene.v().getPhantomClasses().size(); + libClasses = classes - appClasses - phantomClasses; + libReachableClasses = (reachableClasses.size() - reachableAppClasses.size() - 1); // -FakeMain + } - @Override - public void export(Exporter exporter) { - exporter.collectMetric("#Class:", String.valueOf(classes)); - exporter.collectMetric("#Appclass:", String.valueOf(appClasses)); - exporter.collectMetric("#Libclass:", String.valueOf(libClasses)); - exporter.collectMetric("#Phantomclass:", String.valueOf(phantomClasses)); - exporter.collectMetric("#Class(reachable):", String.valueOf(reachableClasses.size())); - exporter.collectMetric("#Appclass(reachable):", String.valueOf(reachableAppClasses.size())); - exporter.collectMetric("#Libclass(reachable):", String.valueOf(libReachableClasses)); + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Class:", String.valueOf(classes)); + exporter.collectMetric("#Appclass:", String.valueOf(appClasses)); + exporter.collectMetric("#Libclass:", String.valueOf(libClasses)); + exporter.collectMetric("#Phantomclass:", String.valueOf(phantomClasses)); + exporter.collectMetric("#Class(reachable):", String.valueOf(reachableClasses.size())); + exporter.collectMetric("#Appclass(reachable):", String.valueOf(reachableAppClasses.size())); + exporter.collectMetric("#Libclass(reachable):", String.valueOf(libReachableClasses)); - if (CoreConfig.v().getOutConfig().dumpStats) { - exporter.dumpClassTypes(PTAScene.v().getClasses()); - } + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpClassTypes(PTAScene.v().getClasses()); } + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java index 97faaca4f14..4f7fe8e25ee 100644 --- a/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/CallGraphStat.java @@ -18,6 +18,10 @@ package qilin.stat; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; @@ -32,178 +36,198 @@ import sootup.core.model.SootClass; import sootup.core.model.SootMethod; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - public class CallGraphStat implements AbstractStat { - private final PTA pta; + private final PTA pta; - private final Set reachableMethods = new HashSet<>(); - private int reachableStatic = 0; - private final Set reachableParameterizedMethods = new HashSet<>(); - private final Set reachableAppParameterizedMethods = new HashSet<>(); - private final Set reachableAppMethods = new HashSet<>(); - private int reachableAppStatic = 0; - private int CSCallEdges = 0; - private int CSStaticToStatic = 0; - private int CSStaticToInstance = 0; - private int CSInstanceToStatic = 0; - private int CSInstancetoInstance = 0; - private int CSApp2lib = 0; - private int CSApp2app = 0; - private int CSLib2lib = 0; - private int CSLib2app = 0; - private int CICallEdges = 0; - private int CIApp2lib = 0; - private int CIApp2app = 0; - private int CILib2lib = 0; - private int CILib2app = 0; - private int CIStaticToStatic = 0; - private int CIStaticToInstance = 0; - private int CIInstanceToStatic = 0; - private int CIInstancetoInstance = 0; - private int allMethods = 0; + private final Set reachableMethods = new HashSet<>(); + private int reachableStatic = 0; + private final Set reachableParameterizedMethods = new HashSet<>(); + private final Set reachableAppParameterizedMethods = new HashSet<>(); + private final Set reachableAppMethods = new HashSet<>(); + private int reachableAppStatic = 0; + private int CSCallEdges = 0; + private int CSStaticToStatic = 0; + private int CSStaticToInstance = 0; + private int CSInstanceToStatic = 0; + private int CSInstancetoInstance = 0; + private int CSApp2lib = 0; + private int CSApp2app = 0; + private int CSLib2lib = 0; + private int CSLib2app = 0; + private int CICallEdges = 0; + private int CIApp2lib = 0; + private int CIApp2app = 0; + private int CILib2lib = 0; + private int CILib2app = 0; + private int CIStaticToStatic = 0; + private int CIStaticToInstance = 0; + private int CIInstanceToStatic = 0; + private int CIInstancetoInstance = 0; + private int allMethods = 0; - public CallGraphStat(PTA pta) { - this.pta = pta; - init(); - } + public CallGraphStat(PTA pta) { + this.pta = pta; + init(); + } - private void init() { - // stat method numbers - Collection clazzs = PTAScene.v().getView().getClasses(); - for (SootClass clazz : clazzs) { - allMethods += clazz.getMethods().size(); - } - // - CallGraph csCallGraph = pta.getCgb().getCallGraph(); - CSCallEdges = csCallGraph.size(); - for (final MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { - final SootMethod m = momc.method(); - boolean toApp = PTAUtils.isApplicationMethod(m); - reachableParameterizedMethods.add(momc); - reachableMethods.add(m); -// if (m.toString().equals("")) { -// System.out.println(PTAUtils.getMethodBody(m)); -// } + private void init() { + // stat method numbers + Collection clazzs = PTAScene.v().getView().getClasses(); + for (SootClass clazz : clazzs) { + allMethods += clazz.getMethods().size(); + } + // + CallGraph csCallGraph = pta.getCgb().getCallGraph(); + CSCallEdges = csCallGraph.size(); + for (final MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + final SootMethod m = momc.method(); + boolean toApp = PTAUtils.isApplicationMethod(m); + reachableParameterizedMethods.add(momc); + reachableMethods.add(m); + // if (m.toString().equals("")) { + // System.out.println(PTAUtils.getMethodBody(m)); + // } - if (toApp) { - reachableAppParameterizedMethods.add(momc); - reachableAppMethods.add(momc.method()); - } + if (toApp) { + reachableAppParameterizedMethods.add(momc); + reachableAppMethods.add(momc.method()); + } - for (Iterator iterator = csCallGraph.edgesInto(momc); iterator.hasNext(); ) { - Edge e = iterator.next(); - final SootMethod srcm = e.getSrc().method(); - boolean fromApp = PTAUtils.isApplicationMethod(srcm); - if (fromApp && toApp) { - CSApp2app++; - } else if (fromApp) { - CSApp2lib++; - } else if (!toApp) { - CSLib2lib++; - } else { - CSLib2app++; - } - if (e.src().isStatic()) { - if (e.isStatic()) { - CSStaticToStatic++; - } else { - CSStaticToInstance++; - } - } else if (e.isStatic()) { - CSInstanceToStatic++; - } else { - CSInstancetoInstance++; - } - } + for (Iterator iterator = csCallGraph.edgesInto(momc); iterator.hasNext(); ) { + Edge e = iterator.next(); + final SootMethod srcm = e.getSrc().method(); + boolean fromApp = PTAUtils.isApplicationMethod(srcm); + if (fromApp && toApp) { + CSApp2app++; + } else if (fromApp) { + CSApp2lib++; + } else if (!toApp) { + CSLib2lib++; + } else { + CSLib2app++; } - CallGraph ciCallGraph = pta.getCallGraph(); - CICallEdges = ciCallGraph.size(); - for (SootMethod sm : reachableMethods) { - boolean toApp = PTAUtils.isApplicationMethod(sm); - if (sm.isStatic()) { - reachableStatic++; - if (toApp) { - reachableAppStatic++; - } - } - for (Iterator iterator = ciCallGraph.edgesInto(new ContextMethod(sm, pta.emptyContext())); iterator.hasNext(); ) { - Edge e = iterator.next(); - final SootMethod srcm = e.getSrc().method(); -// if (sm.toString().equals("")) { -// System.out.println("from:" + srcm); -// } - boolean fromApp = PTAUtils.isApplicationMethod(srcm); - if (fromApp && toApp) { - CIApp2app++; - } else if (fromApp) { - CIApp2lib++; - } else if (!toApp) { - CILib2lib++; - } else { - CILib2app++; - } - - if (e.src().isStatic()) { - if (e.isStatic()) { - CIStaticToStatic++; - } else { - CIStaticToInstance++; - } - } else if (e.isStatic()) { - CIInstanceToStatic++; - } else { - CIInstancetoInstance++; - } - } + if (e.src().isStatic()) { + if (e.isStatic()) { + CSStaticToStatic++; + } else { + CSStaticToInstance++; + } + } else if (e.isStatic()) { + CSInstanceToStatic++; + } else { + CSInstancetoInstance++; } + } } + CallGraph ciCallGraph = pta.getCallGraph(); + CICallEdges = ciCallGraph.size(); + for (SootMethod sm : reachableMethods) { + boolean toApp = PTAUtils.isApplicationMethod(sm); + if (sm.isStatic()) { + reachableStatic++; + if (toApp) { + reachableAppStatic++; + } + } + for (Iterator iterator = + ciCallGraph.edgesInto(new ContextMethod(sm, pta.emptyContext())); + iterator.hasNext(); ) { + Edge e = iterator.next(); + final SootMethod srcm = e.getSrc().method(); + // if (sm.toString().equals("")) { + // System.out.println("from:" + srcm); + // } + boolean fromApp = PTAUtils.isApplicationMethod(srcm); + if (fromApp && toApp) { + CIApp2app++; + } else if (fromApp) { + CIApp2lib++; + } else if (!toApp) { + CILib2lib++; + } else { + CILib2app++; + } - private long thisReceiverCount() { - return pta.getCgb().getReceiverToSitesMap().entrySet().stream() - .filter(e -> e.getKey() instanceof ContextVarNode) - .filter(e -> e.getKey().base() instanceof LocalVarNode) - .filter(e -> ((LocalVarNode) e.getKey().base()).isThis()).count(); + if (e.src().isStatic()) { + if (e.isStatic()) { + CIStaticToStatic++; + } else { + CIStaticToInstance++; + } + } else if (e.isStatic()) { + CIInstanceToStatic++; + } else { + CIInstancetoInstance++; + } + } } + } - @Override - public void export(Exporter exporter) { - exporter.collectMetric("#Method (Static):", String.valueOf( allMethods - 1));// -fakeMain - exporter.collectMetric("#Reachable Method (CI):", String.valueOf(reachableMethods.size() - 1));// -fakeMain - exporter.collectMetric("\t#Reachable-Static Method (CI):", String.valueOf(reachableStatic - 1));// -fakeMain - exporter.collectMetric("#Reachable Method (CS):", String.valueOf(reachableParameterizedMethods.size() - 1));// -fakeMain - exporter.collectMetric("#Reachable App Method (CI):", String.valueOf(reachableAppMethods.size())); - exporter.collectMetric("\t#Reachable-App-Static Method (CI):", String.valueOf(reachableAppStatic)); - exporter.collectMetric("#Reachable App Method (CS):", String.valueOf(reachableAppParameterizedMethods.size())); - exporter.collectMetric("#Call Edge(CI):", String.valueOf(CICallEdges - FakeMainFactory.implicitCallEdges)); - exporter.collectMetric("\t#Static-Static Call Edge(CI):", String.valueOf(CIStaticToStatic - FakeMainFactory.implicitCallEdges)); - exporter.collectMetric("\t#Static-Instance Call Edge(CI):", String.valueOf(CIStaticToInstance)); - exporter.collectMetric("\t#Instance-Static Call Edge(CI):", String.valueOf(CIInstanceToStatic)); - exporter.collectMetric("\t#Instance-Instance Call Edge(CI):", String.valueOf(CIInstancetoInstance)); - exporter.collectMetric("\t#Application-Application Call Edge(CI):", String.valueOf(CIApp2app)); - exporter.collectMetric("\t#Application-Library Call Edge(CI):", String.valueOf(CIApp2lib)); - exporter.collectMetric("\t#Library-Application Call Edge(CI):", String.valueOf(CILib2app)); - exporter.collectMetric("\t#Library-Library Call Edge(CI):", String.valueOf(CILib2lib)); - exporter.collectMetric("#Call Edge(CS):", String.valueOf(CSCallEdges - FakeMainFactory.implicitCallEdges)); - exporter.collectMetric("\t#Static-Static Call Edge(CS):", String.valueOf(CSStaticToStatic - FakeMainFactory.implicitCallEdges)); - exporter.collectMetric("\t#Static-Instance Call Edge(CS):", String.valueOf(CSStaticToInstance)); - exporter.collectMetric("\t#Instance-Static Call Edge(CS):", String.valueOf(CSInstanceToStatic)); - exporter.collectMetric("\t#Instance-Instance Call Edge(CS):", String.valueOf(CSInstancetoInstance)); - exporter.collectMetric("\t#Application-Application Call Edge(CS):", String.valueOf(CSApp2app)); - exporter.collectMetric("\t#Application-Library Call Edge(CS):", String.valueOf(CSApp2lib)); - exporter.collectMetric("\t#Library-Application Call Edge(CS):", String.valueOf(CSLib2app)); - exporter.collectMetric("\t#Library-Library Call Edge(CS):", String.valueOf(CSLib2lib)); - exporter.collectMetric("#receivers:", String.valueOf(pta.getCgb().getReceiverToSitesMap().size())); - exporter.collectMetric("\t#thisreceivers:", String.valueOf(thisReceiverCount())); - exporter.collectMetric("#avg p2s size for virtualcalls:", String.valueOf((CSCallEdges - CSStaticToStatic - CSInstanceToStatic) - * 1.0 / pta.getCgb().getReceiverToSitesMap().size())); - if (CoreConfig.v().getOutConfig().dumpStats) { - exporter.dumpReachableMethods(reachableMethods); - exporter.dumpAppReachableMethods(reachableAppMethods); - exporter.dumpInsensCallGraph(pta.getCallGraph()); - } + private long thisReceiverCount() { + return pta.getCgb().getReceiverToSitesMap().entrySet().stream() + .filter(e -> e.getKey() instanceof ContextVarNode) + .filter(e -> e.getKey().base() instanceof LocalVarNode) + .filter(e -> ((LocalVarNode) e.getKey().base()).isThis()) + .count(); + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Method (Static):", String.valueOf(allMethods - 1)); // -fakeMain + exporter.collectMetric( + "#Reachable Method (CI):", String.valueOf(reachableMethods.size() - 1)); // -fakeMain + exporter.collectMetric( + "\t#Reachable-Static Method (CI):", String.valueOf(reachableStatic - 1)); // -fakeMain + exporter.collectMetric( + "#Reachable Method (CS):", + String.valueOf(reachableParameterizedMethods.size() - 1)); // -fakeMain + exporter.collectMetric( + "#Reachable App Method (CI):", String.valueOf(reachableAppMethods.size())); + exporter.collectMetric( + "\t#Reachable-App-Static Method (CI):", String.valueOf(reachableAppStatic)); + exporter.collectMetric( + "#Reachable App Method (CS):", String.valueOf(reachableAppParameterizedMethods.size())); + exporter.collectMetric( + "#Call Edge(CI):", String.valueOf(CICallEdges - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric( + "\t#Static-Static Call Edge(CI):", + String.valueOf(CIStaticToStatic - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("\t#Static-Instance Call Edge(CI):", String.valueOf(CIStaticToInstance)); + exporter.collectMetric("\t#Instance-Static Call Edge(CI):", String.valueOf(CIInstanceToStatic)); + exporter.collectMetric( + "\t#Instance-Instance Call Edge(CI):", String.valueOf(CIInstancetoInstance)); + exporter.collectMetric("\t#Application-Application Call Edge(CI):", String.valueOf(CIApp2app)); + exporter.collectMetric("\t#Application-Library Call Edge(CI):", String.valueOf(CIApp2lib)); + exporter.collectMetric("\t#Library-Application Call Edge(CI):", String.valueOf(CILib2app)); + exporter.collectMetric("\t#Library-Library Call Edge(CI):", String.valueOf(CILib2lib)); + exporter.collectMetric( + "#Call Edge(CS):", String.valueOf(CSCallEdges - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric( + "\t#Static-Static Call Edge(CS):", + String.valueOf(CSStaticToStatic - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("\t#Static-Instance Call Edge(CS):", String.valueOf(CSStaticToInstance)); + exporter.collectMetric("\t#Instance-Static Call Edge(CS):", String.valueOf(CSInstanceToStatic)); + exporter.collectMetric( + "\t#Instance-Instance Call Edge(CS):", String.valueOf(CSInstancetoInstance)); + exporter.collectMetric("\t#Application-Application Call Edge(CS):", String.valueOf(CSApp2app)); + exporter.collectMetric("\t#Application-Library Call Edge(CS):", String.valueOf(CSApp2lib)); + exporter.collectMetric("\t#Library-Application Call Edge(CS):", String.valueOf(CSLib2app)); + exporter.collectMetric("\t#Library-Library Call Edge(CS):", String.valueOf(CSLib2lib)); + exporter.collectMetric( + "#receivers:", String.valueOf(pta.getCgb().getReceiverToSitesMap().size())); + exporter.collectMetric("\t#thisreceivers:", String.valueOf(thisReceiverCount())); + exporter.collectMetric( + "#avg p2s size for virtualcalls:", + String.valueOf( + (CSCallEdges - CSStaticToStatic - CSInstanceToStatic) + * 1.0 + / pta.getCgb().getReceiverToSitesMap().size())); + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpReachableMethods(reachableMethods); + exporter.dumpAppReachableMethods(reachableAppMethods); + exporter.dumpInsensCallGraph(pta.getCallGraph()); } + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/Exporter.java b/sootup.qilin/src/main/java/qilin/stat/Exporter.java index ee5788315a1..6ab4061d964 100644 --- a/sootup.qilin/src/main/java/qilin/stat/Exporter.java +++ b/sootup.qilin/src/main/java/qilin/stat/Exporter.java @@ -18,6 +18,11 @@ package qilin.stat; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.*; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; @@ -36,262 +41,269 @@ import sootup.core.model.SootMethod; import sootup.core.types.Type; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.*; - public class Exporter { - private final String metrics = "Metrics.csv"; - private final String staticFPTs = "StaticFieldPointsTo.csv"; + private final String metrics = "Metrics.csv"; + private final String staticFPTs = "StaticFieldPointsTo.csv"; - private static final int STATLENGTH = 50; - private final StringBuffer report = new StringBuffer(); + private static final int STATLENGTH = 50; + private final StringBuffer report = new StringBuffer(); - public void addLine(String str) { - report.append(str).append('\n'); - } + public void addLine(String str) { + report.append(str).append('\n'); + } - private String makeUp(String string) { - final String makeUpString = " "; - String tmp = ""; - for (int i = 0; i < Math.max(0, STATLENGTH - string.length()); ++i) { - tmp = tmp.concat(makeUpString); - } -// StringBuilder ret = new StringBuilder(); -// ret.append(makeUpString.repeat(Math.max(0, STATLENGTH - string.length()))); - return string + tmp; + private String makeUp(String string) { + final String makeUpString = " "; + String tmp = ""; + for (int i = 0; i < Math.max(0, STATLENGTH - string.length()); ++i) { + tmp = tmp.concat(makeUpString); } + // StringBuilder ret = new StringBuilder(); + // ret.append(makeUpString.repeat(Math.max(0, STATLENGTH - string.length()))); + return string + tmp; + } - public void collectMetric(String desc, String value) { - addLine(makeUp(desc) + value); - } + public void collectMetric(String desc, String value) { + addLine(makeUp(desc) + value); + } - private String getFilePath(String fileName) { - String finalPath = CoreConfig.v().getOutConfig().outDir; - finalPath = finalPath + File.separator + CoreConfig.v().getAppConfig().MAIN_CLASS + File.separator + CoreConfig.v().getPtaConfig().ptaName + File.separator; - File file = new File(finalPath); - if (!file.exists()) { - file.mkdirs(); - } - finalPath = finalPath + fileName; - return finalPath; + private String getFilePath(String fileName) { + String finalPath = CoreConfig.v().getOutConfig().outDir; + finalPath = + finalPath + + File.separator + + CoreConfig.v().getAppConfig().MAIN_CLASS + + File.separator + + CoreConfig.v().getPtaConfig().ptaName + + File.separator; + File file = new File(finalPath); + if (!file.exists()) { + file.mkdirs(); } + finalPath = finalPath + fileName; + return finalPath; + } - private void dumpMethods(Collection methods, String fileName) { - StringBuilder builder = new StringBuilder(); - for (SootMethod sm : methods) { - String sig = sm.getSignature().toString(); - sig = Util.stripQuotes(sig); - builder.append(sig); - builder.append("\n"); - } - String finalPath = getFilePath(fileName); - Util.writeToFile(finalPath, builder.toString()); + private void dumpMethods(Collection methods, String fileName) { + StringBuilder builder = new StringBuilder(); + for (SootMethod sm : methods) { + String sig = sm.getSignature().toString(); + sig = Util.stripQuotes(sig); + builder.append(sig); + builder.append("\n"); } + String finalPath = getFilePath(fileName); + Util.writeToFile(finalPath, builder.toString()); + } - public void dumpReachableMethods(Collection reachables) { - String reachMethods = "Reachable.csv"; - dumpMethods(reachables, reachMethods); - } + public void dumpReachableMethods(Collection reachables) { + String reachMethods = "Reachable.csv"; + dumpMethods(reachables, reachMethods); + } - public void dumpAppReachableMethods(Collection appReachables) { - String appReachMethods = "AppReachable.csv"; - dumpMethods(appReachables, appReachMethods); - } + public void dumpAppReachableMethods(Collection appReachables) { + String appReachMethods = "AppReachable.csv"; + dumpMethods(appReachables, appReachMethods); + } - public void dumpSingleCallMethods(Collection singleCallMs) { - String singleCalls = "SingleCallMethods.csv"; - dumpMethods(singleCallMs, singleCalls); - } + public void dumpSingleCallMethods(Collection singleCallMs) { + String singleCalls = "SingleCallMethods.csv"; + dumpMethods(singleCallMs, singleCalls); + } - public void dumpSingleReceiverMethods(Collection singleReceiverMs) { - String singleReceivers = "SingleReceiverMethods.csv"; - dumpMethods(singleReceiverMs, singleReceivers); - } + public void dumpSingleReceiverMethods(Collection singleReceiverMs) { + String singleReceivers = "SingleReceiverMethods.csv"; + dumpMethods(singleReceiverMs, singleReceivers); + } - public void dumpSingleCallSingleReceiverMethods(Collection singleCallSingleReceiverMs) { - String singleCallSingleReceivers = "SingleCallSingleReceiverMethods.csv"; - dumpMethods(singleCallSingleReceiverMs, singleCallSingleReceivers); - } + public void dumpSingleCallSingleReceiverMethods( + Collection singleCallSingleReceiverMs) { + String singleCallSingleReceivers = "SingleCallSingleReceiverMethods.csv"; + dumpMethods(singleCallSingleReceiverMs, singleCallSingleReceivers); + } - public void dumpClassTypes(Collection classes) { - StringBuilder builder = new StringBuilder(); - for (SootClass sc : classes) { - builder.append(sc.getName()); - builder.append("\n"); - } - String classTypes = "ClassType.csv"; - String finalPath = getFilePath(classTypes); - Util.writeToFile(finalPath, builder.toString()); + public void dumpClassTypes(Collection classes) { + StringBuilder builder = new StringBuilder(); + for (SootClass sc : classes) { + builder.append(sc.getName()); + builder.append("\n"); } + String classTypes = "ClassType.csv"; + String finalPath = getFilePath(classTypes); + Util.writeToFile(finalPath, builder.toString()); + } - public void dumpPolyCalls(Map polys) { - StringBuilder builder = new StringBuilder(); - for (AbstractInvokeExpr ie : polys.keySet()) { - SootMethod tgt = (SootMethod) PTAScene.v().getView().getMethod(ie.getMethodSignature()).get(); - String polySig = polys.get(ie).getSignature() + "/" + tgt.getDeclaringClassType() + "." + tgt.getName() + "\n"; - builder.append(polySig); - } - String polyCalls = "PolyCalls.csv"; - String finalPath = getFilePath(polyCalls); - Util.writeToFile(finalPath, builder.toString()); + public void dumpPolyCalls(Map polys) { + StringBuilder builder = new StringBuilder(); + for (AbstractInvokeExpr ie : polys.keySet()) { + SootMethod tgt = (SootMethod) PTAScene.v().getView().getMethod(ie.getMethodSignature()).get(); + String polySig = + polys.get(ie).getSignature() + + "/" + + tgt.getDeclaringClassType() + + "." + + tgt.getName() + + "\n"; + builder.append(polySig); } + String polyCalls = "PolyCalls.csv"; + String finalPath = getFilePath(polyCalls); + Util.writeToFile(finalPath, builder.toString()); + } - public void dumpMayFailCasts(Map> casts) { - StringBuilder builder = new StringBuilder(); - for (SootMethod sm : casts.keySet()) { - for (Stmt stmt : casts.get(sm)) { - JAssignStmt as = (JAssignStmt) stmt; - JCastExpr ce = (JCastExpr) as.getRightOp(); - final Type targetType = ce.getType(); - builder.append(sm.toString()); - builder.append("\t"); - builder.append(targetType.toString()); - builder.append("\t"); - builder.append(sm).append("/").append(ce.getOp().toString()); - builder.append("\t"); - builder.append(sm).append("/").append(as.getLeftOp().toString()); - builder.append("\n"); - } - } - String mayFailCasts = "MayFailCasts.csv"; - String finalPath = getFilePath(mayFailCasts); - Util.writeToFile(finalPath, builder.toString()); + public void dumpMayFailCasts(Map> casts) { + StringBuilder builder = new StringBuilder(); + for (SootMethod sm : casts.keySet()) { + for (Stmt stmt : casts.get(sm)) { + JAssignStmt as = (JAssignStmt) stmt; + JCastExpr ce = (JCastExpr) as.getRightOp(); + final Type targetType = ce.getType(); + builder.append(sm.toString()); + builder.append("\t"); + builder.append(targetType.toString()); + builder.append("\t"); + builder.append(sm).append("/").append(ce.getOp().toString()); + builder.append("\t"); + builder.append(sm).append("/").append(as.getLeftOp().toString()); + builder.append("\n"); + } } + String mayFailCasts = "MayFailCasts.csv"; + String finalPath = getFilePath(mayFailCasts); + Util.writeToFile(finalPath, builder.toString()); + } - public void dumpMethodThrowPointsto(Map m2pts) { - String methodThrowPts = "MethodThrowPointsTo.csv"; - String finalPath = getFilePath(methodThrowPts); - try { - File mfile = new File(finalPath); - mfile.delete(); - mfile.createNewFile(); - BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); - for (SootMethod sm : m2pts.keySet()) { - PointsToSet pts = m2pts.get(sm).toCIPointsToSet(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - StringBuilder builder = new StringBuilder(); - builder.append(n.toString()); - builder.append("\t"); - String sig = Util.stripQuotes(sm.getSignature().toString()); - builder.append(sig); - builder.append("\n"); - try { - writer.write(builder.toString()); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - writer.flush(); - writer.close(); - } catch (Exception e) { + public void dumpMethodThrowPointsto(Map m2pts) { + String methodThrowPts = "MethodThrowPointsTo.csv"; + String finalPath = getFilePath(methodThrowPts); + try { + File mfile = new File(finalPath); + mfile.delete(); + mfile.createNewFile(); + BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); + for (SootMethod sm : m2pts.keySet()) { + PointsToSet pts = m2pts.get(sm).toCIPointsToSet(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + StringBuilder builder = new StringBuilder(); + builder.append(n.toString()); + builder.append("\t"); + String sig = Util.stripQuotes(sm.getSignature().toString()); + builder.append(sig); + builder.append("\n"); + try { + writer.write(builder.toString()); + } catch (IOException e) { e.printStackTrace(); + } } + } + writer.flush(); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); } + } - public void dumpInsensCallGraph(CallGraph ciCallGraph) { - String insensCallGraphEdges = "InsensCallGraphEdges.csv"; - String finalPath = getFilePath(insensCallGraphEdges); - try { - File mfile = new File(finalPath); - mfile.delete(); - mfile.createNewFile(); - BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); - for (Edge edge : ciCallGraph) { - String srcSig = Util.stripQuotes(edge.src().getSignature().toString()); - String dstSig = Util.stripQuotes(edge.tgt().getSignature().toString()); - String str = edge.srcStmt() + " in method " + srcSig + "\t" + dstSig + "\n"; - writer.write(str); - } - writer.flush(); - writer.close(); - } catch (Exception e) { - e.printStackTrace(); - } + public void dumpInsensCallGraph(CallGraph ciCallGraph) { + String insensCallGraphEdges = "InsensCallGraphEdges.csv"; + String finalPath = getFilePath(insensCallGraphEdges); + try { + File mfile = new File(finalPath); + mfile.delete(); + mfile.createNewFile(); + BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); + for (Edge edge : ciCallGraph) { + String srcSig = Util.stripQuotes(edge.src().getSignature().toString()); + String dstSig = Util.stripQuotes(edge.tgt().getSignature().toString()); + String str = edge.srcStmt() + " in method " + srcSig + "\t" + dstSig + "\n"; + writer.write(str); + } + writer.flush(); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); } + } - public void dumpReachableLocalVars(Collection lvns) { - StringBuilder builder = new StringBuilder(); - for (LocalVarNode lvn : lvns) { - String varName = getDoopVarName(lvn); - builder.append(varName).append("\n"); - } - String insensReachVars = "InsensReachVars.csv"; - String finalPath = getFilePath(insensReachVars); - Util.writeToFile(finalPath, builder.toString()); + public void dumpReachableLocalVars(Collection lvns) { + StringBuilder builder = new StringBuilder(); + for (LocalVarNode lvn : lvns) { + String varName = getDoopVarName(lvn); + builder.append(varName).append("\n"); } + String insensReachVars = "InsensReachVars.csv"; + String finalPath = getFilePath(insensReachVars); + Util.writeToFile(finalPath, builder.toString()); + } - public void dumpReachableLocalVarsNoNative(Collection lvns) { - StringBuilder builder = new StringBuilder(); - for (LocalVarNode lvn : lvns) { - String varName = getDoopVarName(lvn); - builder.append(varName).append("\n"); - } - String insensReachVars = "InsensReachVarsNoNatives.csv"; - String finalPath = getFilePath(insensReachVars); - Util.writeToFile(finalPath, builder.toString()); + public void dumpReachableLocalVarsNoNative(Collection lvns) { + StringBuilder builder = new StringBuilder(); + for (LocalVarNode lvn : lvns) { + String varName = getDoopVarName(lvn); + builder.append(varName).append("\n"); } + String insensReachVars = "InsensReachVarsNoNatives.csv"; + String finalPath = getFilePath(insensReachVars); + Util.writeToFile(finalPath, builder.toString()); + } - private String getDoopVarName(LocalVarNode lvn) { - SootMethod m = lvn.getMethod(); - Object v = lvn.getVariable(); - String varName = v.toString(); - if (v instanceof Parm parm) { - if (parm.isThis()) { - varName = "@this"; - } else if (parm.isReturn()) { + private String getDoopVarName(LocalVarNode lvn) { + SootMethod m = lvn.getMethod(); + Object v = lvn.getVariable(); + String varName = v.toString(); + if (v instanceof Parm parm) { + if (parm.isThis()) { + varName = "@this"; + } else if (parm.isReturn()) { - } else if (parm.isThrowRet()) { + } else if (parm.isThrowRet()) { - } else { - varName = "@parameter" + parm.getIndex(); - } - } - return m.getSignature() + "/" + varName; + } else { + varName = "@parameter" + parm.getIndex(); + } } + return m.getSignature() + "/" + varName; + } - public void dumpInsensPointsTo(Collection lvns, PTA pta) { - String insensVarPTs = "InsensVarPointsTo.csv"; - String finalPath = getFilePath(insensVarPTs); - try { - File mfile = new File(finalPath); - mfile.delete(); - mfile.createNewFile(); - BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); - for (LocalVarNode lvn : lvns) { - String varName = getDoopVarName(lvn); - final Set callocSites = new HashSet<>(); - PointsToSet cpts = pta.reachingObjects(lvn).toCIPointsToSet(); - for (Iterator it = cpts.iterator(); it.hasNext(); ) { - AllocNode heap = it.next(); - callocSites.add(heap); - } - for (AllocNode heap : callocSites) { - String str = heap.getNewExpr() + "\t" + varName + "\n"; - if (heap.getMethod() != null) { - str = heap.getMethod() + "/" + heap.getNewExpr() + "\t" + varName + "\n"; - } - writer.write(str); - } - } - writer.flush(); - writer.close(); - } catch (Exception e) { - e.printStackTrace(); + public void dumpInsensPointsTo(Collection lvns, PTA pta) { + String insensVarPTs = "InsensVarPointsTo.csv"; + String finalPath = getFilePath(insensVarPTs); + try { + File mfile = new File(finalPath); + mfile.delete(); + mfile.createNewFile(); + BufferedWriter writer = new BufferedWriter(new FileWriter(mfile, true)); + for (LocalVarNode lvn : lvns) { + String varName = getDoopVarName(lvn); + final Set callocSites = new HashSet<>(); + PointsToSet cpts = pta.reachingObjects(lvn).toCIPointsToSet(); + for (Iterator it = cpts.iterator(); it.hasNext(); ) { + AllocNode heap = it.next(); + callocSites.add(heap); } + for (AllocNode heap : callocSites) { + String str = heap.getNewExpr() + "\t" + varName + "\n"; + if (heap.getMethod() != null) { + str = heap.getMethod() + "/" + heap.getNewExpr() + "\t" + varName + "\n"; + } + writer.write(str); + } + } + writer.flush(); + writer.close(); + } catch (Exception e) { + e.printStackTrace(); } + } - public String report() { - String tmp = report.toString(); - if (CoreConfig.v().getOutConfig().dumpStats) { - String statistics = "Statistics.txt"; - String finalPath = getFilePath(statistics); - Util.writeToFile(finalPath, tmp); - } - return tmp; + public String report() { + String tmp = report.toString(); + if (CoreConfig.v().getOutConfig().dumpStats) { + String statistics = "Statistics.txt"; + String finalPath = getFilePath(statistics); + Util.writeToFile(finalPath, tmp); } + return tmp; + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java index f5a1db92707..13c46aecc21 100644 --- a/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/IEvaluator.java @@ -19,9 +19,9 @@ package qilin.stat; public interface IEvaluator { - int GB = 1024 * 1024 * 1024; + int GB = 1024 * 1024 * 1024; - void begin(); + void begin(); - void end(); + void end(); } diff --git a/sootup.qilin/src/main/java/qilin/stat/PAGStat.java b/sootup.qilin/src/main/java/qilin/stat/PAGStat.java index d2989a25dcd..bf348472651 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PAGStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PAGStat.java @@ -18,63 +18,63 @@ package qilin.stat; -import qilin.core.PTA; -import qilin.core.pag.*; - import java.util.Map; import java.util.Set; +import qilin.core.PTA; +import qilin.core.pag.*; public class PAGStat implements AbstractStat { - private final PTA pta; - private final PAG pag; + private final PTA pta; + private final PAG pag; - private int newEdges = 0; // v = new O; - private int simpleEdges = 0; // include assign, global_assign, and o.f assign. - private int hloadEdges = 0; // v = o.f; - private int hstoreEdges = 0; // o.f = v; - private int storeEdges = 0; // v.f = v; - private int loadEdges = 0; // v = v.f; + private int newEdges = 0; // v = new O; + private int simpleEdges = 0; // include assign, global_assign, and o.f assign. + private int hloadEdges = 0; // v = o.f; + private int hstoreEdges = 0; // o.f = v; + private int storeEdges = 0; // v.f = v; + private int loadEdges = 0; // v = v.f; - public PAGStat(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - init(); - } + public PAGStat(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + init(); + } - private void init() { - for (Set s : pag.getAlloc().values()) { - newEdges += s.size(); - } - for (Map.Entry> e : pag.getSimple().entrySet()) { - Set tagets = e.getValue(); - int nt = tagets.size(); - simpleEdges += nt; - if (e.getKey() instanceof ContextField) { - hloadEdges += nt; - } else { - for (ValNode v : tagets) { - if (v instanceof ContextField) { - hstoreEdges++; - } - } - } - } - for (Map.Entry> s : pag.getStoreInv().entrySet()) { - storeEdges += s.getValue().size(); - } - for (Map.Entry> s : pag.getLoad().entrySet()) { - loadEdges += s.getValue().size(); + private void init() { + for (Set s : pag.getAlloc().values()) { + newEdges += s.size(); + } + for (Map.Entry> e : pag.getSimple().entrySet()) { + Set tagets = e.getValue(); + int nt = tagets.size(); + simpleEdges += nt; + if (e.getKey() instanceof ContextField) { + hloadEdges += nt; + } else { + for (ValNode v : tagets) { + if (v instanceof ContextField) { + hstoreEdges++; + } } + } } - - @Override - public void export(Exporter exporter) { - exporter.collectMetric("#Alloc-pag-edge:", String.valueOf(newEdges)); - exporter.collectMetric("#Simple-pag-edge:", String.valueOf(simpleEdges)); - exporter.collectMetric("\t#Local-to-Local:", String.valueOf((simpleEdges - hloadEdges - hstoreEdges))); - exporter.collectMetric("\t#Field-to-Local:", String.valueOf(hloadEdges)); - exporter.collectMetric("\t#Local-to-Field:", String.valueOf(hstoreEdges)); - exporter.collectMetric("#Store-pag-edge:", String.valueOf(storeEdges)); - exporter.collectMetric("#Load-pag-edge:", String.valueOf(loadEdges)); + for (Map.Entry> s : pag.getStoreInv().entrySet()) { + storeEdges += s.getValue().size(); + } + for (Map.Entry> s : pag.getLoad().entrySet()) { + loadEdges += s.getValue().size(); } + } + + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Alloc-pag-edge:", String.valueOf(newEdges)); + exporter.collectMetric("#Simple-pag-edge:", String.valueOf(simpleEdges)); + exporter.collectMetric( + "\t#Local-to-Local:", String.valueOf((simpleEdges - hloadEdges - hstoreEdges))); + exporter.collectMetric("\t#Field-to-Local:", String.valueOf(hloadEdges)); + exporter.collectMetric("\t#Local-to-Field:", String.valueOf(hstoreEdges)); + exporter.collectMetric("#Store-pag-edge:", String.valueOf(storeEdges)); + exporter.collectMetric("#Load-pag-edge:", String.valueOf(loadEdges)); + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java index 187c7852eb9..8bc3b182cba 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/PTAEvaluator.java @@ -23,90 +23,90 @@ /** * Gather stats on the performance and precision of a PTA run. - *

- * Each new run of the PTA will over-write stats - *

- * - Wall time (sec) - Memory (max, current) before and after - Reachable - * methods (context and no-context) - Total reachable casts - Reachable casts - * that may fail - Call graph edges - Context sensitive call graph edges - Total - * reachable virtual call sites - Polymorphic virtual call sites (sites with >1 - * target methods) - Number of pointers (local and global) - Total points to - * sets size (local and global) context insensitive (convert to alloc site) + * + *

Each new run of the PTA will over-write stats + * + *

- Wall time (sec) - Memory (max, current) before and after - Reachable methods (context and + * no-context) - Total reachable casts - Reachable casts that may fail - Call graph edges - Context + * sensitive call graph edges - Total reachable virtual call sites - Polymorphic virtual call sites + * (sites with >1 target methods) - Number of pointers (local and global) - Total points to sets + * size (local and global) context insensitive (convert to alloc site) */ public class PTAEvaluator implements IEvaluator { - protected final RuntimeStat runtimeStat; - protected final Exporter exporter; - protected final PTA pta; - - public PTAEvaluator(PTA pta) { - this.pta = pta; - runtimeStat = new RuntimeStat(); - exporter = new Exporter(); - } - - /** - * Note the start of a qilin.pta run. - */ - @Override - public void begin() { - Runtime runtime = Runtime.getRuntime();// Getting the runtime reference - // from system - exporter.addLine(" ====== Memory Usage ======"); - exporter.collectMetric("Used Memory Before:", (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB");// Print - // used memory - exporter.collectMetric("Free Memory Before:", runtime.freeMemory() / GB + " GB");// Print free memory - exporter.collectMetric("Total Memory Before:", runtime.totalMemory() / GB + " GB");// Print total available memory - exporter.collectMetric("Max Memory Before:", runtime.maxMemory() / GB + " GB");// Print Maximum available memory - exporter.collectMetric("Analysis: ", CoreConfig.v().getPtaConfig().ptaName); - runtimeStat.begin(); - } + protected final RuntimeStat runtimeStat; + protected final Exporter exporter; + protected final PTA pta; - /** - * Note the end of a qilin.pta run. - */ - @Override - public void end() { - // done with processing - runtimeStat.end(); - /** - * all method reachable from the harness main - */ - PAGStat pagStat = new PAGStat(pta); - BenchmarkStat benchmarkStat = new BenchmarkStat(pta); - CallGraphStat callGraphStat = new CallGraphStat(pta); - TypeClientStat typeClientStat = new TypeClientStat(pta); - PointsToStat ptsStat = new PointsToStat(pta); - AliasStat aliasStat = new AliasStat(pta); - YummyStat yummyStat = new YummyStat(pta); - runtimeStat.export(exporter); - // memory stats - Runtime runtime = Runtime.getRuntime();// Getting the runtime reference - // from system - exporter.collectMetric("Used Memory After:", (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB");// Print - // used memory - exporter.collectMetric("Free Memory After:", runtime.freeMemory() / GB + " GB");// Print free memory - exporter.collectMetric("Total Memory After:", runtime.totalMemory() / GB + " GB");// Print total available memory - exporter.collectMetric("Max Memory After:", runtime.maxMemory() / GB + " GB");// Print Maximum available memory - exporter.addLine(" ====== Yummy ======"); - yummyStat.export(exporter); - exporter.addLine(" ====== Call Graph ======"); - callGraphStat.export(exporter); - exporter.addLine(" ====== Statements ======"); - typeClientStat.export(exporter); - exporter.addLine(" ====== Nodes ======"); - ptsStat.export(exporter); - exporter.addLine(" ====== Assignments ======"); - pagStat.export(exporter); - exporter.addLine(" ====== Aliases ======"); - aliasStat.export(exporter); - exporter.addLine(" ====== Classes ======"); - benchmarkStat.export(exporter); + public PTAEvaluator(PTA pta) { + this.pta = pta; + runtimeStat = new RuntimeStat(); + exporter = new Exporter(); + } - } + /** Note the start of a qilin.pta run. */ + @Override + public void begin() { + Runtime runtime = Runtime.getRuntime(); // Getting the runtime reference + // from system + exporter.addLine(" ====== Memory Usage ======"); + exporter.collectMetric( + "Used Memory Before:", + (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB"); // Print + // used memory + exporter.collectMetric( + "Free Memory Before:", runtime.freeMemory() / GB + " GB"); // Print free memory + exporter.collectMetric( + "Total Memory Before:", runtime.totalMemory() / GB + " GB"); // Print total available memory + exporter.collectMetric( + "Max Memory Before:", runtime.maxMemory() / GB + " GB"); // Print Maximum available memory + exporter.collectMetric("Analysis: ", CoreConfig.v().getPtaConfig().ptaName); + runtimeStat.begin(); + } - @Override - public String toString() { - return exporter.report(); - } + /** Note the end of a qilin.pta run. */ + @Override + public void end() { + // done with processing + runtimeStat.end(); + /** all method reachable from the harness main */ + PAGStat pagStat = new PAGStat(pta); + BenchmarkStat benchmarkStat = new BenchmarkStat(pta); + CallGraphStat callGraphStat = new CallGraphStat(pta); + TypeClientStat typeClientStat = new TypeClientStat(pta); + PointsToStat ptsStat = new PointsToStat(pta); + AliasStat aliasStat = new AliasStat(pta); + YummyStat yummyStat = new YummyStat(pta); + runtimeStat.export(exporter); + // memory stats + Runtime runtime = Runtime.getRuntime(); // Getting the runtime reference + // from system + exporter.collectMetric( + "Used Memory After:", (runtime.totalMemory() - runtime.freeMemory()) / GB + " GB"); // Print + // used memory + exporter.collectMetric( + "Free Memory After:", runtime.freeMemory() / GB + " GB"); // Print free memory + exporter.collectMetric( + "Total Memory After:", runtime.totalMemory() / GB + " GB"); // Print total available memory + exporter.collectMetric( + "Max Memory After:", runtime.maxMemory() / GB + " GB"); // Print Maximum available memory + exporter.addLine(" ====== Yummy ======"); + yummyStat.export(exporter); + exporter.addLine(" ====== Call Graph ======"); + callGraphStat.export(exporter); + exporter.addLine(" ====== Statements ======"); + typeClientStat.export(exporter); + exporter.addLine(" ====== Nodes ======"); + ptsStat.export(exporter); + exporter.addLine(" ====== Assignments ======"); + pagStat.export(exporter); + exporter.addLine(" ====== Aliases ======"); + aliasStat.export(exporter); + exporter.addLine(" ====== Classes ======"); + benchmarkStat.export(exporter); + } + @Override + public String toString() { + return exporter.report(); + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java index 07638617561..7cf02e67eb9 100644 --- a/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/PointsToStat.java @@ -18,6 +18,7 @@ package qilin.stat; +import java.util.*; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; @@ -31,268 +32,295 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.*; - public class PointsToStat implements AbstractStat { - private final PTA pta; - private final PAG pag; - private int contextCnt = 0; - private double avgCtxPerMthd = 0.0; + private final PTA pta; + private final PAG pag; + private int contextCnt = 0; + private double avgCtxPerMthd = 0.0; - private int ciAllocs = 0; - private int csAllocs = 0; - private int totalGlobalPointers = 0; - private int totalGlobalPointsToCi = 0; - private int totalGlobalPointsToCs = 0; - private int appGlobalPointers = 0; - private int appGlobalPointsToCi = 0; - private int appGlobalPointsToCs = 0; - private int totalLocalPointersCi = 0; - private int totalLocalPointersCs = 0; - private int totalLocalCiToCi = 0; - private int totalLocalCiToCs = 0; - private int totalLocalCsToCi = 0; - private int totalLocalCsToCs = 0; - private int appLocalPointersCi = 0; - private int appLocalPointersCs = 0; - private int appLocalCiToCi = 0; - private int appLocalCiToCs = 0; - private int appLocalCsToCi = 0; - private int appLocalCsToCs = 0; - private int totalFieldPointsToCs = 0; - private int methodThrowCnt = 0; + private int ciAllocs = 0; + private int csAllocs = 0; + private int totalGlobalPointers = 0; + private int totalGlobalPointsToCi = 0; + private int totalGlobalPointsToCs = 0; + private int appGlobalPointers = 0; + private int appGlobalPointsToCi = 0; + private int appGlobalPointsToCs = 0; + private int totalLocalPointersCi = 0; + private int totalLocalPointersCs = 0; + private int totalLocalCiToCi = 0; + private int totalLocalCiToCs = 0; + private int totalLocalCsToCi = 0; + private int totalLocalCsToCs = 0; + private int appLocalPointersCi = 0; + private int appLocalPointersCs = 0; + private int appLocalCiToCi = 0; + private int appLocalCiToCs = 0; + private int appLocalCsToCi = 0; + private int appLocalCsToCs = 0; + private int totalFieldPointsToCs = 0; + private int methodThrowCnt = 0; - private final Map methodThrowPts; - private final Set mLocalVarNodes = new HashSet<>(); - private int ptsCnt = 0; - private int varCnt = 0; - private final Set mLocalVarNodesNoNative = new HashSet<>(); - private int ptsCntNoNative = 0; - private int varCntNoNative = 0; + private final Map methodThrowPts; + private final Set mLocalVarNodes = new HashSet<>(); + private int ptsCnt = 0; + private int varCnt = 0; + private final Set mLocalVarNodesNoNative = new HashSet<>(); + private int ptsCntNoNative = 0; + private int varCntNoNative = 0; - public PointsToStat(PTA pta) { - this.pta = pta; - this.pag = pta.getPag(); - methodThrowPts = new HashMap<>(); - init(); - } + public PointsToStat(PTA pta) { + this.pta = pta; + this.pag = pta.getPag(); + methodThrowPts = new HashMap<>(); + init(); + } - private final Set handledNatives = Set.of( - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ); + private final Set handledNatives = + Set.of( + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ""); - protected Set getPointsToNewExpr(PointsToSet pts) { - final Set allocSites = new HashSet<>(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - allocSites.add(n.getNewExpr()); - } - return allocSites; + protected Set getPointsToNewExpr(PointsToSet pts) { + final Set allocSites = new HashSet<>(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + allocSites.add(n.getNewExpr()); } + return allocSites; + } - private void init() { - ciAllocs = pag.getAllocNodes().size(); - csAllocs = pag.getAlloc().keySet().size(); - // globals - for (SootField global : pag.getGlobalPointers()) { - try { - if (!global.isStatic()) - continue; - GlobalVarNode gvn = pag.findGlobalVarNode(global); - boolean app = gvn.getDeclaringClass().isApplicationClass(); + private void init() { + ciAllocs = pag.getAllocNodes().size(); + csAllocs = pag.getAlloc().keySet().size(); + // globals + for (SootField global : pag.getGlobalPointers()) { + try { + if (!global.isStatic()) continue; + GlobalVarNode gvn = pag.findGlobalVarNode(global); + boolean app = gvn.getDeclaringClass().isApplicationClass(); - totalGlobalPointers++; - if (app) { - appGlobalPointers++; - } + totalGlobalPointers++; + if (app) { + appGlobalPointers++; + } - PointsToSet pts = pta.reachingObjects(gvn); - final Set allocSites = getPointsToNewExpr(pts); + PointsToSet pts = pta.reachingObjects(gvn); + final Set allocSites = getPointsToNewExpr(pts); - totalGlobalPointsToCi += allocSites.size(); - totalGlobalPointsToCs += pts.size(); - if (app) { - appGlobalPointsToCi += allocSites.size(); - appGlobalPointsToCs += pts.size(); - } - } catch (Exception e) { - e.printStackTrace(); - } + totalGlobalPointsToCi += allocSites.size(); + totalGlobalPointsToCs += pts.size(); + if (app) { + appGlobalPointsToCi += allocSites.size(); + appGlobalPointsToCs += pts.size(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + // locals exclude Exceptions + for (Local local : pag.getLocalPointers()) { + try { + Collection varNodes = pag.getVarNodes(local); + LocalVarNode lvn = pag.findLocalVarNode(local); + if (local.toString().contains("intermediate/")) { + continue; + } + mLocalVarNodes.add(lvn); + if (!handledNatives.contains(lvn.getMethod().toString())) { + mLocalVarNodesNoNative.add(lvn); + } + boolean app = PTAUtils.isApplicationMethod(lvn.getMethod()); + totalLocalPointersCi++; + if (app) { + appLocalPointersCi++; } - // locals exclude Exceptions - for (Local local : pag.getLocalPointers()) { - try { - Collection varNodes = pag.getVarNodes(local); - LocalVarNode lvn = pag.findLocalVarNode(local); - if (local.toString().contains("intermediate/")) { - continue; - } - mLocalVarNodes.add(lvn); - if (!handledNatives.contains(lvn.getMethod().toString())) { - mLocalVarNodesNoNative.add(lvn); - } - boolean app = PTAUtils.isApplicationMethod(lvn.getMethod()); - totalLocalPointersCi++; - if (app) { - appLocalPointersCi++; - } - - totalLocalPointersCs += varNodes.size(); - if (app) { - appLocalPointersCs += varNodes.size(); - } - PointsToSet pts = pta.reachingObjects(local); - final Set allocSites = getPointsToNewExpr(pts); + totalLocalPointersCs += varNodes.size(); + if (app) { + appLocalPointersCs += varNodes.size(); + } - totalLocalCiToCi += allocSites.size(); - totalLocalCiToCs += pts.size(); - if (app) { - appLocalCiToCi += allocSites.size(); - appLocalCiToCs += pts.size(); - } + PointsToSet pts = pta.reachingObjects(local); + final Set allocSites = getPointsToNewExpr(pts); - for (VarNode cvn : varNodes) { - PointsToSet cpts = pta.reachingObjects(cvn); - final Set callocSites = getPointsToNewExpr(cpts); - totalLocalCsToCi += callocSites.size(); - totalLocalCsToCs += cpts.size(); - if (app) { - appLocalCsToCi += callocSites.size(); - appLocalCsToCs += cpts.size(); - } - } - } catch (Exception e) { - e.printStackTrace(); - } + totalLocalCiToCi += allocSites.size(); + totalLocalCiToCs += pts.size(); + if (app) { + appLocalCiToCi += allocSites.size(); + appLocalCiToCs += pts.size(); } - // field points-to - for (ContextField cfvn : pag.getContextFields()) { - totalFieldPointsToCs += cfvn.getP2Set().size(); + for (VarNode cvn : varNodes) { + PointsToSet cpts = pta.reachingObjects(cvn); + final Set callocSites = getPointsToNewExpr(cpts); + totalLocalCsToCi += callocSites.size(); + totalLocalCsToCs += cpts.size(); + if (app) { + appLocalCsToCi += callocSites.size(); + appLocalCsToCs += cpts.size(); + } } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // field points-to + for (ContextField cfvn : pag.getContextFields()) { + totalFieldPointsToCs += cfvn.getP2Set().size(); + } - // stat context. - Map> mpag2contexts = pag.getMethod2ContextsMap(); - int[] cnts = new int[2]; - mpag2contexts.forEach((k, v) -> { - cnts[0]++; - cnts[1] += v.size(); + // stat context. + Map> mpag2contexts = pag.getMethod2ContextsMap(); + int[] cnts = new int[2]; + mpag2contexts.forEach( + (k, v) -> { + cnts[0]++; + cnts[1] += v.size(); }); - contextCnt = cnts[1]; - avgCtxPerMthd = cnts[1] * 1.0 / cnts[0]; + contextCnt = cnts[1]; + avgCtxPerMthd = cnts[1] * 1.0 / cnts[0]; - // stat method throw points-to. - for (SootMethod sm : pta.getNakedReachableMethods()) { - Node mThrow = pag.getMethodPAG(sm).nodeFactory().caseMethodThrow(); - PointsToSet pts = pta.reachingObjects(mThrow); - if (!pts.isEmpty()) { - methodThrowCnt++; - methodThrowPts.put(sm, pts); - } - } + // stat method throw points-to. + for (SootMethod sm : pta.getNakedReachableMethods()) { + Node mThrow = pag.getMethodPAG(sm).nodeFactory().caseMethodThrow(); + PointsToSet pts = pta.reachingObjects(mThrow); + if (!pts.isEmpty()) { + methodThrowCnt++; + methodThrowPts.put(sm, pts); + } + } - // stat avg pts. - for (SootMethod sm : pta.getNakedReachableMethods()) { - MethodPAG mpag = pag.getMethodPAG(sm); - MethodNodeFactory mnf = mpag.nodeFactory(); - if (!sm.isStatic()) { - mLocalVarNodes.add((LocalVarNode) mnf.caseThis()); - if (!handledNatives.contains(sm.toString())) { - mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseThis()); - } - } - for (int i = 0; i < sm.getParameterCount(); ++i) { - Type mType = sm.getParameterType(i); - if (mType instanceof ReferenceType) { - mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); - if (!handledNatives.contains(sm.toString())) { - mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseParm(i)); - } - } - } + // stat avg pts. + for (SootMethod sm : pta.getNakedReachableMethods()) { + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory mnf = mpag.nodeFactory(); + if (!sm.isStatic()) { + mLocalVarNodes.add((LocalVarNode) mnf.caseThis()); + if (!handledNatives.contains(sm.toString())) { + mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseThis()); } - Set tmp = new HashSet<>(); - for (LocalVarNode lvn : mLocalVarNodes) { - SootMethod sm = lvn.getMethod(); - if (PTAUtils.isFakeMainMethod(sm)) { - tmp.add(lvn); - continue; - } - PointsToSet cpts = pta.reachingObjects(lvn); - final Set callocSites = getPointsToNewExpr(cpts); - if (callocSites.size() > 0) { - ptsCnt += callocSites.size(); - varCnt++; - if (!handledNatives.contains(sm.toString())) { - ptsCntNoNative += callocSites.size(); - varCntNoNative++; - } - } else { - tmp.add(lvn); - } + } + for (int i = 0; i < sm.getParameterCount(); ++i) { + Type mType = sm.getParameterType(i); + if (mType instanceof ReferenceType) { + mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); + if (!handledNatives.contains(sm.toString())) { + mLocalVarNodesNoNative.add((LocalVarNode) mnf.caseParm(i)); + } } - mLocalVarNodes.removeAll(tmp); - mLocalVarNodesNoNative.removeAll(tmp); - System.out.println("PTS relation:" + ptsCnt); - System.out.println("VAR CNT:" + varCnt); - System.out.println("AVG PTS: " + (ptsCnt * 1.0 / varCnt)); - System.out.println("PTS relation (no native):" + ptsCntNoNative); - System.out.println("VAR CNT (no native):" + varCntNoNative); - System.out.println("AVG PTS (no native): " + (ptsCntNoNative * 1.0 / varCntNoNative)); + } } + Set tmp = new HashSet<>(); + for (LocalVarNode lvn : mLocalVarNodes) { + SootMethod sm = lvn.getMethod(); + if (PTAUtils.isFakeMainMethod(sm)) { + tmp.add(lvn); + continue; + } + PointsToSet cpts = pta.reachingObjects(lvn); + final Set callocSites = getPointsToNewExpr(cpts); + if (callocSites.size() > 0) { + ptsCnt += callocSites.size(); + varCnt++; + if (!handledNatives.contains(sm.toString())) { + ptsCntNoNative += callocSites.size(); + varCntNoNative++; + } + } else { + tmp.add(lvn); + } + } + mLocalVarNodes.removeAll(tmp); + mLocalVarNodesNoNative.removeAll(tmp); + System.out.println("PTS relation:" + ptsCnt); + System.out.println("VAR CNT:" + varCnt); + System.out.println("AVG PTS: " + (ptsCnt * 1.0 / varCnt)); + System.out.println("PTS relation (no native):" + ptsCntNoNative); + System.out.println("VAR CNT (no native):" + varCntNoNative); + System.out.println("AVG PTS (no native): " + (ptsCntNoNative * 1.0 / varCntNoNative)); + } - @Override - public void export(Exporter exporter) { - exporter.collectMetric("#Context:", String.valueOf(contextCnt)); - exporter.collectMetric("#Avg Context per Method:", String.valueOf(avgCtxPerMthd)); - exporter.collectMetric("#Method with Throw Pointer-to:", String.valueOf(methodThrowCnt)); + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Context:", String.valueOf(contextCnt)); + exporter.collectMetric("#Avg Context per Method:", String.valueOf(avgCtxPerMthd)); + exporter.collectMetric("#Method with Throw Pointer-to:", String.valueOf(methodThrowCnt)); - exporter.collectMetric("#Alloc Node(CI): ", String.valueOf(ciAllocs)); - exporter.collectMetric("#Alloc Node(CS): ", String.valueOf(csAllocs)); + exporter.collectMetric("#Alloc Node(CI): ", String.valueOf(ciAllocs)); + exporter.collectMetric("#Alloc Node(CS): ", String.valueOf(csAllocs)); - exporter.collectMetric("#Global CS Pointer-to Relation:", String.valueOf(totalGlobalPointsToCs)); - exporter.collectMetric("#Local CS Pointer-to Relation:", String.valueOf(totalLocalCsToCs)); - exporter.collectMetric("#Field CS Pointer-to Relation:", String.valueOf(totalFieldPointsToCs)); + exporter.collectMetric( + "#Global CS Pointer-to Relation:", String.valueOf(totalGlobalPointsToCs)); + exporter.collectMetric("#Local CS Pointer-to Relation:", String.valueOf(totalLocalCsToCs)); + exporter.collectMetric("#Field CS Pointer-to Relation:", String.valueOf(totalFieldPointsToCs)); - exporter.collectMetric("#Global Pointer (lib + app):", String.valueOf(totalGlobalPointers)); - exporter.collectMetric("#Global Avg Points-To Target(CI):", String.valueOf(((double) totalGlobalPointsToCi) / ((double) totalGlobalPointers))); - exporter.collectMetric("#Global Avg Points-To Target(CS):", String.valueOf(((double) totalGlobalPointsToCs) / ((double) totalGlobalPointers))); - exporter.collectMetric("#App Global Pointer:", String.valueOf(appGlobalPointers)); - exporter.collectMetric("#App Global Avg Points-To Target(CI):", String.valueOf(((double) appGlobalPointsToCi) / ((double) appGlobalPointers))); - exporter.collectMetric("#App Global Avg Points-To Target(CS):", String.valueOf(((double) appGlobalPointsToCs) / ((double) appGlobalPointers))); - exporter.collectMetric("#Avg Points-to Target(CI):", String.valueOf(((double) ptsCnt) / (varCnt))); - exporter.collectMetric("#Avg Points-to Target without Native Var(CI):", String.valueOf(((double) ptsCntNoNative) / (varCntNoNative))); - exporter.collectMetric("#Local Pointer (lib + app):", String.valueOf(totalLocalPointersCi)); - exporter.collectMetric("#Local Avg Points-To Target(CI):", String.valueOf(((double) totalLocalCiToCi) / ((double) totalLocalPointersCi))); - exporter.collectMetric("#Local Avg Points-To Target(CS):", String.valueOf(((double) totalLocalCiToCs) / ((double) totalLocalPointersCi))); - exporter.collectMetric("#App Local Pointer:", String.valueOf(appLocalPointersCi)); - exporter.collectMetric("#App Local Avg Points-To Target(CI):", String.valueOf(((double) appLocalCiToCi) / ((double) appLocalPointersCi))); - exporter.collectMetric("#App Local Avg Points-To Target(CS):", String.valueOf(((double) appLocalCiToCs) / ((double) appLocalPointersCi))); - exporter.collectMetric("#Context Local Pointer (lib + app):", String.valueOf(totalLocalPointersCs)); - exporter.collectMetric("#Context Local Avg Points-To Target(CI):", String.valueOf(((double) totalLocalCsToCi) / ((double) totalLocalPointersCs))); - exporter.collectMetric("#Context Local Avg Points-To Target(CS):", String.valueOf(((double) totalLocalCsToCs) / ((double) totalLocalPointersCs))); - exporter.collectMetric("#App Context Local Pointer:", String.valueOf(appLocalPointersCs)); - exporter.collectMetric("#App Context Local Avg Points-To Target(CI):", String.valueOf(((double) appLocalCsToCi) / ((double) appLocalPointersCs))); - exporter.collectMetric("#App Context Local Avg Points-To Target(CS):", String.valueOf(((double) appLocalCsToCs) / ((double) appLocalPointersCs))); - if (CoreConfig.v().getOutConfig().dumpStats) { - exporter.dumpMethodThrowPointsto(methodThrowPts); - exporter.dumpReachableLocalVars(mLocalVarNodes); - exporter.dumpReachableLocalVarsNoNative(mLocalVarNodesNoNative); - exporter.dumpInsensPointsTo(mLocalVarNodes, pta); - } + exporter.collectMetric("#Global Pointer (lib + app):", String.valueOf(totalGlobalPointers)); + exporter.collectMetric( + "#Global Avg Points-To Target(CI):", + String.valueOf(((double) totalGlobalPointsToCi) / ((double) totalGlobalPointers))); + exporter.collectMetric( + "#Global Avg Points-To Target(CS):", + String.valueOf(((double) totalGlobalPointsToCs) / ((double) totalGlobalPointers))); + exporter.collectMetric("#App Global Pointer:", String.valueOf(appGlobalPointers)); + exporter.collectMetric( + "#App Global Avg Points-To Target(CI):", + String.valueOf(((double) appGlobalPointsToCi) / ((double) appGlobalPointers))); + exporter.collectMetric( + "#App Global Avg Points-To Target(CS):", + String.valueOf(((double) appGlobalPointsToCs) / ((double) appGlobalPointers))); + exporter.collectMetric( + "#Avg Points-to Target(CI):", String.valueOf(((double) ptsCnt) / (varCnt))); + exporter.collectMetric( + "#Avg Points-to Target without Native Var(CI):", + String.valueOf(((double) ptsCntNoNative) / (varCntNoNative))); + exporter.collectMetric("#Local Pointer (lib + app):", String.valueOf(totalLocalPointersCi)); + exporter.collectMetric( + "#Local Avg Points-To Target(CI):", + String.valueOf(((double) totalLocalCiToCi) / ((double) totalLocalPointersCi))); + exporter.collectMetric( + "#Local Avg Points-To Target(CS):", + String.valueOf(((double) totalLocalCiToCs) / ((double) totalLocalPointersCi))); + exporter.collectMetric("#App Local Pointer:", String.valueOf(appLocalPointersCi)); + exporter.collectMetric( + "#App Local Avg Points-To Target(CI):", + String.valueOf(((double) appLocalCiToCi) / ((double) appLocalPointersCi))); + exporter.collectMetric( + "#App Local Avg Points-To Target(CS):", + String.valueOf(((double) appLocalCiToCs) / ((double) appLocalPointersCi))); + exporter.collectMetric( + "#Context Local Pointer (lib + app):", String.valueOf(totalLocalPointersCs)); + exporter.collectMetric( + "#Context Local Avg Points-To Target(CI):", + String.valueOf(((double) totalLocalCsToCi) / ((double) totalLocalPointersCs))); + exporter.collectMetric( + "#Context Local Avg Points-To Target(CS):", + String.valueOf(((double) totalLocalCsToCs) / ((double) totalLocalPointersCs))); + exporter.collectMetric("#App Context Local Pointer:", String.valueOf(appLocalPointersCs)); + exporter.collectMetric( + "#App Context Local Avg Points-To Target(CI):", + String.valueOf(((double) appLocalCsToCi) / ((double) appLocalPointersCs))); + exporter.collectMetric( + "#App Context Local Avg Points-To Target(CS):", + String.valueOf(((double) appLocalCsToCs) / ((double) appLocalPointersCs))); + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpMethodThrowPointsto(methodThrowPts); + exporter.dumpReachableLocalVars(mLocalVarNodes); + exporter.dumpReachableLocalVarsNoNative(mLocalVarNodesNoNative); + exporter.dumpInsensPointsTo(mLocalVarNodes, pta); } + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java b/sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java index 4aa963a0ea7..d4d3d9900db 100644 --- a/sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/RuntimeStat.java @@ -21,20 +21,20 @@ import java.util.Date; public class RuntimeStat implements AbstractStat { - private Date startTime; - private long elapsedTime; + private Date startTime; + private long elapsedTime; - public void begin() { - startTime = new Date(); - } + public void begin() { + startTime = new Date(); + } - public void end() { - Date endTime = new Date(); - elapsedTime = endTime.getTime() - startTime.getTime(); - } + public void end() { + Date endTime = new Date(); + elapsedTime = endTime.getTime() - startTime.getTime(); + } - @Override - public void export(Exporter exporter) { - exporter.collectMetric("Time (sec):", String.valueOf(((double) elapsedTime) / 1000.0)); - } + @Override + public void export(Exporter exporter) { + exporter.collectMetric("Time (sec):", String.valueOf(((double) elapsedTime) / 1000.0)); + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java index 3f67dc561f1..493aa243d43 100644 --- a/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java +++ b/sootup.qilin/src/main/java/qilin/stat/SimplifiedEvaluator.java @@ -18,6 +18,7 @@ package qilin.stat; +import java.util.*; import qilin.core.PTA; import qilin.core.builder.FakeMainFactory; import qilin.core.builder.MethodNodeFactory; @@ -39,173 +40,176 @@ import sootup.core.types.ReferenceType; import sootup.core.types.Type; -import java.util.*; - public class SimplifiedEvaluator implements IEvaluator { - protected final PTA pta; - protected final Exporter exporter; - protected Stopwatch stopwatch; - - public SimplifiedEvaluator(PTA pta) { - this.pta = pta; - exporter = new Exporter(); + protected final PTA pta; + protected final Exporter exporter; + protected Stopwatch stopwatch; + + public SimplifiedEvaluator(PTA pta) { + this.pta = pta; + exporter = new Exporter(); + } + + @Override + public void begin() { + stopwatch = Stopwatch.newAndStart("PTA evaluator"); + } + + @Override + public void end() { + stopwatch.stop(); + exporter.collectMetric("Time (sec):", String.valueOf(((double) stopwatch.elapsed()))); + exporter.collectMetric( + "#Reachable Method (CI):", String.valueOf(pta.getNakedReachableMethods().size() - 1)); + CallGraph ciCallGraph = pta.getCallGraph(); + exporter.collectMetric( + "#Call Edge(CI):", String.valueOf(ciCallGraph.size() - FakeMainFactory.implicitCallEdges)); + + CallGraph callGraph = pta.getCallGraph(); + + // loop over all reachable method's statement to find casts, local + // references, virtual call sites + Set reachableMethods = new HashSet<>(); + for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + final SootMethod sm = momc.method(); + reachableMethods.add(sm); } - - @Override - public void begin() { - stopwatch = Stopwatch.newAndStart("PTA evaluator"); - } - - @Override - public void end() { - stopwatch.stop(); - exporter.collectMetric("Time (sec):", String.valueOf(((double) stopwatch.elapsed()))); - exporter.collectMetric("#Reachable Method (CI):", String.valueOf(pta.getNakedReachableMethods().size() - 1)); - CallGraph ciCallGraph = pta.getCallGraph(); - exporter.collectMetric("#Call Edge(CI):", String.valueOf(ciCallGraph.size() - FakeMainFactory.implicitCallEdges)); - - CallGraph callGraph = pta.getCallGraph(); - - // loop over all reachable method's statement to find casts, local - // references, virtual call sites - Set reachableMethods = new HashSet<>(); - for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { - final SootMethod sm = momc.method(); - reachableMethods.add(sm); - } - int totalPolyCalls = 0; - int totalCastsMayFail = 0; - for (SootMethod sm : reachableMethods) { - // All the statements in the method - for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { - // virtual calls - if (st.containsInvokeExpr()) { - AbstractInvokeExpr ie = st.getInvokeExpr(); - if (!(ie instanceof JStaticInvokeExpr)) { - // Virtual, Special or Instance - // have to check target soot method, cannot just - // count edges - Set targets = new HashSet<>(); - for (Iterator it = callGraph.edgesOutOf(st); it.hasNext(); ) - targets.add(it.next().tgt()); - if (targets.size() > 1) { - totalPolyCalls++; - } - } - } else if (st instanceof JAssignStmt assignStmt) { - Value rhs = assignStmt.getRightOp(); - Value lhs = assignStmt.getLeftOp(); - if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = rhs.getType(); - Value v = ((JCastExpr) rhs).getOp(); - if (!(v instanceof Local)) { - continue; - } - boolean fails = false; - Collection pts = pta.reachingObjects((Local) v).toCollection(); - for (Node n : pts) { - if (fails) { - break; - } - fails = !PTAUtils.castNeverFails(n.getType(), targetType); - } - if (fails) { - totalCastsMayFail++; - } - } - } + int totalPolyCalls = 0; + int totalCastsMayFail = 0; + for (SootMethod sm : reachableMethods) { + // All the statements in the method + for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { + // virtual calls + if (st.containsInvokeExpr()) { + AbstractInvokeExpr ie = st.getInvokeExpr(); + if (!(ie instanceof JStaticInvokeExpr)) { + // Virtual, Special or Instance + // have to check target soot method, cannot just + // count edges + Set targets = new HashSet<>(); + for (Iterator it = callGraph.edgesOutOf(st); it.hasNext(); ) + targets.add(it.next().tgt()); + if (targets.size() > 1) { + totalPolyCalls++; } - } - AliasStat aliasStat = new AliasStat(pta); - aliasStat.aliasesProcessing(); - exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail)); - exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls)); - exporter.collectMetric("#globalAlias_incstst:", String.valueOf(aliasStat.getGlobalAliasesIncludingStSt())); - ptsStat(); - } - - private void ptsStat() { - int ptsCntNoNative = 0; - int varCntNoNative = 0; - PAG pag = pta.getPag(); - // locals exclude Exceptions - for (Local local : pag.getLocalPointers()) { - try { - LocalVarNode lvn = pag.findLocalVarNode(local); - if (local.toString().contains("intermediate/")) { - continue; - } - mLocalVarNodes.add(lvn); - } catch (Exception e) { - e.printStackTrace(); + } + } else if (st instanceof JAssignStmt assignStmt) { + Value rhs = assignStmt.getRightOp(); + Value lhs = assignStmt.getLeftOp(); + if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { + final Type targetType = rhs.getType(); + Value v = ((JCastExpr) rhs).getOp(); + if (!(v instanceof Local)) { + continue; } - } - - // stat avg pts. - for (SootMethod sm : pta.getNakedReachableMethods()) { - MethodPAG mpag = pag.getMethodPAG(sm); - MethodNodeFactory mnf = mpag.nodeFactory(); - if (!sm.isStatic()) { - mLocalVarNodes.add((LocalVarNode) mnf.caseThis()); + boolean fails = false; + Collection pts = pta.reachingObjects((Local) v).toCollection(); + for (Node n : pts) { + if (fails) { + break; + } + fails = !PTAUtils.castNeverFails(n.getType(), targetType); } - for (int i = 0; i < sm.getParameterCount(); ++i) { - Type mType = sm.getParameterType(i); - if (mType instanceof ReferenceType) { - mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); - } + if (fails) { + totalCastsMayFail++; } + } } - Set tmp = new HashSet<>(); - for (LocalVarNode lvn : mLocalVarNodes) { - SootMethod sm = lvn.getMethod(); - if (PTAUtils.isFakeMainMethod(sm)) { - tmp.add(lvn); - continue; - } - final Set callocSites = getPointsToNewExpr(pta.reachingObjects(lvn)); - if (callocSites.size() > 0) { - if (!handledNatives.contains(sm.toString())) { - ptsCntNoNative += callocSites.size(); - varCntNoNative++; - } - } else { - tmp.add(lvn); - } + } + } + AliasStat aliasStat = new AliasStat(pta); + aliasStat.aliasesProcessing(); + exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail)); + exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls)); + exporter.collectMetric( + "#globalAlias_incstst:", String.valueOf(aliasStat.getGlobalAliasesIncludingStSt())); + ptsStat(); + } + + private void ptsStat() { + int ptsCntNoNative = 0; + int varCntNoNative = 0; + PAG pag = pta.getPag(); + // locals exclude Exceptions + for (Local local : pag.getLocalPointers()) { + try { + LocalVarNode lvn = pag.findLocalVarNode(local); + if (local.toString().contains("intermediate/")) { + continue; } - mLocalVarNodes.removeAll(tmp); - - exporter.collectMetric("#Avg Points-to Target without Native Var(CI):", String.valueOf(((double) ptsCntNoNative) / (varCntNoNative))); + mLocalVarNodes.add(lvn); + } catch (Exception e) { + e.printStackTrace(); + } } - private final Set handledNatives = Set.of( - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ); - - private final Set mLocalVarNodes = new HashSet<>(); - - protected Set getPointsToNewExpr(PointsToSet pts) { - final Set allocSites = new HashSet<>(); - for (AllocNode n : pts.toCollection()) { - allocSites.add(n.getNewExpr()); + // stat avg pts. + for (SootMethod sm : pta.getNakedReachableMethods()) { + MethodPAG mpag = pag.getMethodPAG(sm); + MethodNodeFactory mnf = mpag.nodeFactory(); + if (!sm.isStatic()) { + mLocalVarNodes.add((LocalVarNode) mnf.caseThis()); + } + for (int i = 0; i < sm.getParameterCount(); ++i) { + Type mType = sm.getParameterType(i); + if (mType instanceof ReferenceType) { + mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i)); } - return allocSites; + } } - - @Override - public String toString() { - return exporter.report(); + Set tmp = new HashSet<>(); + for (LocalVarNode lvn : mLocalVarNodes) { + SootMethod sm = lvn.getMethod(); + if (PTAUtils.isFakeMainMethod(sm)) { + tmp.add(lvn); + continue; + } + final Set callocSites = getPointsToNewExpr(pta.reachingObjects(lvn)); + if (callocSites.size() > 0) { + if (!handledNatives.contains(sm.toString())) { + ptsCntNoNative += callocSites.size(); + varCntNoNative++; + } + } else { + tmp.add(lvn); + } + } + mLocalVarNodes.removeAll(tmp); + + exporter.collectMetric( + "#Avg Points-to Target without Native Var(CI):", + String.valueOf(((double) ptsCntNoNative) / (varCntNoNative))); + } + + private final Set handledNatives = + Set.of( + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ""); + + private final Set mLocalVarNodes = new HashSet<>(); + + protected Set getPointsToNewExpr(PointsToSet pts) { + final Set allocSites = new HashSet<>(); + for (AllocNode n : pts.toCollection()) { + allocSites.add(n.getNewExpr()); } + return allocSites; + } + + @Override + public String toString() { + return exporter.report(); + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java index 9d80c04e753..90478a1577a 100644 --- a/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/TypeClientStat.java @@ -18,6 +18,7 @@ package qilin.stat; +import java.util.*; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; @@ -40,128 +41,130 @@ import sootup.core.types.Type; import sootup.core.views.View; -import java.util.*; - public class TypeClientStat implements AbstractStat { - private final PTA pta; + private final PTA pta; - private int totalCasts = 0; - private int appCasts = 0; - private int totalCastsMayFail = 0; - private int appCastsMayFail = 0; - private int totalVirtualCalls = 0; - private int appVirtualCalls = 0; - private int totalPolyCalls = 0; - private int appPolyCalls = 0; - private int totalStaticCalls = 0; - private int totalPolyCallTargets = 0; - private int unreachable = 0; - private final Map polyCalls = new HashMap<>(); - private final Map> mayFailCasts = new HashMap<>(); + private int totalCasts = 0; + private int appCasts = 0; + private int totalCastsMayFail = 0; + private int appCastsMayFail = 0; + private int totalVirtualCalls = 0; + private int appVirtualCalls = 0; + private int totalPolyCalls = 0; + private int appPolyCalls = 0; + private int totalStaticCalls = 0; + private int totalPolyCallTargets = 0; + private int unreachable = 0; + private final Map polyCalls = new HashMap<>(); + private final Map> mayFailCasts = new HashMap<>(); - public TypeClientStat(PTA pta) { - this.pta = pta; - init(); - } + public TypeClientStat(PTA pta) { + this.pta = pta; + init(); + } - private void init() { - CallGraph callGraph = pta.getCallGraph(); + private void init() { + CallGraph callGraph = pta.getCallGraph(); - // loop over all reachable method's statement to find casts, local - // references, virtual call sites - Set reachableMethods = new HashSet<>(); - for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { - final SootMethod sm = momc.method(); - reachableMethods.add(sm); - } + // loop over all reachable method's statement to find casts, local + // references, virtual call sites + Set reachableMethods = new HashSet<>(); + for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) { + final SootMethod sm = momc.method(); + reachableMethods.add(sm); + } - for (SootMethod sm : reachableMethods) { - View view = PTAScene.v().getView(); - SootClass sc = (SootClass) view.getClass(sm.getDeclaringClassType()).get(); - boolean app = sc.isApplicationClass(); + for (SootMethod sm : reachableMethods) { + View view = PTAScene.v().getView(); + SootClass sc = (SootClass) view.getClass(sm.getDeclaringClassType()).get(); + boolean app = sc.isApplicationClass(); - // All the statements in the method - for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { - // virtual calls - if (st.containsInvokeExpr()) { - AbstractInvokeExpr ie = st.getInvokeExpr(); - if (ie instanceof JStaticInvokeExpr) { - totalStaticCalls++; - } else {// Virtual, Special or Instance - totalVirtualCalls++; - if (app) { - appVirtualCalls++; - } - // have to check target soot method, cannot just - // count edges - Set targets = new HashSet<>(); + // All the statements in the method + for (Stmt st : PTAUtils.getMethodBody(sm).getStmts()) { + // virtual calls + if (st.containsInvokeExpr()) { + AbstractInvokeExpr ie = st.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { + totalStaticCalls++; + } else { // Virtual, Special or Instance + totalVirtualCalls++; + if (app) { + appVirtualCalls++; + } + // have to check target soot method, cannot just + // count edges + Set targets = new HashSet<>(); - for (Iterator it = callGraph.edgesOutOf(st); it.hasNext(); ) - targets.add(it.next().tgt()); - if (targets.size() == 0) { - unreachable++; - } - if (targets.size() > 1) { - totalPolyCallTargets += targets.size(); - totalPolyCalls++; - polyCalls.put(ie, sm); - if (app) { - appPolyCalls++; - } - } - } - } else if (st instanceof JAssignStmt assignStmt) { - Value rhs = assignStmt.getRightOp(); - Value lhs = assignStmt.getLeftOp(); - if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { - final Type targetType = rhs.getType(); - Value v = ((JCastExpr) rhs).getOp(); - if (!(v instanceof Local)) { - continue; - } - totalCasts++; - if (app) { - appCasts++; - } - boolean fails = false; - Collection pts = pta.reachingObjects((Local) v).toCollection(); - for (AllocNode n : pts) { - if (fails) { - break; - } - fails = !PTAUtils.castNeverFails(n.getType(), targetType); - } + for (Iterator it = callGraph.edgesOutOf(st); it.hasNext(); ) + targets.add(it.next().tgt()); + if (targets.size() == 0) { + unreachable++; + } + if (targets.size() > 1) { + totalPolyCallTargets += targets.size(); + totalPolyCalls++; + polyCalls.put(ie, sm); + if (app) { + appPolyCalls++; + } + } + } + } else if (st instanceof JAssignStmt assignStmt) { + Value rhs = assignStmt.getRightOp(); + Value lhs = assignStmt.getLeftOp(); + if (rhs instanceof JCastExpr && lhs.getType() instanceof ReferenceType) { + final Type targetType = rhs.getType(); + Value v = ((JCastExpr) rhs).getOp(); + if (!(v instanceof Local)) { + continue; + } + totalCasts++; + if (app) { + appCasts++; + } + boolean fails = false; + Collection pts = pta.reachingObjects((Local) v).toCollection(); + for (AllocNode n : pts) { + if (fails) { + break; + } + fails = !PTAUtils.castNeverFails(n.getType(), targetType); + } - if (fails) { - totalCastsMayFail++; - mayFailCasts.computeIfAbsent(sm, k -> new HashSet<>()).add(st); - if (app) { - appCastsMayFail++; - } - } - } - } + if (fails) { + totalCastsMayFail++; + mayFailCasts.computeIfAbsent(sm, k -> new HashSet<>()).add(st); + if (app) { + appCastsMayFail++; + } } + } } + } } + } - @Override - public void export(Exporter exporter) { - exporter.collectMetric("#Cast (Total):", String.valueOf(totalCasts)); - exporter.collectMetric("#Cast (AppOnly):", String.valueOf(appCasts)); - exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail)); - exporter.collectMetric("#May Fail Cast (AppOnly):", String.valueOf(appCastsMayFail)); - exporter.collectMetric("#Static Call Site(Total):", String.valueOf(totalStaticCalls - FakeMainFactory.implicitCallEdges)); - exporter.collectMetric("#Virtual Call Site(Total):", String.valueOf(totalVirtualCalls)); - exporter.collectMetric("#Virtual Call Site(AppOnly):", String.valueOf(appVirtualCalls)); - exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls)); - exporter.collectMetric("#Virtual Call Site(Polymorphic AppOnly):", String.valueOf(appPolyCalls)); - exporter.collectMetric("#Virtual Call Site(Unreachable):", String.valueOf(unreachable)); - exporter.collectMetric("#Avg Poly Call Targets:", String.valueOf(1.0 * totalPolyCallTargets / totalPolyCalls)); + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Cast (Total):", String.valueOf(totalCasts)); + exporter.collectMetric("#Cast (AppOnly):", String.valueOf(appCasts)); + exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail)); + exporter.collectMetric("#May Fail Cast (AppOnly):", String.valueOf(appCastsMayFail)); + exporter.collectMetric( + "#Static Call Site(Total):", + String.valueOf(totalStaticCalls - FakeMainFactory.implicitCallEdges)); + exporter.collectMetric("#Virtual Call Site(Total):", String.valueOf(totalVirtualCalls)); + exporter.collectMetric("#Virtual Call Site(AppOnly):", String.valueOf(appVirtualCalls)); + exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls)); + exporter.collectMetric( + "#Virtual Call Site(Polymorphic AppOnly):", String.valueOf(appPolyCalls)); + exporter.collectMetric("#Virtual Call Site(Unreachable):", String.valueOf(unreachable)); + exporter.collectMetric( + "#Avg Poly Call Targets:", String.valueOf(1.0 * totalPolyCallTargets / totalPolyCalls)); - if (CoreConfig.v().getOutConfig().dumpStats) { - exporter.dumpPolyCalls(polyCalls); - exporter.dumpMayFailCasts(mayFailCasts); - } + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpPolyCalls(polyCalls); + exporter.dumpMayFailCasts(mayFailCasts); } + } } diff --git a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java index 21d304c6402..ef45017c22d 100644 --- a/sootup.qilin/src/main/java/qilin/stat/YummyStat.java +++ b/sootup.qilin/src/main/java/qilin/stat/YummyStat.java @@ -18,6 +18,10 @@ package qilin.stat; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.builder.MethodNodeFactory; @@ -28,77 +32,72 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - public class YummyStat implements AbstractStat { - private final PTA pta; - private long singleCallCnt; - private long singleReceiverCnt; - private long singleCallSingleReceiverCnt; - private final Set singleCalls = new HashSet<>(); - private final Set singleReceivers = new HashSet<>(); - private final Set singleCallSingleReceivers = new HashSet<>(); - - public YummyStat(PTA pta) { - this.pta = pta; - init(); - } - - private void init() { - Map> target2callsites = new HashMap<>(); - CallGraph ciCallGraph = pta.getCallGraph(); - for (Edge edge : ciCallGraph) { - Stmt callUnit = edge.srcUnit(); - SootMethod target = edge.tgt(); - if (callUnit != null && target != null) { - target2callsites.computeIfAbsent(target, k -> new HashSet<>()).add(callUnit); - } - } + private final PTA pta; + private long singleCallCnt; + private long singleReceiverCnt; + private long singleCallSingleReceiverCnt; + private final Set singleCalls = new HashSet<>(); + private final Set singleReceivers = new HashSet<>(); + private final Set singleCallSingleReceivers = new HashSet<>(); - target2callsites.entrySet().stream() - .filter(e -> e.getValue().size() == 1) - .map(Map.Entry::getKey).filter(m -> !m.isStatic()) - .forEach(singleCalls::add); - - singleCallCnt = singleCalls.size(); + public YummyStat(PTA pta) { + this.pta = pta; + init(); + } + private void init() { + Map> target2callsites = new HashMap<>(); + CallGraph ciCallGraph = pta.getCallGraph(); + for (Edge edge : ciCallGraph) { + Stmt callUnit = edge.srcUnit(); + SootMethod target = edge.tgt(); + if (callUnit != null && target != null) { + target2callsites.computeIfAbsent(target, k -> new HashSet<>()).add(callUnit); + } + } - Set instanceReachables = new HashSet<>(); - for (final MethodOrMethodContext momc : pta.getReachableMethods()) { - SootMethod method = momc.method(); - if (method.isConcrete() && !method.isStatic()) { - instanceReachables.add(method); - } - } + target2callsites.entrySet().stream() + .filter(e -> e.getValue().size() == 1) + .map(Map.Entry::getKey) + .filter(m -> !m.isStatic()) + .forEach(singleCalls::add); - for (SootMethod method : instanceReachables) { - MethodNodeFactory nf = pta.getPag().getMethodPAG(method).nodeFactory(); - PointsToSet pts = pta.reachingObjects(nf.caseThis()).toCIPointsToSet(); - int ptSize = pts.size(); - if (ptSize == 1) { - singleReceivers.add(method); - } - } + singleCallCnt = singleCalls.size(); - singleReceiverCnt = singleReceivers.size(); + Set instanceReachables = new HashSet<>(); + for (final MethodOrMethodContext momc : pta.getReachableMethods()) { + SootMethod method = momc.method(); + if (method.isConcrete() && !method.isStatic()) { + instanceReachables.add(method); + } + } - singleCalls.stream().filter(singleReceivers::contains).forEach(singleCallSingleReceivers::add); - singleCallSingleReceiverCnt = singleCallSingleReceivers.size(); + for (SootMethod method : instanceReachables) { + MethodNodeFactory nf = pta.getPag().getMethodPAG(method).nodeFactory(); + PointsToSet pts = pta.reachingObjects(nf.caseThis()).toCIPointsToSet(); + int ptSize = pts.size(); + if (ptSize == 1) { + singleReceivers.add(method); + } } + singleReceiverCnt = singleReceivers.size(); + + singleCalls.stream().filter(singleReceivers::contains).forEach(singleCallSingleReceivers::add); + singleCallSingleReceiverCnt = singleCallSingleReceivers.size(); + } - @Override - public void export(Exporter exporter) { - exporter.collectMetric("#Single-Call Methods:", String.valueOf(singleCallCnt)); - exporter.collectMetric("#Single-Receiver Methods:", String.valueOf(singleReceiverCnt)); - exporter.collectMetric("#Single-Call-Single-Receiver Methods:", String.valueOf(singleCallSingleReceiverCnt)); - if (CoreConfig.v().getOutConfig().dumpStats) { - exporter.dumpSingleCallMethods(singleCalls); - exporter.dumpSingleReceiverMethods(singleReceivers); - exporter.dumpSingleCallSingleReceiverMethods(singleCallSingleReceivers); - } + @Override + public void export(Exporter exporter) { + exporter.collectMetric("#Single-Call Methods:", String.valueOf(singleCallCnt)); + exporter.collectMetric("#Single-Receiver Methods:", String.valueOf(singleReceiverCnt)); + exporter.collectMetric( + "#Single-Call-Single-Receiver Methods:", String.valueOf(singleCallSingleReceiverCnt)); + if (CoreConfig.v().getOutConfig().dumpStats) { + exporter.dumpSingleCallMethods(singleCalls); + exporter.dumpSingleReceiverMethods(singleReceivers); + exporter.dumpSingleCallSingleReceiverMethods(singleCallSingleReceivers); } + } } diff --git a/sootup.qilin/src/main/java/qilin/util/ANSIColor.java b/sootup.qilin/src/main/java/qilin/util/ANSIColor.java index 8c4c8655f54..3ea03db8a2d 100644 --- a/sootup.qilin/src/main/java/qilin/util/ANSIColor.java +++ b/sootup.qilin/src/main/java/qilin/util/ANSIColor.java @@ -19,19 +19,19 @@ package qilin.util; public class ANSIColor { - public static final String RESET = "\u001b[0m"; - public static final String BOLD = "\u001b[1m"; - public static final String BLACK = "\u001b[30m"; - public static final String RED = "\u001b[31m"; - public static final String GREEN = "\u001b[32m"; - public static final String YELLOW = "\u001b[33m"; - public static final String BLUE = "\u001b[34m"; - public static final String PURPLE = "\u001b[35m"; - public static final String CYAN = "\u001b[36m"; - public static final String WHITE = "\u001b[37m"; - public static final String BG_BLACK = "\u001b[40m"; + public static final String RESET = "\u001b[0m"; + public static final String BOLD = "\u001b[1m"; + public static final String BLACK = "\u001b[30m"; + public static final String RED = "\u001b[31m"; + public static final String GREEN = "\u001b[32m"; + public static final String YELLOW = "\u001b[33m"; + public static final String BLUE = "\u001b[34m"; + public static final String PURPLE = "\u001b[35m"; + public static final String CYAN = "\u001b[36m"; + public static final String WHITE = "\u001b[37m"; + public static final String BG_BLACK = "\u001b[40m"; - public static String color(final String color, final String s) { - return color + s + RESET; - } + public static String color(final String color, final String s) { + return color + s + RESET; + } } diff --git a/sootup.qilin/src/main/java/qilin/util/DataFactory.java b/sootup.qilin/src/main/java/qilin/util/DataFactory.java index e9db175be98..57e6342e228 100644 --- a/sootup.qilin/src/main/java/qilin/util/DataFactory.java +++ b/sootup.qilin/src/main/java/qilin/util/DataFactory.java @@ -21,28 +21,28 @@ import java.util.*; public class DataFactory { - public static List createList() { - return new ArrayList<>(); -// return new CopyOnWriteArrayList<>(); - } + public static List createList() { + return new ArrayList<>(); + // return new CopyOnWriteArrayList<>(); + } - public static Set createSet() { - return new HashSet<>(); -// return ConcurrentHashMap.newKeySet(); - } + public static Set createSet() { + return new HashSet<>(); + // return ConcurrentHashMap.newKeySet(); + } - public static Set createSet(int initCapacity) { - return new HashSet<>(initCapacity); -// return ConcurrentHashMap.newKeySet(initCapacity); - } + public static Set createSet(int initCapacity) { + return new HashSet<>(initCapacity); + // return ConcurrentHashMap.newKeySet(initCapacity); + } - public static Map createMap() { - return new HashMap<>(); -// return new ConcurrentHashMap<>(); - } + public static Map createMap() { + return new HashMap<>(); + // return new ConcurrentHashMap<>(); + } - public static Map createMap(int initCapacity) { - return new HashMap<>(initCapacity); -// return new ConcurrentHashMap<>(initCapacity); - } + public static Map createMap(int initCapacity) { + return new HashMap<>(initCapacity); + // return new ConcurrentHashMap<>(initCapacity); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java b/sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java index 5ee60e47e64..20a5daf57bd 100644 --- a/sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java +++ b/sootup.qilin/src/main/java/qilin/util/MemoryWatcher.java @@ -18,62 +18,62 @@ package qilin.util; +import java.util.Timer; +import java.util.TimerTask; import oshi.SystemInfo; import oshi.software.os.OSProcess; import oshi.software.os.OperatingSystem; -import java.util.Timer; -import java.util.TimerTask; - public class MemoryWatcher extends Timer { - private final long pid; - private final String name; - private final long[] maxMemory; + private final long pid; + private final String name; + private final long[] maxMemory; - public MemoryWatcher(long pid, String name) { - this.pid = pid; - this.name = name; - this.maxMemory = new long[1]; - } + public MemoryWatcher(long pid, String name) { + this.pid = pid; + this.name = name; + this.maxMemory = new long[1]; + } - private TimerTask task; + private TimerTask task; - public void start() { - this.maxMemory[0] = 0; - task = new TimerTask() { - @Override - public void run() { - SystemInfo si = new SystemInfo(); - OperatingSystem os = si.getOperatingSystem(); - OSProcess process = os.getProcess((int) pid); - long mem = process.getResidentSetSize(); - if (mem > maxMemory[0]) { - maxMemory[0] = mem; - } + public void start() { + this.maxMemory[0] = 0; + task = + new TimerTask() { + @Override + public void run() { + SystemInfo si = new SystemInfo(); + OperatingSystem os = si.getOperatingSystem(); + OSProcess process = os.getProcess((int) pid); + long mem = process.getResidentSetSize(); + if (mem > maxMemory[0]) { + maxMemory[0] = mem; } + } }; - schedule(task, 0, 100); - } + schedule(task, 0, 100); + } - public void stop() { - task.cancel(); - this.cancel(); - } + public void stop() { + task.cancel(); + this.cancel(); + } - public double inKiloByte() { - return maxMemory[0] / 1024.0; - } + public double inKiloByte() { + return maxMemory[0] / 1024.0; + } - public double inMegaByte() { - return maxMemory[0] / (1024.0 * 1024.0); - } + public double inMegaByte() { + return maxMemory[0] / (1024.0 * 1024.0); + } - public double inGigaByte() { - return maxMemory[0] / (1024.0 * 1024.0 * 1024.0); - } + public double inGigaByte() { + return maxMemory[0] / (1024.0 * 1024.0 * 1024.0); + } - @Override - public String toString() { - return String.format("%s consumed memory: %.2f MB", this.name, this.inMegaByte()); - } + @Override + public String toString() { + return String.format("%s consumed memory: %.2f MB", this.name, this.inMegaByte()); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index b65d09a95d3..03809b0ed1f 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -18,6 +18,11 @@ package qilin.util; +import java.io.*; +import java.net.URL; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import qilin.CoreConfig; @@ -63,778 +68,781 @@ import sootup.core.util.printer.JimplePrinter; import sootup.java.core.JavaIdentifierFactory; -import java.io.*; -import java.net.URL; -import java.util.*; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - public final class PTAUtils { - private static final Logger logger = LoggerFactory.getLogger(PTAUtils.class); - static final String output_dir = CoreConfig.v().getOutConfig().outDir; - static Map nodes = new TreeMap<>(); - private static final ClassType clRunnable = getClassType("java.lang.Runnable"); - - public static ClassType getClassType(String fullyQualifiedClassName) { - return JavaIdentifierFactory.getInstance().getClassType(fullyQualifiedClassName); - } - - public static boolean isApplicationMethod(SootMethod sm) { - ClassType classType = sm.getDeclaringClassType(); - SootClass sc = (SootClass) PTAScene.v().getView().getClass(classType).get(); - return sc.isApplicationClass(); - } - - public static boolean isStaticInitializer(SootMethod method) { - return method.getName().equals(""); - } - - public static boolean isConstructor(SootMethod method) { - return method.getName().equals(""); - } - - public static Map> calcStaticThisPTS(PTA pta) { - Map> pts = new HashMap<>(); - Set workList = new HashSet<>(); - PAG pag = pta.getPag(); - // add all instance methods which potentially contain static call - for (SootMethod method : pta.getNakedReachableMethods()) { - if (PTAUtils.isFakeMainMethod(method) || method.isConcrete() && !method.isStatic()) { - MethodPAG srcmpag = pag.getMethodPAG(method); - LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); - final PointsToSet other = pta.reachingObjects(thisRef).toCIPointsToSet(); - - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof JStaticInvokeExpr) { - for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { - Edge e = it.next(); - SootMethod tgtmtd = e.tgt(); - MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - LocalVarNode tgtThisRef = (LocalVarNode) tgtnf.caseThis(); - // create "THIS" ptr for static method - Set addTo = pts.computeIfAbsent(tgtThisRef, k -> new HashSet<>()); - boolean returnValue = false; - for (Iterator itx = other.iterator(); itx.hasNext(); ) { - AllocNode node = itx.next(); - if (addTo.add(node)) { - returnValue = true; - } - } - if (returnValue) { - workList.add(tgtmtd); - } - } - } - } - } - } - while (!workList.isEmpty()) { - SootMethod method = workList.iterator().next(); - workList.remove(method); - MethodPAG srcmpag = pag.getMethodPAG(method); - LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); - final Set other = pts.computeIfAbsent(thisRef, k -> new HashSet<>()); - - for (final Stmt s : srcmpag.getInvokeStmts()) { - AbstractInvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof JStaticInvokeExpr) { - for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { - Edge e = it.next(); - SootMethod tgtmtd = e.tgt(); - MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - LocalVarNode tgtThisRef = (LocalVarNode) tgtnf.caseThis(); - // create "THIS" ptr for static method - Set addTo = pts.computeIfAbsent(tgtThisRef, k -> new HashSet<>()); - if (addTo.addAll(other)) { - workList.add(tgtmtd); - } - } - } - } - } - return pts; - } - - public static Object getIR(Object sparkNode) { - if (sparkNode instanceof VarNode) { - return ((VarNode) sparkNode).getVariable(); - } else if (sparkNode instanceof AllocNode) { - return ((AllocNode) sparkNode).getNewExpr(); - } else {// sparkField? - return sparkNode; - } - } - - public static boolean mustAlias(PTA pta, VarNode v1, VarNode v2) { - PointsToSet v1pts = pta.reachingObjects(v1).toCIPointsToSet(); - PointsToSet v2pts = pta.reachingObjects(v2).toCIPointsToSet(); - return v1pts.pointsToSetEquals(v2pts); - } - - public static void printPts(PTA pta, PointsToSet pts) { - final StringBuffer ret = new StringBuffer(); - for (Iterator it = pts.iterator(); it.hasNext(); ) { - AllocNode n = it.next(); - ret.append("\t").append(n).append("\n"); - } - System.out.print(ret); - } - - /** - * dump callgraph to sootoutput/callgraph.dot - */ - public static void dumpCallGraph(Iterable callgraph, boolean appOnly) { - String filename = "callgraph"; - DotGraph canvas = setDotGraph(filename); - - int mn = -1; - Set methodSet = new HashSet<>(); - List methodList = new ArrayList<>(); - - for (Edge edge : callgraph) { - MethodOrMethodContext srcmtd = edge.getSrc(); - if (appOnly && !PTAUtils.isApplicationMethod(srcmtd.method())) - continue; - MethodOrMethodContext dstmtd = edge.getTgt(); - String srcName = srcmtd.toString(); - - if (methodSet.add(srcName)) { - canvas.drawNode(srcName).setLabel("" + ++mn); - methodList.add(mn, srcName); - } - String dstName = dstmtd.toString(); - - if (methodSet.add(dstName)) { - canvas.drawNode(dstName).setLabel("" + ++mn); - methodList.add(mn, dstName); - } - canvas.drawEdge(srcName, dstName); - } - - plotDotGraph(canvas, filename); - try { - PrintWriter out = new PrintWriter(new File(output_dir, "callgraphnodes")); - for (int i = 0; i < methodList.size(); i++) - out.println(i + ":" + methodList.get(i)); - out.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - - /** - * slice a callgrph, put nodes &edges related to method into set1&set2 - */ - private static void slice(CallGraph callgraph, MethodOrMethodContext method, Set set1, - Set set2) { - for (Iterator it = callgraph.edgesInto(method); it.hasNext(); ) { - Edge edge = it.next(); - set2.add(edge); - MethodOrMethodContext src = edge.getSrc(); - if (set1.add(src)) - slice(callgraph, src, set1, set2); - } - - } - - /** - * dump callgraph strench to method - */ - public static void dumpSlicedCallGraph(CallGraph callgraph, MethodOrMethodContext method) { - Set tgts = new HashSet<>(); - Set edges = new HashSet<>(); - tgts.add(method); - slice(callgraph, method, tgts, edges); - - dumpCallGraph(edges, false); - } - - /** - * dump callgraph from entry to the method - */ - public static void dumpSlicedCallGraph2(CallGraph callgraph, MethodOrMethodContext method) { - Set edges = new HashSet<>(); - Set visited = new HashSet<>(); - Queue queue = new UniqueQueue<>(); - queue.add(method); - while (!queue.isEmpty()) { - MethodOrMethodContext front = queue.poll(); - for (Iterator it = callgraph.edgesInto(front); it.hasNext(); ) { - Edge edge = it.next(); - MethodOrMethodContext src = edge.getSrc(); - if (visited.add(src)) { - queue.add(src); - edges.add(edge); - break; - } - } - } - dumpCallGraph(edges, false); - } - - public static boolean isUnresolved(Type type) { - if (type instanceof ArrayType at) { - type = at.getBaseType(); - } - if (!(type instanceof ClassType rt)) - return false; -// if (!rt.hasSootClass()) { -// return true; -// } - Optional ocl = PTAScene.v().getView().getClass(rt); - return ocl.isEmpty(); -// SootClass cl = rt.getSootClass(); -// return cl.resolvingLevel() < SootClass.HIERARCHY; - } - - public static boolean castNeverFails(Type src, Type dst) { - if (dst == null) - return true; - if (dst == src) - return true; - if (src == null) - return false; - if (dst.equals(src)) - return true; - if (src instanceof NullType) - return true; -// if (src instanceof AnySubType) -// return true; - if (dst instanceof NullType) - return false; -// if (dst instanceof AnySubType) -// throw new RuntimeException("oops src=" + src + " dst=" + dst); - return PTAScene.v().canStoreType(src, dst); - } - - public static QueueReader dispatch(Type type, VirtualCallSite site) { - final ChunkedQueue targetsQueue = new ChunkedQueue<>(); - final QueueReader targets = targetsQueue.reader(); - if (site.kind() == Kind.THREAD && !PTAScene.v().canStoreType(type, clRunnable)) { - return targets; - } - MethodOrMethodContext container = site.container(); - if (site.iie() instanceof JSpecialInvokeExpr && site.kind() != Kind.THREAD) { - SootMethod target = VirtualCalls.v().resolveSpecial((JSpecialInvokeExpr) site.iie(), site.subSig(), container.method()); - // if the call target resides in a phantom class then - // "target" will be null, simply do not add the target in that case - if (target != null) { - targetsQueue.add(target); - } - } else { - Type mType = site.recNode().getType(); - VirtualCalls.v().resolve(type, mType, site.subSig(), container.method(), targetsQueue); - } - return targets; - } - - public static boolean addWithTypeFiltering(PointsToSetInternal pts, Type type, Node node) { - if (PTAUtils.castNeverFails(node.getType(), type)) { - return pts.add(node.getNumber()); - } - return false; - } - - /** - * dump pts to sootoutput/pts - */ - public static void dumpPts(PTA pta, boolean appOnly) { - try { - PrintWriter file = new PrintWriter(new File(output_dir, "pts.txt")); - file.println("Points-to results:"); - for (final ValNode vn : pta.getPag().getValNodes()) { - if (!(vn instanceof VarNode)) { - continue; - } - SootClass clz = null; - if (vn instanceof LocalVarNode) { - SootMethod sm = ((LocalVarNode) vn).getMethod(); - if (sm != null) { - clz = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); - } - } else if (vn instanceof GlobalVarNode gvn) { - clz = gvn.getDeclaringClass(); - } else if (vn instanceof ContextVarNode cv) { - VarNode varNode = cv.base(); - if (varNode instanceof LocalVarNode cvbase) { - clz = (SootClass) PTAScene.v().getView().getClass(cvbase.getMethod().getDeclaringClassType()).get(); - } else if (varNode instanceof GlobalVarNode gvn) { - clz = gvn.getDeclaringClass(); - } - } - if (appOnly && clz != null && !clz.isApplicationClass()) { - continue; + private static final Logger logger = LoggerFactory.getLogger(PTAUtils.class); + static final String output_dir = CoreConfig.v().getOutConfig().outDir; + static Map nodes = new TreeMap<>(); + private static final ClassType clRunnable = getClassType("java.lang.Runnable"); + + public static ClassType getClassType(String fullyQualifiedClassName) { + return JavaIdentifierFactory.getInstance().getClassType(fullyQualifiedClassName); + } + + public static boolean isApplicationMethod(SootMethod sm) { + ClassType classType = sm.getDeclaringClassType(); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(classType).get(); + return sc.isApplicationClass(); + } + + public static boolean isStaticInitializer(SootMethod method) { + return method.getName().equals(""); + } + + public static boolean isConstructor(SootMethod method) { + return method.getName().equals(""); + } + + public static Map> calcStaticThisPTS(PTA pta) { + Map> pts = new HashMap<>(); + Set workList = new HashSet<>(); + PAG pag = pta.getPag(); + // add all instance methods which potentially contain static call + for (SootMethod method : pta.getNakedReachableMethods()) { + if (PTAUtils.isFakeMainMethod(method) || method.isConcrete() && !method.isStatic()) { + MethodPAG srcmpag = pag.getMethodPAG(method); + LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); + final PointsToSet other = pta.reachingObjects(thisRef).toCIPointsToSet(); + + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { + for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + LocalVarNode tgtThisRef = (LocalVarNode) tgtnf.caseThis(); + // create "THIS" ptr for static method + Set addTo = pts.computeIfAbsent(tgtThisRef, k -> new HashSet<>()); + boolean returnValue = false; + for (Iterator itx = other.iterator(); itx.hasNext(); ) { + AllocNode node = itx.next(); + if (addTo.add(node)) { + returnValue = true; } - - String label = getNodeLabel(vn); - nodes.put("[" + label + "]", vn); - file.print(label + " -> {"); - PointsToSet p2set = pta.reachingObjects(vn); - - if (p2set == null || p2set.isEmpty()) { - file.print(" empty }\n"); - continue; - } - for (Iterator it = p2set.iterator(); it.hasNext(); ) { - Node n = it.next(); - label = getNodeLabel(n); - nodes.put("[" + label + "]", n); - file.print(" "); - file.print(label); - } - file.print(" }\n"); + } + if (returnValue) { + workList.add(tgtmtd); + } } - dumpNodeNames(file); - file.close(); - } catch (IOException e) { - throw new RuntimeException("Couldn't dump solution." + e); - } - } - - public static void slicePAG(AllocNode allocNode, PAG pag, String filename) { - Map> edges = new HashMap<>(); - Queue queue = new UniqueQueue<>(); - Set tov = pag.allocLookup(allocNode); - edges.computeIfAbsent(allocNode, k -> new HashSet<>()).addAll(tov); - queue.addAll(tov); - Set visited = new HashSet<>(tov); - while (!queue.isEmpty()) { - ValNode front = queue.poll(); - Set tovx = pag.simpleLookup(front); - Set toex = edges.computeIfAbsent(front, k -> new HashSet<>()); - for (ValNode vn : tovx) { - if (toex.add(vn)) { - queue.add(vn); - visited.add(vn); - } + } + } + } + } + while (!workList.isEmpty()) { + SootMethod method = workList.iterator().next(); + workList.remove(method); + MethodPAG srcmpag = pag.getMethodPAG(method); + LocalVarNode thisRef = (LocalVarNode) srcmpag.nodeFactory().caseThis(); + final Set other = pts.computeIfAbsent(thisRef, k -> new HashSet<>()); + + for (final Stmt s : srcmpag.getInvokeStmts()) { + AbstractInvokeExpr ie = s.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { + for (Iterator it = pta.getCallGraph().edgesOutOf(s); it.hasNext(); ) { + Edge e = it.next(); + SootMethod tgtmtd = e.tgt(); + MethodPAG tgtmpag = pag.getMethodPAG(tgtmtd); + MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); + LocalVarNode tgtThisRef = (LocalVarNode) tgtnf.caseThis(); + // create "THIS" ptr for static method + Set addTo = pts.computeIfAbsent(tgtThisRef, k -> new HashSet<>()); + if (addTo.addAll(other)) { + workList.add(tgtmtd); } - } - DotGraph canvas = setDotGraph("hello"); - edges.forEach((n, elements) -> { - drawNode(canvas, n); - elements.forEach(element -> { + } + } + } + } + return pts; + } + + public static Object getIR(Object sparkNode) { + if (sparkNode instanceof VarNode) { + return ((VarNode) sparkNode).getVariable(); + } else if (sparkNode instanceof AllocNode) { + return ((AllocNode) sparkNode).getNewExpr(); + } else { // sparkField? + return sparkNode; + } + } + + public static boolean mustAlias(PTA pta, VarNode v1, VarNode v2) { + PointsToSet v1pts = pta.reachingObjects(v1).toCIPointsToSet(); + PointsToSet v2pts = pta.reachingObjects(v2).toCIPointsToSet(); + return v1pts.pointsToSetEquals(v2pts); + } + + public static void printPts(PTA pta, PointsToSet pts) { + final StringBuffer ret = new StringBuffer(); + for (Iterator it = pts.iterator(); it.hasNext(); ) { + AllocNode n = it.next(); + ret.append("\t").append(n).append("\n"); + } + System.out.print(ret); + } + + /** dump callgraph to sootoutput/callgraph.dot */ + public static void dumpCallGraph(Iterable callgraph, boolean appOnly) { + String filename = "callgraph"; + DotGraph canvas = setDotGraph(filename); + + int mn = -1; + Set methodSet = new HashSet<>(); + List methodList = new ArrayList<>(); + + for (Edge edge : callgraph) { + MethodOrMethodContext srcmtd = edge.getSrc(); + if (appOnly && !PTAUtils.isApplicationMethod(srcmtd.method())) continue; + MethodOrMethodContext dstmtd = edge.getTgt(); + String srcName = srcmtd.toString(); + + if (methodSet.add(srcName)) { + canvas.drawNode(srcName).setLabel("" + ++mn); + methodList.add(mn, srcName); + } + String dstName = dstmtd.toString(); + + if (methodSet.add(dstName)) { + canvas.drawNode(dstName).setLabel("" + ++mn); + methodList.add(mn, dstName); + } + canvas.drawEdge(srcName, dstName); + } + + plotDotGraph(canvas, filename); + try { + PrintWriter out = new PrintWriter(new File(output_dir, "callgraphnodes")); + for (int i = 0; i < methodList.size(); i++) out.println(i + ":" + methodList.get(i)); + out.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + /** slice a callgrph, put nodes &edges related to method into set1&set2 */ + private static void slice( + CallGraph callgraph, + MethodOrMethodContext method, + Set set1, + Set set2) { + for (Iterator it = callgraph.edgesInto(method); it.hasNext(); ) { + Edge edge = it.next(); + set2.add(edge); + MethodOrMethodContext src = edge.getSrc(); + if (set1.add(src)) slice(callgraph, src, set1, set2); + } + } + + /** dump callgraph strench to method */ + public static void dumpSlicedCallGraph(CallGraph callgraph, MethodOrMethodContext method) { + Set tgts = new HashSet<>(); + Set edges = new HashSet<>(); + tgts.add(method); + slice(callgraph, method, tgts, edges); + + dumpCallGraph(edges, false); + } + + /** dump callgraph from entry to the method */ + public static void dumpSlicedCallGraph2(CallGraph callgraph, MethodOrMethodContext method) { + Set edges = new HashSet<>(); + Set visited = new HashSet<>(); + Queue queue = new UniqueQueue<>(); + queue.add(method); + while (!queue.isEmpty()) { + MethodOrMethodContext front = queue.poll(); + for (Iterator it = callgraph.edgesInto(front); it.hasNext(); ) { + Edge edge = it.next(); + MethodOrMethodContext src = edge.getSrc(); + if (visited.add(src)) { + queue.add(src); + edges.add(edge); + break; + } + } + } + dumpCallGraph(edges, false); + } + + public static boolean isUnresolved(Type type) { + if (type instanceof ArrayType at) { + type = at.getBaseType(); + } + if (!(type instanceof ClassType rt)) return false; + // if (!rt.hasSootClass()) { + // return true; + // } + Optional ocl = PTAScene.v().getView().getClass(rt); + return ocl.isEmpty(); + // SootClass cl = rt.getSootClass(); + // return cl.resolvingLevel() < SootClass.HIERARCHY; + } + + public static boolean castNeverFails(Type src, Type dst) { + if (dst == null) return true; + if (dst == src) return true; + if (src == null) return false; + if (dst.equals(src)) return true; + if (src instanceof NullType) return true; + // if (src instanceof AnySubType) + // return true; + if (dst instanceof NullType) return false; + // if (dst instanceof AnySubType) + // throw new RuntimeException("oops src=" + src + " dst=" + dst); + return PTAScene.v().canStoreType(src, dst); + } + + public static QueueReader dispatch(Type type, VirtualCallSite site) { + final ChunkedQueue targetsQueue = new ChunkedQueue<>(); + final QueueReader targets = targetsQueue.reader(); + if (site.kind() == Kind.THREAD && !PTAScene.v().canStoreType(type, clRunnable)) { + return targets; + } + MethodOrMethodContext container = site.container(); + if (site.iie() instanceof JSpecialInvokeExpr && site.kind() != Kind.THREAD) { + SootMethod target = + VirtualCalls.v() + .resolveSpecial((JSpecialInvokeExpr) site.iie(), site.subSig(), container.method()); + // if the call target resides in a phantom class then + // "target" will be null, simply do not add the target in that case + if (target != null) { + targetsQueue.add(target); + } + } else { + Type mType = site.recNode().getType(); + VirtualCalls.v().resolve(type, mType, site.subSig(), container.method(), targetsQueue); + } + return targets; + } + + public static boolean addWithTypeFiltering(PointsToSetInternal pts, Type type, Node node) { + if (PTAUtils.castNeverFails(node.getType(), type)) { + return pts.add(node.getNumber()); + } + return false; + } + + /** dump pts to sootoutput/pts */ + public static void dumpPts(PTA pta, boolean appOnly) { + try { + PrintWriter file = new PrintWriter(new File(output_dir, "pts.txt")); + file.println("Points-to results:"); + for (final ValNode vn : pta.getPag().getValNodes()) { + if (!(vn instanceof VarNode)) { + continue; + } + SootClass clz = null; + if (vn instanceof LocalVarNode) { + SootMethod sm = ((LocalVarNode) vn).getMethod(); + if (sm != null) { + clz = (SootClass) PTAScene.v().getView().getClass(sm.getDeclaringClassType()).get(); + } + } else if (vn instanceof GlobalVarNode gvn) { + clz = gvn.getDeclaringClass(); + } else if (vn instanceof ContextVarNode cv) { + VarNode varNode = cv.base(); + if (varNode instanceof LocalVarNode cvbase) { + clz = + (SootClass) + PTAScene.v() + .getView() + .getClass(cvbase.getMethod().getDeclaringClassType()) + .get(); + } else if (varNode instanceof GlobalVarNode gvn) { + clz = gvn.getDeclaringClass(); + } + } + if (appOnly && clz != null && !clz.isApplicationClass()) { + continue; + } + + String label = getNodeLabel(vn); + nodes.put("[" + label + "]", vn); + file.print(label + " -> {"); + PointsToSet p2set = pta.reachingObjects(vn); + + if (p2set == null || p2set.isEmpty()) { + file.print(" empty }\n"); + continue; + } + for (Iterator it = p2set.iterator(); it.hasNext(); ) { + Node n = it.next(); + label = getNodeLabel(n); + nodes.put("[" + label + "]", n); + file.print(" "); + file.print(label); + } + file.print(" }\n"); + } + dumpNodeNames(file); + file.close(); + } catch (IOException e) { + throw new RuntimeException("Couldn't dump solution." + e); + } + } + + public static void slicePAG(AllocNode allocNode, PAG pag, String filename) { + Map> edges = new HashMap<>(); + Queue queue = new UniqueQueue<>(); + Set tov = pag.allocLookup(allocNode); + edges.computeIfAbsent(allocNode, k -> new HashSet<>()).addAll(tov); + queue.addAll(tov); + Set visited = new HashSet<>(tov); + while (!queue.isEmpty()) { + ValNode front = queue.poll(); + Set tovx = pag.simpleLookup(front); + Set toex = edges.computeIfAbsent(front, k -> new HashSet<>()); + for (ValNode vn : tovx) { + if (toex.add(vn)) { + queue.add(vn); + visited.add(vn); + } + } + } + DotGraph canvas = setDotGraph("hello"); + edges.forEach( + (n, elements) -> { + drawNode(canvas, n); + elements.forEach( + element -> { drawNode(canvas, element); drawEdge(canvas, n, element, "black"); - }); + }); }); - canvas.plot(filename); - for (Node n : visited) { - System.out.println(n); - } - } - - public static void dumpMPAG(PAG pag, SootMethod method) { - String filename = method.getSignature() + ".dot"; - DotGraph canvas = setDotGraph(filename); - QueueReader reader = pag.getMethodPAG(method).getInternalReader().clone(); - while (reader.hasNext()) { - Node src = reader.next(); - Node dst = reader.next(); - drawNode(canvas, src); - drawNode(canvas, dst); - String color = src instanceof AllocNode ? "green" : // alloc - src instanceof FieldRefNode ? "red" : // load - dst instanceof FieldRefNode ? "blue" : // store - "black"; // simple - drawEdge(canvas, src, dst, color); - } - plotDotGraph(canvas, filename); - } - - /** - * dump mPAGs to sootoutput/@filename.dot - */ - public static void dumpMPAGs(PTA pta, String filename) { - DotGraph canvas = setDotGraph(filename); - for (SootMethod m : pta.getNakedReachableMethods()) { - QueueReader reader = pta.getPag().getMethodPAG(m).getInternalReader().clone(); - while (reader.hasNext()) { - Node src = reader.next(); - Node dst = reader.next(); - drawNode(canvas, src); - drawNode(canvas, dst); - String color = src instanceof AllocNode ? "green" : // alloc - src instanceof FieldRefNode ? "red" : // load - dst instanceof FieldRefNode ? "blue" : // store - "black"; // simple - drawEdge(canvas, src, dst, color); - } - } - plotDotGraph(canvas, filename); - } - - /** - * dump pag to sootoutput/@filename.dot - */ - public static void dumpPAG(PAG pag, String filename) { - DotGraph canvas = setDotGraph(filename); - - // draw edges - drawPAGMap(canvas, pag.getAlloc(), "green"); - drawPAGMap(canvas, pag.getSimple(), "black"); - drawInvPAGMap(canvas, pag.getStoreInv(), "blue"); - drawPAGMap(canvas, pag.getLoad(), "red"); - // collect nodes. - Set nodes = new HashSet<>(); - pag.getAlloc().forEach((k, v) -> { - nodes.add(k); - nodes.addAll(v); - }); - pag.getSimple().forEach((k, v) -> { - nodes.add(k); - nodes.addAll(v); - }); - pag.getStoreInv().forEach((k, v) -> { - nodes.add(k); - nodes.addAll(v); - }); - pag.getLoad().forEach((k, v) -> { - nodes.add(k); - nodes.addAll(v); - }); - // draw nodes. - nodes.forEach(node -> drawNode(canvas, node)); - plotDotGraph(canvas, filename); - } - - private static void plotDotGraph(DotGraph canvas, String filename) { - canvas.plot(output_dir + "/" + filename + ".dot"); - } - - private static DotGraph setDotGraph(String fileName) { - DotGraph canvas = new DotGraph(fileName); - canvas.setNodeShape(DotGraphConstants.NODE_SHAPE_BOX); - canvas.setGraphLabel(fileName); - return canvas; - } - - public static String getNodeLabel(Node node) { - int num = node.getNumber(); - if (node instanceof LocalVarNode) - return "L" + num; - else if (node instanceof ContextVarNode) { - return "L" + num; - } else if (node instanceof GlobalVarNode) - return "G" + num; - else if (node instanceof ContextField) - return "OF" + num; - else if (node instanceof FieldRefNode) - return "VF" + num; - else if (node instanceof AllocNode) - return "O" + num; - else - throw new RuntimeException("no such node type exists!"); - } - - private static void drawNode(DotGraph canvas, Node node) { - DotGraphNode dotNode = canvas.drawNode(node.toString()); - dotNode.setLabel("[" + getNodeLabel(node) + "]"); - nodes.put("[" + getNodeLabel(node) + "]", node); - } - - private static void drawEdge(DotGraph canvas, Node src, Node dst, String color) { - canvas.drawEdge(src.toString(), dst.toString()).setAttribute("color", color); - } - - private static void dumpNodeNames(PrintWriter file) { - nodes.forEach((l, n) -> file.println(l + n)); - } - - public static void dumpNodeNames(String fileName) { - try { - PrintWriter out = new PrintWriter(new File(output_dir, fileName)); - dumpNodeNames(out); - out.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - - private static void drawPAGMap(DotGraph canvas, Map> map, String color) { - map.forEach((n, elements) -> { - elements.forEach(element -> { - drawEdge(canvas, n, element, color); + canvas.plot(filename); + for (Node n : visited) { + System.out.println(n); + } + } + + public static void dumpMPAG(PAG pag, SootMethod method) { + String filename = method.getSignature() + ".dot"; + DotGraph canvas = setDotGraph(filename); + QueueReader reader = pag.getMethodPAG(method).getInternalReader().clone(); + while (reader.hasNext()) { + Node src = reader.next(); + Node dst = reader.next(); + drawNode(canvas, src); + drawNode(canvas, dst); + String color = + src instanceof AllocNode + ? "green" + : // alloc + src instanceof FieldRefNode + ? "red" + : // load + dst instanceof FieldRefNode + ? "blue" + : // store + "black"; // simple + drawEdge(canvas, src, dst, color); + } + plotDotGraph(canvas, filename); + } + + /** dump mPAGs to sootoutput/@filename.dot */ + public static void dumpMPAGs(PTA pta, String filename) { + DotGraph canvas = setDotGraph(filename); + for (SootMethod m : pta.getNakedReachableMethods()) { + QueueReader reader = pta.getPag().getMethodPAG(m).getInternalReader().clone(); + while (reader.hasNext()) { + Node src = reader.next(); + Node dst = reader.next(); + drawNode(canvas, src); + drawNode(canvas, dst); + String color = + src instanceof AllocNode + ? "green" + : // alloc + src instanceof FieldRefNode + ? "red" + : // load + dst instanceof FieldRefNode + ? "blue" + : // store + "black"; // simple + drawEdge(canvas, src, dst, color); + } + } + plotDotGraph(canvas, filename); + } + + /** dump pag to sootoutput/@filename.dot */ + public static void dumpPAG(PAG pag, String filename) { + DotGraph canvas = setDotGraph(filename); + + // draw edges + drawPAGMap(canvas, pag.getAlloc(), "green"); + drawPAGMap(canvas, pag.getSimple(), "black"); + drawInvPAGMap(canvas, pag.getStoreInv(), "blue"); + drawPAGMap(canvas, pag.getLoad(), "red"); + // collect nodes. + Set nodes = new HashSet<>(); + pag.getAlloc() + .forEach( + (k, v) -> { + nodes.add(k); + nodes.addAll(v); }); + pag.getSimple() + .forEach( + (k, v) -> { + nodes.add(k); + nodes.addAll(v); + }); + pag.getStoreInv() + .forEach( + (k, v) -> { + nodes.add(k); + nodes.addAll(v); + }); + pag.getLoad() + .forEach( + (k, v) -> { + nodes.add(k); + nodes.addAll(v); + }); + // draw nodes. + nodes.forEach(node -> drawNode(canvas, node)); + plotDotGraph(canvas, filename); + } + + private static void plotDotGraph(DotGraph canvas, String filename) { + canvas.plot(output_dir + "/" + filename + ".dot"); + } + + private static DotGraph setDotGraph(String fileName) { + DotGraph canvas = new DotGraph(fileName); + canvas.setNodeShape(DotGraphConstants.NODE_SHAPE_BOX); + canvas.setGraphLabel(fileName); + return canvas; + } + + public static String getNodeLabel(Node node) { + int num = node.getNumber(); + if (node instanceof LocalVarNode) return "L" + num; + else if (node instanceof ContextVarNode) { + return "L" + num; + } else if (node instanceof GlobalVarNode) return "G" + num; + else if (node instanceof ContextField) return "OF" + num; + else if (node instanceof FieldRefNode) return "VF" + num; + else if (node instanceof AllocNode) return "O" + num; + else throw new RuntimeException("no such node type exists!"); + } + + private static void drawNode(DotGraph canvas, Node node) { + DotGraphNode dotNode = canvas.drawNode(node.toString()); + dotNode.setLabel("[" + getNodeLabel(node) + "]"); + nodes.put("[" + getNodeLabel(node) + "]", node); + } + + private static void drawEdge(DotGraph canvas, Node src, Node dst, String color) { + canvas.drawEdge(src.toString(), dst.toString()).setAttribute("color", color); + } + + private static void dumpNodeNames(PrintWriter file) { + nodes.forEach((l, n) -> file.println(l + n)); + } + + public static void dumpNodeNames(String fileName) { + try { + PrintWriter out = new PrintWriter(new File(output_dir, fileName)); + dumpNodeNames(out); + out.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + private static void drawPAGMap( + DotGraph canvas, Map> map, String color) { + map.forEach( + (n, elements) -> { + elements.forEach( + element -> { + drawEdge(canvas, n, element, color); + }); }); - } - - private static void drawInvPAGMap(DotGraph canvas, Map> map, String color) { - map.forEach((n, elements) -> { - elements.forEach(element -> { + } + + private static void drawInvPAGMap( + DotGraph canvas, Map> map, String color) { + map.forEach( + (n, elements) -> { + elements.forEach( + element -> { drawEdge(canvas, element, n, color); - }); + }); }); - } - - public static boolean isThrowable(Type type) { - if (type instanceof ClassType) { - return PTAScene.v().canStoreType(type, PTAUtils.getClassType("java.lang.Throwable")); - } + } + + public static boolean isThrowable(Type type) { + if (type instanceof ClassType) { + return PTAScene.v().canStoreType(type, PTAUtils.getClassType("java.lang.Throwable")); + } + return false; + } + + public static boolean subtypeOfAbstractStringBuilder(Type t) { + if (!(t instanceof ClassType rt)) { + return false; + } + String s = rt.toString(); + return (s.equals("java.lang.StringBuffer") || s.equals("java.lang.StringBuilder")); + } + + public static boolean supportFinalize(AllocNode heap) { + MethodSubSignature sigFinalize = + JavaIdentifierFactory.getInstance().parseMethodSubSignature("void finalize()"); + Type type = heap.getType(); + if (type instanceof ClassType refType && type != PTAUtils.getClassType("java.lang.Object")) { + SootMethod finalizeMethod = VirtualCalls.v().resolveNonSpecial(refType, sigFinalize); + if (finalizeMethod != null + && finalizeMethod.toString().equals("")) { return false; - } - - public static boolean subtypeOfAbstractStringBuilder(Type t) { - if (!(t instanceof ClassType rt)) { - return false; - } - String s = rt.toString(); - return (s.equals("java.lang.StringBuffer") || s.equals("java.lang.StringBuilder")); - } - - public static boolean supportFinalize(AllocNode heap) { - MethodSubSignature sigFinalize = JavaIdentifierFactory.getInstance().parseMethodSubSignature("void finalize()"); - Type type = heap.getType(); - if (type instanceof ClassType refType && type != PTAUtils.getClassType("java.lang.Object")) { - SootMethod finalizeMethod = VirtualCalls.v().resolveNonSpecial(refType, sigFinalize); - if (finalizeMethod != null && finalizeMethod.toString().equals("")) { - return false; - } - return finalizeMethod != null; - } - return false; - } - - public static Context plusplusOp(AllocNode heap) { - ContextElement[] array; - int s; - if (heap instanceof ContextAllocNode csHeap) { - ContextElements ctxElems = (ContextElements) csHeap.context(); - int ms = ctxElems.size(); - ContextElement[] oldArray = ctxElems.getElements(); - array = new ContextElement[ms + 1]; - array[0] = csHeap.base(); - System.arraycopy(oldArray, 0, array, 1, ms); - s = ms + 1; - } else { - array = new ContextElement[1]; - array[0] = heap; - s = 1; - } - return new ContextElements(array, s); - } - - public static boolean isFakeMainMethod(SootMethod method) { - String sig = ""; - return method.getSignature().equals(sig); - } - - /** - * comma separated list of classes in which no matter what the length of k - * for object sensitivity, we want to limit the depth of the object - * sensitivity to 0. Also add subclasses of each - */ - private static final String[] NO_CONTEXT = {"java.lang.Throwable", "java.lang.StringBuffer", "java.lang.StringBuilder"}; - private static Set ignoreList = null; - - public static boolean isOfPrimitiveBaseType(AllocNode heap) { - if (heap.getType() instanceof ArrayType arrayType) { - return arrayType.getBaseType() instanceof PrimitiveType; - } - return false; - } - - public static boolean isPrimitiveArrayType(Type type) { - if (type instanceof ArrayType arrayType) { - return arrayType.getArrayElementType() instanceof PrimitiveType; - } - return false; - } - - /** - * Write the jimple file for clz. ParentDir is the absolute path of parent - * directory. - */ - public static void writeJimple(String parentDir, SootClass clz) { - PackageName pkgName = clz.getType().getPackageName(); - String clzName = clz.getType().getClassName(); - File packageDirectory = new File( - parentDir + File.separator + pkgName.getPackageName().replace(".", File.separator)); - - try { - packageDirectory.mkdirs(); - OutputStream streamOut = new FileOutputStream( - packageDirectory + File.separator + clzName + ".jimple"); - PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut)); - new JimplePrinter().printTo(clz, writerOut); - writerOut.flush(); - writerOut.close(); - streamOut.close(); - - } catch (Exception e) { - logger.error("Error writing jimple to file {}", clz, e); - } - } - - public static void dumpJimple(String outputDir) { - for (SootClass clz : PTAScene.v().getLibraryClasses()) { - writeJimple(outputDir, clz); - } - for (SootClass clz : PTAScene.v().getApplicationClasses()) { - writeJimple(outputDir, clz); - } - } - - /** - * Given a file name with separators, convert them in to . so it is a legal - * class name. modified: Ammonia: handle .* not only .class - */ - public static String fromFileToClass(String name) { - return name.substring(0, name.lastIndexOf('.')).replace(File.separatorChar, '.'); - } - - /** - * Given a jarFile, return a list of the classes contained in the jarfile with . - * replacing /. - */ - public static List getClassesFromJar(JarFile jarFile) { - LinkedList classes = new LinkedList<>(); - Enumeration allEntries = jarFile.entries(); - - while (allEntries.hasMoreElements()) { - JarEntry entry = allEntries.nextElement(); - String name = entry.getName(); - if (!name.endsWith(".class")) { - continue; - } - - String clsName = name.substring(0, name.length() - 6).replace('/', '.'); - classes.add(clsName); - } - return classes; - } - - public static String findMainFromMetaInfo(String appPath) { - String mainClass = null; - try { - JarFile jar = new JarFile(appPath); - Enumeration allEntries = jar.entries(); - while (allEntries.hasMoreElements()) { - JarEntry entry = allEntries.nextElement(); - String name = entry.getName(); - if (!name.endsWith(".MF")) { - continue; - } - String urlstring = "jar:file:" + appPath + "!/" + name; - URL url = new URL(urlstring); - Scanner scanner = new Scanner(url.openStream()); - while (scanner.hasNext()) { - String string = scanner.next(); - if ("Main-Class:".equals(string) && scanner.hasNext()) { - mainClass = scanner.next(); - break; - } - } - if (mainClass == null) { - System.out.println("cannot find meta info."); - } - scanner.close(); - jar.close(); - break; - } - } catch (IOException e) { - System.out.println("cannot find meta info."); - } - return mainClass; - } - - private static final Map methodToBody = DataFactory.createMap(); - - public static Body getMethodBody(SootMethod m) { - Body body = methodToBody.get(m); - if (body == null) { - if (m.isConcrete()) { - body = m.getBody(); - } else { - body = Body.builder().build(); - } - methodToBody.putIfAbsent(m, body); - } - return body; - } - - public static void updateMethodBody(SootMethod m, Body body) { - methodToBody.put(m, body); - } - - public static boolean isEmptyArray(AllocNode heap) { - Object var = heap.getNewExpr(); - if (var instanceof JNewArrayExpr nae) { - Value sizeVal = nae.getSize(); - if (sizeVal instanceof IntConstant size) { - return size.getValue() == 0; - } - } - return false; - } - - public static LocalVarNode paramToArg(PAG pag, Stmt invokeStmt, MethodPAG srcmpag, VarNode pi) { - MethodNodeFactory srcnf = srcmpag.nodeFactory(); - AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); - Parm mPi = (Parm) pi.getVariable(); - LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); - LocalVarNode receiver; - if (ie instanceof AbstractInstanceInvokeExpr iie) { - receiver = pag.findLocalVarNode(iie.getBase()); - } else { - // static call - receiver = thisRef; - } - if (mPi.isThis()) { - return receiver; - } else if (mPi.isReturn()) { - if (invokeStmt instanceof JAssignStmt assignStmt) { - Value mR = assignStmt.getLeftOp(); - return (LocalVarNode) pag.findValNode(mR); - } else { - return null; - } - } else if (mPi.isThrowRet()) { - return srcnf.makeInvokeStmtThrowVarNode(invokeStmt, srcmpag.getMethod()); - } - // Normal formal parameters. - Value arg = ie.getArg(mPi.getIndex()); - if (arg == null) { - return null; - } else { - return pag.findLocalVarNode(arg); - } - } - - /* - * We use this method to replace EntryPoints.v().clinitsOf() because it is infested with bugs. - * */ - public static Set clinitsOf(SootClass cl) { - Set ret = new HashSet<>(); - Set visit = new HashSet<>(); - Queue worklist = new UniqueQueue<>(); - Optional curr = Optional.of(cl); - while (curr.isPresent()) { - SootClass sc = curr.get(); - worklist.add(sc); - curr = sc.getSuperclass(); - } - while (!worklist.isEmpty()) { - SootClass sc = worklist.poll(); - if (visit.add(sc)) { - Set itfs = sc.getInterfaces(); - for (ClassType itf : itfs) { - Optional xsc = PTAScene.v().getView().getClass(itf); - if (xsc.isPresent()) { - worklist.add(xsc.get()); - } - } - } - } - for (SootClass sc : visit) { - MethodSubSignature subclinit = JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); - final Optional initStart = sc.getMethod(subclinit); - if (initStart.isPresent()) { - ret.add(initStart.get()); - } - } - return ret; - } -} \ No newline at end of file + } + return finalizeMethod != null; + } + return false; + } + + public static Context plusplusOp(AllocNode heap) { + ContextElement[] array; + int s; + if (heap instanceof ContextAllocNode csHeap) { + ContextElements ctxElems = (ContextElements) csHeap.context(); + int ms = ctxElems.size(); + ContextElement[] oldArray = ctxElems.getElements(); + array = new ContextElement[ms + 1]; + array[0] = csHeap.base(); + System.arraycopy(oldArray, 0, array, 1, ms); + s = ms + 1; + } else { + array = new ContextElement[1]; + array[0] = heap; + s = 1; + } + return new ContextElements(array, s); + } + + public static boolean isFakeMainMethod(SootMethod method) { + String sig = ""; + return method.getSignature().equals(sig); + } + + /** + * comma separated list of classes in which no matter what the length of k for object sensitivity, + * we want to limit the depth of the object sensitivity to 0. Also add subclasses of each + */ + private static final String[] NO_CONTEXT = { + "java.lang.Throwable", "java.lang.StringBuffer", "java.lang.StringBuilder" + }; + + private static Set ignoreList = null; + + public static boolean isOfPrimitiveBaseType(AllocNode heap) { + if (heap.getType() instanceof ArrayType arrayType) { + return arrayType.getBaseType() instanceof PrimitiveType; + } + return false; + } + + public static boolean isPrimitiveArrayType(Type type) { + if (type instanceof ArrayType arrayType) { + return arrayType.getArrayElementType() instanceof PrimitiveType; + } + return false; + } + + /** Write the jimple file for clz. ParentDir is the absolute path of parent directory. */ + public static void writeJimple(String parentDir, SootClass clz) { + PackageName pkgName = clz.getType().getPackageName(); + String clzName = clz.getType().getClassName(); + File packageDirectory = + new File( + parentDir + File.separator + pkgName.getPackageName().replace(".", File.separator)); + + try { + packageDirectory.mkdirs(); + OutputStream streamOut = + new FileOutputStream(packageDirectory + File.separator + clzName + ".jimple"); + PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut)); + new JimplePrinter().printTo(clz, writerOut); + writerOut.flush(); + writerOut.close(); + streamOut.close(); + + } catch (Exception e) { + logger.error("Error writing jimple to file {}", clz, e); + } + } + + public static void dumpJimple(String outputDir) { + for (SootClass clz : PTAScene.v().getLibraryClasses()) { + writeJimple(outputDir, clz); + } + for (SootClass clz : PTAScene.v().getApplicationClasses()) { + writeJimple(outputDir, clz); + } + } + + /** + * Given a file name with separators, convert them in to . so it is a legal class name. modified: + * Ammonia: handle .* not only .class + */ + public static String fromFileToClass(String name) { + return name.substring(0, name.lastIndexOf('.')).replace(File.separatorChar, '.'); + } + + /** Given a jarFile, return a list of the classes contained in the jarfile with . replacing /. */ + public static List getClassesFromJar(JarFile jarFile) { + LinkedList classes = new LinkedList<>(); + Enumeration allEntries = jarFile.entries(); + + while (allEntries.hasMoreElements()) { + JarEntry entry = allEntries.nextElement(); + String name = entry.getName(); + if (!name.endsWith(".class")) { + continue; + } + + String clsName = name.substring(0, name.length() - 6).replace('/', '.'); + classes.add(clsName); + } + return classes; + } + + public static String findMainFromMetaInfo(String appPath) { + String mainClass = null; + try { + JarFile jar = new JarFile(appPath); + Enumeration allEntries = jar.entries(); + while (allEntries.hasMoreElements()) { + JarEntry entry = allEntries.nextElement(); + String name = entry.getName(); + if (!name.endsWith(".MF")) { + continue; + } + String urlstring = "jar:file:" + appPath + "!/" + name; + URL url = new URL(urlstring); + Scanner scanner = new Scanner(url.openStream()); + while (scanner.hasNext()) { + String string = scanner.next(); + if ("Main-Class:".equals(string) && scanner.hasNext()) { + mainClass = scanner.next(); + break; + } + } + if (mainClass == null) { + System.out.println("cannot find meta info."); + } + scanner.close(); + jar.close(); + break; + } + } catch (IOException e) { + System.out.println("cannot find meta info."); + } + return mainClass; + } + + private static final Map methodToBody = DataFactory.createMap(); + + public static Body getMethodBody(SootMethod m) { + Body body = methodToBody.get(m); + if (body == null) { + if (m.isConcrete()) { + body = m.getBody(); + } else { + body = Body.builder().build(); + } + methodToBody.putIfAbsent(m, body); + } + return body; + } + + public static void updateMethodBody(SootMethod m, Body body) { + methodToBody.put(m, body); + } + + public static boolean isEmptyArray(AllocNode heap) { + Object var = heap.getNewExpr(); + if (var instanceof JNewArrayExpr nae) { + Value sizeVal = nae.getSize(); + if (sizeVal instanceof IntConstant size) { + return size.getValue() == 0; + } + } + return false; + } + + public static LocalVarNode paramToArg(PAG pag, Stmt invokeStmt, MethodPAG srcmpag, VarNode pi) { + MethodNodeFactory srcnf = srcmpag.nodeFactory(); + AbstractInvokeExpr ie = invokeStmt.getInvokeExpr(); + Parm mPi = (Parm) pi.getVariable(); + LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis(); + LocalVarNode receiver; + if (ie instanceof AbstractInstanceInvokeExpr iie) { + receiver = pag.findLocalVarNode(iie.getBase()); + } else { + // static call + receiver = thisRef; + } + if (mPi.isThis()) { + return receiver; + } else if (mPi.isReturn()) { + if (invokeStmt instanceof JAssignStmt assignStmt) { + Value mR = assignStmt.getLeftOp(); + return (LocalVarNode) pag.findValNode(mR); + } else { + return null; + } + } else if (mPi.isThrowRet()) { + return srcnf.makeInvokeStmtThrowVarNode(invokeStmt, srcmpag.getMethod()); + } + // Normal formal parameters. + Value arg = ie.getArg(mPi.getIndex()); + if (arg == null) { + return null; + } else { + return pag.findLocalVarNode(arg); + } + } + + /* + * We use this method to replace EntryPoints.v().clinitsOf() because it is infested with bugs. + * */ + public static Set clinitsOf(SootClass cl) { + Set ret = new HashSet<>(); + Set visit = new HashSet<>(); + Queue worklist = new UniqueQueue<>(); + Optional curr = Optional.of(cl); + while (curr.isPresent()) { + SootClass sc = curr.get(); + worklist.add(sc); + curr = sc.getSuperclass(); + } + while (!worklist.isEmpty()) { + SootClass sc = worklist.poll(); + if (visit.add(sc)) { + Set itfs = sc.getInterfaces(); + for (ClassType itf : itfs) { + Optional xsc = PTAScene.v().getView().getClass(itf); + if (xsc.isPresent()) { + worklist.add(xsc.get()); + } + } + } + } + for (SootClass sc : visit) { + MethodSubSignature subclinit = + JavaIdentifierFactory.getInstance().parseMethodSubSignature("void ()"); + final Optional initStart = sc.getMethod(subclinit); + if (initStart.isPresent()) { + ret.add(initStart.get()); + } + } + return ret; + } +} diff --git a/sootup.qilin/src/main/java/qilin/util/Pair.java b/sootup.qilin/src/main/java/qilin/util/Pair.java index d511f939dd3..3d53d45d857 100644 --- a/sootup.qilin/src/main/java/qilin/util/Pair.java +++ b/sootup.qilin/src/main/java/qilin/util/Pair.java @@ -22,38 +22,37 @@ public class Pair { - private final T1 first; - private final T2 second; - - public Pair(T1 first, T2 second) { - this.first = first; - this.second = second; - } - - public T1 getFirst() { - return first; - } - - public T2 getSecond() { - return second; - } - - @Override - public int hashCode() { - return Objects.hash(first, second); - } - - @Override - public boolean equals(Object o) { - if (o instanceof Pair anoPair) { - return Objects.equals(first, anoPair.first) && Objects.equals(second, anoPair.second); - } - return false; - } - - @Override - public String toString() { - return "<" + first + ", " + second + ">"; + private final T1 first; + private final T2 second; + + public Pair(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + public T1 getFirst() { + return first; + } + + public T2 getSecond() { + return second; + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Pair anoPair) { + return Objects.equals(first, anoPair.first) && Objects.equals(second, anoPair.second); } + return false; + } + @Override + public String toString() { + return "<" + first + ", " + second + ">"; + } } diff --git a/sootup.qilin/src/main/java/qilin/util/Stopwatch.java b/sootup.qilin/src/main/java/qilin/util/Stopwatch.java index 2e21ab93f46..a927afc061d 100644 --- a/sootup.qilin/src/main/java/qilin/util/Stopwatch.java +++ b/sootup.qilin/src/main/java/qilin/util/Stopwatch.java @@ -19,53 +19,53 @@ package qilin.util; public class Stopwatch { - private final String name; - private long elapsedTime; - private long startTime; - private boolean inCounting; + private final String name; + private long elapsedTime; + private long startTime; + private boolean inCounting; - public static Stopwatch newAndStart(final String name) { - Stopwatch stopwatch = new Stopwatch(name); - stopwatch.start(); - return stopwatch; - } + public static Stopwatch newAndStart(final String name) { + Stopwatch stopwatch = new Stopwatch(name); + stopwatch.start(); + return stopwatch; + } - private Stopwatch(final String name) { - this.elapsedTime = 0L; - this.inCounting = false; - this.name = name; - } + private Stopwatch(final String name) { + this.elapsedTime = 0L; + this.inCounting = false; + this.name = name; + } - private void start() { - if (!this.inCounting) { - this.inCounting = true; - this.startTime = System.currentTimeMillis(); - } + private void start() { + if (!this.inCounting) { + this.inCounting = true; + this.startTime = System.currentTimeMillis(); } + } - public void stop() { - if (this.inCounting) { - this.elapsedTime += System.currentTimeMillis() - this.startTime; - this.inCounting = false; - } + public void stop() { + if (this.inCounting) { + this.elapsedTime += System.currentTimeMillis() - this.startTime; + this.inCounting = false; } + } - public float elapsed() { - return this.elapsedTime / 1000.0f; - } + public float elapsed() { + return this.elapsedTime / 1000.0f; + } - public void reset() { - this.elapsedTime = 0L; - this.inCounting = false; - } + public void reset() { + this.elapsedTime = 0L; + this.inCounting = false; + } - public void restart() { - reset(); - start(); - } + public void restart() { + reset(); + start(); + } - @Override - public String toString() { - return String.format("%s elapsed time: %.2fs", this.name, this.elapsed()); - } + @Override + public String toString() { + return String.format("%s elapsed time: %.2fs", this.name, this.elapsed()); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/Triple.java b/sootup.qilin/src/main/java/qilin/util/Triple.java index c8d84403d87..0be3f9034c1 100644 --- a/sootup.qilin/src/main/java/qilin/util/Triple.java +++ b/sootup.qilin/src/main/java/qilin/util/Triple.java @@ -21,45 +21,45 @@ import java.util.Objects; public class Triple { - private final T1 first; - private final T2 second; - private final T3 third; + private final T1 first; + private final T2 second; + private final T3 third; - public Triple(final T1 first, final T2 second, final T3 third) { - this.first = first; - this.second = second; - this.third = third; - } + public Triple(final T1 first, final T2 second, final T3 third) { + this.first = first; + this.second = second; + this.third = third; + } - public T1 getFirst() { - return this.first; - } + public T1 getFirst() { + return this.first; + } - public T2 getSecond() { - return this.second; - } + public T2 getSecond() { + return this.second; + } - public T3 getThird() { - return this.third; - } + public T3 getThird() { + return this.third; + } - @Override - public int hashCode() { - return Objects.hash(this.first, this.second, this.third); - } + @Override + public int hashCode() { + return Objects.hash(this.first, this.second, this.third); + } - @Override - public boolean equals(final Object o) { - if (o instanceof final Triple anoTriple) { - return Objects.equals(this.first, anoTriple.first) && Objects.equals(this.second, anoTriple.second) - && Objects.equals(this.third, anoTriple.third); - } - return false; + @Override + public boolean equals(final Object o) { + if (o instanceof final Triple anoTriple) { + return Objects.equals(this.first, anoTriple.first) + && Objects.equals(this.second, anoTriple.second) + && Objects.equals(this.third, anoTriple.third); } + return false; + } - @Override - public String toString() { - return "<" + this.first + ", " + this.second + ", " - + this.third + ">"; - } + @Override + public String toString() { + return "<" + this.first + ", " + this.second + ", " + this.third + ">"; + } } diff --git a/sootup.qilin/src/main/java/qilin/util/UnionFindSet.java b/sootup.qilin/src/main/java/qilin/util/UnionFindSet.java index aa364ec46a4..8e70b93b1a0 100644 --- a/sootup.qilin/src/main/java/qilin/util/UnionFindSet.java +++ b/sootup.qilin/src/main/java/qilin/util/UnionFindSet.java @@ -25,69 +25,70 @@ import java.util.stream.Collectors; public class UnionFindSet { - private final Map entries; - private int nrsets; + private final Map entries; + private int nrsets; - public UnionFindSet(final Collection elems) { - this.entries = new HashMap<>(); - elems.forEach(elem -> this.entries.put(elem, new Entry(elem))); - this.nrsets = this.entries.size(); - } + public UnionFindSet(final Collection elems) { + this.entries = new HashMap<>(); + elems.forEach(elem -> this.entries.put(elem, new Entry(elem))); + this.nrsets = this.entries.size(); + } - public boolean union(final E e1, final E e2) { - final Entry root1 = this.findRoot(this.entries.get(e1)); - final Entry root2 = this.findRoot(this.entries.get(e2)); - if (root1 == root2) { - return false; - } - if (root1.rank < root2.rank) { - root1.parent = root2; - } else if (root1.rank > root2.rank) { - root2.parent = root1; - } else { - root2.parent = root1; - ++root2.rank; - } - --this.nrsets; - return true; + public boolean union(final E e1, final E e2) { + final Entry root1 = this.findRoot(this.entries.get(e1)); + final Entry root2 = this.findRoot(this.entries.get(e2)); + if (root1 == root2) { + return false; } - - public boolean isConnected(final E e1, final E e2) { - final Entry root1 = this.findRoot(this.entries.get(e1)); - final Entry root2 = this.findRoot(this.entries.get(e2)); - return root1 == root2; + if (root1.rank < root2.rank) { + root1.parent = root2; + } else if (root1.rank > root2.rank) { + root2.parent = root1; + } else { + root2.parent = root1; + ++root2.rank; } + --this.nrsets; + return true; + } - public E find(final E e) { - final Entry ent = this.findRoot(this.entries.get(e)); - return ent.elem; - } + public boolean isConnected(final E e1, final E e2) { + final Entry root1 = this.findRoot(this.entries.get(e1)); + final Entry root2 = this.findRoot(this.entries.get(e2)); + return root1 == root2; + } - public int numberOfSets() { - return this.nrsets; - } + public E find(final E e) { + final Entry ent = this.findRoot(this.entries.get(e)); + return ent.elem; + } - public Collection> getDisjointSets() { - return this.entries.keySet().stream() - .collect(Collectors.groupingBy(this::find, Collectors.toSet())).values(); - } + public int numberOfSets() { + return this.nrsets; + } + + public Collection> getDisjointSets() { + return this.entries.keySet().stream() + .collect(Collectors.groupingBy(this::find, Collectors.toSet())) + .values(); + } - private Entry findRoot(final Entry ent) { - if (ent.parent != ent) { - ent.parent = this.findRoot(ent.parent); - } - return ent.parent; + private Entry findRoot(final Entry ent) { + if (ent.parent != ent) { + ent.parent = this.findRoot(ent.parent); } + return ent.parent; + } - private class Entry { - private final E elem; - private Entry parent; - private int rank; + private class Entry { + private final E elem; + private Entry parent; + private int rank; - private Entry(final E elem) { - this.elem = elem; - this.parent = this; - this.rank = 0; - } + private Entry(final E elem) { + this.elem = elem; + this.parent = this; + this.rank = 0; } + } } diff --git a/sootup.qilin/src/main/java/qilin/util/Util.java b/sootup.qilin/src/main/java/qilin/util/Util.java index bb94314934f..7f2a17a949b 100644 --- a/sootup.qilin/src/main/java/qilin/util/Util.java +++ b/sootup.qilin/src/main/java/qilin/util/Util.java @@ -18,71 +18,70 @@ package qilin.util; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.*; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Util { - private static final Logger logger = LoggerFactory.getLogger(Util.class); + private static final Logger logger = LoggerFactory.getLogger(Util.class); - public static byte[] toUtf8(String s) { - try { - ByteArrayOutputStream bs = new ByteArrayOutputStream(s.length()); - DataOutputStream d = new DataOutputStream(bs); - d.writeUTF(s); - return bs.toByteArray(); - } catch (IOException e) { - logger.debug("Some sort of IO exception in toUtf8 with " + s); - } - return null; + public static byte[] toUtf8(String s) { + try { + ByteArrayOutputStream bs = new ByteArrayOutputStream(s.length()); + DataOutputStream d = new DataOutputStream(bs); + d.writeUTF(s); + return bs.toByteArray(); + } catch (IOException e) { + logger.debug("Some sort of IO exception in toUtf8 with " + s); } + return null; + } - public static boolean addToMap(Map> map, K key, V value) { - return map.computeIfAbsent(key, k -> DataFactory.createSet()).add(value); - } + public static boolean addToMap(Map> map, K key, V value) { + return map.computeIfAbsent(key, k -> DataFactory.createSet()).add(value); + } - public static boolean removeFromMap(Map> map, K key, V value) { - if (!map.containsKey(key)) { - return false; - } - return map.get(key).remove(value); + public static boolean removeFromMap(Map> map, K key, V value) { + if (!map.containsKey(key)) { + return false; } + return map.get(key).remove(value); + } - public static void add(Map map, T name, String... aliases) { - for (String alias : aliases) { - map.put(alias, name); - } + public static void add(Map map, T name, String... aliases) { + for (String alias : aliases) { + map.put(alias, name); } + } - public static String[] concat(String[] a, String[] b) { - String[] c = new String[a.length + b.length]; - System.arraycopy(a, 0, c, 0, a.length); - System.arraycopy(b, 0, c, a.length, b.length); - return c; - } + public static String[] concat(String[] a, String[] b) { + String[] c = new String[a.length + b.length]; + System.arraycopy(a, 0, c, 0, a.length); + System.arraycopy(b, 0, c, a.length, b.length); + return c; + } - public static void writeToFile(String file, String content) { - try { - File mfile = new File(file); - if (!mfile.exists()) { - System.out.println(file); - mfile.createNewFile(); - } - FileWriter writer = new FileWriter(mfile); - writer.write(content); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } + public static void writeToFile(String file, String content) { + try { + File mfile = new File(file); + if (!mfile.exists()) { + System.out.println(file); + mfile.createNewFile(); + } + FileWriter writer = new FileWriter(mfile); + writer.write(content); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); } + } - private final static Pattern qPat = Pattern.compile("'"); + private static final Pattern qPat = Pattern.compile("'"); - public static String stripQuotes(CharSequence s) { - return qPat.matcher(s).replaceAll(""); - } + public static String stripQuotes(CharSequence s) { + return qPat.matcher(s).replaceAll(""); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java b/sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java index 0b2f866cb56..b500eee193e 100644 --- a/sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java +++ b/sootup.qilin/src/main/java/qilin/util/collect/SetFactory.java @@ -23,16 +23,16 @@ import java.util.Set; public class SetFactory { - private final Map, Set> sets; + private final Map, Set> sets; - public SetFactory() { - this.sets = new HashMap<>(); - } + public SetFactory() { + this.sets = new HashMap<>(); + } - public Set get(final Set set) { - if (!this.sets.containsKey(set)) { - this.sets.put(set, set); - } - return this.sets.get(set); + public Set get(final Set set) { + if (!this.sets.containsKey(set)) { + this.sets.put(set, set); } + return this.sets.get(set); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java b/sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java index c271d4cb046..fcc2fe33216 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/ConcurrentDirectedGraphImpl.java @@ -25,39 +25,39 @@ import java.util.concurrent.ConcurrentHashMap; public class ConcurrentDirectedGraphImpl implements DirectedGraph { - protected Set nodes; - protected Map> preds; - protected Map> succs; - - public ConcurrentDirectedGraphImpl() { - this.nodes = ConcurrentHashMap.newKeySet(); - this.preds = new ConcurrentHashMap<>(); - this.succs = new ConcurrentHashMap<>(); - } - - public void addNode(final N node) { - this.nodes.add(node); - } - - public void addEdge(final N from, final N to) { - this.addNode(from); - this.addNode(to); - this.preds.computeIfAbsent(to, k -> ConcurrentHashMap.newKeySet()).add(from); - this.succs.computeIfAbsent(from, k -> ConcurrentHashMap.newKeySet()).add(to); - } - - @Override - public Collection allNodes() { - return this.nodes; - } - - @Override - public Collection predsOf(final N n) { - return this.preds.getOrDefault(n, Collections.emptySet()); - } - - @Override - public Collection succsOf(final N n) { - return this.succs.getOrDefault(n, Collections.emptySet()); - } + protected Set nodes; + protected Map> preds; + protected Map> succs; + + public ConcurrentDirectedGraphImpl() { + this.nodes = ConcurrentHashMap.newKeySet(); + this.preds = new ConcurrentHashMap<>(); + this.succs = new ConcurrentHashMap<>(); + } + + public void addNode(final N node) { + this.nodes.add(node); + } + + public void addEdge(final N from, final N to) { + this.addNode(from); + this.addNode(to); + this.preds.computeIfAbsent(to, k -> ConcurrentHashMap.newKeySet()).add(from); + this.succs.computeIfAbsent(from, k -> ConcurrentHashMap.newKeySet()).add(to); + } + + @Override + public Collection allNodes() { + return this.nodes; + } + + @Override + public Collection predsOf(final N n) { + return this.preds.getOrDefault(n, Collections.emptySet()); + } + + @Override + public Collection succsOf(final N n) { + return this.succs.getOrDefault(n, Collections.emptySet()); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java index f2f26e44107..1af26413808 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraph.java @@ -25,31 +25,35 @@ import java.util.stream.Collectors; public interface DirectedGraph { - Collection allNodes(); - - Collection predsOf(final N p); - - Collection succsOf(final N p); - - /* no cache, very slow.*/ - default Collection computeReachableNodes(N source) { - Set reachableNodes = new HashSet<>(); - Stack stack = new Stack<>(); - stack.push(source); - while (!stack.isEmpty()) { - N node = stack.pop(); - if (reachableNodes.add(node)) { - stack.addAll(succsOf(node)); - } - } - return reachableNodes; - } - - default Collection computeRootNodes() { - return allNodes().stream().filter(node -> predsOf(node).size() == 0).collect(Collectors.toSet()); - } - - default Collection computeTailNodes() { - return allNodes().stream().filter(node -> succsOf(node).size() == 0).collect(Collectors.toSet()); + Collection allNodes(); + + Collection predsOf(final N p); + + Collection succsOf(final N p); + + /* no cache, very slow.*/ + default Collection computeReachableNodes(N source) { + Set reachableNodes = new HashSet<>(); + Stack stack = new Stack<>(); + stack.push(source); + while (!stack.isEmpty()) { + N node = stack.pop(); + if (reachableNodes.add(node)) { + stack.addAll(succsOf(node)); + } } + return reachableNodes; + } + + default Collection computeRootNodes() { + return allNodes().stream() + .filter(node -> predsOf(node).size() == 0) + .collect(Collectors.toSet()); + } + + default Collection computeTailNodes() { + return allNodes().stream() + .filter(node -> succsOf(node).size() == 0) + .collect(Collectors.toSet()); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java index c56e7526c7e..148f27b1437 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/DirectedGraphImpl.java @@ -21,39 +21,39 @@ import java.util.*; public class DirectedGraphImpl implements DirectedGraph { - protected Set nodes; - protected Map> preds; - protected Map> succs; - - public DirectedGraphImpl() { - this.nodes = new HashSet<>(); - this.preds = new HashMap<>(); - this.succs = new HashMap<>(); - } - - public void addNode(final N node) { - this.nodes.add(node); - } - - public void addEdge(final N from, final N to) { - this.addNode(from); - this.addNode(to); - this.preds.computeIfAbsent(to, k -> new HashSet<>()).add(from); - this.succs.computeIfAbsent(from, k -> new HashSet<>()).add(to); - } - - @Override - public Collection allNodes() { - return this.nodes; - } - - @Override - public Collection predsOf(final N n) { - return this.preds.getOrDefault(n, Collections.emptySet()); - } - - @Override - public Collection succsOf(final N n) { - return this.succs.getOrDefault(n, Collections.emptySet()); - } + protected Set nodes; + protected Map> preds; + protected Map> succs; + + public DirectedGraphImpl() { + this.nodes = new HashSet<>(); + this.preds = new HashMap<>(); + this.succs = new HashMap<>(); + } + + public void addNode(final N node) { + this.nodes.add(node); + } + + public void addEdge(final N from, final N to) { + this.addNode(from); + this.addNode(to); + this.preds.computeIfAbsent(to, k -> new HashSet<>()).add(from); + this.succs.computeIfAbsent(from, k -> new HashSet<>()).add(to); + } + + @Override + public Collection allNodes() { + return this.nodes; + } + + @Override + public Collection predsOf(final N n) { + return this.preds.getOrDefault(n, Collections.emptySet()); + } + + @Override + public Collection succsOf(final N n) { + return this.succs.getOrDefault(n, Collections.emptySet()); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java b/sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java index 446a18e6261..25f76580c1e 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/MergedNode.java @@ -24,42 +24,42 @@ import java.util.Set; public class MergedNode { - private Set> preds; - private Set> succs; - private final Set content; + private Set> preds; + private Set> succs; + private final Set content; - public MergedNode(final Collection content) { - this.content = new HashSet<>(content); - } + public MergedNode(final Collection content) { + this.content = new HashSet<>(content); + } - public void addPred(final MergedNode pred) { - if (this.preds == null) { - this.preds = new HashSet<>(4); - } - this.preds.add(pred); + public void addPred(final MergedNode pred) { + if (this.preds == null) { + this.preds = new HashSet<>(4); } + this.preds.add(pred); + } - public Set> getPreds() { - return (this.preds == null) ? Collections.emptySet() : this.preds; - } + public Set> getPreds() { + return (this.preds == null) ? Collections.emptySet() : this.preds; + } - public void addSucc(final MergedNode succ) { - if (this.succs == null) { - this.succs = new HashSet<>(4); - } - this.succs.add(succ); + public void addSucc(final MergedNode succ) { + if (this.succs == null) { + this.succs = new HashSet<>(4); } + this.succs.add(succ); + } - public Set> getSuccs() { - return (this.succs == null) ? Collections.emptySet() : this.succs; - } + public Set> getSuccs() { + return (this.succs == null) ? Collections.emptySet() : this.succs; + } - public Set getContent() { - return this.content; - } + public Set getContent() { + return this.content; + } - @Override - public String toString() { - return this.content.toString(); - } + @Override + public String toString() { + return this.content.toString(); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java b/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java index 9e7b888c0ff..1afb0b80c9b 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/Reachability.java @@ -21,51 +21,51 @@ import java.util.*; public class Reachability { - private final DirectedGraph graph; - private final Map> reachableNodes; - private final Map> reachToNodes; + private final DirectedGraph graph; + private final Map> reachableNodes; + private final Map> reachToNodes; - public Reachability(final DirectedGraph graph) { - this.reachableNodes = new HashMap<>(); - this.reachToNodes = new HashMap<>(); - this.graph = graph; - } + public Reachability(final DirectedGraph graph) { + this.reachableNodes = new HashMap<>(); + this.reachToNodes = new HashMap<>(); + this.graph = graph; + } - public Set reachableNodesFrom(final N source) { - if (!this.reachableNodes.containsKey(source)) { - final Set visited = new HashSet<>(); - final Deque stack = new ArrayDeque<>(); - stack.push(source); - while (!stack.isEmpty()) { - final N node = stack.pop(); - visited.add(node); - this.graph.succsOf(node).stream().filter(n -> !visited.contains(n)).forEach(stack::push); - } - this.reachableNodes.put(source, visited); - } - return this.reachableNodes.get(source); + public Set reachableNodesFrom(final N source) { + if (!this.reachableNodes.containsKey(source)) { + final Set visited = new HashSet<>(); + final Deque stack = new ArrayDeque<>(); + stack.push(source); + while (!stack.isEmpty()) { + final N node = stack.pop(); + visited.add(node); + this.graph.succsOf(node).stream().filter(n -> !visited.contains(n)).forEach(stack::push); + } + this.reachableNodes.put(source, visited); } + return this.reachableNodes.get(source); + } - public Set nodesReach(final N target) { - if (!this.reachToNodes.containsKey(target)) { - final Set visited = new HashSet<>(); - final Deque stack = new ArrayDeque<>(); - stack.push(target); - while (!stack.isEmpty()) { - final N node = stack.pop(); - visited.add(node); - this.graph.predsOf(node).stream().filter(n -> !visited.contains(n)).forEach(stack::push); - } - this.reachToNodes.put(target, visited); - } - return this.reachToNodes.get(target); + public Set nodesReach(final N target) { + if (!this.reachToNodes.containsKey(target)) { + final Set visited = new HashSet<>(); + final Deque stack = new ArrayDeque<>(); + stack.push(target); + while (!stack.isEmpty()) { + final N node = stack.pop(); + visited.add(node); + this.graph.predsOf(node).stream().filter(n -> !visited.contains(n)).forEach(stack::push); + } + this.reachToNodes.put(target, visited); } + return this.reachToNodes.get(target); + } - public Set passedNodes(final N source, final N target) { - final Set reachableFromSource = this.reachableNodesFrom(source); - final Set reachToTarget = this.nodesReach(target); - final Set ret = new HashSet<>(reachableFromSource); - ret.retainAll(reachToTarget); - return ret; - } + public Set passedNodes(final N source, final N target) { + final Set reachableFromSource = this.reachableNodesFrom(source); + final Set reachToTarget = this.nodesReach(target); + final Set ret = new HashSet<>(reachableFromSource); + ret.retainAll(reachToTarget); + return ret; + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java b/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java index 2be136e2feb..efb023b4497 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/SCCMergedGraph.java @@ -21,44 +21,53 @@ import java.util.*; public class SCCMergedGraph implements DirectedGraph> { - private Set> nodes; - private final Map> nodeMap = new HashMap<>(); + private Set> nodes; + private final Map> nodeMap = new HashMap<>(); - public SCCMergedGraph(final DirectedGraph graph) { - this.init(graph); - } + public SCCMergedGraph(final DirectedGraph graph) { + this.init(graph); + } - public MergedNode getMergedNode(N contentNode) { - return nodeMap.get(contentNode); - } + public MergedNode getMergedNode(N contentNode) { + return nodeMap.get(contentNode); + } - @Override - public Collection> allNodes() { - return this.nodes; - } + @Override + public Collection> allNodes() { + return this.nodes; + } - @Override - public Collection> predsOf(final MergedNode node) { - return node.getPreds(); - } + @Override + public Collection> predsOf(final MergedNode node) { + return node.getPreds(); + } - @Override - public Collection> succsOf(final MergedNode node) { - return node.getSuccs(); - } + @Override + public Collection> succsOf(final MergedNode node) { + return node.getSuccs(); + } - private void init(final DirectedGraph graph) { - this.nodes = new HashSet<>(); - final StronglyConnectedComponents scc = new StronglyConnectedComponents<>(graph); - scc.getComponents().forEach(component -> { - final MergedNode node2 = new MergedNode<>(component); - component.forEach(n -> nodeMap.put(n, node2)); - this.nodes.add(node2); - }); - this.nodes.forEach(node -> node.getContent().stream().map(graph::succsOf).flatMap(Collection::stream) - .map(nodeMap::get).filter(succ -> succ != node).forEach(succ -> { - node.addSucc(succ); - succ.addPred(node); - })); - } + private void init(final DirectedGraph graph) { + this.nodes = new HashSet<>(); + final StronglyConnectedComponents scc = new StronglyConnectedComponents<>(graph); + scc.getComponents() + .forEach( + component -> { + final MergedNode node2 = new MergedNode<>(component); + component.forEach(n -> nodeMap.put(n, node2)); + this.nodes.add(node2); + }); + this.nodes.forEach( + node -> + node.getContent().stream() + .map(graph::succsOf) + .flatMap(Collection::stream) + .map(nodeMap::get) + .filter(succ -> succ != node) + .forEach( + succ -> { + node.addSucc(succ); + succ.addPred(node); + })); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java b/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java index 3b256448a00..f985550fe91 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/StronglyConnectedComponents.java @@ -21,78 +21,80 @@ import java.util.*; public class StronglyConnectedComponents { - private final List> componentList; - private final List> trueComponentList; - private int index; - private Map indexForNode; - private Map lowlinkForNode; - private Stack stack; - private DirectedGraph graph; + private final List> componentList; + private final List> trueComponentList; + private int index; + private Map indexForNode; + private Map lowlinkForNode; + private Stack stack; + private DirectedGraph graph; - public StronglyConnectedComponents(final DirectedGraph graph) { - this.componentList = new ArrayList<>(); - this.trueComponentList = new ArrayList<>(); - this.index = 0; - this.graph = graph; - this.stack = new Stack<>(); - this.indexForNode = new HashMap<>(); - this.lowlinkForNode = new HashMap<>(); - for (final N node : graph.allNodes()) { - if (!this.indexForNode.containsKey(node)) { - this.recurse(node); - } - } - this.validate(graph, this.componentList); - this.indexForNode = null; - this.lowlinkForNode = null; - this.stack = null; - this.graph = null; + public StronglyConnectedComponents(final DirectedGraph graph) { + this.componentList = new ArrayList<>(); + this.trueComponentList = new ArrayList<>(); + this.index = 0; + this.graph = graph; + this.stack = new Stack<>(); + this.indexForNode = new HashMap<>(); + this.lowlinkForNode = new HashMap<>(); + for (final N node : graph.allNodes()) { + if (!this.indexForNode.containsKey(node)) { + this.recurse(node); + } } + this.validate(graph, this.componentList); + this.indexForNode = null; + this.lowlinkForNode = null; + this.stack = null; + this.graph = null; + } - public List> getComponents() { - return this.componentList; - } + public List> getComponents() { + return this.componentList; + } - public List> getTrueComponents() { - return this.trueComponentList; - } + public List> getTrueComponents() { + return this.trueComponentList; + } - private void recurse(final N node) { - this.indexForNode.put(node, this.index); - this.lowlinkForNode.put(node, this.index); - ++this.index; - this.stack.push(node); - for (final N succ : this.graph.succsOf(node)) { - if (!this.indexForNode.containsKey(succ)) { - this.recurse(succ); - this.lowlinkForNode.put(node, Math.min(this.lowlinkForNode.get(node), this.lowlinkForNode.get(succ))); - } else { - if (!this.stack.contains(succ)) { - continue; - } - this.lowlinkForNode.put(node, Math.min(this.lowlinkForNode.get(node), this.indexForNode.get(succ))); - } + private void recurse(final N node) { + this.indexForNode.put(node, this.index); + this.lowlinkForNode.put(node, this.index); + ++this.index; + this.stack.push(node); + for (final N succ : this.graph.succsOf(node)) { + if (!this.indexForNode.containsKey(succ)) { + this.recurse(succ); + this.lowlinkForNode.put( + node, Math.min(this.lowlinkForNode.get(node), this.lowlinkForNode.get(succ))); + } else { + if (!this.stack.contains(succ)) { + continue; } - if (this.lowlinkForNode.get(node) == (int) this.indexForNode.get(node)) { - final List scc = new ArrayList<>(); - N v2; - do { - v2 = this.stack.pop(); - scc.add(v2); - } while (node != v2); - this.componentList.add(scc); - if (scc.size() > 1) { - this.trueComponentList.add(scc); - } else { - final N n = scc.get(0); - if (this.graph.succsOf(n).contains(n)) { - this.trueComponentList.add(scc); - } - } + this.lowlinkForNode.put( + node, Math.min(this.lowlinkForNode.get(node), this.indexForNode.get(succ))); + } + } + if (this.lowlinkForNode.get(node) == (int) this.indexForNode.get(node)) { + final List scc = new ArrayList<>(); + N v2; + do { + v2 = this.stack.pop(); + scc.add(v2); + } while (node != v2); + this.componentList.add(scc); + if (scc.size() > 1) { + this.trueComponentList.add(scc); + } else { + final N n = scc.get(0); + if (this.graph.succsOf(n).contains(n)) { + this.trueComponentList.add(scc); } + } } + } - private void validate(final DirectedGraph graph, final List> SCCs) { - assert graph.allNodes().size() == SCCs.stream().mapToInt(List::size).sum(); - } + private void validate(final DirectedGraph graph, final List> SCCs) { + assert graph.allNodes().size() == SCCs.stream().mapToInt(List::size).sum(); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java b/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java index c257438b48f..07294cd3c8a 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/TopologicalSorter.java @@ -21,42 +21,42 @@ import java.util.*; public class TopologicalSorter { - private DirectedGraph graph; - private List sortedList; - private Set visited; - - public List sort(final DirectedGraph graph) { - return this.sort(graph, false); - } - - public List sort(final DirectedGraph graph, final boolean reverse) { - this.initialize(graph); - graph.allNodes().stream().filter(n -> graph.succsOf(n).isEmpty()).forEach(this::visit); - List result = this.sortedList; - if (reverse) { - Collections.reverse(result); - } - this.clear(); - return result; + private DirectedGraph graph; + private List sortedList; + private Set visited; + + public List sort(final DirectedGraph graph) { + return this.sort(graph, false); + } + + public List sort(final DirectedGraph graph, final boolean reverse) { + this.initialize(graph); + graph.allNodes().stream().filter(n -> graph.succsOf(n).isEmpty()).forEach(this::visit); + List result = this.sortedList; + if (reverse) { + Collections.reverse(result); } - - private void initialize(final DirectedGraph graph) { - this.graph = graph; - this.sortedList = new LinkedList<>(); - this.visited = new HashSet<>(); + this.clear(); + return result; + } + + private void initialize(final DirectedGraph graph) { + this.graph = graph; + this.sortedList = new LinkedList<>(); + this.visited = new HashSet<>(); + } + + private void visit(final N node) { + if (!this.visited.contains(node)) { + this.visited.add(node); + this.graph.predsOf(node).forEach(this::visit); + this.sortedList.add(node); } + } - private void visit(final N node) { - if (!this.visited.contains(node)) { - this.visited.add(node); - this.graph.predsOf(node).forEach(this::visit); - this.sortedList.add(node); - } - } - - private void clear() { - this.graph = null; - this.sortedList = null; - this.visited = null; - } + private void clear() { + this.graph = null; + this.sortedList = null; + this.visited = null; + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/Tree.java b/sootup.qilin/src/main/java/qilin/util/graph/Tree.java index d146fddfacb..4d75d4a77f7 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/Tree.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/Tree.java @@ -21,17 +21,17 @@ import java.util.Collection; public interface Tree { - N getRoot(); + N getRoot(); - Collection getLeaves(); + Collection getLeaves(); - boolean isALeaf(N n); + boolean isALeaf(N n); - Collection getAllNodes(); + Collection getAllNodes(); - int size(); + int size(); - N parentOf(N n); + N parentOf(N n); - Collection childrenOf(N n); + Collection childrenOf(N n); } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java b/sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java index 2d40f351dcd..8c02d064a45 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/TreeImpl.java @@ -25,69 +25,69 @@ import java.util.stream.Collectors; public class TreeImpl implements Tree { - Map> data2Node; - TreeNode root; + Map> data2Node; + TreeNode root; - public TreeImpl() { - this.data2Node = new HashMap<>(); - } + public TreeImpl() { + this.data2Node = new HashMap<>(); + } - @Override - public N getRoot() { - if (root == null) { - for (TreeNode n : data2Node.values()) { - if (n.isRoot()) { - root = n; - break; - } - } + @Override + public N getRoot() { + if (root == null) { + for (TreeNode n : data2Node.values()) { + if (n.isRoot()) { + root = n; + break; } - return root != null ? root.getElem() : null; + } } + return root != null ? root.getElem() : null; + } - @Override - public Collection getLeaves() { - return getAllNodes().stream().filter(this::isALeaf).collect(Collectors.toSet()); - } + @Override + public Collection getLeaves() { + return getAllNodes().stream().filter(this::isALeaf).collect(Collectors.toSet()); + } - @Override - public boolean isALeaf(N o) { - return data2Node.containsKey(o) && data2Node.get(o).isLeaf(); - } + @Override + public boolean isALeaf(N o) { + return data2Node.containsKey(o) && data2Node.get(o).isLeaf(); + } - @Override - public Collection getAllNodes() { - return data2Node.keySet(); - } + @Override + public Collection getAllNodes() { + return data2Node.keySet(); + } - public Collection> getAllTreeNodes() { - return data2Node.values(); - } + public Collection> getAllTreeNodes() { + return data2Node.values(); + } - @Override - public int size() { - return data2Node.size(); - } + @Override + public int size() { + return data2Node.size(); + } - @Override - public N parentOf(N o) { - return data2Node.containsKey(o) ? data2Node.get(o).getParent().getElem() : null; - } + @Override + public N parentOf(N o) { + return data2Node.containsKey(o) ? data2Node.get(o).getParent().getElem() : null; + } - @Override - public Collection childrenOf(N o) { - if (data2Node.containsKey(o)) { - TreeNode node = data2Node.get(o); - return node.getChildren().stream().map(TreeNode::getElem).collect(Collectors.toSet()); - } - return Collections.emptySet(); + @Override + public Collection childrenOf(N o) { + if (data2Node.containsKey(o)) { + TreeNode node = data2Node.get(o); + return node.getChildren().stream().map(TreeNode::getElem).collect(Collectors.toSet()); } + return Collections.emptySet(); + } - public boolean addTreeEdge(N parent, N child) { - TreeNode p = data2Node.computeIfAbsent(parent, k -> new TreeNode<>(parent)); - TreeNode c = data2Node.computeIfAbsent(child, k -> new TreeNode<>(child)); - boolean f = p.addChild(c); - c.setParent(p); - return f; - } + public boolean addTreeEdge(N parent, N child) { + TreeNode p = data2Node.computeIfAbsent(parent, k -> new TreeNode<>(parent)); + TreeNode c = data2Node.computeIfAbsent(child, k -> new TreeNode<>(child)); + boolean f = p.addChild(c); + c.setParent(p); + return f; + } } diff --git a/sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java b/sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java index 3d991d6891f..b9d2142ede8 100644 --- a/sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java +++ b/sootup.qilin/src/main/java/qilin/util/graph/TreeNode.java @@ -22,40 +22,40 @@ import java.util.Set; public class TreeNode { - private final D elem; - private TreeNode parent; - private final Set> children; - - public TreeNode(D e) { - this.elem = e; - this.children = new HashSet<>(); - } - - public D getElem() { - return elem; - } - - public TreeNode getParent() { - return parent; - } - - public boolean isLeaf() { - return this.children.isEmpty(); - } - - public boolean isRoot() { - return this.parent == null; - } - - public void setParent(TreeNode parent) { - this.parent = parent; - } - - public Set> getChildren() { - return children; - } - - public boolean addChild(TreeNode child) { - return this.children.add(child); - } + private final D elem; + private TreeNode parent; + private final Set> children; + + public TreeNode(D e) { + this.elem = e; + this.children = new HashSet<>(); + } + + public D getElem() { + return elem; + } + + public TreeNode getParent() { + return parent; + } + + public boolean isLeaf() { + return this.children.isEmpty(); + } + + public boolean isRoot() { + return this.parent == null; + } + + public void setParent(TreeNode parent) { + this.parent = parent; + } + + public Set> getChildren() { + return children; + } + + public boolean addChild(TreeNode child) { + return this.children.add(child); + } } diff --git a/sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java b/sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java index 3aaa6892632..975ab7692e4 100644 --- a/sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java +++ b/sootup.qilin/src/main/java/qilin/util/queue/UniqueQueue.java @@ -21,117 +21,116 @@ import java.util.*; public class UniqueQueue implements Queue { - private final Set set; - private final Queue queue; - - public UniqueQueue() { - this.set = new HashSet<>(); - this.queue = new LinkedList<>(); - } - - @Override - public boolean add(T t) { - if (set.contains(t)) { - return false; - } else { - set.add(t); - queue.add(t); - return true; - } - } - - @Override - public void clear() { - set.clear(); - queue.clear(); - } - - @Override - public boolean offer(T t) { - return add(t); - } - - @Override - public T remove() { - return poll(); - } - - @Override - public T poll() { - T t = queue.poll(); - if (t != null) { - set.remove(t); - } - return t; - } - - @Override - public T peek() { - return queue.peek(); - } - - @Override - public int size() { - return set.size(); - } - - @Override - public boolean isEmpty() { - return set.isEmpty(); - } - - @Override - public boolean contains(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public Iterator iterator() { - throw new UnsupportedOperationException(); - } - - @Override - public Object[] toArray() { - throw new UnsupportedOperationException(); - } - - @Override - public T1[] toArray(T1[] t1s) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean containsAll(Collection collection) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean addAll(Collection collection) { - boolean ret = false; - for (T t : collection) { - ret |= add(t); - } - return ret; - } - - @Override - public boolean removeAll(Collection collection) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean retainAll(Collection collection) { - throw new UnsupportedOperationException(); - } - - @Override - public T element() { - throw new UnsupportedOperationException(); - } - + private final Set set; + private final Queue queue; + + public UniqueQueue() { + this.set = new HashSet<>(); + this.queue = new LinkedList<>(); + } + + @Override + public boolean add(T t) { + if (set.contains(t)) { + return false; + } else { + set.add(t); + queue.add(t); + return true; + } + } + + @Override + public void clear() { + set.clear(); + queue.clear(); + } + + @Override + public boolean offer(T t) { + return add(t); + } + + @Override + public T remove() { + return poll(); + } + + @Override + public T poll() { + T t = queue.poll(); + if (t != null) { + set.remove(t); + } + return t; + } + + @Override + public T peek() { + return queue.peek(); + } + + @Override + public int size() { + return set.size(); + } + + @Override + public boolean isEmpty() { + return set.isEmpty(); + } + + @Override + public boolean contains(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + throw new UnsupportedOperationException(); + } + + @Override + public Object[] toArray() { + throw new UnsupportedOperationException(); + } + + @Override + public T1[] toArray(T1[] t1s) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(Collection collection) { + boolean ret = false; + for (T t : collection) { + ret |= add(t); + } + return ret; + } + + @Override + public boolean removeAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public T element() { + throw new UnsupportedOperationException(); + } } diff --git a/sootup.qilin/src/main/java/soot/Context.java b/sootup.qilin/src/main/java/soot/Context.java index 2cff77aea3d..6fffb4b1029 100644 --- a/sootup.qilin/src/main/java/soot/Context.java +++ b/sootup.qilin/src/main/java/soot/Context.java @@ -23,8 +23,7 @@ */ /** - * A context in a context-sensitive all graph. May be a unit (in a 1CFA call graph) or a Spark AllocNode (in an - * object-sensitive call graph). + * A context in a context-sensitive all graph. May be a unit (in a 1CFA call graph) or a Spark + * AllocNode (in an object-sensitive call graph). */ -public interface Context { -} +public interface Context {} diff --git a/sootup.qilin/src/main/java/soot/EntryPoints.java b/sootup.qilin/src/main/java/soot/EntryPoints.java deleted file mode 100644 index 9083f25204e..00000000000 --- a/sootup.qilin/src/main/java/soot/EntryPoints.java +++ /dev/null @@ -1,207 +0,0 @@ -package soot; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Optional; - -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2003 Ondrej Lhotak - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import qilin.core.PTAScene; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.signatures.MethodSignature; -import sootup.core.signatures.MethodSubSignature; -import sootup.java.core.JavaIdentifierFactory; - -/** - * Returns the various potential entry points of a Java program. - * - * @author Ondrej Lhotak - */ -public class EntryPoints { - - final MethodSubSignature sigMain; - final MethodSubSignature sigFinalize; - final MethodSubSignature sigExit; - final MethodSubSignature sigClinit; - final MethodSubSignature sigInit; - final MethodSubSignature sigStart; - final MethodSubSignature sigRun; - final MethodSubSignature sigObjRun; - final MethodSubSignature sigForName; - - private static EntryPoints instance = new EntryPoints(); - private EntryPoints() { - sigMain = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_MAIN); - sigFinalize = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_FINALIZE); - - sigExit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_EXIT); - sigClinit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_CLINIT); - sigInit = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_INIT); - sigStart = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_START); - sigRun = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_RUN); - sigObjRun = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_OBJ_RUN); - sigForName = JavaIdentifierFactory.getInstance().parseMethodSubSignature(JavaMethods.SIG_FOR_NAME); - } - - public static EntryPoints v() { - return instance; - } - - protected void addMethod(List set, SootClass cls, MethodSubSignature methodSubSig) { - Optional osm = cls.getMethod(methodSubSig); - osm.ifPresent(set::add); - } - - protected void addMethod(List set, String methodSig) { - MethodSignature ms = JavaIdentifierFactory.getInstance().parseMethodSignature(methodSig); - Optional osm = PTAScene.v().getView().getMethod(ms); - osm.ifPresent(set::add); - } - - /** - * Returns only the application entry points, not including entry points invoked implicitly by the VM. - */ - public List application() { - List ret = new ArrayList(); - if (PTAScene.v().hasMainClass()) { - SootClass mainClass = PTAScene.v().getMainClass(); - addMethod(ret, mainClass, sigMain); - for (SootMethod clinit : clinitsOf(mainClass)) { - ret.add(clinit); - } - } - return ret; - } - - /** Returns only the entry points invoked implicitly by the VM. */ - public List implicit() { - List ret = new ArrayList(); - -// if (Options.v().src_prec() == Options.src_prec_dotnet) { -// return ret; -// } - - addMethod(ret, JavaMethods.INITIALIZE_SYSTEM_CLASS); - addMethod(ret, JavaMethods.THREAD_GROUP_INIT); - // addMethod( ret, ""); - addMethod(ret, JavaMethods.THREAD_EXIT); - addMethod(ret, JavaMethods.THREADGROUP_UNCAUGHT_EXCEPTION); - // addMethod( ret, ""); - addMethod(ret, JavaMethods.CLASSLOADER_INIT); - addMethod(ret, JavaMethods.CLASSLOADER_LOAD_CLASS_INTERNAL); - addMethod(ret, JavaMethods.CLASSLOADER_CHECK_PACKAGE_ACC); - addMethod(ret, JavaMethods.CLASSLOADER_ADD_CLASS); - addMethod(ret, JavaMethods.CLASSLOADER_FIND_NATIVE); - addMethod(ret, JavaMethods.PRIV_ACTION_EXC_INIT); - // addMethod( ret, ""); - addMethod(ret, JavaMethods.RUN_FINALIZE); - addMethod(ret, JavaMethods.THREAD_INIT_RUNNABLE); - addMethod(ret, JavaMethods.THREAD_INIT_STRING); - return ret; - } - - /** Returns all the entry points. */ - public List all() { - List ret = new ArrayList(); - ret.addAll(application()); - ret.addAll(implicit()); - return ret; - } - - /** Returns a list of all static initializers. */ - public List clinits() { - List ret = new ArrayList(); - Collection classes = PTAScene.v().getView().getClasses(); - for (SootClass cl : classes) { - addMethod(ret, cl, sigClinit); - } - return ret; - } - - /** Returns a list of all clinits of class cl and its superclasses. */ - public Iterable clinitsOf(SootClass cl) { - // Do not create an actual list, since this method gets called quite often - // Instead, callers usually just want to iterate over the result. - Optional oinit = cl.getMethod(sigClinit); - Optional osuperClass = cl.getSuperclass(); - // check super classes until finds a constructor or no super class there anymore. - while (oinit.isPresent() && osuperClass.isPresent()) { - oinit = osuperClass.get().getMethod(sigClinit); - osuperClass = osuperClass.get().getSuperclass(); - } - if (!oinit.isPresent()) { - return Collections.emptyList(); - } - SootMethod initStart = oinit.get(); - return new Iterable() { - - @Override - public Iterator iterator() { - return new Iterator() { - SootMethod current = initStart; - - @Override - public SootMethod next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - SootMethod n = current; - - // Pre-fetch the next element - current = null; - SootClass currentClass = (SootClass) PTAScene.v().getView().getClass(n.getDeclaringClassType()).get(); - while (true) { - Optional osuperClass = currentClass.getSuperclass(); - if (!osuperClass.isPresent()) { - break; - } - - Optional om = osuperClass.get().getMethod(sigClinit); - if (om.isPresent()) { - current = om.get(); - break; - } - - currentClass = osuperClass.get(); - } - - return n; - } - - @Override - public boolean hasNext() { - return current != null; - } - }; - } - }; - } -} diff --git a/sootup.qilin/src/main/java/soot/JavaMethods.java b/sootup.qilin/src/main/java/soot/JavaMethods.java index 40f9b4f5742..21225f9c53a 100644 --- a/sootup.qilin/src/main/java/soot/JavaMethods.java +++ b/sootup.qilin/src/main/java/soot/JavaMethods.java @@ -24,34 +24,36 @@ public class JavaMethods { - public static final String SIG_MAIN = "void main(java.lang.String[])"; - public static final String SIG_FINALIZE = "void finalize()"; - public static final String SIG_EXIT = "void exit()"; - public static final String SIG_CLINIT = "void ()"; - public static final String SIG_INIT = "void ()"; - public static final String SIG_START = "void start()"; - public static final String SIG_RUN = "void run()"; - public static final String SIG_OBJ_RUN = "java.lang.Object run()"; - public static final String SIG_FOR_NAME = "java.lang.Class forName(java.lang.String)"; + public static final String SIG_MAIN = "void main(java.lang.String[])"; + public static final String SIG_FINALIZE = "void finalize()"; + public static final String SIG_EXIT = "void exit()"; + public static final String SIG_CLINIT = "void ()"; + public static final String SIG_INIT = "void ()"; + public static final String SIG_START = "void start()"; + public static final String SIG_RUN = "void run()"; + public static final String SIG_OBJ_RUN = "java.lang.Object run()"; + public static final String SIG_FOR_NAME = "java.lang.Class forName(java.lang.String)"; - public static final String INITIALIZE_SYSTEM_CLASS = ""; - public static final String THREAD_GROUP_INIT = "()>"; - public static final String THREAD_EXIT = ""; - public static final String THREADGROUP_UNCAUGHT_EXCEPTION - = ""; - public static final String CLASSLOADER_INIT = "()>"; - public static final String CLASSLOADER_LOAD_CLASS_INTERNAL - = ""; - public static final String CLASSLOADER_CHECK_PACKAGE_ACC - = ""; - public static final String CLASSLOADER_ADD_CLASS = ""; - public static final String CLASSLOADER_FIND_NATIVE - = ""; - public static final String PRIV_ACTION_EXC_INIT - = "(java.lang.Exception)>"; - public static final String RUN_FINALIZE = ""; - public static final String THREAD_INIT_RUNNABLE - = "(java.lang.ThreadGroup,java.lang.Runnable)>"; - public static final String THREAD_INIT_STRING = "(java.lang.ThreadGroup,java.lang.String)>"; + public static final String INITIALIZE_SYSTEM_CLASS = + ""; + public static final String THREAD_GROUP_INIT = "()>"; + public static final String THREAD_EXIT = ""; + public static final String THREADGROUP_UNCAUGHT_EXCEPTION = + ""; + public static final String CLASSLOADER_INIT = "()>"; + public static final String CLASSLOADER_LOAD_CLASS_INTERNAL = + ""; + public static final String CLASSLOADER_CHECK_PACKAGE_ACC = + ""; + public static final String CLASSLOADER_ADD_CLASS = + ""; + public static final String CLASSLOADER_FIND_NATIVE = + ""; + public static final String PRIV_ACTION_EXC_INIT = + "(java.lang.Exception)>"; + public static final String RUN_FINALIZE = ""; + public static final String THREAD_INIT_RUNNABLE = + "(java.lang.ThreadGroup,java.lang.Runnable)>"; + public static final String THREAD_INIT_STRING = + "(java.lang.ThreadGroup,java.lang.String)>"; } - diff --git a/sootup.qilin/src/main/java/soot/Kind.java b/sootup.qilin/src/main/java/soot/Kind.java index cac962fe303..ca681735e9d 100644 --- a/sootup.qilin/src/main/java/soot/Kind.java +++ b/sootup.qilin/src/main/java/soot/Kind.java @@ -31,251 +31,231 @@ */ public final class Kind implements Numberable { - public static final Kind INVALID = new Kind("INVALID"); - /** - * Due to explicit invokestatic instruction. - */ - public static final Kind STATIC = new Kind("STATIC"); - /** - * Due to explicit invokevirtual instruction. - */ - public static final Kind VIRTUAL = new Kind("VIRTUAL"); - /** - * Due to explicit invokeinterface instruction. - */ - public static final Kind INTERFACE = new Kind("INTERFACE"); - /** - * Due to explicit invokespecial instruction. - */ - public static final Kind SPECIAL = new Kind("SPECIAL"); - /** - * Implicit call to static initializer. - */ - public static final Kind CLINIT = new Kind("CLINIT"); - /** - * Fake edges from our generic callback model. - */ - public static final Kind GENERIC_FAKE = new Kind("GENERIC_FAKE"); - /** - * Implicit call to Thread.run() due to Thread.start() call. - */ - public static final Kind THREAD = new Kind("THREAD"); - /** - * Implicit call to java.lang.Runnable.run() due to Executor.execute() call. - */ - public static final Kind EXECUTOR = new Kind("EXECUTOR"); - /** - * Implicit call to AsyncTask.doInBackground() due to AsyncTask.execute() call. - */ - public static final Kind ASYNCTASK = new Kind("ASYNCTASK"); - /** - * Implicit call to java.lang.ref.Finalizer.register from new bytecode. - */ - public static final Kind FINALIZE = new Kind("FINALIZE"); - /** - * Implicit call to Handler.handleMessage(android.os.Message) due to Handler.sendxxxxMessagexxxx() call. - */ - public static final Kind HANDLER = new Kind("HANDLER"); - /** - * Implicit call to finalize() from java.lang.ref.Finalizer.invokeFinalizeMethod(). - */ - public static final Kind INVOKE_FINALIZE = new Kind("INVOKE_FINALIZE"); - /** - * Implicit call to run() through AccessController.doPrivileged(). - */ - public static final Kind PRIVILEGED = new Kind("PRIVILEGED"); - /** - * Implicit call to constructor from java.lang.Class.newInstance(). - */ - public static final Kind NEWINSTANCE = new Kind("NEWINSTANCE"); - /** - * Due to call to Method.invoke(..). - */ - public static final Kind REFL_INVOKE = new Kind("REFL_METHOD_INVOKE"); - /** - * Due to call to Constructor.newInstance(..). - */ - public static final Kind REFL_CONSTR_NEWINSTANCE = new Kind("REFL_CONSTRUCTOR_NEWINSTANCE"); - /** - * Due to call to Class.newInstance(..) when reflection log is enabled. - */ - public static final Kind REFL_CLASS_NEWINSTANCE = new Kind("REFL_CLASS_NEWINSTANCE"); - - private final String name; - private int num; - - private Kind(String name) { - this.name = name; - } - - public String name() { - return name; - } - - @Override - public int getNumber() { - return num; - } - - @Override - public void setNumber(int num) { - this.num = num; - } - - @Override - public String toString() { - return name(); - } - - public boolean passesParameters() { - return passesParameters(this); - } - - public boolean isFake() { - return isFake(this); - } - - /** - * Returns true if the call is due to an explicit invoke statement. - */ - public boolean isExplicit() { - return isExplicit(this); - } - - /** - * Returns true if the call is due to an explicit instance invoke statement. - */ - public boolean isInstance() { - return isInstance(this); - } - - /** - * Returns true if the call is due to an explicit virtual invoke statement. - */ - public boolean isVirtual() { - return isVirtual(this); - } - - public boolean isSpecial() { - return isSpecial(this); - } - - /** - * Returns true if the call is to static initializer. - */ - public boolean isClinit() { - return isClinit(this); - } - - /** - * Returns true if the call is due to an explicit static invoke statement. - */ - public boolean isStatic() { - return isStatic(this); - } - - public boolean isThread() { - return isThread(this); - } - - public boolean isExecutor() { - return isExecutor(this); - } - - public boolean isAsyncTask() { - return isAsyncTask(this); - } - - public boolean isPrivileged() { - return isPrivileged(this); - } - - public boolean isReflection() { - return isReflection(this); - } - - public boolean isReflInvoke() { - return isReflInvoke(this); - } - - public boolean isHandler() { - return isHandler(this); - } - - public static boolean passesParameters(Kind k) { - return isExplicit(k) || k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == FINALIZE || k == PRIVILEGED - || k == NEWINSTANCE || k == INVOKE_FINALIZE || k == REFL_INVOKE || k == REFL_CONSTR_NEWINSTANCE - || k == REFL_CLASS_NEWINSTANCE || k == GENERIC_FAKE; - } - - public static boolean isFake(Kind k) { - return k == THREAD || k == EXECUTOR || k == ASYNCTASK || k == PRIVILEGED || k == HANDLER || k == GENERIC_FAKE; - } - - /** - * Returns true if the call is due to an explicit invoke statement. - */ - public static boolean isExplicit(Kind k) { - return isInstance(k) || isStatic(k); - } - - /** - * Returns true if the call is due to an explicit instance invoke statement. - */ - public static boolean isInstance(Kind k) { - return k == VIRTUAL || k == INTERFACE || k == SPECIAL; - } - - /** - * Returns true if the call is due to an explicit virtual invoke statement. - */ - public static boolean isVirtual(Kind k) { - return k == VIRTUAL; - } - - public static boolean isSpecial(Kind k) { - return k == SPECIAL; - } - - /** - * Returns true if the call is to static initializer. - */ - public static boolean isClinit(Kind k) { - return k == CLINIT; - } - - /** - * Returns true if the call is due to an explicit static invoke statement. - */ - public static boolean isStatic(Kind k) { - return k == STATIC; - } - - public static boolean isThread(Kind k) { - return k == THREAD; - } - - public static boolean isExecutor(Kind k) { - return k == EXECUTOR; - } - - public static boolean isAsyncTask(Kind k) { - return k == ASYNCTASK; - } - - public static boolean isPrivileged(Kind k) { - return k == PRIVILEGED; - } - - public static boolean isReflection(Kind k) { - return k == REFL_CLASS_NEWINSTANCE || k == REFL_CONSTR_NEWINSTANCE || k == REFL_INVOKE; - } - - public static boolean isReflInvoke(Kind k) { - return k == REFL_INVOKE; - } - - public static boolean isHandler(Kind k) { - return k == HANDLER; - } + public static final Kind INVALID = new Kind("INVALID"); + + /** Due to explicit invokestatic instruction. */ + public static final Kind STATIC = new Kind("STATIC"); + + /** Due to explicit invokevirtual instruction. */ + public static final Kind VIRTUAL = new Kind("VIRTUAL"); + + /** Due to explicit invokeinterface instruction. */ + public static final Kind INTERFACE = new Kind("INTERFACE"); + + /** Due to explicit invokespecial instruction. */ + public static final Kind SPECIAL = new Kind("SPECIAL"); + + /** Implicit call to static initializer. */ + public static final Kind CLINIT = new Kind("CLINIT"); + + /** Fake edges from our generic callback model. */ + public static final Kind GENERIC_FAKE = new Kind("GENERIC_FAKE"); + + /** Implicit call to Thread.run() due to Thread.start() call. */ + public static final Kind THREAD = new Kind("THREAD"); + + /** Implicit call to java.lang.Runnable.run() due to Executor.execute() call. */ + public static final Kind EXECUTOR = new Kind("EXECUTOR"); + + /** Implicit call to AsyncTask.doInBackground() due to AsyncTask.execute() call. */ + public static final Kind ASYNCTASK = new Kind("ASYNCTASK"); + + /** Implicit call to java.lang.ref.Finalizer.register from new bytecode. */ + public static final Kind FINALIZE = new Kind("FINALIZE"); + + /** + * Implicit call to Handler.handleMessage(android.os.Message) due to Handler.sendxxxxMessagexxxx() + * call. + */ + public static final Kind HANDLER = new Kind("HANDLER"); + + /** Implicit call to finalize() from java.lang.ref.Finalizer.invokeFinalizeMethod(). */ + public static final Kind INVOKE_FINALIZE = new Kind("INVOKE_FINALIZE"); + + /** Implicit call to run() through AccessController.doPrivileged(). */ + public static final Kind PRIVILEGED = new Kind("PRIVILEGED"); + + /** Implicit call to constructor from java.lang.Class.newInstance(). */ + public static final Kind NEWINSTANCE = new Kind("NEWINSTANCE"); + + /** Due to call to Method.invoke(..). */ + public static final Kind REFL_INVOKE = new Kind("REFL_METHOD_INVOKE"); + + /** Due to call to Constructor.newInstance(..). */ + public static final Kind REFL_CONSTR_NEWINSTANCE = new Kind("REFL_CONSTRUCTOR_NEWINSTANCE"); + + /** Due to call to Class.newInstance(..) when reflection log is enabled. */ + public static final Kind REFL_CLASS_NEWINSTANCE = new Kind("REFL_CLASS_NEWINSTANCE"); + + private final String name; + private int num; + + private Kind(String name) { + this.name = name; + } + + public String name() { + return name; + } + + @Override + public int getNumber() { + return num; + } + + @Override + public void setNumber(int num) { + this.num = num; + } + + @Override + public String toString() { + return name(); + } + + public boolean passesParameters() { + return passesParameters(this); + } + + public boolean isFake() { + return isFake(this); + } + + /** Returns true if the call is due to an explicit invoke statement. */ + public boolean isExplicit() { + return isExplicit(this); + } + + /** Returns true if the call is due to an explicit instance invoke statement. */ + public boolean isInstance() { + return isInstance(this); + } + + /** Returns true if the call is due to an explicit virtual invoke statement. */ + public boolean isVirtual() { + return isVirtual(this); + } + + public boolean isSpecial() { + return isSpecial(this); + } + + /** Returns true if the call is to static initializer. */ + public boolean isClinit() { + return isClinit(this); + } + + /** Returns true if the call is due to an explicit static invoke statement. */ + public boolean isStatic() { + return isStatic(this); + } + + public boolean isThread() { + return isThread(this); + } + + public boolean isExecutor() { + return isExecutor(this); + } + + public boolean isAsyncTask() { + return isAsyncTask(this); + } + + public boolean isPrivileged() { + return isPrivileged(this); + } + + public boolean isReflection() { + return isReflection(this); + } + + public boolean isReflInvoke() { + return isReflInvoke(this); + } + + public boolean isHandler() { + return isHandler(this); + } + + public static boolean passesParameters(Kind k) { + return isExplicit(k) + || k == THREAD + || k == EXECUTOR + || k == ASYNCTASK + || k == FINALIZE + || k == PRIVILEGED + || k == NEWINSTANCE + || k == INVOKE_FINALIZE + || k == REFL_INVOKE + || k == REFL_CONSTR_NEWINSTANCE + || k == REFL_CLASS_NEWINSTANCE + || k == GENERIC_FAKE; + } + + public static boolean isFake(Kind k) { + return k == THREAD + || k == EXECUTOR + || k == ASYNCTASK + || k == PRIVILEGED + || k == HANDLER + || k == GENERIC_FAKE; + } + + /** Returns true if the call is due to an explicit invoke statement. */ + public static boolean isExplicit(Kind k) { + return isInstance(k) || isStatic(k); + } + + /** Returns true if the call is due to an explicit instance invoke statement. */ + public static boolean isInstance(Kind k) { + return k == VIRTUAL || k == INTERFACE || k == SPECIAL; + } + + /** Returns true if the call is due to an explicit virtual invoke statement. */ + public static boolean isVirtual(Kind k) { + return k == VIRTUAL; + } + + public static boolean isSpecial(Kind k) { + return k == SPECIAL; + } + + /** Returns true if the call is to static initializer. */ + public static boolean isClinit(Kind k) { + return k == CLINIT; + } + + /** Returns true if the call is due to an explicit static invoke statement. */ + public static boolean isStatic(Kind k) { + return k == STATIC; + } + + public static boolean isThread(Kind k) { + return k == THREAD; + } + + public static boolean isExecutor(Kind k) { + return k == EXECUTOR; + } + + public static boolean isAsyncTask(Kind k) { + return k == ASYNCTASK; + } + + public static boolean isPrivileged(Kind k) { + return k == PRIVILEGED; + } + + public static boolean isReflection(Kind k) { + return k == REFL_CLASS_NEWINSTANCE || k == REFL_CONSTR_NEWINSTANCE || k == REFL_INVOKE; + } + + public static boolean isReflInvoke(Kind k) { + return k == REFL_INVOKE; + } + + public static boolean isHandler(Kind k) { + return k == HANDLER; + } } diff --git a/sootup.qilin/src/main/java/soot/MethodOrMethodContext.java b/sootup.qilin/src/main/java/soot/MethodOrMethodContext.java index 9b765866cc4..93e84f69077 100644 --- a/sootup.qilin/src/main/java/soot/MethodOrMethodContext.java +++ b/sootup.qilin/src/main/java/soot/MethodOrMethodContext.java @@ -30,8 +30,7 @@ * @author Ondrej Lhotak */ public interface MethodOrMethodContext { - public SootMethod method(); + public SootMethod method(); - public Context context(); + public Context context(); } - diff --git a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java index c3ba1c88374..0550d14f9eb 100644 --- a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java +++ b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java @@ -1,8 +1,5 @@ package soot.jimple.toolkits.callgraph; -import java.util.Collection; -import java.util.HashSet; - /*- * #%L * Soot - a J*va Optimization Framework @@ -25,12 +22,13 @@ * #L% */ +import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; - import soot.Kind; import soot.MethodOrMethodContext; import soot.util.queue.ChunkedQueue; @@ -39,375 +37,366 @@ import sootup.core.model.SootMethod; /** - * Represents the edges in a call graph. This class is meant to act as only a container of edges; code for various call graph - * builders should be kept out of it, as well as most code for accessing the edges. + * Represents the edges in a call graph. This class is meant to act as only a container of edges; + * code for various call graph builders should be kept out of it, as well as most code for accessing + * the edges. * * @author Ondrej Lhotak */ public class CallGraph implements Iterable { - protected Set edges = new LinkedHashSet(); - protected ChunkedQueue stream = new ChunkedQueue(); - protected QueueReader reader = stream.reader(); - protected Map srcMethodToEdge = new LinkedHashMap(); - protected Map srcUnitToEdge = new LinkedHashMap(); - protected Map tgtToEdge = new LinkedHashMap(); - protected Edge dummy = new Edge(null, null, null, Kind.INVALID); - - /** - * Used to add an edge to the call graph. Returns true iff the edge was not already present. - */ - public boolean addEdge(Edge e) { - if (!edges.add(e)) { - return false; - } - - stream.add(e); - - Edge position = srcUnitToEdge.get(e.srcUnit()); - if (position == null) { - srcUnitToEdge.put(e.srcUnit(), e); - position = dummy; - } - e.insertAfterByUnit(position); - - position = srcMethodToEdge.get(e.getSrc()); - if (position == null) { - srcMethodToEdge.put(e.getSrc(), e); - position = dummy; - } - e.insertAfterBySrc(position); - - position = tgtToEdge.get(e.getTgt()); - if (position == null) { - tgtToEdge.put(e.getTgt(), e); - position = dummy; - } - e.insertAfterByTgt(position); - return true; + protected Set edges = new LinkedHashSet(); + protected ChunkedQueue stream = new ChunkedQueue(); + protected QueueReader reader = stream.reader(); + protected Map srcMethodToEdge = + new LinkedHashMap(); + protected Map srcUnitToEdge = new LinkedHashMap(); + protected Map tgtToEdge = + new LinkedHashMap(); + protected Edge dummy = new Edge(null, null, null, Kind.INVALID); + + /** Used to add an edge to the call graph. Returns true iff the edge was not already present. */ + public boolean addEdge(Edge e) { + if (!edges.add(e)) { + return false; } - /** - * Removes all outgoing edges that start at the given unit - * - * @param u - * The unit from which to remove all outgoing edges - * @return True if at least one edge has been removed, otherwise false - */ - public boolean removeAllEdgesOutOf(Stmt u) { - boolean hasRemoved = false; - Set edgesToRemove = new HashSet<>(); - for (QueueReader edgeRdr = listener(); edgeRdr.hasNext();) { - Edge e = edgeRdr.next(); - if (e.srcUnit() == u) { - e.remove(); - removeEdge(e, false); - edgesToRemove.add(e); - hasRemoved = true; - } - } - if (hasRemoved) { - reader.remove(edgesToRemove); - } - return hasRemoved; - } + stream.add(e); - /** - * Swaps an invocation statement. All edges that previously went from the given statement to some callee now go from the - * new statement to the same callee. This method is intended to be used when a Jimple statement is replaced, but the - * replacement does not semantically affect the edges. - * - * @param out - * The old statement - * @param in - * The new statement - * @return True if at least one edge was affected by this operation - */ - public boolean swapEdgesOutOf(Stmt out, Stmt in) { - boolean hasSwapped = false; - for (Iterator edgeRdr = edgesOutOf(out); edgeRdr.hasNext();) { - Edge e = edgeRdr.next(); - MethodOrMethodContext src = e.getSrc(); - MethodOrMethodContext tgt = e.getTgt(); - removeEdge(e); - e.remove(); - addEdge(new Edge(src, in, tgt)); - hasSwapped = true; - } - return hasSwapped; + Edge position = srcUnitToEdge.get(e.srcUnit()); + if (position == null) { + srcUnitToEdge.put(e.srcUnit(), e); + position = dummy; } + e.insertAfterByUnit(position); - /** - * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. - */ - public boolean removeEdge(Edge e) { - return removeEdge(e, true); + position = srcMethodToEdge.get(e.getSrc()); + if (position == null) { + srcMethodToEdge.put(e.getSrc(), e); + position = dummy; } + e.insertAfterBySrc(position); - /** - * Removes the edge e from the call graph. Returns true iff the edge was originally present in the call graph. - * - * @param e - * the edge - * @param removeInEdgeList - * when true (recommended), it is ensured that the edge reader is informed about the removal - * @return whether the removal was successful. - */ - public boolean removeEdge(Edge e, boolean removeInEdgeList) { - if (!edges.remove(e)) { - return false; - } + position = tgtToEdge.get(e.getTgt()); + if (position == null) { + tgtToEdge.put(e.getTgt(), e); + position = dummy; + } + e.insertAfterByTgt(position); + return true; + } + + /** + * Removes all outgoing edges that start at the given unit + * + * @param u The unit from which to remove all outgoing edges + * @return True if at least one edge has been removed, otherwise false + */ + public boolean removeAllEdgesOutOf(Stmt u) { + boolean hasRemoved = false; + Set edgesToRemove = new HashSet<>(); + for (QueueReader edgeRdr = listener(); edgeRdr.hasNext(); ) { + Edge e = edgeRdr.next(); + if (e.srcUnit() == u) { e.remove(); - - if (srcUnitToEdge.get(e.srcUnit()) == e) { - if (e.nextByUnit().srcUnit() == e.srcUnit()) { - srcUnitToEdge.put(e.srcUnit(), e.nextByUnit()); - } else { - srcUnitToEdge.remove(e.srcUnit()); - } - } - - if (srcMethodToEdge.get(e.getSrc()) == e) { - if (e.nextBySrc().getSrc() == e.getSrc()) { - srcMethodToEdge.put(e.getSrc(), e.nextBySrc()); - } else { - srcMethodToEdge.remove(e.getSrc()); - } - } - - if (tgtToEdge.get(e.getTgt()) == e) { - if (e.nextByTgt().getTgt() == e.getTgt()) { - tgtToEdge.put(e.getTgt(), e.nextByTgt()); - } else { - tgtToEdge.remove(e.getTgt()); - } - } - // This is an linear operation, so we want to avoid it if possible. - if (removeInEdgeList) { - reader.remove(e); - } - return true; + removeEdge(e, false); + edgesToRemove.add(e); + hasRemoved = true; + } } - - /** - * Removes the edges from the call graph. Returns true iff one edge was originally present in the call graph. - * - * @param edges - * the edges - * @return whether the removal was successful. - */ - public boolean removeEdges(Collection edges) { - if (!this.edges.removeAll(edges)) { - return false; - } - for (Edge e : edges) { - removeEdge(e, false); - } - reader.remove(edges); - return true; + if (hasRemoved) { + reader.remove(edgesToRemove); } - - /** - * Does this method have no incoming edge? - * - * @param method - * @return - */ - public boolean isEntryMethod(SootMethod method) { - return !tgtToEdge.containsKey(method); + return hasRemoved; + } + + /** + * Swaps an invocation statement. All edges that previously went from the given statement to some + * callee now go from the new statement to the same callee. This method is intended to be used + * when a Jimple statement is replaced, but the replacement does not semantically affect the + * edges. + * + * @param out The old statement + * @param in The new statement + * @return True if at least one edge was affected by this operation + */ + public boolean swapEdgesOutOf(Stmt out, Stmt in) { + boolean hasSwapped = false; + for (Iterator edgeRdr = edgesOutOf(out); edgeRdr.hasNext(); ) { + Edge e = edgeRdr.next(); + MethodOrMethodContext src = e.getSrc(); + MethodOrMethodContext tgt = e.getTgt(); + removeEdge(e); + e.remove(); + addEdge(new Edge(src, in, tgt)); + hasSwapped = true; } - - /** - * Find the specific call edge that is going out from the callsite u and the call target is callee. Without advanced data - * structure, we can only sequentially search for the match. Fortunately, the number of outgoing edges for a unit is not - * too large. - * - * @param u - * @param callee - * @return - */ - public Edge findEdge(Stmt u, SootMethod callee) { - Edge e = srcUnitToEdge.get(u); - if (e != null) { - while (e.srcUnit() == u && e.kind() != Kind.INVALID) { - if (e.tgt() == callee) { - return e; - } - e = e.nextByUnit(); - } - } - return null; + return hasSwapped; + } + + /** + * Removes the edge e from the call graph. Returns true iff the edge was originally present in the + * call graph. + */ + public boolean removeEdge(Edge e) { + return removeEdge(e, true); + } + + /** + * Removes the edge e from the call graph. Returns true iff the edge was originally present in the + * call graph. + * + * @param e the edge + * @param removeInEdgeList when true (recommended), it is ensured that the edge reader is informed + * about the removal + * @return whether the removal was successful. + */ + public boolean removeEdge(Edge e, boolean removeInEdgeList) { + if (!edges.remove(e)) { + return false; } - - /** - * Returns an iterator over all methods that are the sources of at least one edge. - */ - public Iterator sourceMethods() { - return srcMethodToEdge.keySet().iterator(); + e.remove(); + + if (srcUnitToEdge.get(e.srcUnit()) == e) { + if (e.nextByUnit().srcUnit() == e.srcUnit()) { + srcUnitToEdge.put(e.srcUnit(), e.nextByUnit()); + } else { + srcUnitToEdge.remove(e.srcUnit()); + } } - /** - * Returns an iterator over all edges that have u as their source unit. - */ - public Iterator edgesOutOf(Stmt u) { - return new TargetsOfUnitIterator(u); + if (srcMethodToEdge.get(e.getSrc()) == e) { + if (e.nextBySrc().getSrc() == e.getSrc()) { + srcMethodToEdge.put(e.getSrc(), e.nextBySrc()); + } else { + srcMethodToEdge.remove(e.getSrc()); + } } - class TargetsOfUnitIterator implements Iterator { - private final Stmt u; - private Edge position; - - TargetsOfUnitIterator(Stmt u) { - this.u = u; - if (u == null) { - throw new RuntimeException(); - } - this.position = srcUnitToEdge.get(u); - if (position == null) { - position = dummy; - } - } - - @Override - public boolean hasNext() { - if (position.srcUnit() != u) { - return false; - } - return position.kind() != Kind.INVALID; - } - - @Override - public Edge next() { - Edge ret = position; - position = position.nextByUnit(); - return ret; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } + if (tgtToEdge.get(e.getTgt()) == e) { + if (e.nextByTgt().getTgt() == e.getTgt()) { + tgtToEdge.put(e.getTgt(), e.nextByTgt()); + } else { + tgtToEdge.remove(e.getTgt()); + } } - - /** - * Returns an iterator over all edges that have m as their source method. - */ - public Iterator edgesOutOf(MethodOrMethodContext m) { - return new TargetsOfMethodIterator(m); + // This is an linear operation, so we want to avoid it if possible. + if (removeInEdgeList) { + reader.remove(e); } - - class TargetsOfMethodIterator implements Iterator { - private final MethodOrMethodContext m; - private Edge position; - - TargetsOfMethodIterator(MethodOrMethodContext m) { - this.m = m; - if (m == null) { - throw new RuntimeException(); - } - this.position = srcMethodToEdge.get(m); - if (position == null) { - position = dummy; - } - } - - @Override - public boolean hasNext() { - if (position.getSrc() != m) { - return false; - } - return position.kind() != Kind.INVALID; - } - - @Override - public Edge next() { - Edge ret = position; - position = position.nextBySrc(); - return ret; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); + return true; + } + + /** + * Removes the edges from the call graph. Returns true iff one edge was originally present in the + * call graph. + * + * @param edges the edges + * @return whether the removal was successful. + */ + public boolean removeEdges(Collection edges) { + if (!this.edges.removeAll(edges)) { + return false; + } + for (Edge e : edges) { + removeEdge(e, false); + } + reader.remove(edges); + return true; + } + + /** + * Does this method have no incoming edge? + * + * @param method + * @return + */ + public boolean isEntryMethod(SootMethod method) { + return !tgtToEdge.containsKey(method); + } + + /** + * Find the specific call edge that is going out from the callsite u and the call target is + * callee. Without advanced data structure, we can only sequentially search for the match. + * Fortunately, the number of outgoing edges for a unit is not too large. + * + * @param u + * @param callee + * @return + */ + public Edge findEdge(Stmt u, SootMethod callee) { + Edge e = srcUnitToEdge.get(u); + if (e != null) { + while (e.srcUnit() == u && e.kind() != Kind.INVALID) { + if (e.tgt() == callee) { + return e; } + e = e.nextByUnit(); + } } - - /** - * Returns an iterator over all edges that have m as their target method. - */ - public Iterator edgesInto(MethodOrMethodContext m) { - return new CallersOfMethodIterator(m); + return null; + } + + /** Returns an iterator over all methods that are the sources of at least one edge. */ + public Iterator sourceMethods() { + return srcMethodToEdge.keySet().iterator(); + } + + /** Returns an iterator over all edges that have u as their source unit. */ + public Iterator edgesOutOf(Stmt u) { + return new TargetsOfUnitIterator(u); + } + + class TargetsOfUnitIterator implements Iterator { + private final Stmt u; + private Edge position; + + TargetsOfUnitIterator(Stmt u) { + this.u = u; + if (u == null) { + throw new RuntimeException(); + } + this.position = srcUnitToEdge.get(u); + if (position == null) { + position = dummy; + } } - class CallersOfMethodIterator implements Iterator { - private final MethodOrMethodContext m; - private Edge position; - - CallersOfMethodIterator(MethodOrMethodContext m) { - this.m = m; - if (m == null) { - throw new RuntimeException(); - } - this.position = tgtToEdge.get(m); - if (position == null) { - position = dummy; - } - } + @Override + public boolean hasNext() { + if (position.srcUnit() != u) { + return false; + } + return position.kind() != Kind.INVALID; + } - @Override - public boolean hasNext() { - if (position.getTgt() != m) { - return false; - } - return position.kind() != Kind.INVALID; - } + @Override + public Edge next() { + Edge ret = position; + position = position.nextByUnit(); + return ret; + } - @Override - public Edge next() { - Edge ret = position; - position = position.nextByTgt(); - return ret; - } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** Returns an iterator over all edges that have m as their source method. */ + public Iterator edgesOutOf(MethodOrMethodContext m) { + return new TargetsOfMethodIterator(m); + } + + class TargetsOfMethodIterator implements Iterator { + private final MethodOrMethodContext m; + private Edge position; + + TargetsOfMethodIterator(MethodOrMethodContext m) { + this.m = m; + if (m == null) { + throw new RuntimeException(); + } + this.position = srcMethodToEdge.get(m); + if (position == null) { + position = dummy; + } + } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } + @Override + public boolean hasNext() { + if (position.getSrc() != m) { + return false; + } + return position.kind() != Kind.INVALID; } - /** - * Returns a QueueReader object containing all edges added so far, and which will be informed of any new edges that are - * later added to the graph. - */ - public QueueReader listener() { - return reader.clone(); + @Override + public Edge next() { + Edge ret = position; + position = position.nextBySrc(); + return ret; } - /** - * Returns a QueueReader object which will contain ONLY NEW edges which will be added to the graph. - */ - public QueueReader newListener() { - return stream.reader(); + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** Returns an iterator over all edges that have m as their target method. */ + public Iterator edgesInto(MethodOrMethodContext m) { + return new CallersOfMethodIterator(m); + } + + class CallersOfMethodIterator implements Iterator { + private final MethodOrMethodContext m; + private Edge position; + + CallersOfMethodIterator(MethodOrMethodContext m) { + this.m = m; + if (m == null) { + throw new RuntimeException(); + } + this.position = tgtToEdge.get(m); + if (position == null) { + position = dummy; + } } @Override - public String toString() { - StringBuilder out = new StringBuilder(); - for (QueueReader reader = listener(); reader.hasNext();) { - Edge e = reader.next(); - out.append(e.toString()).append('\n'); - } - return out.toString(); + public boolean hasNext() { + if (position.getTgt() != m) { + return false; + } + return position.kind() != Kind.INVALID; } - /** - * Returns the number of edges in the call graph. - */ - public int size() { - return edges.size(); + @Override + public Edge next() { + Edge ret = position; + position = position.nextByTgt(); + return ret; } @Override - public Iterator iterator() { - return edges.iterator(); + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Returns a QueueReader object containing all edges added so far, and which will be informed of + * any new edges that are later added to the graph. + */ + public QueueReader listener() { + return reader.clone(); + } + + /** + * Returns a QueueReader object which will contain ONLY NEW edges which will be added to the + * graph. + */ + public QueueReader newListener() { + return stream.reader(); + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + for (QueueReader reader = listener(); reader.hasNext(); ) { + Edge e = reader.next(); + out.append(e.toString()).append('\n'); } + return out.toString(); + } + + /** Returns the number of edges in the call graph. */ + public int size() { + return edges.size(); + } + + @Override + public Iterator iterator() { + return edges.iterator(); + } } diff --git a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java index 972b95737a9..09590f522f8 100644 --- a/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java +++ b/sootup.qilin/src/main/java/soot/jimple/toolkits/callgraph/Edge.java @@ -41,263 +41,252 @@ */ public final class Edge implements Invalidable { - /** - * The method in which the call occurs; may be null for calls not occurring in a specific method (eg. implicit calls by the - * VM) - */ - private MethodOrMethodContext src; - - /** - * The target method of the call edge. - */ - private MethodOrMethodContext tgt; - - /** - * The unit at which the call occurs; may be null for calls not occurring at a specific statement (eg. calls in native - * code) - */ - private Stmt srcUnit; - - /** - * The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as isExplicit() should be - * added. - */ - private final Kind kind; - - private boolean invalid = false; - - public Edge(MethodOrMethodContext src, Stmt srcUnit, MethodOrMethodContext tgt, Kind kind) { - this.src = src; - this.srcUnit = srcUnit; - this.tgt = tgt; - this.kind = kind; - } - - public Edge(MethodOrMethodContext src, Stmt srcUnit, MethodOrMethodContext tgt) { - this.kind = ieToKind(srcUnit.getInvokeExpr()); - this.src = src; - this.srcUnit = srcUnit; - this.tgt = tgt; - } - - public SootMethod src() { - return (src == null) ? null : src.method(); - } - - public Context srcCtxt() { - return (src == null) ? null : src.context(); - } - - public MethodOrMethodContext getSrc() { - return src; - } - - public Stmt srcUnit() { - return srcUnit; - } - - public Stmt srcStmt() { - return srcUnit; - } - - public SootMethod tgt() { - return (tgt == null) ? null : tgt.method(); - } - - public Context tgtCtxt() { - return (tgt == null) ? null : tgt.context(); - } - - public MethodOrMethodContext getTgt() { - return tgt; - } - - public Kind kind() { - return kind; - } - - public static Kind ieToKind(AbstractInvokeExpr ie) { - if (ie instanceof JVirtualInvokeExpr) { - return Kind.VIRTUAL; - } else if (ie instanceof JSpecialInvokeExpr) { - return Kind.SPECIAL; - } else if (ie instanceof JInterfaceInvokeExpr) { - return Kind.INTERFACE; - } else if (ie instanceof JStaticInvokeExpr) { - return Kind.STATIC; - } else { - throw new RuntimeException(); - } - } - - /** - * Returns true if the call is due to an explicit invoke statement. - */ - public boolean isExplicit() { - return Kind.isExplicit(this.kind); - } - - /** - * Returns true if the call is due to an explicit instance invoke statement. - */ - public boolean isInstance() { - return Kind.isInstance(this.kind); - } - - public boolean isVirtual() { - return Kind.isVirtual(this.kind); - } - - public boolean isSpecial() { - return Kind.isSpecial(this.kind); - } - - /** - * Returns true if the call is to static initializer. - */ - public boolean isClinit() { - return Kind.isClinit(this.kind); - } - - /** - * Returns true if the call is due to an explicit static invoke statement. - */ - public boolean isStatic() { - return Kind.isStatic(this.kind); - } - - public boolean isThreadRunCall() { - return Kind.isThread(this.kind); - } - - public boolean passesParameters() { - return Kind.passesParameters(this.kind); - } - - @Override - public boolean isInvalid() { - return invalid; - } - - @Override - public void invalidate() { - // Since the edge remains in the QueueReaders for a while, the GC could not claim old units. - src = null; - srcUnit = null; - tgt = null; - invalid = true; - } - - @Override - public int hashCode() { - if (invalid) { - return 0; - } - int ret = (tgt.hashCode() + 20) + (kind == null ? 0 : kind.getNumber()); - if (src != null) { - ret = ret * 32 + src.hashCode(); - } - if (srcUnit != null) { - ret = ret * 32 + srcUnit.hashCode(); - } - return ret; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof Edge)) { - return false; - } - Edge o = (Edge) other; - return (o.src == this.src) && (o.srcUnit == srcUnit) && (o.tgt == tgt) && (o.kind == kind); - } - - @Override - public String toString() { - return String.valueOf(this.kind) + " edge: " + srcUnit + " in " + src + " ==> " + tgt; - } - - private Edge nextByUnit = this; - private Edge prevByUnit = this; - private Edge nextBySrc = this; - private Edge prevBySrc = this; - private Edge nextByTgt = this; - private Edge prevByTgt = this; - - void insertAfterByUnit(Edge other) { - nextByUnit = other.nextByUnit; - nextByUnit.prevByUnit = this; - other.nextByUnit = this; - prevByUnit = other; - } - - void insertAfterBySrc(Edge other) { - nextBySrc = other.nextBySrc; - nextBySrc.prevBySrc = this; - other.nextBySrc = this; - prevBySrc = other; - } - - void insertAfterByTgt(Edge other) { - nextByTgt = other.nextByTgt; - nextByTgt.prevByTgt = this; - other.nextByTgt = this; - prevByTgt = other; - } - - void insertBeforeByUnit(Edge other) { - prevByUnit = other.prevByUnit; - prevByUnit.nextByUnit = this; - other.prevByUnit = this; - nextByUnit = other; - } - - void insertBeforeBySrc(Edge other) { - prevBySrc = other.prevBySrc; - prevBySrc.nextBySrc = this; - other.prevBySrc = this; - nextBySrc = other; - } - - void insertBeforeByTgt(Edge other) { - prevByTgt = other.prevByTgt; - prevByTgt.nextByTgt = this; - other.prevByTgt = this; - nextByTgt = other; - } - - void remove() { - invalid = true; - nextByUnit.prevByUnit = prevByUnit; - prevByUnit.nextByUnit = nextByUnit; - nextBySrc.prevBySrc = prevBySrc; - prevBySrc.nextBySrc = nextBySrc; - nextByTgt.prevByTgt = prevByTgt; - prevByTgt.nextByTgt = nextByTgt; - } - - Edge nextByUnit() { - return nextByUnit; - } - - Edge nextBySrc() { - return nextBySrc; - } - - Edge nextByTgt() { - return nextByTgt; - } - - Edge prevByUnit() { - return prevByUnit; - } - - Edge prevBySrc() { - return prevBySrc; - } - - Edge prevByTgt() { - return prevByTgt; - } + /** + * The method in which the call occurs; may be null for calls not occurring in a specific method + * (eg. implicit calls by the VM) + */ + private MethodOrMethodContext src; + + /** The target method of the call edge. */ + private MethodOrMethodContext tgt; + + /** + * The unit at which the call occurs; may be null for calls not occurring at a specific statement + * (eg. calls in native code) + */ + private Stmt srcUnit; + + /** + * The kind of edge. Note: kind should not be tested by other classes; instead, accessors such as + * isExplicit() should be added. + */ + private final Kind kind; + + private boolean invalid = false; + + public Edge(MethodOrMethodContext src, Stmt srcUnit, MethodOrMethodContext tgt, Kind kind) { + this.src = src; + this.srcUnit = srcUnit; + this.tgt = tgt; + this.kind = kind; + } + + public Edge(MethodOrMethodContext src, Stmt srcUnit, MethodOrMethodContext tgt) { + this.kind = ieToKind(srcUnit.getInvokeExpr()); + this.src = src; + this.srcUnit = srcUnit; + this.tgt = tgt; + } + + public SootMethod src() { + return (src == null) ? null : src.method(); + } + + public Context srcCtxt() { + return (src == null) ? null : src.context(); + } + + public MethodOrMethodContext getSrc() { + return src; + } + + public Stmt srcUnit() { + return srcUnit; + } + + public Stmt srcStmt() { + return srcUnit; + } + + public SootMethod tgt() { + return (tgt == null) ? null : tgt.method(); + } + + public Context tgtCtxt() { + return (tgt == null) ? null : tgt.context(); + } + + public MethodOrMethodContext getTgt() { + return tgt; + } + + public Kind kind() { + return kind; + } + + public static Kind ieToKind(AbstractInvokeExpr ie) { + if (ie instanceof JVirtualInvokeExpr) { + return Kind.VIRTUAL; + } else if (ie instanceof JSpecialInvokeExpr) { + return Kind.SPECIAL; + } else if (ie instanceof JInterfaceInvokeExpr) { + return Kind.INTERFACE; + } else if (ie instanceof JStaticInvokeExpr) { + return Kind.STATIC; + } else { + throw new RuntimeException(); + } + } + + /** Returns true if the call is due to an explicit invoke statement. */ + public boolean isExplicit() { + return Kind.isExplicit(this.kind); + } + + /** Returns true if the call is due to an explicit instance invoke statement. */ + public boolean isInstance() { + return Kind.isInstance(this.kind); + } + + public boolean isVirtual() { + return Kind.isVirtual(this.kind); + } + + public boolean isSpecial() { + return Kind.isSpecial(this.kind); + } + + /** Returns true if the call is to static initializer. */ + public boolean isClinit() { + return Kind.isClinit(this.kind); + } + + /** Returns true if the call is due to an explicit static invoke statement. */ + public boolean isStatic() { + return Kind.isStatic(this.kind); + } + + public boolean isThreadRunCall() { + return Kind.isThread(this.kind); + } + + public boolean passesParameters() { + return Kind.passesParameters(this.kind); + } + + @Override + public boolean isInvalid() { + return invalid; + } + + @Override + public void invalidate() { + // Since the edge remains in the QueueReaders for a while, the GC could not claim old units. + src = null; + srcUnit = null; + tgt = null; + invalid = true; + } + + @Override + public int hashCode() { + if (invalid) { + return 0; + } + int ret = (tgt.hashCode() + 20) + (kind == null ? 0 : kind.getNumber()); + if (src != null) { + ret = ret * 32 + src.hashCode(); + } + if (srcUnit != null) { + ret = ret * 32 + srcUnit.hashCode(); + } + return ret; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Edge)) { + return false; + } + Edge o = (Edge) other; + return (o.src == this.src) && (o.srcUnit == srcUnit) && (o.tgt == tgt) && (o.kind == kind); + } + + @Override + public String toString() { + return String.valueOf(this.kind) + " edge: " + srcUnit + " in " + src + " ==> " + tgt; + } + + private Edge nextByUnit = this; + private Edge prevByUnit = this; + private Edge nextBySrc = this; + private Edge prevBySrc = this; + private Edge nextByTgt = this; + private Edge prevByTgt = this; + + void insertAfterByUnit(Edge other) { + nextByUnit = other.nextByUnit; + nextByUnit.prevByUnit = this; + other.nextByUnit = this; + prevByUnit = other; + } + + void insertAfterBySrc(Edge other) { + nextBySrc = other.nextBySrc; + nextBySrc.prevBySrc = this; + other.nextBySrc = this; + prevBySrc = other; + } + + void insertAfterByTgt(Edge other) { + nextByTgt = other.nextByTgt; + nextByTgt.prevByTgt = this; + other.nextByTgt = this; + prevByTgt = other; + } + + void insertBeforeByUnit(Edge other) { + prevByUnit = other.prevByUnit; + prevByUnit.nextByUnit = this; + other.prevByUnit = this; + nextByUnit = other; + } + + void insertBeforeBySrc(Edge other) { + prevBySrc = other.prevBySrc; + prevBySrc.nextBySrc = this; + other.prevBySrc = this; + nextBySrc = other; + } + + void insertBeforeByTgt(Edge other) { + prevByTgt = other.prevByTgt; + prevByTgt.nextByTgt = this; + other.prevByTgt = this; + nextByTgt = other; + } + + void remove() { + invalid = true; + nextByUnit.prevByUnit = prevByUnit; + prevByUnit.nextByUnit = nextByUnit; + nextBySrc.prevBySrc = prevBySrc; + prevBySrc.nextBySrc = nextBySrc; + nextByTgt.prevByTgt = prevByTgt; + prevByTgt.nextByTgt = nextByTgt; + } + + Edge nextByUnit() { + return nextByUnit; + } + + Edge nextBySrc() { + return nextBySrc; + } + + Edge nextByTgt() { + return nextByTgt; + } + + Edge prevByUnit() { + return prevByUnit; + } + + Edge prevBySrc() { + return prevBySrc; + } + + Edge prevByTgt() { + return prevByTgt; + } } - diff --git a/sootup.qilin/src/main/java/soot/util/ArrayNumberer.java b/sootup.qilin/src/main/java/soot/util/ArrayNumberer.java index ca2a95159b9..9fe868ff6eb 100644 --- a/sootup.qilin/src/main/java/soot/util/ArrayNumberer.java +++ b/sootup.qilin/src/main/java/soot/util/ArrayNumberer.java @@ -35,120 +35,120 @@ */ public class ArrayNumberer implements IterableNumberer { - protected E[] numberToObj; - protected int lastNumber; - protected BitSet freeNumbers; - - @SuppressWarnings("unchecked") - public ArrayNumberer() { - this.numberToObj = (E[]) new Numberable[1024]; - this.lastNumber = 0; + protected E[] numberToObj; + protected int lastNumber; + protected BitSet freeNumbers; + + @SuppressWarnings("unchecked") + public ArrayNumberer() { + this.numberToObj = (E[]) new Numberable[1024]; + this.lastNumber = 0; + } + + public ArrayNumberer(E[] elements) { + this.numberToObj = elements; + this.lastNumber = elements.length; + } + + private void resize(int n) { + numberToObj = Arrays.copyOf(numberToObj, n); + } + + @Override + public synchronized void add(E o) { + if (o.getNumber() != 0) { + return; } - public ArrayNumberer(E[] elements) { - this.numberToObj = elements; - this.lastNumber = elements.length; + // In case we removed entries from the numberer, we want to re-use the free space + int chosenNumber = -1; + if (freeNumbers != null) { + int ns = freeNumbers.nextSetBit(0); + if (ns != -1) { + chosenNumber = ns; + freeNumbers.clear(ns); + } } - - private void resize(int n) { - numberToObj = Arrays.copyOf(numberToObj, n); + if (chosenNumber == -1) { + chosenNumber = ++lastNumber; } - - @Override - public synchronized void add(E o) { - if (o.getNumber() != 0) { - return; - } - - // In case we removed entries from the numberer, we want to re-use the free space - int chosenNumber = -1; - if (freeNumbers != null) { - int ns = freeNumbers.nextSetBit(0); - if (ns != -1) { - chosenNumber = ns; - freeNumbers.clear(ns); - } - } - if (chosenNumber == -1) { - chosenNumber = ++lastNumber; - } - if (chosenNumber >= numberToObj.length) { - resize(numberToObj.length * 2); - } - numberToObj[chosenNumber] = o; - o.setNumber(chosenNumber); + if (chosenNumber >= numberToObj.length) { + resize(numberToObj.length * 2); } - - @Override - public long get(E o) { - if (o == null) { - return 0; - } - int ret = o.getNumber(); - if (ret == 0) { - throw new RuntimeException("unnumbered: " + o); - } - return ret; + numberToObj[chosenNumber] = o; + o.setNumber(chosenNumber); + } + + @Override + public long get(E o) { + if (o == null) { + return 0; } - - @Override - public E get(long number) { - if (number == 0) { - return null; - } - E ret = numberToObj[(int) number]; - if (ret == null) { - return null; - } - return ret; + int ret = o.getNumber(); + if (ret == 0) { + throw new RuntimeException("unnumbered: " + o); } + return ret; + } - @Override - public int size() { - return lastNumber; + @Override + public E get(long number) { + if (number == 0) { + return null; } - - @Override - public Iterator iterator() { - return new Iterator() { - int cur = 1; - - @Override - public final boolean hasNext() { - return cur <= lastNumber && cur < numberToObj.length && numberToObj[cur] != null; - } - - @Override - public final E next() { - if (hasNext()) { - return numberToObj[cur++]; - } - throw new NoSuchElementException(); - } - - @Override - public final void remove() { - ArrayNumberer.this.remove(numberToObj[cur - 1]); - } - }; + E ret = numberToObj[(int) number]; + if (ret == null) { + return null; } - - @Override - public boolean remove(E o) { - if (o == null) { - return false; + return ret; + } + + @Override + public int size() { + return lastNumber; + } + + @Override + public Iterator iterator() { + return new Iterator() { + int cur = 1; + + @Override + public final boolean hasNext() { + return cur <= lastNumber && cur < numberToObj.length && numberToObj[cur] != null; + } + + @Override + public final E next() { + if (hasNext()) { + return numberToObj[cur++]; } + throw new NoSuchElementException(); + } + + @Override + public final void remove() { + ArrayNumberer.this.remove(numberToObj[cur - 1]); + } + }; + } + + @Override + public boolean remove(E o) { + if (o == null) { + return false; + } - int num = o.getNumber(); - if (num == 0) { - return false; - } - if (freeNumbers == null) { - freeNumbers = new BitSet(2 * num); - } - numberToObj[num] = null; - o.setNumber(0); - freeNumbers.set(num); - return true; + int num = o.getNumber(); + if (num == 0) { + return false; + } + if (freeNumbers == null) { + freeNumbers = new BitSet(2 * num); } + numberToObj[num] = null; + o.setNumber(0); + freeNumbers.set(num); + return true; + } } diff --git a/sootup.qilin/src/main/java/soot/util/BitSetIterator.java b/sootup.qilin/src/main/java/soot/util/BitSetIterator.java index 3b3fb5d2b70..61a6822a44b 100644 --- a/sootup.qilin/src/main/java/soot/util/BitSetIterator.java +++ b/sootup.qilin/src/main/java/soot/util/BitSetIterator.java @@ -25,68 +25,68 @@ import java.util.NoSuchElementException; /** - * A fast enumerator for sparse bit sets. When the enumerator is created, it takes a snapshot of the underlying BitVector, - * and iterates through the set bits. Note that this class almost implements the Iterator interface, but it doesn't because - * the return type of next is int rather than Object. + * A fast enumerator for sparse bit sets. When the enumerator is created, it takes a snapshot of the + * underlying BitVector, and iterates through the set bits. Note that this class almost implements + * the Iterator interface, but it doesn't because the return type of next is int rather than Object. */ public class BitSetIterator { - long[] bits; // Bits inherited from the underlying BitVector - int index; // The 64-bit block currently being examined - long save = 0; // A copy of the 64-bit block (for fast access) + long[] bits; // Bits inherited from the underlying BitVector + int index; // The 64-bit block currently being examined + long save = 0; // A copy of the 64-bit block (for fast access) - /* - * Computes log_2(x) modulo 67. This uses the fact that 2 is a primitive root modulo 67 - */ - final static int[] lookup = { -1, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, -1, 13, 10, 17, 62, 60, 28, - 42, 30, 20, 51, 25, 44, 55, 47, 5, 32, -1, 38, 14, 22, 11, 58, 18, 53, -1, 9, 61, 27, 29, 50, 43, 46, 31, 37, 21, 57, - 52, 8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33 }; + /* + * Computes log_2(x) modulo 67. This uses the fact that 2 is a primitive root modulo 67 + */ + static final int[] lookup = { + -1, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, -1, 13, 10, 17, 62, 60, 28, 42, + 30, 20, 51, 25, 44, 55, 47, 5, 32, -1, 38, 14, 22, 11, 58, 18, 53, -1, 9, 61, 27, 29, 50, 43, + 46, 31, 37, 21, 57, 52, 8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33 + }; - /** Creates a new BitSetIterator */ - BitSetIterator(long[] bits) { - // this.bits = new long[bits.length]; - // System.arraycopy(bits,0,this.bits,0,bits.length); - this.bits = bits; - index = 0; + /** Creates a new BitSetIterator */ + BitSetIterator(long[] bits) { + // this.bits = new long[bits.length]; + // System.arraycopy(bits,0,this.bits,0,bits.length); + this.bits = bits; + index = 0; - /* Zip through empty blocks */ - while (index < bits.length && bits[index] == 0L) { - index++; - } - if (index < bits.length) { - save = bits[index]; - } + /* Zip through empty blocks */ + while (index < bits.length && bits[index] == 0L) { + index++; } - - /** Returns true if there are more set bits in the BitVector; false otherwise. */ - public boolean hasNext() { - return index < bits.length; + if (index < bits.length) { + save = bits[index]; } + } + + /** Returns true if there are more set bits in the BitVector; false otherwise. */ + public boolean hasNext() { + return index < bits.length; + } - /** - * Returns the index of the next set bit. Note that the return type is int, and not Object. - */ - public int next() { - if (index >= bits.length) { - throw new NoSuchElementException(); - } + /** Returns the index of the next set bit. Note that the return type is int, and not Object. */ + public int next() { + if (index >= bits.length) { + throw new NoSuchElementException(); + } - long k = (save & (save - 1)); // Clears the last non-zero bit. save is guaranteed non-zero. - long diff = save ^ k; // Finds out which bit it is. diff has exactly one bit set. - save = k; + long k = (save & (save - 1)); // Clears the last non-zero bit. save is guaranteed non-zero. + long diff = save ^ k; // Finds out which bit it is. diff has exactly one bit set. + save = k; - // Computes the position of the set bit. - int result = (diff < 0) ? 64 * index + 63 : 64 * index + lookup[(int) (diff % 67)]; + // Computes the position of the set bit. + int result = (diff < 0) ? 64 * index + 63 : 64 * index + lookup[(int) (diff % 67)]; - if (save == 0) { - index++; - while (index < bits.length && bits[index] == 0L) { - index++; - } - if (index < bits.length) { - save = bits[index]; - } - } - return result; + if (save == 0) { + index++; + while (index < bits.length && bits[index] == 0L) { + index++; + } + if (index < bits.length) { + save = bits[index]; + } } + return result; + } } diff --git a/sootup.qilin/src/main/java/soot/util/BitVector.java b/sootup.qilin/src/main/java/soot/util/BitVector.java index 34e7bf27307..0bcdd145312 100644 --- a/sootup.qilin/src/main/java/soot/util/BitVector.java +++ b/sootup.qilin/src/main/java/soot/util/BitVector.java @@ -23,441 +23,442 @@ */ /** - * This is the Soot internal implementation of java.util.BitSet with Felix and Jerome's clever efficient iterator. It was - * re-implemented from scratch by Ondrej Lhotak to avoid licence issues. It was named BitVector rather than BitSet to avoid a - * name clash with the one in the standard Java library. + * This is the Soot internal implementation of java.util.BitSet with Felix and Jerome's clever + * efficient iterator. It was re-implemented from scratch by Ondrej Lhotak to avoid licence issues. + * It was named BitVector rather than BitSet to avoid a name clash with the one in the standard Java + * library. * * @author Ondrej Lhotak */ public class BitVector { - private long[] bits; + private long[] bits; - public BitVector() { - this(64); - } + public BitVector() { + this(64); + } - /** Copy constructor */ - // Added by Adam Richard. More efficient than clone(), and easier to extend - public BitVector(BitVector other) { - final long[] otherBits = other.bits; - bits = new long[otherBits.length]; - System.arraycopy(otherBits, 0, bits, 0, otherBits.length); - } + /** Copy constructor */ + // Added by Adam Richard. More efficient than clone(), and easier to extend + public BitVector(BitVector other) { + final long[] otherBits = other.bits; + bits = new long[otherBits.length]; + System.arraycopy(otherBits, 0, bits, 0, otherBits.length); + } - public BitVector(int numBits) { - int lastIndex = indexOf(numBits - 1); - bits = new long[lastIndex + 1]; - } + public BitVector(int numBits) { + int lastIndex = indexOf(numBits - 1); + bits = new long[lastIndex + 1]; + } - private int indexOf(int bit) { - return bit >> 6; - } + private int indexOf(int bit) { + return bit >> 6; + } - private long mask(int bit) { - return 1L << (bit & 63); - } + private long mask(int bit) { + return 1L << (bit & 63); + } - public void and(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int numToAnd = otherBits.length; - if (bits.length < numToAnd) { - numToAnd = bits.length; - } - int i; - for (i = 0; i < numToAnd; i++) { - bits[i] = bits[i] & otherBits[i]; - } - for (; i < bits.length; i++) { - bits[i] = 0L; - } + public void and(BitVector other) { + if (this == other) { + return; } - - public void andNot(BitVector other) { - final long[] otherBits = other.bits; - int numToAnd = otherBits.length; - if (bits.length < numToAnd) { - numToAnd = bits.length; - } - for (int i = 0; i < numToAnd; i++) { - bits[i] = bits[i] & ~otherBits[i]; - } + final long[] otherBits = other.bits; + int numToAnd = otherBits.length; + if (bits.length < numToAnd) { + numToAnd = bits.length; } - - public void clear(int bit) { - if (indexOf(bit) < bits.length) { - bits[indexOf(bit)] &= ~mask(bit); - } + int i; + for (i = 0; i < numToAnd; i++) { + bits[i] = bits[i] & otherBits[i]; } - - @Override - public Object clone() { - try { - BitVector ret = (BitVector) super.clone(); - System.arraycopy(bits, 0, ret.bits, 0, ret.bits.length); - return ret; - } catch (CloneNotSupportedException e) { - // cannot occur - throw new RuntimeException(e); - } + for (; i < bits.length; i++) { + bits[i] = 0L; } + } - @Override - public boolean equals(Object o) { - if (!(o instanceof BitVector)) { - return false; - } - final long[] otherBits = ((BitVector) o).bits; - long[] longer = otherBits; - int min = bits.length; - if (otherBits.length < min) { - min = otherBits.length; - longer = bits; - } - int i; - for (i = 0; i < min; i++) { - if (bits[i] != otherBits[i]) { - return false; - } - } - for (; i < longer.length; i++) { - if (longer[i] != 0L) { - return false; - } - } - return true; + public void andNot(BitVector other) { + final long[] otherBits = other.bits; + int numToAnd = otherBits.length; + if (bits.length < numToAnd) { + numToAnd = bits.length; } - - public boolean get(int bit) { - if (indexOf(bit) >= bits.length) { - return false; - } - return (bits[indexOf(bit)] & mask(bit)) != 0L; + for (int i = 0; i < numToAnd; i++) { + bits[i] = bits[i] & ~otherBits[i]; } + } - @Override - public int hashCode() { - long ret = 0; - for (long element : bits) { - ret ^= element; - } - return (int) ((ret >> 32) ^ ret); + public void clear(int bit) { + if (indexOf(bit) < bits.length) { + bits[indexOf(bit)] &= ~mask(bit); } - - /** Returns index of highest-numbered one bit. */ - public int length() { - int i; - for (i = bits.length - 1; i >= 0; i--) { - if (bits[i] != 0L) { - break; - } - } - if (i < 0) { - return 0; - } - long j = bits[i]; - i++; - i <<= 6; - for (long k = 1L << 63; (k & j) == 0L; k >>= 1, i--) { - } - return i; + } + + @Override + public Object clone() { + try { + BitVector ret = (BitVector) super.clone(); + System.arraycopy(bits, 0, ret.bits, 0, ret.bits.length); + return ret; + } catch (CloneNotSupportedException e) { + // cannot occur + throw new RuntimeException(e); } + } - public void copyFrom(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int j; - for (j = otherBits.length - 1; j >= 0; j--) { - if (otherBits[j] != 0L) { - break; - } - } - expand(j << 6); - int i = j + 1; - for (; j >= 0; j--) { - bits[j] = otherBits[j]; - } - for (; i < bits.length; i++) { - bits[i] = 0L; - } + @Override + public boolean equals(Object o) { + if (!(o instanceof BitVector)) { + return false; } - - public void or(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int j; - for (j = otherBits.length - 1; j >= 0; j--) { - if (otherBits[j] != 0L) { - break; - } - } - expand(j << 6); - for (; j >= 0; j--) { - bits[j] |= otherBits[j]; - } + final long[] otherBits = ((BitVector) o).bits; + long[] longer = otherBits; + int min = bits.length; + if (otherBits.length < min) { + min = otherBits.length; + longer = bits; } - - /** - * Count the number of ones in the bitvector. - * - * @author Adam Richard This is Brian Kernighan's algorithm from: http://graphics.stanford.edu/~seander/bithacks.html and - * is efficient for sparse bit sets. - */ - public int cardinality() { - int c = 0; - for (long v : bits) { - while (v != 0) { - v &= v - 1; - ++c; - } - } - return c; - } - - /** - * Returns true if the both the current and the specified bitvectors have at least one bit set in common. - * - * @author Quentin Sabah Inspired by the BitVector.and method. - */ - public boolean intersects(BitVector other) { - final long[] otherBits = other.bits; - int numToCheck = otherBits.length; - if (bits.length < numToCheck) { - numToCheck = bits.length; - } - int i; - for (i = 0; i < numToCheck; i++) { - if ((bits[i] & otherBits[i]) != 0) { - return true; - } - } + int i; + for (i = 0; i < min; i++) { + if (bits[i] != otherBits[i]) { return false; + } } - - private void expand(int bit) { - int n = indexOf(bit) + 1; - if (n <= bits.length) { - return; - } - if (bits.length * 2 > n) { - n = bits.length * 2; - } - long[] newBits = new long[n]; - System.arraycopy(bits, 0, newBits, 0, bits.length); - bits = newBits; + for (; i < longer.length; i++) { + if (longer[i] != 0L) { + return false; + } } + return true; + } - public void xor(BitVector other) { - if (this == other) { - return; - } - final long[] otherBits = other.bits; - int j; - for (j = otherBits.length - 1; j >= 0; j--) { - if (otherBits[j] != 0L) { - break; - } - } - expand(j << 6); - for (; j >= 0; j--) { - bits[j] ^= otherBits[j]; - } + public boolean get(int bit) { + if (indexOf(bit) >= bits.length) { + return false; } - - public boolean set(int bit) { - expand(bit); - boolean ret = !get(bit); - bits[indexOf(bit)] |= mask(bit); - return ret; + return (bits[indexOf(bit)] & mask(bit)) != 0L; + } + + @Override + public int hashCode() { + long ret = 0; + for (long element : bits) { + ret ^= element; } - - /** Returns number of bits in the underlying array. */ - public int size() { - return bits.length << 6; + return (int) ((ret >> 32) ^ ret); + } + + /** Returns index of highest-numbered one bit. */ + public int length() { + int i; + for (i = bits.length - 1; i >= 0; i--) { + if (bits[i] != 0L) { + break; + } } + if (i < 0) { + return 0; + } + long j = bits[i]; + i++; + i <<= 6; + for (long k = 1L << 63; (k & j) == 0L; k >>= 1, i--) {} + return i; + } + + public void copyFrom(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + int i = j + 1; + for (; j >= 0; j--) { + bits[j] = otherBits[j]; + } + for (; i < bits.length; i++) { + bits[i] = 0L; + } + } - @Override - public String toString() { - StringBuilder ret = new StringBuilder(); - ret.append('{'); - boolean start = true; - for (BitSetIterator it = new BitSetIterator(bits); it.hasNext();) { - int bit = it.next(); - if (start) { - start = false; - } else { - ret.append(", "); - } - ret.append(bit); - } - ret.append('}'); - return ret.toString(); - } - - /** - * Computes this = this OR ((orset AND andset ) AND (NOT andnotset)) Returns true iff this is modified. - */ - public boolean orAndAndNot(BitVector orset, BitVector andset, BitVector andnotset) { - final long[] a, b, c, d; - final int al, bl, cl, dl; - { - a = this.bits; - al = a.length; - } - if (orset == null) { - b = null; - bl = 0; - } else { - b = orset.bits; - bl = b.length; - } - if (andset == null) { - c = null; - cl = 0; - } else { - c = andset.bits; - cl = c.length; - } - if (andnotset == null) { - d = null; - dl = 0; - } else { - d = andnotset.bits; - dl = d.length; - } - - final long[] e; - if (al < bl) { - e = new long[bl]; - System.arraycopy(a, 0, e, 0, al); - this.bits = e; - } else { - e = a; - } - - boolean ret = false; - if (c == null) { - if (dl <= bl) { - int i = 0; - for (; i < dl; i++) { - long l = b[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - for (; i < bl; i++) { - long l = b[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } else { - for (int i = 0; i < bl; i++) { - long l = b[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } - } else if (bl <= cl && bl <= dl) { - // bl is the shortest - for (int i = 0; i < bl; i++) { - long l = b[i] & c[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } else if (cl <= bl && cl <= dl) { - // cl is the shortest - for (int i = 0; i < cl; i++) { - long l = b[i] & c[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } else { - // dl is the shortest - int i = 0; - for (; i < dl; i++) { - long l = b[i] & c[i] & ~d[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - for (int shorter = (bl < cl) ? bl : cl; i < shorter; i++) { - long l = b[i] & c[i]; - if ((l & ~e[i]) != 0) { - ret = true; - } - e[i] |= l; - } - } + public void or(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + for (; j >= 0; j--) { + bits[j] |= otherBits[j]; + } + } + + /** + * Count the number of ones in the bitvector. + * + * @author Adam Richard This is Brian Kernighan's algorithm from: + * http://graphics.stanford.edu/~seander/bithacks.html and is efficient for sparse bit sets. + */ + public int cardinality() { + int c = 0; + for (long v : bits) { + while (v != 0) { + v &= v - 1; + ++c; + } + } + return c; + } + + /** + * Returns true if the both the current and the specified bitvectors have at least one bit set in + * common. + * + * @author Quentin Sabah Inspired by the BitVector.and method. + */ + public boolean intersects(BitVector other) { + final long[] otherBits = other.bits; + int numToCheck = otherBits.length; + if (bits.length < numToCheck) { + numToCheck = bits.length; + } + int i; + for (i = 0; i < numToCheck; i++) { + if ((bits[i] & otherBits[i]) != 0) { + return true; + } + } + return false; + } - return ret; + private void expand(int bit) { + int n = indexOf(bit) + 1; + if (n <= bits.length) { + return; + } + if (bits.length * 2 > n) { + n = bits.length * 2; + } + long[] newBits = new long[n]; + System.arraycopy(bits, 0, newBits, 0, bits.length); + bits = newBits; + } + + public void xor(BitVector other) { + if (this == other) { + return; + } + final long[] otherBits = other.bits; + int j; + for (j = otherBits.length - 1; j >= 0; j--) { + if (otherBits[j] != 0L) { + break; + } + } + expand(j << 6); + for (; j >= 0; j--) { + bits[j] ^= otherBits[j]; + } + } + + public boolean set(int bit) { + expand(bit); + boolean ret = !get(bit); + bits[indexOf(bit)] |= mask(bit); + return ret; + } + + /** Returns number of bits in the underlying array. */ + public int size() { + return bits.length << 6; + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + ret.append('{'); + boolean start = true; + for (BitSetIterator it = new BitSetIterator(bits); it.hasNext(); ) { + int bit = it.next(); + if (start) { + start = false; + } else { + ret.append(", "); + } + ret.append(bit); + } + ret.append('}'); + return ret.toString(); + } + + /** + * Computes this = this OR ((orset AND andset ) AND (NOT andnotset)) Returns true iff this is + * modified. + */ + public boolean orAndAndNot(BitVector orset, BitVector andset, BitVector andnotset) { + final long[] a, b, c, d; + final int al, bl, cl, dl; + { + a = this.bits; + al = a.length; + } + if (orset == null) { + b = null; + bl = 0; + } else { + b = orset.bits; + bl = b.length; + } + if (andset == null) { + c = null; + cl = 0; + } else { + c = andset.bits; + cl = c.length; + } + if (andnotset == null) { + d = null; + dl = 0; + } else { + d = andnotset.bits; + dl = d.length; } - public static BitVector and(BitVector set1, BitVector set2) { - int min = set1.size(); - { - int max = set2.size(); - if (min > max) { - min = max; - } - // max is not necessarily correct at this point, so let it go - // out of scope - } + final long[] e; + if (al < bl) { + e = new long[bl]; + System.arraycopy(a, 0, e, 0, al); + this.bits = e; + } else { + e = a; + } - BitVector ret = new BitVector(min); - long[] retbits = ret.bits; - long[] bits1 = set1.bits; - long[] bits2 = set2.bits; - min >>= 6; - for (int i = 0; i < min; i++) { - retbits[i] = bits1[i] & bits2[i]; - } - return ret; + boolean ret = false; + if (c == null) { + if (dl <= bl) { + int i = 0; + for (; i < dl; i++) { + long l = b[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + for (; i < bl; i++) { + long l = b[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else { + for (int i = 0; i < bl; i++) { + long l = b[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } + } else if (bl <= cl && bl <= dl) { + // bl is the shortest + for (int i = 0; i < bl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else if (cl <= bl && cl <= dl) { + // cl is the shortest + for (int i = 0; i < cl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + } else { + // dl is the shortest + int i = 0; + for (; i < dl; i++) { + long l = b[i] & c[i] & ~d[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } + for (int shorter = (bl < cl) ? bl : cl; i < shorter; i++) { + long l = b[i] & c[i]; + if ((l & ~e[i]) != 0) { + ret = true; + } + e[i] |= l; + } } - public static BitVector or(BitVector set1, BitVector set2) { - int min = set1.size(); - int max = set2.size(); - if (min > max) { - min = max; - max = set1.size(); - } + return ret; + } + + public static BitVector and(BitVector set1, BitVector set2) { + int min = set1.size(); + { + int max = set2.size(); + if (min > max) { + min = max; + } + // max is not necessarily correct at this point, so let it go + // out of scope + } - BitVector ret = new BitVector(max); - long[] retbits = ret.bits; - long[] bits1 = set1.bits; - long[] bits2 = set2.bits; - min >>= 6; - max >>= 6; - for (int i = 0; i < min; i++) { - retbits[i] = bits1[i] | bits2[i]; - } - if (bits1.length == min) { - System.arraycopy(bits2, min, retbits, min, max - min); - } else { - System.arraycopy(bits1, min, retbits, min, max - min); - } - return ret; + BitVector ret = new BitVector(min); + long[] retbits = ret.bits; + long[] bits1 = set1.bits; + long[] bits2 = set2.bits; + min >>= 6; + for (int i = 0; i < min; i++) { + retbits[i] = bits1[i] & bits2[i]; + } + return ret; + } + + public static BitVector or(BitVector set1, BitVector set2) { + int min = set1.size(); + int max = set2.size(); + if (min > max) { + min = max; + max = set1.size(); } - public BitSetIterator iterator() { - return new BitSetIterator(bits); + BitVector ret = new BitVector(max); + long[] retbits = ret.bits; + long[] bits1 = set1.bits; + long[] bits2 = set2.bits; + min >>= 6; + max >>= 6; + for (int i = 0; i < min; i++) { + retbits[i] = bits1[i] | bits2[i]; } -} + if (bits1.length == min) { + System.arraycopy(bits2, min, retbits, min, max - min); + } else { + System.arraycopy(bits1, min, retbits, min, max - min); + } + return ret; + } + public BitSetIterator iterator() { + return new BitSetIterator(bits); + } +} diff --git a/sootup.qilin/src/main/java/soot/util/Chain.java b/sootup.qilin/src/main/java/soot/util/Chain.java index 4b7b39390a3..f5451ad8b95 100644 --- a/sootup.qilin/src/main/java/soot/util/Chain.java +++ b/sootup.qilin/src/main/java/soot/util/Chain.java @@ -28,106 +28,107 @@ import java.util.List; /** - * Augmented data type guaranteeing O(1) insertion and removal from a set of ordered, unique elements. + * Augmented data type guaranteeing O(1) insertion and removal from a set of ordered, unique + * elements. * - * @param - * element type + * @param element type */ public interface Chain extends Collection, Serializable { - /** Inserts toInsert in the Chain before point. */ - public void insertBefore(E toInsert, E point); + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(E toInsert, E point); - /** Inserts toInsert in the Chain after point. */ - public void insertAfter(E toInsert, E point); + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(E toInsert, E point); - /** Inserts toInsert in the Chain before point. */ - public void insertBefore(Chain toInsert, E point); + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(Chain toInsert, E point); - /** Inserts toInsert in the Chain after point. */ - public void insertAfter(Chain toInsert, E point); + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(Chain toInsert, E point); - /** Inserts toInsert in the Chain before point. */ - public void insertBefore(List toInsert, E point); + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(List toInsert, E point); - /** Inserts toInsert in the Chain after point. */ - public void insertAfter(List toInsert, E point); + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(List toInsert, E point); - /** Inserts toInsert in the Chain before point. */ - public void insertBefore(Collection toInsert, E point); + /** Inserts toInsert in the Chain before point. */ + public void insertBefore(Collection toInsert, E point); - /** Inserts toInsert in the Chain after point. */ - public void insertAfter(Collection toInsert, E point); + /** Inserts toInsert in the Chain after point. */ + public void insertAfter(Collection toInsert, E point); - /** Replaces out in the Chain by in. */ - public void swapWith(E out, E in); + /** Replaces out in the Chain by in. */ + public void swapWith(E out, E in); - /** - * Removes the given object from this Chain. Parameter has to be of type {@link Object} to be compatible with the - * {@link Collection} interface. - */ - @Override - public boolean remove(Object u); + /** + * Removes the given object from this Chain. Parameter has to be of type {@link Object} to be + * compatible with the {@link Collection} interface. + */ + @Override + public boolean remove(Object u); - /** Adds the given object at the beginning of the Chain. */ - public void addFirst(E u); + /** Adds the given object at the beginning of the Chain. */ + public void addFirst(E u); - /** Adds the given object at the end of the Chain. */ - public void addLast(E u); + /** Adds the given object at the end of the Chain. */ + public void addLast(E u); - /** Removes the first object contained in this Chain. */ - public void removeFirst(); + /** Removes the first object contained in this Chain. */ + public void removeFirst(); - /** Removes the last object contained in this Chain. */ - public void removeLast(); + /** Removes the last object contained in this Chain. */ + public void removeLast(); - /** - * Returns true if object someObject follows object someReferenceObject in the Chain, i.e. - * someReferenceObject comes first and then someObject. - */ - public boolean follows(E someObject, E someReferenceObject); + /** + * Returns true if object someObject follows object someReferenceObject + * in the Chain, i.e. someReferenceObject comes first and then someObject. + */ + public boolean follows(E someObject, E someReferenceObject); - /** Returns the first object in this Chain. */ - public E getFirst(); + /** Returns the first object in this Chain. */ + public E getFirst(); - /** Returns the last object in this Chain. */ - public E getLast(); + /** Returns the last object in this Chain. */ + public E getLast(); - /** Returns the object immediately following point. */ - public E getSuccOf(E point); + /** Returns the object immediately following point. */ + public E getSuccOf(E point); - /** Returns the object immediately preceding point. */ - public E getPredOf(E point); + /** Returns the object immediately preceding point. */ + public E getPredOf(E point); - /** - * Returns an iterator over a copy of this chain. This avoids ConcurrentModificationExceptions from being thrown if the - * underlying Chain is modified during iteration. Do not use this to remove elements which have not yet been iterated over! - */ - public Iterator snapshotIterator(); + /** + * Returns an iterator over a copy of this chain. This avoids ConcurrentModificationExceptions + * from being thrown if the underlying Chain is modified during iteration. Do not use this to + * remove elements which have not yet been iterated over! + */ + public Iterator snapshotIterator(); - /** Returns an iterator over this Chain. */ - @Override - public Iterator iterator(); + /** Returns an iterator over this Chain. */ + @Override + public Iterator iterator(); - /** Returns an iterator over this Chain, starting at the given object. */ - public Iterator iterator(E u); + /** Returns an iterator over this Chain, starting at the given object. */ + public Iterator iterator(E u); - /** Returns an iterator over this Chain, starting at head and reaching tail (inclusive). */ - public Iterator iterator(E head, E tail); + /** Returns an iterator over this Chain, starting at head and reaching tail (inclusive). */ + public Iterator iterator(E head, E tail); - /** Returns the size of this Chain. */ - @Override - public int size(); + /** Returns the size of this Chain. */ + @Override + public int size(); - /** Returns the number of times this chain has been modified. */ - long getModificationCount(); - - /** - * Gets all elements in the chain. There is no guarantee on sorting. On the other hand, the collection returned by this - * method is thread-safe. You can iterate over it even in the case of concurrent modifications to the underlying chain. - * - * @return All elements in the chain in an unsorted collection - */ - public Collection getElementsUnsorted(); + /** Returns the number of times this chain has been modified. */ + long getModificationCount(); + /** + * Gets all elements in the chain. There is no guarantee on sorting. On the other hand, the + * collection returned by this method is thread-safe. You can iterate over it even in the case of + * concurrent modifications to the underlying chain. + * + * @return All elements in the chain in an unsorted collection + */ + public Collection getElementsUnsorted(); } diff --git a/sootup.qilin/src/main/java/soot/util/Invalidable.java b/sootup.qilin/src/main/java/soot/util/Invalidable.java index 208fc07fb18..2d98b74dcfd 100644 --- a/sootup.qilin/src/main/java/soot/util/Invalidable.java +++ b/sootup.qilin/src/main/java/soot/util/Invalidable.java @@ -23,20 +23,19 @@ */ /** - * A class implementing this interface can be invalidated. The invalidation state can be retrieved by other classes. + * A class implementing this interface can be invalidated. The invalidation state can be retrieved + * by other classes. * * @author Marc Miltenberger */ public interface Invalidable { - /** - * Return true if the object is invalid. - * - * @return true if the object is invalid. - */ - public boolean isInvalid(); + /** + * Return true if the object is invalid. + * + * @return true if the object is invalid. + */ + public boolean isInvalid(); - /** - * Invalidates the object. Does nothing if the object is already invalid. - */ - public void invalidate(); + /** Invalidates the object. Does nothing if the object is already invalid. */ + public void invalidate(); } diff --git a/sootup.qilin/src/main/java/soot/util/IterableNumberer.java b/sootup.qilin/src/main/java/soot/util/IterableNumberer.java index a4e57582dd5..6099ae081c7 100644 --- a/sootup.qilin/src/main/java/soot/util/IterableNumberer.java +++ b/sootup.qilin/src/main/java/soot/util/IterableNumberer.java @@ -30,7 +30,7 @@ * @author xiao, generalize the interface */ public interface IterableNumberer extends Numberer, Iterable { - /** Returns an iterator over all objects added to the numberer. */ - @Override - Iterator iterator(); + /** Returns an iterator over all objects added to the numberer. */ + @Override + Iterator iterator(); } diff --git a/sootup.qilin/src/main/java/soot/util/Numberable.java b/sootup.qilin/src/main/java/soot/util/Numberable.java index 5321ce05753..f8464889692 100644 --- a/sootup.qilin/src/main/java/soot/util/Numberable.java +++ b/sootup.qilin/src/main/java/soot/util/Numberable.java @@ -27,10 +27,8 @@ * * @author Ondrej Lhotak */ - public interface Numberable { - public void setNumber(int number); + public void setNumber(int number); - public int getNumber(); + public int getNumber(); } - diff --git a/sootup.qilin/src/main/java/soot/util/NumberedString.java b/sootup.qilin/src/main/java/soot/util/NumberedString.java index 05e5216b8fe..7ea4cd2ea80 100644 --- a/sootup.qilin/src/main/java/soot/util/NumberedString.java +++ b/sootup.qilin/src/main/java/soot/util/NumberedString.java @@ -29,60 +29,60 @@ */ public final class NumberedString implements Numberable { - private final String s; - private volatile int number; + private final String s; + private volatile int number; - public NumberedString(String s) { - this.s = s; - } + public NumberedString(String s) { + this.s = s; + } - @Override - public final void setNumber(int number) { - this.number = number; - } + @Override + public final void setNumber(int number) { + this.number = number; + } - @Override - public final int getNumber() { - return number; - } + @Override + public final int getNumber() { + return number; + } - @Override - public final String toString() { - return getString(); - } + @Override + public final String toString() { + return getString(); + } - public final String getString() { - if (number == 0) { - throw new RuntimeException("oops"); - } - return s; + public final String getString() { + if (number == 0) { + throw new RuntimeException("oops"); } + return s; + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + number; - result = prime * result + ((s == null) ? 0 : s.hashCode()); - return result; - } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + number; + result = prime * result + ((s == null) ? 0 : s.hashCode()); + return result; + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || this.getClass() != obj.getClass()) { - return false; - } - NumberedString other = (NumberedString) obj; - if (this.number != other.number) { - return false; - } - if (this.s == null) { - return other.s == null; - } else { - return this.s.equals(other.s); - } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + NumberedString other = (NumberedString) obj; + if (this.number != other.number) { + return false; + } + if (this.s == null) { + return other.s == null; + } else { + return this.s.equals(other.s); } + } } diff --git a/sootup.qilin/src/main/java/soot/util/Numberer.java b/sootup.qilin/src/main/java/soot/util/Numberer.java index 9efe5ea5a2a..0c77d440cc5 100644 --- a/sootup.qilin/src/main/java/soot/util/Numberer.java +++ b/sootup.qilin/src/main/java/soot/util/Numberer.java @@ -28,26 +28,26 @@ * @author xiao, generalize the interface */ public interface Numberer { - /** Tells the numberer that a new object needs to be assigned a number. */ - public void add(E o); + /** Tells the numberer that a new object needs to be assigned a number. */ + public void add(E o); - /** - * Removes the number for a given object. - * - * @param o - * the element - * @return true if the removal was successful, false when not - */ - public boolean remove(E o); + /** + * Removes the number for a given object. + * + * @param o the element + * @return true if the removal was successful, false when not + */ + public boolean remove(E o); - /** - * Should return the number that was assigned to object o that was previously passed as an argument to add(). - */ - public long get(E o); + /** + * Should return the number that was assigned to object o that was previously passed as an + * argument to add(). + */ + public long get(E o); - /** Should return the object that was assigned the number. */ - public E get(long number); + /** Should return the object that was assigned the number. */ + public E get(long number); - /** Should return the number of objects that have been assigned numbers. */ - public int size(); + /** Should return the number of objects that have been assigned numbers. */ + public int size(); } diff --git a/sootup.qilin/src/main/java/soot/util/StringNumberer.java b/sootup.qilin/src/main/java/soot/util/StringNumberer.java index 785aa81af74..10ced1a80b4 100644 --- a/sootup.qilin/src/main/java/soot/util/StringNumberer.java +++ b/sootup.qilin/src/main/java/soot/util/StringNumberer.java @@ -23,7 +23,6 @@ */ import heros.ThreadSafe; - import java.util.HashMap; import java.util.Map; @@ -35,20 +34,20 @@ @ThreadSafe public class StringNumberer extends ArrayNumberer { - private final Map stringToNumbered = new HashMap(1024); + private final Map stringToNumbered = + new HashMap(1024); - public synchronized NumberedString findOrAdd(String s) { - NumberedString ret = stringToNumbered.get(s); - if (ret == null) { - ret = new NumberedString(s); - stringToNumbered.put(s, ret); - add(ret); - } - return ret; + public synchronized NumberedString findOrAdd(String s) { + NumberedString ret = stringToNumbered.get(s); + if (ret == null) { + ret = new NumberedString(s); + stringToNumbered.put(s, ret); + add(ret); } + return ret; + } - public NumberedString find(String s) { - return stringToNumbered.get(s); - } + public NumberedString find(String s) { + return stringToNumbered.get(s); + } } - diff --git a/sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java b/sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java index 48fa2ee94ac..bb8c9a0a91c 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java +++ b/sootup.qilin/src/main/java/soot/util/dot/AbstractDotGraphElement.java @@ -26,114 +26,105 @@ import java.util.Collections; import java.util.LinkedHashMap; -/** - * @author Timothy Hoffman - */ +/** @author Timothy Hoffman */ public abstract class AbstractDotGraphElement { - private LinkedHashMap attributes; + private LinkedHashMap attributes; - /** - * Sets an attribute for this dot element. - * - * @param id - * the attribute id to be set - * @param value - * the attribute value - */ - public void setAttribute(String id, String value) { - this.setAttribute(new DotGraphAttribute(id, value)); - } + /** + * Sets an attribute for this dot element. + * + * @param id the attribute id to be set + * @param value the attribute value + */ + public void setAttribute(String id, String value) { + this.setAttribute(new DotGraphAttribute(id, value)); + } - /** - * Sets an attribute for this dot element. - * - * @param attr - * {@link DotGraphAttribute} specifying the attribute name and value - */ - public void setAttribute(DotGraphAttribute attr) { - LinkedHashMap attrs = this.attributes; - if (attrs == null) { - this.attributes = attrs = new LinkedHashMap(); - } - attrs.put(attr.getID(), attr); + /** + * Sets an attribute for this dot element. + * + * @param attr {@link DotGraphAttribute} specifying the attribute name and value + */ + public void setAttribute(DotGraphAttribute attr) { + LinkedHashMap attrs = this.attributes; + if (attrs == null) { + this.attributes = attrs = new LinkedHashMap(); } + attrs.put(attr.getID(), attr); + } - /** - * @return unmodifiable {@link Collection} of {@link DotGraphAttribute} for this {@link AbstractDotGraphElement} - */ - public Collection getAttributes() { - LinkedHashMap attrs = this.attributes; - return attrs == null ? Collections.emptyList() : Collections.unmodifiableCollection(attrs.values()); - } + /** + * @return unmodifiable {@link Collection} of {@link DotGraphAttribute} for this {@link + * AbstractDotGraphElement} + */ + public Collection getAttributes() { + LinkedHashMap attrs = this.attributes; + return attrs == null + ? Collections.emptyList() + : Collections.unmodifiableCollection(attrs.values()); + } - /** - * @param id - * @return the {@link DotGraphAttribute} with the given {@code id} - */ - public DotGraphAttribute getAttribute(String id) { - LinkedHashMap attrs = this.attributes; - return attrs == null ? null : attrs.get(id); - } + /** + * @param id + * @return the {@link DotGraphAttribute} with the given {@code id} + */ + public DotGraphAttribute getAttribute(String id) { + LinkedHashMap attrs = this.attributes; + return attrs == null ? null : attrs.get(id); + } - /** - * @param id - * @return the value for the {@link DotGraphAttribute} with the given {@code id} - */ - public String getAttributeValue(String id) { - DotGraphAttribute attr = getAttribute(id); - return attr == null ? null : attr.getValue(); - } + /** + * @param id + * @return the value for the {@link DotGraphAttribute} with the given {@code id} + */ + public String getAttributeValue(String id) { + DotGraphAttribute attr = getAttribute(id); + return attr == null ? null : attr.getValue(); + } - /** - * Removes the attribute with the given {@link id} from this dot element. - * - * @param id - */ - public void removeAttribute(String id) { - LinkedHashMap attrs = this.attributes; - if (attrs != null) { - attrs.remove(id); - } + /** + * Removes the attribute with the given {@link id} from this dot element. + * + * @param id + */ + public void removeAttribute(String id) { + LinkedHashMap attrs = this.attributes; + if (attrs != null) { + attrs.remove(id); } + } - /** - * Removes the given attribute from this dot element. - * - * @param attr - * {@link DotGraphAttribute} specifying the attribute to remove - */ - public void removeAttribute(DotGraphAttribute attr) { - LinkedHashMap attrs = this.attributes; - if (attrs != null) { - attrs.remove(attr.getID(), attr); - } + /** + * Removes the given attribute from this dot element. + * + * @param attr {@link DotGraphAttribute} specifying the attribute to remove + */ + public void removeAttribute(DotGraphAttribute attr) { + LinkedHashMap attrs = this.attributes; + if (attrs != null) { + attrs.remove(attr.getID(), attr); } + } - /** - * Removes all attributes from this dot element. - */ - public void removeAllAttributes() { - this.attributes = null; - } + /** Removes all attributes from this dot element. */ + public void removeAllAttributes() { + this.attributes = null; + } - /** - * Sets the label for this dot element. - * - * @param label - * a label string - */ - public void setLabel(String label) { - label = DotGraphUtility.replaceQuotes(label); - label = DotGraphUtility.replaceReturns(label); - this.setAttribute("label", "\"" + label + "\""); - } + /** + * Sets the label for this dot element. + * + * @param label a label string + */ + public void setLabel(String label) { + label = DotGraphUtility.replaceQuotes(label); + label = DotGraphUtility.replaceReturns(label); + this.setAttribute("label", "\"" + label + "\""); + } - /** - * @return the label for this dot element - */ - public String getLabel() { - return this.getAttributeValue("label"); - } + /** @return the label for this dot element */ + public String getLabel() { + return this.getAttributeValue("label"); + } } - diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraph.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraph.java index d5baff15a6c..dd05d8893af 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraph.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraph.java @@ -29,298 +29,276 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Allow a serialized drawing, following steps: + * *
    - *
  1. new DotGraph
  2. - *
  3. draw(Directed/Undirected)Edge, attachAttributes, addNode
  4. - *
  5. plot
  6. + *
  7. new DotGraph + *
  8. draw(Directed/Undirected)Edge, attachAttributes, addNode + *
  9. plot *
*/ public class DotGraph extends AbstractDotGraphElement implements Renderable { - private static final Logger logger = LoggerFactory.getLogger(DotGraph.class); - - /** - * The extension added to output files, exported so that clients can search for the filenames. - */ - public static final String DOT_EXTENSION = ".dot"; - - private final HashMap nodes; - /* draw elements are sub graphs, edges, commands */ - private final List drawElements; - - private final boolean isSubGraph; - - private boolean dontQuoteNodeNames; - - private String graphname; - - private DotGraph(String graphname, boolean isSubGraph) { - this.graphname = graphname; - this.isSubGraph = isSubGraph; - this.nodes = new HashMap(100); - this.drawElements = new LinkedList(); - this.dontQuoteNodeNames = false; + private static final Logger logger = LoggerFactory.getLogger(DotGraph.class); + + /** The extension added to output files, exported so that clients can search for the filenames. */ + public static final String DOT_EXTENSION = ".dot"; + + private final HashMap nodes; + /* draw elements are sub graphs, edges, commands */ + private final List drawElements; + + private final boolean isSubGraph; + + private boolean dontQuoteNodeNames; + + private String graphname; + + private DotGraph(String graphname, boolean isSubGraph) { + this.graphname = graphname; + this.isSubGraph = isSubGraph; + this.nodes = new HashMap(100); + this.drawElements = new LinkedList(); + this.dontQuoteNodeNames = false; + } + + /** + * Creates a new graph for drawing. + * + * @param graphname, the name used to identify the graph in the dot source. + */ + public DotGraph(String graphname) { + this(graphname, false); + } + + /** + * Generates the drawing on canvas to the dot file. + * + * @param filename the name for the output file. By convention, it should end with DOT_EXTENSION, + * but this is not enforced. + */ + public void plot(String filename) { + try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename))) { + render(out, 0); + } catch (IOException ioe) { + logger.debug(ioe.getMessage()); } - - /** - * Creates a new graph for drawing. - * - * @param graphname, - * the name used to identify the graph in the dot source. - */ - public DotGraph(String graphname) { - this(graphname, false); + } + + /** + * Draws a directed edge (including the source and end nodes, if they have not already been + * drawn). + * + * @param from, the source node + * @param to, the end node + * @return a directed graph edge connecting {@code from} with {@code to} + */ + public DotGraphEdge drawEdge(String from, String to) { + return drawEdge(from, to, true); + } + + /** + * Draws a undirected edge (including the nodes, if they have not already been drawn). + * + * @param node1 + * @param node2 + * @return an undirected graph edge connecting {@code node1} with {@code node2} + */ + public DotGraphEdge drawUndirectedEdge(String node1, String node2) { + return drawEdge(node1, node2, false); + } + + private DotGraphEdge drawEdge(String from, String to, boolean directed) { + DotGraphNode src = drawNode(from); + DotGraphNode dst = drawNode(to); + DotGraphEdge edge = new DotGraphEdge(src, dst, directed); + + this.drawElements.add(edge); + + return edge; + } + + /** + * Draws a node. + * + * @param name, the node to draw. + * @return the {@link DotGraphNode} corresponding to the specified name. + */ + public DotGraphNode drawNode(String name) { + DotGraphNode node = getNode(name); + + if (node == null) { + throw new RuntimeException("Assertion failed."); } - /** - * Generates the drawing on canvas to the dot file. - * - * @param filename - * the name for the output file. By convention, it should end with DOT_EXTENSION, but this is not enforced. - */ - public void plot(String filename) { - try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(filename))) { - render(out, 0); - } catch (IOException ioe) { - logger.debug(ioe.getMessage()); - } + if (!this.drawElements.contains(node)) { + this.drawElements.add(node); } - /** - * Draws a directed edge (including the source and end nodes, if they have not already been drawn). - * - * @param from, - * the source node - * @param to, - * the end node - * @return a directed graph edge connecting {@code from} with {@code to} - */ - public DotGraphEdge drawEdge(String from, String to) { - return drawEdge(from, to, true); + return node; + } + + /** + * Gets the graph node by name. + * + * @param name, unique name of the node. + * @return the node with the specified name, adding a new node to the graph if there is no such + * node. + */ + public DotGraphNode getNode(String name) { + if (name == null) { + return null; } - /** - * Draws a undirected edge (including the nodes, if they have not already been drawn). - * - * @param node1 - * @param node2 - * - * @return an undirected graph edge connecting {@code node1} with {@code node2} - */ - public DotGraphEdge drawUndirectedEdge(String node1, String node2) { - return drawEdge(node1, node2, false); + DotGraphNode node = nodes.get(name); + if (node == null) { + node = new DotGraphNode(name, dontQuoteNodeNames); + nodes.put(name, node); } - - private DotGraphEdge drawEdge(String from, String to, boolean directed) { - DotGraphNode src = drawNode(from); - DotGraphNode dst = drawNode(to); - DotGraphEdge edge = new DotGraphEdge(src, dst, directed); - - this.drawElements.add(edge); - - return edge; - } - - /** - * Draws a node. - * - * @param name, - * the node to draw. - * @return the {@link DotGraphNode} corresponding to the specified name. - */ - public DotGraphNode drawNode(String name) { - DotGraphNode node = getNode(name); - - if (node == null) { - throw new RuntimeException("Assertion failed."); - } - - if (!this.drawElements.contains(node)) { - this.drawElements.add(node); - } - - return node; - } - - /** - * Gets the graph node by name. - * - * @param name, - * unique name of the node. - * @return the node with the specified name, adding a new node to the graph if there is no such node. - */ - public DotGraphNode getNode(String name) { - if (name == null) { - return null; - } - - DotGraphNode node = nodes.get(name); - if (node == null) { - node = new DotGraphNode(name, dontQuoteNodeNames); - nodes.put(name, node); - } - return node; + return node; + } + + /** + * Checks if the graph already contains the node with the specified name. + * + * @param name, unique name of the node. + * @return true if the node with the specified name is already in the graph, false otherwise + */ + public boolean containsNode(String name) { + return name != null && nodes.containsKey(name); + } + + /** + * Checks if the graph already contains the given {@link DotGraphNode}. + * + * @param node + * @return true if the node is already in the graph, false otherwise + */ + public boolean containsNode(DotGraphNode node) { + return this.drawElements.contains(node); + } + + /** + * NOTE: default is true + * + * @param value + */ + public void quoteNodeNames(boolean value) { + this.dontQuoteNodeNames = !value; + } + + /** + * Sets all node shapes, see the list of node shapes in DotGraphConstants. + * + * @param shape, the node shape + */ + public void setNodeShape(String shape) { + String command = "node [shape=" + shape + "];"; + this.drawElements.add(new DotGraphCommand(command)); + } + + /** + * Sets all node styles + * + * @param style, the node style + */ + public void setNodeStyle(String style) { + String command = "node [style=" + style + "];"; + this.drawElements.add(new DotGraphCommand(command)); + } + + /** sets the size of drawing area, in inches */ + public void setGraphSize(double width, double height) { + String size = "\"" + width + "," + height + "\""; + this.setAttribute("size", size); + } + + /** + * sets the pages size, once this is set, the generated graph will be broken into several pages. + */ + public void setPageSize(double width, double height) { + String size = "\"" + width + ", " + height + "\""; + this.setAttribute("page", size); + } + + /** sets the graph rotation angles */ + public void setOrientation(String orientation) { + this.setAttribute("orientation", orientation); + } + + /** sets the graph name */ + public void setGraphName(String name) { + this.graphname = name; + } + + /** NOTE: Alias for {@link #setLabel(java.lang.String)}. */ + public void setGraphLabel(String label) { + this.setLabel(label); + } + + /** + * sets any general attributes + * + *

NOTE: Alias for {@link #setAttribute(java.lang.String, java.lang.String)}. + * + * @param id is the attribute name. + * @param value is the attribute value. + */ + public void setGraphAttribute(String id, String value) { + this.setAttribute(id, value); + } + + /** + * sets any general attributes + * + *

NOTE: Alias for {@link #setAttribute(soot.util.dot.DotGraphAttribute)}. + * + * @param attr a {@link DotGraphAttribute} specifying the attribute name and value. + */ + public void setGraphAttribute(DotGraphAttribute attr) { + this.setAttribute(attr); + } + + /** + * creates a sub graph. + * + *

NOTE: Some renderers require subgraph labels to start with "cluster". + * + * @return the newly created sub graph. + */ + public DotGraph createSubGraph(String label) { + // file name is used as label of sub graph. + DotGraph subgraph = new DotGraph(label, true); + + this.drawElements.add(subgraph); + + return subgraph; + } + + /* implements renderable interface. */ + @Override + public void render(OutputStream out, int indent) throws IOException { + // header + if (!isSubGraph) { + DotGraphUtility.renderLine(out, "digraph \"" + this.graphname + "\" {", indent); + } else { + DotGraphUtility.renderLine(out, "subgraph \"" + this.graphname + "\" {", indent); } - /** - * Checks if the graph already contains the node with the specified name. - * - * @param name, - * unique name of the node. - * - * @return true if the node with the specified name is already in the graph, false otherwise - */ - public boolean containsNode(String name) { - return name != null && nodes.containsKey(name); + /* render graph attributes */ + for (DotGraphAttribute attr : this.getAttributes()) { + DotGraphUtility.renderLine(out, attr.toString() + ';', indent + 4); } - /** - * Checks if the graph already contains the given {@link DotGraphNode}. - * - * @param node - * - * @return true if the node is already in the graph, false otherwise - */ - public boolean containsNode(DotGraphNode node) { - return this.drawElements.contains(node); + /* render elements */ + for (Renderable element : this.drawElements) { + element.render(out, indent + 4); } - /** - * NOTE: default is true - * - * @param value - */ - public void quoteNodeNames(boolean value) { - this.dontQuoteNodeNames = !value; - } - - /** - * Sets all node shapes, see the list of node shapes in DotGraphConstants. - * - * @param shape, - * the node shape - */ - public void setNodeShape(String shape) { - String command = "node [shape=" + shape + "];"; - this.drawElements.add(new DotGraphCommand(command)); - } - - /** - * Sets all node styles - * - * @param style, - * the node style - */ - public void setNodeStyle(String style) { - String command = "node [style=" + style + "];"; - this.drawElements.add(new DotGraphCommand(command)); - } - - /** - * sets the size of drawing area, in inches - */ - public void setGraphSize(double width, double height) { - String size = "\"" + width + "," + height + "\""; - this.setAttribute("size", size); - } - - /** - * sets the pages size, once this is set, the generated graph will be broken into several pages. - */ - public void setPageSize(double width, double height) { - String size = "\"" + width + ", " + height + "\""; - this.setAttribute("page", size); - } - - /** - * sets the graph rotation angles - */ - public void setOrientation(String orientation) { - this.setAttribute("orientation", orientation); - } - - /** - * sets the graph name - */ - public void setGraphName(String name) { - this.graphname = name; - } - - /** - * NOTE: Alias for {@link #setLabel(java.lang.String)}. - */ - public void setGraphLabel(String label) { - this.setLabel(label); - } - - /** - * sets any general attributes - * - * NOTE: Alias for {@link #setAttribute(java.lang.String, java.lang.String)}. - * - * @param id - * is the attribute name. - * @param value - * is the attribute value. - */ - public void setGraphAttribute(String id, String value) { - this.setAttribute(id, value); - } - - /** - * sets any general attributes - * - * NOTE: Alias for {@link #setAttribute(soot.util.dot.DotGraphAttribute)}. - * - * @param attr - * a {@link DotGraphAttribute} specifying the attribute name and value. - */ - public void setGraphAttribute(DotGraphAttribute attr) { - this.setAttribute(attr); - } - - /** - * creates a sub graph. - * - * NOTE: Some renderers require subgraph labels to start with "cluster". - * - * @return the newly created sub graph. - */ - public DotGraph createSubGraph(String label) { - // file name is used as label of sub graph. - DotGraph subgraph = new DotGraph(label, true); - - this.drawElements.add(subgraph); - - return subgraph; - } - - /* implements renderable interface. */ - @Override - public void render(OutputStream out, int indent) throws IOException { - // header - if (!isSubGraph) { - DotGraphUtility.renderLine(out, "digraph \"" + this.graphname + "\" {", indent); - } else { - DotGraphUtility.renderLine(out, "subgraph \"" + this.graphname + "\" {", indent); - } - - /* render graph attributes */ - for (DotGraphAttribute attr : this.getAttributes()) { - DotGraphUtility.renderLine(out, attr.toString() + ';', indent + 4); - } - - /* render elements */ - for (Renderable element : this.drawElements) { - element.render(out, indent + 4); - } - - // close the description - DotGraphUtility.renderLine(out, "}", indent); - } + // close the description + DotGraphUtility.renderLine(out, "}", indent); + } } diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java index fe3797eb77d..6f4711c4fc5 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphAttribute.java @@ -29,25 +29,24 @@ */ public class DotGraphAttribute { - private final String id; - private final String value; - - public DotGraphAttribute(String id, String v) { - this.id = id; - this.value = v; - } - - @Override - public String toString() { - return this.id + '=' + this.value; - } - - public String getID() { - return this.id; - } - - public String getValue() { - return this.value; - } + private final String id; + private final String value; + + public DotGraphAttribute(String id, String v) { + this.id = id; + this.value = v; + } + + @Override + public String toString() { + return this.id + '=' + this.value; + } + + public String getID() { + return this.id; + } + + public String getValue() { + return this.value; + } } - diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java index 12e30951266..1014b9ace76 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphCommand.java @@ -25,33 +25,25 @@ import java.io.IOException; import java.io.OutputStream; -/** - * Encodes general Dot commands. - */ +/** Encodes general Dot commands. */ public class DotGraphCommand implements Renderable { - private final String command; + private final String command; - /** - * @param cmd - * a dot dommand string - */ - public DotGraphCommand(String cmd) { - this.command = cmd; - } + /** @param cmd a dot dommand string */ + public DotGraphCommand(String cmd) { + this.command = cmd; + } - /** - * Implements Renderable interface. - * - * @param out - * the output stream - * @param indent - * the number of indent space - * @see Renderable - */ - @Override - public void render(OutputStream out, int indent) throws IOException { - DotGraphUtility.renderLine(out, command, indent); - } + /** + * Implements Renderable interface. + * + * @param out the output stream + * @param indent the number of indent space + * @see Renderable + */ + @Override + public void render(OutputStream out, int indent) throws IOException { + DotGraphUtility.renderLine(out, command, indent); + } } - diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java index 5ea434b4af7..ddbdba11390 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphConstants.java @@ -27,28 +27,25 @@ * * @author Feng Qian */ - public interface DotGraphConstants { - public static final String NODE_SHAPE_BOX = "box"; - public static final String NODE_SHAPE_ELLIPSE = "ellipse"; - public static final String NODE_SHAPE_CIRCLE = "circle"; - public static final String NODE_SHAPE_DIAMOND = "diamond"; - public static final String NODE_SHAPE_PLAINTEXT = "plaintext"; - - public static final String NODE_STYLE_SOLID = "solid"; - public static final String NODE_STYLE_DASHED = "dashed"; - public static final String NODE_STYLE_DOTTED = "dotted"; - public static final String NODE_STYLE_BOLD = "bold"; - public static final String NODE_STYLE_INVISIBLE = "invis"; - public static final String NODE_STYLE_FILLED = "filled"; - public static final String NODE_STYLE_DIAGONALS = "diagonals"; - public static final String NODE_STYLE_ROUNDED = "rounded"; - - public static final String EDGE_STYLE_DOTTED = "dotted"; - public static final String EDGE_STYLE_SOLID = "solid"; - - public static final String GRAPH_ORIENT_PORTRAIT = "portrait"; - public static final String GRAPH_ORIENT_LANDSCAPE = "landscape"; - + public static final String NODE_SHAPE_BOX = "box"; + public static final String NODE_SHAPE_ELLIPSE = "ellipse"; + public static final String NODE_SHAPE_CIRCLE = "circle"; + public static final String NODE_SHAPE_DIAMOND = "diamond"; + public static final String NODE_SHAPE_PLAINTEXT = "plaintext"; + + public static final String NODE_STYLE_SOLID = "solid"; + public static final String NODE_STYLE_DASHED = "dashed"; + public static final String NODE_STYLE_DOTTED = "dotted"; + public static final String NODE_STYLE_BOLD = "bold"; + public static final String NODE_STYLE_INVISIBLE = "invis"; + public static final String NODE_STYLE_FILLED = "filled"; + public static final String NODE_STYLE_DIAGONALS = "diagonals"; + public static final String NODE_STYLE_ROUNDED = "rounded"; + + public static final String EDGE_STYLE_DOTTED = "dotted"; + public static final String EDGE_STYLE_SOLID = "solid"; + + public static final String GRAPH_ORIENT_PORTRAIT = "portrait"; + public static final String GRAPH_ORIENT_LANDSCAPE = "landscape"; } - diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java index 6fde5176408..602bf1acad7 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphEdge.java @@ -33,69 +33,62 @@ */ public class DotGraphEdge extends AbstractDotGraphElement implements Renderable { - private final DotGraphNode start; - private final DotGraphNode end; - private final boolean isDirected; + private final DotGraphNode start; + private final DotGraphNode end; + private final boolean isDirected; - /** - * Draws a directed edge. - * - * @param src, - * the source node - * @param dst, - * the end node - */ - public DotGraphEdge(DotGraphNode src, DotGraphNode dst) { - this.start = src; - this.end = dst; - this.isDirected = true; - } - - /** - * Draws a graph edge by specifying directed or undirected. - * - * @param src, - * the source node - * @param dst, - * the end node - * @param directed, - * the edge is directed or not - */ - public DotGraphEdge(DotGraphNode src, DotGraphNode dst, boolean directed) { - this.start = src; - this.end = dst; - this.isDirected = directed; - } + /** + * Draws a directed edge. + * + * @param src, the source node + * @param dst, the end node + */ + public DotGraphEdge(DotGraphNode src, DotGraphNode dst) { + this.start = src; + this.end = dst; + this.isDirected = true; + } - /** - * Sets the edge style. - * - * @param style, - * a style of edge - * @see DotGraphConstants - */ - public void setStyle(String style) { - this.setAttribute("style", style); - } + /** + * Draws a graph edge by specifying directed or undirected. + * + * @param src, the source node + * @param dst, the end node + * @param directed, the edge is directed or not + */ + public DotGraphEdge(DotGraphNode src, DotGraphNode dst, boolean directed) { + this.start = src; + this.end = dst; + this.isDirected = directed; + } - @Override - public void render(OutputStream out, int indent) throws IOException { - StringBuilder line = new StringBuilder(); - line.append(this.start.getName()); - line.append(this.isDirected ? "->" : "--"); - line.append(this.end.getName()); + /** + * Sets the edge style. + * + * @param style, a style of edge + * @see DotGraphConstants + */ + public void setStyle(String style) { + this.setAttribute("style", style); + } - Collection attrs = this.getAttributes(); - if (!attrs.isEmpty()) { - line.append(" ["); - for (DotGraphAttribute attr : attrs) { - line.append(attr.toString()).append(','); - } - line.append(']'); - } - line.append(';'); + @Override + public void render(OutputStream out, int indent) throws IOException { + StringBuilder line = new StringBuilder(); + line.append(this.start.getName()); + line.append(this.isDirected ? "->" : "--"); + line.append(this.end.getName()); - DotGraphUtility.renderLine(out, line.toString(), indent); + Collection attrs = this.getAttributes(); + if (!attrs.isEmpty()) { + line.append(" ["); + for (DotGraphAttribute attr : attrs) { + line.append(attr.toString()).append(','); + } + line.append(']'); } -} + line.append(';'); + DotGraphUtility.renderLine(out, line.toString(), indent); + } +} diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java index f00ed6cae4c..47e16cdfcc8 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphNode.java @@ -26,55 +26,55 @@ import java.io.OutputStream; import java.util.Collection; -/** - * A Dot graph node with various attributes. - */ +/** A Dot graph node with various attributes. */ public class DotGraphNode extends AbstractDotGraphElement implements Renderable { - private final String name; + private final String name; - public DotGraphNode(String name) { - // make any illegal name to be legal - this.name = '"' + DotGraphUtility.replaceQuotes(name) + '"'; - } + public DotGraphNode(String name) { + // make any illegal name to be legal + this.name = '"' + DotGraphUtility.replaceQuotes(name) + '"'; + } - public DotGraphNode(String name, boolean dontQuoteName) { - this.name = dontQuoteName ? DotGraphUtility.replaceQuotes(name) : '"' + DotGraphUtility.replaceQuotes(name) + '"'; - } - - public String getName() { - return this.name; - } + public DotGraphNode(String name, boolean dontQuoteName) { + this.name = + dontQuoteName + ? DotGraphUtility.replaceQuotes(name) + : '"' + DotGraphUtility.replaceQuotes(name) + '"'; + } - public void setHTMLLabel(String label) { - label = DotGraphUtility.replaceReturns(label); - this.setAttribute("label", label); - } + public String getName() { + return this.name; + } - public void setShape(String shape) { - this.setAttribute("shape", shape); - } + public void setHTMLLabel(String label) { + label = DotGraphUtility.replaceReturns(label); + this.setAttribute("label", label); + } - public void setStyle(String style) { - this.setAttribute("style", style); - } + public void setShape(String shape) { + this.setAttribute("shape", shape); + } - @Override - public void render(OutputStream out, int indent) throws IOException { - StringBuilder line = new StringBuilder(); - line.append(this.getName()); + public void setStyle(String style) { + this.setAttribute("style", style); + } - Collection attrs = this.getAttributes(); - if (!attrs.isEmpty()) { - line.append(" ["); - for (DotGraphAttribute attr : attrs) { - line.append(attr.toString()).append(','); - } - line.append(']'); - } - line.append(';'); + @Override + public void render(OutputStream out, int indent) throws IOException { + StringBuilder line = new StringBuilder(); + line.append(this.getName()); - DotGraphUtility.renderLine(out, line.toString(), indent); + Collection attrs = this.getAttributes(); + if (!attrs.isEmpty()) { + line.append(" ["); + for (DotGraphAttribute attr : attrs) { + line.append(attr.toString()).append(','); + } + line.append(']'); } -} + line.append(';'); + DotGraphUtility.renderLine(out, line.toString(), indent); + } +} diff --git a/sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java b/sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java index b12c214b11f..d363c5212f5 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java +++ b/sootup.qilin/src/main/java/soot/util/dot/DotGraphUtility.java @@ -25,104 +25,101 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DotGraphUtility { - private static final Logger logger = LoggerFactory.getLogger(DotGraphUtility.class); + private static final Logger logger = LoggerFactory.getLogger(DotGraphUtility.class); - /** - * Replace any {@code "} with {@code \"}. If the {@code "} character was already escaped (i.e. {@code \"}), then the escape - * character is also escaped (i.e. {@code \\\"}). - * - * @param original - * - * @return - */ - public static String replaceQuotes(String original) { - byte[] ord = original.getBytes(); - int quotes = 0; - boolean escapeActive = false; - for (byte element : ord) { - switch (element) { - case '\\': - escapeActive = true; - break; - case '\"': - quotes++; - if (escapeActive) { - quotes++; - } - // fallthrough - default: - escapeActive = false; - break; - } - } + /** + * Replace any {@code "} with {@code \"}. If the {@code "} character was already escaped (i.e. + * {@code \"}), then the escape character is also escaped (i.e. {@code \\\"}). + * + * @param original + * @return + */ + public static String replaceQuotes(String original) { + byte[] ord = original.getBytes(); + int quotes = 0; + boolean escapeActive = false; + for (byte element : ord) { + switch (element) { + case '\\': + escapeActive = true; + break; + case '\"': + quotes++; + if (escapeActive) { + quotes++; + } + // fallthrough + default: + escapeActive = false; + break; + } + } - if (quotes == 0) { - return original; - } + if (quotes == 0) { + return original; + } - byte[] newsrc = new byte[ord.length + quotes]; - for (int i = 0, j = 0, n = ord.length; i < n; i++, j++) { - if (ord[i] == '\"') { - if (i > 0 && ord[i - 1] == '\\') { - newsrc[j++] = (byte) '\\'; - } - newsrc[j++] = (byte) '\\'; - } - newsrc[j] = ord[i]; + byte[] newsrc = new byte[ord.length + quotes]; + for (int i = 0, j = 0, n = ord.length; i < n; i++, j++) { + if (ord[i] == '\"') { + if (i > 0 && ord[i - 1] == '\\') { + newsrc[j++] = (byte) '\\'; } - - /* - * logger.debug("before "+original); logger.debug("after "+(new String(newsrc))); - */ - return new String(newsrc); + newsrc[j++] = (byte) '\\'; + } + newsrc[j] = ord[i]; } - /** - * Replace any return ({@code \n}) with {@code \\n}. - * - * @param original - * - * @return + /* + * logger.debug("before "+original); logger.debug("after "+(new String(newsrc))); */ - public static String replaceReturns(String original) { - byte[] ord = original.getBytes(); - int quotes = 0; - for (byte element : ord) { - if (element == '\n') { - quotes++; - } - } + return new String(newsrc); + } - if (quotes == 0) { - return original; - } - - byte[] newsrc = new byte[ord.length + quotes]; - for (int i = 0, j = 0, n = ord.length; i < n; i++, j++) { - if (ord[i] == '\n') { - newsrc[j++] = (byte) '\\'; - newsrc[j] = (byte) 'n'; - } else { - newsrc[j] = ord[i]; - } - } + /** + * Replace any return ({@code \n}) with {@code \\n}. + * + * @param original + * @return + */ + public static String replaceReturns(String original) { + byte[] ord = original.getBytes(); + int quotes = 0; + for (byte element : ord) { + if (element == '\n') { + quotes++; + } + } - /* - * logger.debug("before "+original); logger.debug("after "+(new String(newsrc))); - */ - return new String(newsrc); + if (quotes == 0) { + return original; } - public static void renderLine(OutputStream out, String content, int indent) throws IOException { - char[] indentChars = new char[indent]; - Arrays.fill(indentChars, ' '); - StringBuilder sb = new StringBuilder(); - sb.append(indentChars).append(content).append('\n'); - out.write(sb.toString().getBytes()); + byte[] newsrc = new byte[ord.length + quotes]; + for (int i = 0, j = 0, n = ord.length; i < n; i++, j++) { + if (ord[i] == '\n') { + newsrc[j++] = (byte) '\\'; + newsrc[j] = (byte) 'n'; + } else { + newsrc[j] = ord[i]; + } } + + /* + * logger.debug("before "+original); logger.debug("after "+(new String(newsrc))); + */ + return new String(newsrc); + } + + public static void renderLine(OutputStream out, String content, int indent) throws IOException { + char[] indentChars = new char[indent]; + Arrays.fill(indentChars, ' '); + StringBuilder sb = new StringBuilder(); + sb.append(indentChars).append(content).append('\n'); + out.write(sb.toString().getBytes()); + } } diff --git a/sootup.qilin/src/main/java/soot/util/dot/Renderable.java b/sootup.qilin/src/main/java/soot/util/dot/Renderable.java index 2ce0ac63651..8ccbcabeb78 100644 --- a/sootup.qilin/src/main/java/soot/util/dot/Renderable.java +++ b/sootup.qilin/src/main/java/soot/util/dot/Renderable.java @@ -26,5 +26,5 @@ import java.io.OutputStream; public interface Renderable { - public void render(OutputStream device, int indent) throws IOException; + public void render(OutputStream device, int indent) throws IOException; } diff --git a/sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java b/sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java index 3bb23c22277..2909195dfa4 100644 --- a/sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java +++ b/sootup.qilin/src/main/java/soot/util/queue/ChunkedQueue.java @@ -23,75 +23,75 @@ */ /** - * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary - * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not - * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the - * QueueReader was created. + * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. + * One can create arbitrary numbers of QueueReader's for a queue, and each one receives all the + * Object's that are added. Only objects that have not been read by all the QueueReader's are kept. + * A QueueReader only receives the Object's added to the queue after the QueueReader was + * created. * * @author Ondrej Lhotak */ @SuppressWarnings("unchecked") public class ChunkedQueue { - protected static final Object NULL_CONST = new Object(); - protected static final Object DELETED_CONST = new Object(); + protected static final Object NULL_CONST = new Object(); + protected static final Object DELETED_CONST = new Object(); - protected static final int LENGTH = 60; - protected Object[] q; - protected int index; + protected static final int LENGTH = 60; + protected Object[] q; + protected int index; - public ChunkedQueue() { - q = new Object[LENGTH]; - index = 0; - } + public ChunkedQueue() { + q = new Object[LENGTH]; + index = 0; + } - /** Add an object to the queue. */ - public void add(E o) { - if (o == null) { - o = (E) NULL_CONST; - } - if (index == LENGTH - 1) { - Object[] temp = new Object[LENGTH]; - q[index] = temp; - q = temp; - index = 0; - } - q[index++] = o; + /** Add an object to the queue. */ + public void add(E o) { + if (o == null) { + o = (E) NULL_CONST; } - - /** Create reader which will read objects from the queue. */ - public QueueReader reader() { - return new QueueReader((E[]) q, index); + if (index == LENGTH - 1) { + Object[] temp = new Object[LENGTH]; + q[index] = temp; + q = temp; + index = 0; } + q[index++] = o; + } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - boolean isFirst = true; + /** Create reader which will read objects from the queue. */ + public QueueReader reader() { + return new QueueReader((E[]) q, index); + } - int idx = index; - Object[] curArray = q; - while (idx < curArray.length) { - Object curObj = curArray[idx]; - if (curObj == null) { - break; - } - if (isFirst) { - isFirst = false; - } else { - sb.append(", "); - } - if (curObj instanceof Object[]) { - curArray = (Object[]) curObj; - idx = 0; - } else { - sb.append(curObj.toString()); - idx++; - } - } - sb.append("]"); - return sb.toString(); - } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + boolean isFirst = true; + int idx = index; + Object[] curArray = q; + while (idx < curArray.length) { + Object curObj = curArray[idx]; + if (curObj == null) { + break; + } + if (isFirst) { + isFirst = false; + } else { + sb.append(", "); + } + if (curObj instanceof Object[]) { + curArray = (Object[]) curObj; + idx = 0; + } else { + sb.append(curObj.toString()); + idx++; + } + } + sb.append("]"); + return sb.toString(); + } } diff --git a/sootup.qilin/src/main/java/soot/util/queue/QueueReader.java b/sootup.qilin/src/main/java/soot/util/queue/QueueReader.java index b6c647fc9ad..4f490299653 100644 --- a/sootup.qilin/src/main/java/soot/util/queue/QueueReader.java +++ b/sootup.qilin/src/main/java/soot/util/queue/QueueReader.java @@ -1,8 +1,5 @@ package soot.util.queue; -import java.util.Collection; -import java.util.Collections; - /*- * #%L * Soot - a J*va Optimization Framework @@ -25,178 +22,175 @@ * #L% */ +import java.util.Collection; +import java.util.Collections; import java.util.NoSuchElementException; - import soot.util.Invalidable; /** - * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. One can create arbitrary - * numbers of QueueReader's for a queue, and each one receives all the Object's that are added. Only objects that have not - * been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue after the - * QueueReader was created. + * A queue of Object's. One can add objects to the queue, and they are later read by a QueueReader. + * One can create arbitrary numbers of QueueReader's for a queue, and each one receives all the + * Object's that are added. Only objects that have not been read by all the QueueReader's are kept. + * A QueueReader only receives the Object's added to the queue after the QueueReader was + * created. * * @author Ondrej Lhotak */ public class QueueReader implements java.util.Iterator { - protected E[] q; - protected int index; - - protected QueueReader(E[] q, int index) { - this.q = q; - this.index = index; - } - - /** - * Returns (and removes) the next object in the queue, or null if there are none. - */ - @SuppressWarnings("unchecked") - public E next() { - Object ret = null; - do { - if (q[index] == null) { - throw new NoSuchElementException(); - } - if (index == q.length - 1) { - q = (E[]) q[index]; - index = 0; - if (q[index] == null) { - throw new NoSuchElementException(); - } - } - ret = q[index]; - if (ret == ChunkedQueue.NULL_CONST) { - ret = null; - } - index++; - } while (skip(ret)); - return (E) ret; - } - - protected boolean skip(Object ret) { - if (ret instanceof Invalidable) { - final Invalidable invalidable = (Invalidable) ret; - if (invalidable.isInvalid()) { - return true; - } + protected E[] q; + protected int index; + + protected QueueReader(E[] q, int index) { + this.q = q; + this.index = index; + } + + /** Returns (and removes) the next object in the queue, or null if there are none. */ + @SuppressWarnings("unchecked") + public E next() { + Object ret = null; + do { + if (q[index] == null) { + throw new NoSuchElementException(); + } + if (index == q.length - 1) { + q = (E[]) q[index]; + index = 0; + if (q[index] == null) { + throw new NoSuchElementException(); } - return ret == ChunkedQueue.DELETED_CONST; + } + ret = q[index]; + if (ret == ChunkedQueue.NULL_CONST) { + ret = null; + } + index++; + } while (skip(ret)); + return (E) ret; + } + + protected boolean skip(Object ret) { + if (ret instanceof Invalidable) { + final Invalidable invalidable = (Invalidable) ret; + if (invalidable.isInvalid()) { + return true; + } } - - /** Returns true iff there is currently another object in the queue. */ - @SuppressWarnings("unchecked") - public boolean hasNext() { - do { - E ret = q[index]; - if (ret == null) { - return false; - } - if (index == q.length - 1) { - q = (E[]) ret; - index = 0; - if (q[index] == null) { - return false; - } - } - if (skip(ret)) { - index++; - } else { - return true; - } - } while (true); - } - - /** - * Removes an element from the underlying queue. This operation can only delete elements that have not yet been consumed by - * this reader. - * - * @param o - * The element to remove - */ - public void remove(E o) { - if (o instanceof Invalidable) { - ((Invalidable) o).invalidate(); - return; + return ret == ChunkedQueue.DELETED_CONST; + } + + /** Returns true iff there is currently another object in the queue. */ + @SuppressWarnings("unchecked") + public boolean hasNext() { + do { + E ret = q[index]; + if (ret == null) { + return false; + } + if (index == q.length - 1) { + q = (E[]) ret; + index = 0; + if (q[index] == null) { + return false; } - remove(Collections.singleton(o)); + } + if (skip(ret)) { + index++; + } else { + return true; + } + } while (true); + } + + /** + * Removes an element from the underlying queue. This operation can only delete elements that have + * not yet been consumed by this reader. + * + * @param o The element to remove + */ + public void remove(E o) { + if (o instanceof Invalidable) { + ((Invalidable) o).invalidate(); + return; } - - /** - * Removes elements from the underlying queue. This operation can only delete elements that have not yet been consumed by - * this reader. - * - * @param toRemove - * The elements to remove - */ - @SuppressWarnings("unchecked") - public void remove(Collection toRemove) { - boolean allInvalidable = true; - for (E o : toRemove) { - if (!(o instanceof Invalidable)) { - allInvalidable = false; - continue; - } - - ((Invalidable) o).invalidate(); - } - if (allInvalidable) { - return; - } - int idx = 0; - Object[] curQ = q; - while (curQ[idx] != null) { - // Do we need to switch to a new list? - if (idx == curQ.length - 1) { - curQ = (E[]) curQ[idx]; - idx = 0; - } - - // Is this the element to delete? - if (toRemove.contains(curQ[idx])) { - curQ[idx] = ChunkedQueue.DELETED_CONST; - } - - // Next element - idx++; - } + remove(Collections.singleton(o)); + } + + /** + * Removes elements from the underlying queue. This operation can only delete elements that have + * not yet been consumed by this reader. + * + * @param toRemove The elements to remove + */ + @SuppressWarnings("unchecked") + public void remove(Collection toRemove) { + boolean allInvalidable = true; + for (E o : toRemove) { + if (!(o instanceof Invalidable)) { + allInvalidable = false; + continue; + } + + ((Invalidable) o).invalidate(); } - - @SuppressWarnings("unchecked") - public void remove() { - q[index - 1] = (E) ChunkedQueue.DELETED_CONST; + if (allInvalidable) { + return; } - - public QueueReader clone() { - return new QueueReader(q, index); + int idx = 0; + Object[] curQ = q; + while (curQ[idx] != null) { + // Do we need to switch to a new list? + if (idx == curQ.length - 1) { + curQ = (E[]) curQ[idx]; + idx = 0; + } + + // Is this the element to delete? + if (toRemove.contains(curQ[idx])) { + curQ[idx] = ChunkedQueue.DELETED_CONST; + } + + // Next element + idx++; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("["); - boolean isFirst = true; - - int idx = index; - Object[] curArray = q; - while (idx < curArray.length) { - Object curObj = curArray[idx]; - if (curObj == null) { - break; - } - if (isFirst) { - isFirst = false; - } else { - sb.append(", "); - } - if (curObj instanceof Object[]) { - curArray = (Object[]) curObj; - idx = 0; - } else { - sb.append(curObj.toString()); - idx++; - } - } - sb.append("]"); - return sb.toString(); + } + + @SuppressWarnings("unchecked") + public void remove() { + q[index - 1] = (E) ChunkedQueue.DELETED_CONST; + } + + public QueueReader clone() { + return new QueueReader(q, index); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + boolean isFirst = true; + + int idx = index; + Object[] curArray = q; + while (idx < curArray.length) { + Object curObj = curArray[idx]; + if (curObj == null) { + break; + } + if (isFirst) { + isFirst = false; + } else { + sb.append(", "); + } + if (curObj instanceof Object[]) { + curArray = (Object[]) curObj; + idx = 0; + } else { + sb.append(curObj.toString()); + idx++; + } } - + sb.append("]"); + return sb.toString(); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/FlowSensTests.java b/sootup.qilin/src/test/java/qilin/test/FlowSensTests.java index 05a39cd234b..adff75c48d9 100644 --- a/sootup.qilin/src/test/java/qilin/test/FlowSensTests.java +++ b/sootup.qilin/src/test/java/qilin/test/FlowSensTests.java @@ -23,33 +23,33 @@ import qilin.test.util.JunitTests; public class FlowSensTests extends JunitTests { - @Test - public void testLoops() { - checkAssertions(run("qilin.microben.flowsens.Loops")); - } - - @Ignore - public void testFlowSens0() { - checkAssertions(run("qilin.microben.flowsens.FlowSens0")); - } - - @Ignore - public void testInstanceOf0() { - checkAssertions(run("qilin.microben.flowsens.InstanceOf0")); - } - - @Ignore - public void testBranching1() { - checkAssertions(run("qilin.microben.flowsens.Branching1")); - } - - @Ignore - public void testStrongUpdate1() { - checkAssertions(run("qilin.microben.flowsens.StrongUpdate1")); - } - - @Ignore - public void testStrongUpdate2() { - checkAssertions(run("qilin.microben.flowsens.StrongUpdate2")); - } + @Test + public void testLoops() { + checkAssertions(run("qilin.microben.flowsens.Loops")); + } + + @Ignore + public void testFlowSens0() { + checkAssertions(run("qilin.microben.flowsens.FlowSens0")); + } + + @Ignore + public void testInstanceOf0() { + checkAssertions(run("qilin.microben.flowsens.InstanceOf0")); + } + + @Ignore + public void testBranching1() { + checkAssertions(run("qilin.microben.flowsens.Branching1")); + } + + @Ignore + public void testStrongUpdate1() { + checkAssertions(run("qilin.microben.flowsens.StrongUpdate1")); + } + + @Ignore + public void testStrongUpdate2() { + checkAssertions(run("qilin.microben.flowsens.StrongUpdate2")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/context/CFATests.java b/sootup.qilin/src/test/java/qilin/test/context/CFATests.java index 4da40496480..043a155c280 100644 --- a/sootup.qilin/src/test/java/qilin/test/context/CFATests.java +++ b/sootup.qilin/src/test/java/qilin/test/context/CFATests.java @@ -23,23 +23,23 @@ public class CFATests extends JunitTests { - @Test - public void testCFA1k0() { - checkAssertions(run("qilin.microben.context.cfa.CFA1k0", "1c")); - } + @Test + public void testCFA1k0() { + checkAssertions(run("qilin.microben.context.cfa.CFA1k0", "1c")); + } - @Test - public void testCFA1k1() { - checkAssertions(run("qilin.microben.context.cfa.CFA1k1", "1c")); - } + @Test + public void testCFA1k1() { + checkAssertions(run("qilin.microben.context.cfa.CFA1k1", "1c")); + } - @Test - public void testCFA1k2() { - checkAssertions(run("qilin.microben.context.cfa.CFA1k2", "1c")); - } + @Test + public void testCFA1k2() { + checkAssertions(run("qilin.microben.context.cfa.CFA1k2", "1c")); + } - @Test - public void testCFA2k() { - checkAssertions(run("qilin.microben.context.cfa.CFA2k", "2c")); - } -} \ No newline at end of file + @Test + public void testCFA2k() { + checkAssertions(run("qilin.microben.context.cfa.CFA2k", "2c")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java b/sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java index 067865f9812..1eb75ca117b 100644 --- a/sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java +++ b/sootup.qilin/src/test/java/qilin/test/context/CollectionsTests.java @@ -22,53 +22,53 @@ import qilin.test.util.JunitTests; public class CollectionsTests extends JunitTests { - @Test - public void testArrayList0() { - checkAssertions(run("qilin.microben.context.collections.ArrayList0", "2o")); - } + @Test + public void testArrayList0() { + checkAssertions(run("qilin.microben.context.collections.ArrayList0", "2o")); + } - @Test - public void testLinkedList0() { - checkAssertions(run("qilin.microben.context.collections.LinkedList0", "2o")); - } + @Test + public void testLinkedList0() { + checkAssertions(run("qilin.microben.context.collections.LinkedList0", "2o")); + } - @Test - public void testVector0() { - checkAssertions(run("qilin.microben.context.collections.Vector0", "2o")); - } + @Test + public void testVector0() { + checkAssertions(run("qilin.microben.context.collections.Vector0", "2o")); + } - @Test - public void testHashMap0() { - checkAssertions(run("qilin.microben.context.collections.HashMap0", "2o")); - } + @Test + public void testHashMap0() { + checkAssertions(run("qilin.microben.context.collections.HashMap0", "2o")); + } - @Test - public void testTreeMap0() { - checkAssertions(run("qilin.microben.context.collections.TreeMap0", "2o")); - } + @Test + public void testTreeMap0() { + checkAssertions(run("qilin.microben.context.collections.TreeMap0", "2o")); + } - @Test - public void testHashSet0() { - checkAssertions(run("qilin.microben.context.collections.HashSet0", "3o")); - } + @Test + public void testHashSet0() { + checkAssertions(run("qilin.microben.context.collections.HashSet0", "3o")); + } - @Test - public void testTreeSet0() { - checkAssertions(run("qilin.microben.context.collections.TreeSet0", "3o")); - } + @Test + public void testTreeSet0() { + checkAssertions(run("qilin.microben.context.collections.TreeSet0", "3o")); + } - @Test - public void testHashTable0() { - checkAssertions(run("qilin.microben.context.collections.HashTable0", "2o")); - } + @Test + public void testHashTable0() { + checkAssertions(run("qilin.microben.context.collections.HashTable0", "2o")); + } - @Test - public void testPriorityQueue0() { - checkAssertions(run("qilin.microben.context.collections.PriorityQueue0", "2o")); - } + @Test + public void testPriorityQueue0() { + checkAssertions(run("qilin.microben.context.collections.PriorityQueue0", "2o")); + } - @Test - public void testStack0() { - checkAssertions(run("qilin.microben.context.collections.Stack0", "2o")); - } -} \ No newline at end of file + @Test + public void testStack0() { + checkAssertions(run("qilin.microben.context.collections.Stack0", "2o")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/context/HybTests.java b/sootup.qilin/src/test/java/qilin/test/context/HybTests.java index f34e0f11fbb..7a661ef3408 100644 --- a/sootup.qilin/src/test/java/qilin/test/context/HybTests.java +++ b/sootup.qilin/src/test/java/qilin/test/context/HybTests.java @@ -22,18 +22,18 @@ import qilin.test.util.JunitTests; public class HybTests extends JunitTests { - @Test - public void testHyb0() { - checkAssertions(run("qilin.microben.context.hyb.Hyb0", "1h")); - } + @Test + public void testHyb0() { + checkAssertions(run("qilin.microben.context.hyb.Hyb0", "1h")); + } - @Test - public void testHyb1() { - checkAssertions(run("qilin.microben.context.hyb.Hyb1", "1h")); - } + @Test + public void testHyb1() { + checkAssertions(run("qilin.microben.context.hyb.Hyb1", "1h")); + } - @Test - public void testHyb2() { - checkAssertions(run("qilin.microben.context.hyb.Hyb2", "2h")); - } + @Test + public void testHyb2() { + checkAssertions(run("qilin.microben.context.hyb.Hyb2", "2h")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/context/OBJTests.java b/sootup.qilin/src/test/java/qilin/test/context/OBJTests.java index 3c117bffec0..ffb34279e19 100644 --- a/sootup.qilin/src/test/java/qilin/test/context/OBJTests.java +++ b/sootup.qilin/src/test/java/qilin/test/context/OBJTests.java @@ -22,49 +22,48 @@ import qilin.test.util.JunitTests; public class OBJTests extends JunitTests { - @Test - public void testOBJ1k0() { - checkAssertions(run("qilin.microben.context.obj.OBJ1k0", "1o")); - } + @Test + public void testOBJ1k0() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k0", "1o")); + } - @Test - public void testOBJ1k1() { - checkAssertions(run("qilin.microben.context.obj.OBJ1k1", "1o")); - } + @Test + public void testOBJ1k1() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k1", "1o")); + } - @Test - public void testOBJ1k2() { - checkAssertions(run("qilin.microben.context.obj.OBJ1k2", "1o")); - } + @Test + public void testOBJ1k2() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k2", "1o")); + } - @Test - public void testOBJ1k3() { - checkAssertions(run("qilin.microben.context.obj.OBJ1k3", "1o")); - } + @Test + public void testOBJ1k3() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k3", "1o")); + } - @Test - public void testOBJ1k4() { - checkAssertions(run("qilin.microben.context.obj.OBJ1k4", "1o")); - } + @Test + public void testOBJ1k4() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k4", "1o")); + } - @Test - public void testOBJ1k5() { - checkAssertions(run("qilin.microben.context.obj.OBJ1k5", "1o")); - } + @Test + public void testOBJ1k5() { + checkAssertions(run("qilin.microben.context.obj.OBJ1k5", "1o")); + } - @Test - public void testOBJ2k0() { - checkAssertions(run("qilin.microben.context.obj.OBJ2k0", "2o")); - } + @Test + public void testOBJ2k0() { + checkAssertions(run("qilin.microben.context.obj.OBJ2k0", "2o")); + } - @Test - public void testOBJ2k1() { - checkAssertions(run("qilin.microben.context.obj.OBJ2k1", "2o")); - } + @Test + public void testOBJ2k1() { + checkAssertions(run("qilin.microben.context.obj.OBJ2k1", "2o")); + } - @Test - public void testOBJ2k2() { - checkAssertions(run("qilin.microben.context.obj.OBJ2k2", "2o")); - } - -} \ No newline at end of file + @Test + public void testOBJ2k2() { + checkAssertions(run("qilin.microben.context.obj.OBJ2k2", "2o")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/context/TypeTests.java b/sootup.qilin/src/test/java/qilin/test/context/TypeTests.java index 2209e615bc4..9d239007643 100644 --- a/sootup.qilin/src/test/java/qilin/test/context/TypeTests.java +++ b/sootup.qilin/src/test/java/qilin/test/context/TypeTests.java @@ -22,13 +22,13 @@ import qilin.test.util.JunitTests; public class TypeTests extends JunitTests { - @Test - public void testType1k0() { - checkAssertions(run("qilin.microben.context.type.Type1k0", "1t")); - } + @Test + public void testType1k0() { + checkAssertions(run("qilin.microben.context.type.Type1k0", "1t")); + } - @Test - public void testType2k0() { - checkAssertions(run("qilin.microben.context.type.Type2k0", "2t")); - } + @Test + public void testType2k0() { + checkAssertions(run("qilin.microben.context.type.Type2k0", "2t")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java b/sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java index ef61af62f71..213467a4d82 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/ArrayTests.java @@ -22,28 +22,28 @@ import qilin.test.util.JunitTests; public class ArrayTests extends JunitTests { - @Test - public void testArrayIndex() { - checkAssertions(run("qilin.microben.core.array.ArrayIndex")); - } + @Test + public void testArrayIndex() { + checkAssertions(run("qilin.microben.core.array.ArrayIndex")); + } - @Test - public void testMultiArraySimple() { - checkAssertions(run("qilin.microben.core.array.MultiArraySimple")); - } + @Test + public void testMultiArraySimple() { + checkAssertions(run("qilin.microben.core.array.MultiArraySimple")); + } - @Test - public void testMultiArrayComplex() { - checkAssertions(run("qilin.microben.core.array.MultiArrayComplex")); - } + @Test + public void testMultiArrayComplex() { + checkAssertions(run("qilin.microben.core.array.MultiArrayComplex")); + } - @Test - public void testArrayCopy() { - checkAssertions(run("qilin.microben.core.array.ArrayCopy")); - } + @Test + public void testArrayCopy() { + checkAssertions(run("qilin.microben.core.array.ArrayCopy")); + } - @Test - public void testArrayElemTypeFiltering() { - checkAssertions(run("qilin.microben.core.array.ArrayElemTypeFiltering")); - } + @Test + public void testArrayElemTypeFiltering() { + checkAssertions(run("qilin.microben.core.array.ArrayElemTypeFiltering")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/AssignTests.java b/sootup.qilin/src/test/java/qilin/test/core/AssignTests.java index 188c5a3620a..686c22e90f6 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/AssignTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/AssignTests.java @@ -23,67 +23,67 @@ import qilin.test.util.JunitTests; public class AssignTests extends JunitTests { - @Test - public void testCastFail() { - checkAssertions(run("qilin.microben.core.assign.CastFail")); - } + @Test + public void testCastFail() { + checkAssertions(run("qilin.microben.core.assign.CastFail")); + } - @Test - public void testCastSucc() { - checkAssertions(run("qilin.microben.core.assign.CastSucc")); - } + @Test + public void testCastSucc() { + checkAssertions(run("qilin.microben.core.assign.CastSucc")); + } - @Test - public void testReceiver2This() { - checkAssertions(run("qilin.microben.core.assign.Receiver2This")); - } + @Test + public void testReceiver2This() { + checkAssertions(run("qilin.microben.core.assign.Receiver2This")); + } - @Test - public void testSimpleAssign() { - checkAssertions(run("qilin.microben.core.assign.SimpleAssign")); - System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); - } + @Test + public void testSimpleAssign() { + checkAssertions(run("qilin.microben.core.assign.SimpleAssign")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } - @Test - public void testReturnValue0() { - checkAssertions(run("qilin.microben.core.assign.ReturnValue0")); - System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); - } + @Test + public void testReturnValue0() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue0")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } - @Test - public void testReturnValue1() { - checkAssertions(run("qilin.microben.core.assign.ReturnValue1")); - System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); - } + @Test + public void testReturnValue1() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue1")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } - @Test - public void testReturnValue2() { - checkAssertions(run("qilin.microben.core.assign.ReturnValue2")); - } + @Test + public void testReturnValue2() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue2")); + } - @Test - public void testReturnValue3() { - checkAssertions(run("qilin.microben.core.assign.ReturnValue3")); - } + @Test + public void testReturnValue3() { + checkAssertions(run("qilin.microben.core.assign.ReturnValue3")); + } - @Test - public void testInterAssign() { - checkAssertions(run("qilin.microben.core.assign.InterAssign")); - } + @Test + public void testInterAssign() { + checkAssertions(run("qilin.microben.core.assign.InterAssign")); + } - @Test - public void testStaticParameter() { - checkAssertions(run("qilin.microben.core.assign.StaticParameter")); - } + @Test + public void testStaticParameter() { + checkAssertions(run("qilin.microben.core.assign.StaticParameter")); + } - @Test - public void testNullPointer() { - checkAssertions(run("qilin.microben.core.assign.NullPointer")); - } + @Test + public void testNullPointer() { + checkAssertions(run("qilin.microben.core.assign.NullPointer")); + } - @Test - public void testRecursion() { - checkAssertions(run("qilin.microben.core.assign.Recursion")); - System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); - } + @Test + public void testRecursion() { + checkAssertions(run("qilin.microben.core.assign.Recursion")); + System.out.println(PTAConfig.v().getAppConfig().MAIN_CLASS); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/CallTests.java b/sootup.qilin/src/test/java/qilin/test/core/CallTests.java index 61cf8127993..9345667ed3a 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/CallTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/CallTests.java @@ -22,19 +22,18 @@ import qilin.test.util.JunitTests; public class CallTests extends JunitTests { - @Test - public void testVirtualCall0() { - checkAssertions(run("qilin.microben.core.call.VirtualCall0")); - } + @Test + public void testVirtualCall0() { + checkAssertions(run("qilin.microben.core.call.VirtualCall0")); + } - @Test - public void testVirtualCall1() { - checkAssertions(run("qilin.microben.core.call.VirtualCall1")); - } - - @Test - public void testStaticCall() { - checkAssertions(run("qilin.microben.core.call.StaticCall")); - } + @Test + public void testVirtualCall1() { + checkAssertions(run("qilin.microben.core.call.VirtualCall1")); + } + @Test + public void testStaticCall() { + checkAssertions(run("qilin.microben.core.call.StaticCall")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java b/sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java index 751e0b99dd5..e763ced70a7 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/ClinitTests.java @@ -22,23 +22,23 @@ import qilin.test.util.JunitTests; public class ClinitTests extends JunitTests { - @Test - public void testClinitNewExpr() { - checkAssertions(run("qilin.microben.core.clinit.ClinitNewExpr")); - } + @Test + public void testClinitNewExpr() { + checkAssertions(run("qilin.microben.core.clinit.ClinitNewExpr")); + } - @Test - public void testClinitStaticCall() { - checkAssertions(run("qilin.microben.core.clinit.ClinitStaticCall")); - } + @Test + public void testClinitStaticCall() { + checkAssertions(run("qilin.microben.core.clinit.ClinitStaticCall")); + } - @Test - public void testClinitStaticLoad() { - checkAssertions(run("qilin.microben.core.clinit.ClinitStaticLoad")); - } + @Test + public void testClinitStaticLoad() { + checkAssertions(run("qilin.microben.core.clinit.ClinitStaticLoad")); + } - @Test - public void testClinitStaticStore() { - checkAssertions(run("qilin.microben.core.clinit.ClinitStaticStore")); - } + @Test + public void testClinitStaticStore() { + checkAssertions(run("qilin.microben.core.clinit.ClinitStaticStore")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java b/sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java index a60d92ebb26..af0c61ff658 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/ExceptionTests.java @@ -22,18 +22,18 @@ import qilin.test.util.JunitTests; public class ExceptionTests extends JunitTests { - @Test - public void testSimpleException() { - checkAssertions(run("qilin.microben.core.exception.SimpleException")); - } + @Test + public void testSimpleException() { + checkAssertions(run("qilin.microben.core.exception.SimpleException")); + } - @Test - public void testExceptionChain() { - checkAssertions(run("qilin.microben.core.exception.ExceptionChain")); - } + @Test + public void testExceptionChain() { + checkAssertions(run("qilin.microben.core.exception.ExceptionChain")); + } - @Test - public void testMethodThrow() { - checkAssertions(run("qilin.microben.core.exception.MethodThrow")); - } -} \ No newline at end of file + @Test + public void testMethodThrow() { + checkAssertions(run("qilin.microben.core.exception.MethodThrow")); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/core/FieldTests.java b/sootup.qilin/src/test/java/qilin/test/core/FieldTests.java index 3cff7804e51..96d9b628a3b 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/FieldTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/FieldTests.java @@ -22,23 +22,23 @@ import qilin.test.util.JunitTests; public class FieldTests extends JunitTests { - @Test - public void testInstanceLoad() { - checkAssertions(run("qilin.microben.core.field.InstanceLoad")); - } + @Test + public void testInstanceLoad() { + checkAssertions(run("qilin.microben.core.field.InstanceLoad")); + } - @Test - public void testInstanceStore() { - checkAssertions(run("qilin.microben.core.field.InstanceStore")); - } + @Test + public void testInstanceStore() { + checkAssertions(run("qilin.microben.core.field.InstanceStore")); + } - @Test - public void testFieldSensitivity1() { - checkAssertions(run("qilin.microben.core.field.FieldSensitivity1")); - } + @Test + public void testFieldSensitivity1() { + checkAssertions(run("qilin.microben.core.field.FieldSensitivity1")); + } - @Test - public void testFieldSensitivity2() { - checkAssertions(run("qilin.microben.core.field.FieldSensitivity2")); - } + @Test + public void testFieldSensitivity2() { + checkAssertions(run("qilin.microben.core.field.FieldSensitivity2")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java b/sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java index 1f95e50c783..334a11aa6f8 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/GlobalTests.java @@ -22,18 +22,18 @@ import qilin.test.util.JunitTests; public class GlobalTests extends JunitTests { - @Test - public void testStaticLoad() { - checkAssertions(run("qilin.microben.core.global.StaticLoad")); - } + @Test + public void testStaticLoad() { + checkAssertions(run("qilin.microben.core.global.StaticLoad")); + } - @Test - public void testStaticStore() { - checkAssertions(run("qilin.microben.core.global.StaticStore")); - } + @Test + public void testStaticStore() { + checkAssertions(run("qilin.microben.core.global.StaticStore")); + } - @Test - public void testStringConstant() { - checkAssertions(run("qilin.microben.core.global.StringConstant")); - } + @Test + public void testStringConstant() { + checkAssertions(run("qilin.microben.core.global.StringConstant")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/NativeTests.java b/sootup.qilin/src/test/java/qilin/test/core/NativeTests.java index 77e1087e4be..3e618c73e8b 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/NativeTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/NativeTests.java @@ -23,69 +23,69 @@ import qilin.test.util.JunitTests; public class NativeTests extends JunitTests { - @Test - public void testArrayCopy() { - checkAssertions(run("qilin.microben.core.natives.ArrayCopy")); - } + @Test + public void testArrayCopy() { + checkAssertions(run("qilin.microben.core.natives.ArrayCopy")); + } - @Test - public void testObjectClone() { - checkAssertions(run("qilin.microben.core.natives.ObjectClone")); - } + @Test + public void testObjectClone() { + checkAssertions(run("qilin.microben.core.natives.ObjectClone")); + } - @Test - public void testPrivilegedActions0() { - checkAssertions(run("qilin.microben.core.natives.PrivilegedActions0")); - } + @Test + public void testPrivilegedActions0() { + checkAssertions(run("qilin.microben.core.natives.PrivilegedActions0")); + } - @Test - public void testPrivilegedActions1() { - checkAssertions(run("qilin.microben.core.natives.PrivilegedActions1")); - } + @Test + public void testPrivilegedActions1() { + checkAssertions(run("qilin.microben.core.natives.PrivilegedActions1")); + } - @Test - public void testPrivilegedActions2() { - checkAssertions(run("qilin.microben.core.natives.PrivilegedActions2", "2o")); - } + @Test + public void testPrivilegedActions2() { + checkAssertions(run("qilin.microben.core.natives.PrivilegedActions2", "2o")); + } - @Test - public void testSystemIn() { - checkAssertions(run("qilin.microben.core.natives.SystemIn")); - } + @Test + public void testSystemIn() { + checkAssertions(run("qilin.microben.core.natives.SystemIn")); + } - @Test - public void testSystemOut() { - checkAssertions(run("qilin.microben.core.natives.SystemOut")); - } + @Test + public void testSystemOut() { + checkAssertions(run("qilin.microben.core.natives.SystemOut")); + } - @Test - public void testSystemErr() { - checkAssertions(run("qilin.microben.core.natives.SystemErr")); - } + @Test + public void testSystemErr() { + checkAssertions(run("qilin.microben.core.natives.SystemErr")); + } - @Test - public void testFinalize() { - checkAssertions(run("qilin.microben.core.natives.Finalize")); - } + @Test + public void testFinalize() { + checkAssertions(run("qilin.microben.core.natives.Finalize")); + } - @Test - public void testTreadRun() { - checkAssertions(run("qilin.microben.core.natives.TreadRun")); - } + @Test + public void testTreadRun() { + checkAssertions(run("qilin.microben.core.natives.TreadRun")); + } - @Test - @Ignore - public void testCurrentThread() { - checkAssertions(run("qilin.microben.core.natives.CurrentThread")); - } + @Test + @Ignore + public void testCurrentThread() { + checkAssertions(run("qilin.microben.core.natives.CurrentThread")); + } - @Test - public void testRefArrayGet() { - checkAssertions(run("qilin.microben.core.natives.RefArrayGet")); - } + @Test + public void testRefArrayGet() { + checkAssertions(run("qilin.microben.core.natives.RefArrayGet")); + } - @Test - public void testRefArraySet() { - checkAssertions(run("qilin.microben.core.natives.RefArraySet")); - } + @Test + public void testRefArraySet() { + checkAssertions(run("qilin.microben.core.natives.RefArraySet")); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java b/sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java index 06b9c4091b9..3f51fea6d03 100644 --- a/sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java +++ b/sootup.qilin/src/test/java/qilin/test/core/ReflogTests.java @@ -23,66 +23,66 @@ import qilin.test.util.JunitTests; public class ReflogTests extends JunitTests { - @Test - public void testFieldGetStatic() { - checkAssertions(run("qilin.microben.core.reflog.FieldGetStatic")); - } + @Test + public void testFieldGetStatic() { + checkAssertions(run("qilin.microben.core.reflog.FieldGetStatic")); + } - @Test - public void testFieldGet() { - checkAssertions(run("qilin.microben.core.reflog.FieldGet")); - } + @Test + public void testFieldGet() { + checkAssertions(run("qilin.microben.core.reflog.FieldGet")); + } - @Test - public void testFieldSetStatic() { - checkAssertions(run("qilin.microben.core.reflog.FieldSetStatic")); - } + @Test + public void testFieldSetStatic() { + checkAssertions(run("qilin.microben.core.reflog.FieldSetStatic")); + } - @Test - public void testFieldSet() { - checkAssertions(run("qilin.microben.core.reflog.FieldSet")); - } + @Test + public void testFieldSet() { + checkAssertions(run("qilin.microben.core.reflog.FieldSet")); + } - @Test - public void testArrayNewInstance() { - checkAssertions(run("qilin.microben.core.reflog.ArrayNewInstance")); - } + @Test + public void testArrayNewInstance() { + checkAssertions(run("qilin.microben.core.reflog.ArrayNewInstance")); + } - @Test - public void testConstructorNewInstance() { - checkAssertions(run("qilin.microben.core.reflog.ConstructorNewInstance")); - } + @Test + public void testConstructorNewInstance() { + checkAssertions(run("qilin.microben.core.reflog.ConstructorNewInstance")); + } - @Test - public void testMethodInvokeStatic() { - checkAssertions(run("qilin.microben.core.reflog.MethodInvokeStatic")); - } + @Test + public void testMethodInvokeStatic() { + checkAssertions(run("qilin.microben.core.reflog.MethodInvokeStatic")); + } - @Test - public void testMethodInvoke() { - checkAssertions(run("qilin.microben.core.reflog.MethodInvoke")); - } + @Test + public void testMethodInvoke() { + checkAssertions(run("qilin.microben.core.reflog.MethodInvoke")); + } - @Test - public void testClassNewInstance() { - checkAssertions(run("qilin.microben.core.reflog.ClassNewInstance")); - } + @Test + public void testClassNewInstance() { + checkAssertions(run("qilin.microben.core.reflog.ClassNewInstance")); + } - @Test - public void testDoopRefBug() { - PTA pta = run("qilin.microben.core.reflog.DoopRefBug"); - checkAssertions(pta); - } + @Test + public void testDoopRefBug() { + PTA pta = run("qilin.microben.core.reflog.DoopRefBug"); + checkAssertions(pta); + } - @Test - public void testClassForName() { - PTA pta = run("qilin.microben.core.reflog.ClassForName"); - checkAssertions(pta); - } + @Test + public void testClassForName() { + PTA pta = run("qilin.microben.core.reflog.ClassForName"); + checkAssertions(pta); + } - @Test - public void testClassForName1() { - PTA pta = run("qilin.microben.core.reflog.ClassForName1"); - checkAssertions(pta); - } -} \ No newline at end of file + @Test + public void testClassForName1() { + PTA pta = run("qilin.microben.core.reflog.ClassForName1"); + checkAssertions(pta); + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java b/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java index a0320acbb98..5073fea35b5 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java +++ b/sootup.qilin/src/test/java/qilin/test/util/AliasAssertion.java @@ -18,6 +18,7 @@ package qilin.test.util; +import java.util.Objects; import qilin.core.PTA; import qilin.core.sets.PointsToSet; import qilin.pta.PTAConfig; @@ -30,89 +31,94 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; -import java.util.Objects; - public class AliasAssertion implements IAssertion { - private final PTA pta; - private final SootMethod sm; - private final Stmt stmt; - private final Value va; - private final Value vb; - private final boolean groundTruth; + private final PTA pta; + private final SootMethod sm; + private final Stmt stmt; + private final Value va; + private final Value vb; + private final boolean groundTruth; - public AliasAssertion(PTA pta, SootMethod sm, Stmt stmt, Value va, Value vb, boolean groundTruth) { - this.pta = pta; - this.sm = sm; - this.stmt = stmt; - this.va = va; - this.vb = vb; - this.groundTruth = groundTruth; - } + public AliasAssertion( + PTA pta, SootMethod sm, Stmt stmt, Value va, Value vb, boolean groundTruth) { + this.pta = pta; + this.sm = sm; + this.stmt = stmt; + this.va = va; + this.vb = vb; + this.groundTruth = groundTruth; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - AliasAssertion that = (AliasAssertion) o; - return groundTruth == that.groundTruth && - Objects.equals(sm, that.sm) && - Objects.equals(stmt, that.stmt) && - Objects.equals(va, that.va) && - Objects.equals(vb, that.vb); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AliasAssertion that = (AliasAssertion) o; + return groundTruth == that.groundTruth + && Objects.equals(sm, that.sm) + && Objects.equals(stmt, that.stmt) + && Objects.equals(va, that.va) + && Objects.equals(vb, that.vb); + } - @Override - public int hashCode() { - return Objects.hash(sm, stmt, va, vb, groundTruth); - } + @Override + public int hashCode() { + return Objects.hash(sm, stmt, va, vb, groundTruth); + } - @Override - public boolean check() { - return isMayAlias(pta, va, vb) == groundTruth; - } + @Override + public boolean check() { + return isMayAlias(pta, va, vb) == groundTruth; + } - private static boolean DEBUG = true; + private static boolean DEBUG = true; - protected boolean isMayAlias(PTA pta, Value va, Value vb) { - if (va instanceof NullConstant && vb instanceof NullConstant) { - return true; - } - if (va instanceof NullConstant || vb instanceof NullConstant) { - return false; - } - if (va instanceof StringConstant && vb instanceof StringConstant) { - return va.equals(vb); - } else if (va instanceof StringConstant strConst) { - String s = strConst.getValue(); - if (!PTAConfig.v().getPtaConfig().stringConstants) { - s = "STRING_NODE"; - } - PointsToSet pts = pta.reachingObjects((Local) vb).toCIPointsToSet(); - return pts.possibleStringConstants().contains(s); - } else if (vb instanceof StringConstant strConst) { - String s = strConst.getValue(); - if (!PTAConfig.v().getPtaConfig().stringConstants) { - s = "STRING_NODE"; - } - PointsToSet pts = pta.reachingObjects((Local) va).toCIPointsToSet(); - return pts.possibleStringConstants().contains(s); - } else if (va instanceof ClassConstant) { - PointsToSet pts = pta.reachingObjects((Local) vb).toCIPointsToSet(); - return pts.possibleClassConstants().contains(va); - } else if (vb instanceof ClassConstant) { - PointsToSet pts = pta.reachingObjects((Local) va).toCIPointsToSet(); - return pts.possibleClassConstants().contains(vb); - } - PointsToSet pts1 = pta.reachingObjects((Local) va).toCIPointsToSet(); - if (DEBUG) { - System.out.println("va points to: " + PTAUtils.getNodeLabel(pta.getPag().findLocalVarNode(va)) + pta.getPag().findLocalVarNode(va)); - PTAUtils.printPts(pta, pts1); - } - PointsToSet pts2 = pta.reachingObjects((Local) vb).toCIPointsToSet(); - if (DEBUG) { - System.out.println("vb points to: " + PTAUtils.getNodeLabel(pta.getPag().findLocalVarNode(vb)) + pta.getPag().findLocalVarNode(vb)); - PTAUtils.printPts(pta, pts2); - } - return pts1.hasNonEmptyIntersection(pts2); + protected boolean isMayAlias(PTA pta, Value va, Value vb) { + if (va instanceof NullConstant && vb instanceof NullConstant) { + return true; + } + if (va instanceof NullConstant || vb instanceof NullConstant) { + return false; + } + if (va instanceof StringConstant && vb instanceof StringConstant) { + return va.equals(vb); + } else if (va instanceof StringConstant strConst) { + String s = strConst.getValue(); + if (!PTAConfig.v().getPtaConfig().stringConstants) { + s = "STRING_NODE"; + } + PointsToSet pts = pta.reachingObjects((Local) vb).toCIPointsToSet(); + return pts.possibleStringConstants().contains(s); + } else if (vb instanceof StringConstant strConst) { + String s = strConst.getValue(); + if (!PTAConfig.v().getPtaConfig().stringConstants) { + s = "STRING_NODE"; + } + PointsToSet pts = pta.reachingObjects((Local) va).toCIPointsToSet(); + return pts.possibleStringConstants().contains(s); + } else if (va instanceof ClassConstant) { + PointsToSet pts = pta.reachingObjects((Local) vb).toCIPointsToSet(); + return pts.possibleClassConstants().contains(va); + } else if (vb instanceof ClassConstant) { + PointsToSet pts = pta.reachingObjects((Local) va).toCIPointsToSet(); + return pts.possibleClassConstants().contains(vb); + } + PointsToSet pts1 = pta.reachingObjects((Local) va).toCIPointsToSet(); + if (DEBUG) { + System.out.println( + "va points to: " + + PTAUtils.getNodeLabel(pta.getPag().findLocalVarNode(va)) + + pta.getPag().findLocalVarNode(va)); + PTAUtils.printPts(pta, pts1); + } + PointsToSet pts2 = pta.reachingObjects((Local) vb).toCIPointsToSet(); + if (DEBUG) { + System.out.println( + "vb points to: " + + PTAUtils.getNodeLabel(pta.getPag().findLocalVarNode(vb)) + + pta.getPag().findLocalVarNode(vb)); + PTAUtils.printPts(pta, pts2); } + return pts1.hasNonEmptyIntersection(pts2); + } } diff --git a/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java b/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java index 0e476eaa116..24ab323227b 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java +++ b/sootup.qilin/src/test/java/qilin/test/util/AssertionsParser.java @@ -18,6 +18,8 @@ package qilin.test.util; +import java.util.HashSet; +import java.util.Set; import qilin.core.PTA; import qilin.util.PTAUtils; import sootup.core.jimple.common.expr.AbstractInvokeExpr; @@ -26,42 +28,44 @@ import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; -import java.util.HashSet; -import java.util.Set; - public class AssertionsParser { - protected static String mayAliasSig = ""; - protected static String notAliasSig = ""; + protected static String mayAliasSig = + ""; + protected static String notAliasSig = + ""; - public static Set retrieveQueryInfo(PTA pta) { - Set aliasAssertionSet = new HashSet<>(); - for (SootMethod sm : pta.getNakedReachableMethods()) { - if (sm.isNative()) { - continue; - } + public static Set retrieveQueryInfo(PTA pta) { + Set aliasAssertionSet = new HashSet<>(); + for (SootMethod sm : pta.getNakedReachableMethods()) { + if (sm.isNative()) { + continue; + } -// if (sm.getSignature().equals("")) { -// System.out.println(sm); -// System.out.println(PTAUtils.getMethodBody(sm)); -// PTAUtils.dumpMPAG(pta, sm); -// System.out.println("================================================================="); -// } - for (final Stmt stmt : PTAUtils.getMethodBody(sm).getStmts()) { - if (stmt.containsInvokeExpr()) { - AbstractInvokeExpr ie = stmt.getInvokeExpr(); - if (ie instanceof JStaticInvokeExpr) { - final MethodSignature calleeSig = ie.getMethodSignature(); - if (calleeSig.equals(mayAliasSig)) { - aliasAssertionSet.add(new AliasAssertion(pta, sm, stmt, ie.getArg(0), ie.getArg(1), true)); - } else if (calleeSig.equals(notAliasSig)) { - aliasAssertionSet.add(new AliasAssertion(pta, sm, stmt, ie.getArg(0), ie.getArg(1), false)); - } - } - } + // if (sm.getSignature().equals("")) { + // System.out.println(sm); + // System.out.println(PTAUtils.getMethodBody(sm)); + // PTAUtils.dumpMPAG(pta, sm); + // + // System.out.println("================================================================="); + // } + for (final Stmt stmt : PTAUtils.getMethodBody(sm).getStmts()) { + if (stmt.containsInvokeExpr()) { + AbstractInvokeExpr ie = stmt.getInvokeExpr(); + if (ie instanceof JStaticInvokeExpr) { + final MethodSignature calleeSig = ie.getMethodSignature(); + if (calleeSig.equals(mayAliasSig)) { + aliasAssertionSet.add( + new AliasAssertion(pta, sm, stmt, ie.getArg(0), ie.getArg(1), true)); + } else if (calleeSig.equals(notAliasSig)) { + aliasAssertionSet.add( + new AliasAssertion(pta, sm, stmt, ie.getArg(0), ie.getArg(1), false)); } + } } - System.out.println("#alias queries: " + aliasAssertionSet.size()); - return aliasAssertionSet; + } } - + System.out.println("#alias queries: " + aliasAssertionSet.size()); + return aliasAssertionSet; + } } diff --git a/sootup.qilin/src/test/java/qilin/test/util/IAssertion.java b/sootup.qilin/src/test/java/qilin/test/util/IAssertion.java index 964f7ed8621..b4ef9f4e33b 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/IAssertion.java +++ b/sootup.qilin/src/test/java/qilin/test/util/IAssertion.java @@ -19,5 +19,5 @@ package qilin.test.util; public interface IAssertion { - boolean check(); + boolean check(); } diff --git a/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java index c62197a8de4..9c55fb920f2 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java +++ b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java @@ -18,91 +18,122 @@ package qilin.test.util; -import driver.Main; +import static org.junit.Assert.assertTrue; + import driver.PTAFactory; import driver.PTAOption; import driver.PTAPattern; +import java.io.File; +import java.io.IOException; +import java.util.Set; import org.junit.Before; import org.junit.BeforeClass; import qilin.core.PTA; import qilin.core.PTAScene; import qilin.pta.PTAConfig; -import java.io.File; -import java.io.IOException; -import java.util.Set; - -import static org.junit.Assert.assertTrue; - public abstract class JunitTests { - protected static String appPath, jrePath, refLogPath; - protected static boolean isSetUp = false; - @BeforeClass - public static void setUp() throws IOException { - if (isSetUp) { - return; - } - File rootDir = new File("../"); - File testDir = new File(rootDir, "qilin.microben" + File.separator + "build" + File.separator + "classes" + File.separator + "java" + File.separator + "main"); - appPath = testDir.getCanonicalPath(); - System.out.println("APP_PATH:" + appPath); - File refLogDir = new File(rootDir, "qilin.microben" + File.separator + "src" + File.separator + "qilin" + File.separator + "microben" + File.separator + "core" + File.separator + "reflog"); - refLogPath = refLogDir.getCanonicalPath(); - File jreFile = new File(".." + File.separator + "artifact" + File.separator + "benchmarks" + - File.separator + "JREs" + File.separator + "jre1.6.0_45"); - jrePath = jreFile.getCanonicalPath(); - String[] args = generateArgumentsx(); - PTAOption ptaOption = new PTAOption(); - ptaOption.parseCommandLine(args); - Main.setupSoot(); - isSetUp = true; - } + protected static String appPath, jrePath, refLogPath; + protected static boolean isSetUp = false; - @Before - public void reset() { - PTAScene.junitReset(); + @BeforeClass + public static void setUp() throws IOException { + if (isSetUp) { + return; } + File rootDir = new File("../"); + File testDir = + new File( + rootDir, + "qilin.microben" + + File.separator + + "build" + + File.separator + + "classes" + + File.separator + + "java" + + File.separator + + "main"); + appPath = testDir.getCanonicalPath(); + System.out.println("APP_PATH:" + appPath); + File refLogDir = + new File( + rootDir, + "qilin.microben" + + File.separator + + "src" + + File.separator + + "qilin" + + File.separator + + "microben" + + File.separator + + "core" + + File.separator + + "reflog"); + refLogPath = refLogDir.getCanonicalPath(); + File jreFile = + new File( + ".." + + File.separator + + "artifact" + + File.separator + + "benchmarks" + + File.separator + + "JREs" + + File.separator + + "jre1.6.0_45"); + jrePath = jreFile.getCanonicalPath(); + String[] args = generateArgumentsx(); + PTAOption ptaOption = new PTAOption(); + ptaOption.parseCommandLine(args); + isSetUp = true; + } - public PTA run(String mainClass) { - return run(mainClass, "insens"); - } + @Before + public void reset() { + PTAScene.junitReset(); + } - public PTA run(String mainClass, String ptaPattern) { - PTAConfig.v().getAppConfig().MAIN_CLASS = mainClass; - PTAScene.v().setMainClass(PTAScene.v().getSootClass(mainClass)); - PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPattern); - PTAConfig.v().getPtaConfig().ptaName = PTAConfig.v().getPtaConfig().ptaPattern.toString(); - System.out.println(PTAConfig.v().getAppConfig().APP_PATH); - PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); - pta.pureRun(); - return pta; - } + public PTA run(String mainClass) { + return run(mainClass, "insens"); + } - public static String[] generateArgumentsx() { - return new String[]{ - "-singleentry", - "-apppath", - appPath, - "-mainclass", - "qilin.microben.core.exception.SimpleException", - "-se", - "-jre=" + jrePath, - "-clinit=ONFLY", - "-lcs", - "-mh", - "-pae", - "-pe", - "-reflectionlog", - refLogPath + File.separator + "Reflection.log" - }; - } + public PTA run(String mainClass, String ptaPattern) { + PTAConfig.v().getAppConfig().MAIN_CLASS = mainClass; + PTAScene.v().setMainClass(PTAScene.v().getSootClass(mainClass)); + PTAConfig.v().getPtaConfig().ptaPattern = new PTAPattern(ptaPattern); + PTAConfig.v().getPtaConfig().ptaName = PTAConfig.v().getPtaConfig().ptaPattern.toString(); + System.out.println(PTAConfig.v().getAppConfig().APP_PATH); + PTA pta = PTAFactory.createPTA(PTAConfig.v().getPtaConfig().ptaPattern); + pta.pureRun(); + return pta; + } + + public static String[] generateArgumentsx() { + return new String[] { + "-singleentry", + "-apppath", + appPath, + "-mainclass", + "qilin.microben.core.exception.SimpleException", + "-se", + "-jre=" + jrePath, + "-clinit=ONFLY", + "-lcs", + "-mh", + "-pae", + "-pe", + "-reflectionlog", + refLogPath + File.separator + "Reflection.log" + }; + } - protected void checkAssertions(PTA pta) { - Set aliasAssertionSet = AssertionsParser.retrieveQueryInfo(pta); - for (IAssertion mAssert : aliasAssertionSet) { - boolean answer = mAssert.check(); - System.out.println("Assertion is " + answer); - assertTrue(answer); - } + protected void checkAssertions(PTA pta) { + Set aliasAssertionSet = AssertionsParser.retrieveQueryInfo(pta); + for (IAssertion mAssert : aliasAssertionSet) { + boolean answer = mAssert.check(); + System.out.println("Assertion is " + answer); + assertTrue(answer); } + } } From 07a7c470f0361e1f8af7c0fb651acefe378c9289 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Mon, 25 Sep 2023 09:41:28 +1000 Subject: [PATCH 030/145] update --- run.sh | 2 + .../main/java/qilin/core/VirtualCalls.java | 5 +- .../qilin/core/builder/CallGraphBuilder.java | 19 ++++++ .../src/main/java/qilin/util/PTAUtils.java | 8 +-- .../qilin/microben/context/cfa/CFA1k0.java | 36 ++++++++++ .../qilin/microben/context/cfa/CFA1k1.java | 45 +++++++++++++ .../qilin/microben/context/cfa/CFA1k2.java | 50 ++++++++++++++ .../qilin/microben/context/cfa/CFA2k.java | 40 +++++++++++ .../java/qilin/microben/context/cfa/log.txt | 5 ++ .../context/collections/ArrayList0.java | 41 ++++++++++++ .../context/collections/HashMap0.java | 39 +++++++++++ .../context/collections/HashSet0.java | 40 +++++++++++ .../context/collections/HashTable0.java | 39 +++++++++++ .../context/collections/LinkedList0.java | 40 +++++++++++ .../context/collections/PriorityQueue0.java | 39 +++++++++++ .../microben/context/collections/Stack0.java | 39 +++++++++++ .../context/collections/TreeMap0.java | 40 +++++++++++ .../context/collections/TreeSet0.java | 39 +++++++++++ .../microben/context/collections/Vector0.java | 39 +++++++++++ .../microben/context/collections/log.txt | 4 ++ .../java/qilin/microben/context/hyb/Hyb0.java | 38 +++++++++++ .../java/qilin/microben/context/hyb/Hyb1.java | 47 +++++++++++++ .../java/qilin/microben/context/hyb/Hyb2.java | 52 +++++++++++++++ .../qilin/microben/context/obj/OBJ1k0.java | 48 ++++++++++++++ .../qilin/microben/context/obj/OBJ1k1.java | 54 +++++++++++++++ .../qilin/microben/context/obj/OBJ1k2.java | 48 ++++++++++++++ .../qilin/microben/context/obj/OBJ1k3.java | 38 +++++++++++ .../qilin/microben/context/obj/OBJ1k4.java | 48 ++++++++++++++ .../qilin/microben/context/obj/OBJ1k5.java | 45 +++++++++++++ .../qilin/microben/context/obj/OBJ2k0.java | 47 +++++++++++++ .../qilin/microben/context/obj/OBJ2k1.java | 48 ++++++++++++++ .../qilin/microben/context/obj/OBJ2k2.java | 54 +++++++++++++++ .../java/qilin/microben/context/obj/log.txt | 5 ++ .../qilin/microben/context/type/Type1k0.java | 57 ++++++++++++++++ .../qilin/microben/context/type/Type2k0.java | 66 +++++++++++++++++++ .../qilin/microben/core/array/ArrayCopy.java | 35 ++++++++++ .../core/array/ArrayElemTypeFiltering.java | 46 +++++++++++++ .../qilin/microben/core/array/ArrayIndex.java | 36 ++++++++++ .../core/array/MultiArrayComplex.java | 38 +++++++++++ .../microben/core/array/MultiArraySimple.java | 30 +++++++++ .../qilin/microben/core/assign/CastFail.java | 32 +++++++++ .../qilin/microben/core/assign/CastSucc.java | 29 ++++++++ .../microben/core/assign/InterAssign.java | 43 ++++++++++++ .../microben/core/assign/NullPointer.java | 37 +++++++++++ .../microben/core/assign/Receiver2This.java | 50 ++++++++++++++ .../qilin/microben/core/assign/Recursion.java | 38 +++++++++++ .../microben/core/assign/ReturnValue0.java | 35 ++++++++++ .../microben/core/assign/ReturnValue1.java | 33 ++++++++++ .../microben/core/assign/ReturnValue2.java | 34 ++++++++++ .../microben/core/assign/ReturnValue3.java | 40 +++++++++++ .../microben/core/assign/SimpleAssign.java | 29 ++++++++ .../microben/core/assign/StaticParameter.java | 34 ++++++++++ .../qilin/microben/core/call/StaticCall.java | 36 ++++++++++ .../microben/core/call/VirtualCall0.java | 51 ++++++++++++++ .../microben/core/call/VirtualCall1.java | 37 +++++++++++ .../microben/core/clinit/ClinitNewExpr.java | 41 ++++++++++++ .../core/clinit/ClinitStaticCall.java | 38 +++++++++++ .../core/clinit/ClinitStaticLoad.java | 38 +++++++++++ .../core/clinit/ClinitStaticStore.java | 37 +++++++++++ .../core/exception/ExceptionChain.java | 54 +++++++++++++++ .../microben/core/exception/MethodThrow.java | 41 ++++++++++++ .../core/exception/SimpleException.java | 35 ++++++++++ .../qilin/microben/core/exception/log.txt | 4 ++ .../core/field/FieldSensitivity1.java | 41 ++++++++++++ .../core/field/FieldSensitivity2.java | 37 +++++++++++ .../microben/core/field/InstanceLoad.java | 31 +++++++++ .../microben/core/field/InstanceStore.java | 32 +++++++++ .../microben/core/global/StaticLoad.java | 30 +++++++++ .../microben/core/global/StaticStore.java | 31 +++++++++ .../microben/core/global/StringConstant.java | 31 +++++++++ .../src/test/java/qilin/microben/core/log.txt | 4 ++ .../microben/core/natives/ArrayCopy.java | 29 ++++++++ .../microben/core/natives/CurrentThread.java | 59 +++++++++++++++++ .../qilin/microben/core/natives/Finalize.java | 37 +++++++++++ .../microben/core/natives/ObjectClone.java | 29 ++++++++ .../core/natives/PrivilegedActions0.java | 39 +++++++++++ .../core/natives/PrivilegedActions1.java | 41 ++++++++++++ .../core/natives/PrivilegedActions2.java | 53 +++++++++++++++ .../microben/core/natives/RefArrayGet.java | 35 ++++++++++ .../microben/core/natives/RefArraySet.java | 35 ++++++++++ .../microben/core/natives/SystemErr.java | 31 +++++++++ .../qilin/microben/core/natives/SystemIn.java | 36 ++++++++++ .../microben/core/natives/SystemOut.java | 31 +++++++++ .../qilin/microben/core/natives/TreadRun.java | 45 +++++++++++++ .../java/qilin/microben/core/natives/log.txt | 4 ++ .../core/reflog/ArrayNewInstance.java | 30 +++++++++ .../microben/core/reflog/ClassForName.java | 34 ++++++++++ .../microben/core/reflog/ClassForName1.java | 34 ++++++++++ .../core/reflog/ClassNewInstance.java | 29 ++++++++ .../core/reflog/ConstructorNewInstance.java | 37 +++++++++++ .../microben/core/reflog/DoopRefBug.java | 36 ++++++++++ .../qilin/microben/core/reflog/FieldGet.java | 33 ++++++++++ .../microben/core/reflog/FieldGetStatic.java | 32 +++++++++ .../qilin/microben/core/reflog/FieldSet.java | 37 +++++++++++ .../microben/core/reflog/FieldSetStatic.java | 32 +++++++++ .../microben/core/reflog/MethodInvoke.java | 40 +++++++++++ .../core/reflog/MethodInvokeStatic.java | 34 ++++++++++ .../java/qilin/microben/core/reflog/log.txt | 1 + .../qilin/microben/flowsens/Branching1.java | 36 ++++++++++ .../qilin/microben/flowsens/FlowSens0.java | 45 +++++++++++++ .../qilin/microben/flowsens/InstanceOf0.java | 44 +++++++++++++ .../java/qilin/microben/flowsens/Loops.java | 43 ++++++++++++ .../microben/flowsens/StrongUpdate1.java | 39 +++++++++++ .../microben/flowsens/StrongUpdate2.java | 43 ++++++++++++ .../test/java/qilin/microben/flowsens/log.txt | 4 ++ .../java/qilin/microben/utils/Assert.java | 34 ++++++++++ .../test/java/qilin/test/util/JunitTests.java | 17 ++--- 107 files changed, 3773 insertions(+), 17 deletions(-) create mode 100755 run.sh create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA2k.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/cfa/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/ArrayList0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/HashMap0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/HashSet0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/HashTable0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/LinkedList0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/PriorityQueue0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/Stack0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/TreeMap0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/TreeSet0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/Vector0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/collections/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k3.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k4.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k5.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/obj/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/type/Type1k0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/context/type/Type2k0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/array/ArrayCopy.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/array/ArrayElemTypeFiltering.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/array/ArrayIndex.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/array/MultiArrayComplex.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/array/MultiArraySimple.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/CastFail.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/CastSucc.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/InterAssign.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/NullPointer.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/Receiver2This.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/Recursion.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue3.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/SimpleAssign.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/assign/StaticParameter.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/call/StaticCall.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitNewExpr.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticCall.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticLoad.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticStore.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/exception/ExceptionChain.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/exception/MethodThrow.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/exception/SimpleException.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/exception/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/field/InstanceLoad.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/field/InstanceStore.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/global/StaticLoad.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/global/StaticStore.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/global/StringConstant.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/ArrayCopy.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/CurrentThread.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/Finalize.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/ObjectClone.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/RefArrayGet.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/RefArraySet.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/SystemErr.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/SystemIn.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/SystemOut.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/TreadRun.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/natives/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/ArrayNewInstance.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassNewInstance.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/ConstructorNewInstance.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/DoopRefBug.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGet.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGetStatic.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSet.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSetStatic.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvoke.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvokeStatic.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/core/reflog/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/flowsens/Branching1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/flowsens/FlowSens0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/flowsens/InstanceOf0.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/flowsens/Loops.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate1.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate2.java create mode 100644 sootup.qilin/src/test/java/qilin/microben/flowsens/log.txt create mode 100644 sootup.qilin/src/test/java/qilin/microben/utils/Assert.java diff --git a/run.sh b/run.sh new file mode 100755 index 00000000000..297adb46da3 --- /dev/null +++ b/run.sh @@ -0,0 +1,2 @@ +#!/bin/sh +mvn clean install diff --git a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java index af7b7e4377f..23b038b654d 100644 --- a/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java +++ b/sootup.qilin/src/main/java/qilin/core/VirtualCalls.java @@ -112,9 +112,10 @@ public SootMethod resolveNonSpecial(ClassType t, MethodSubSignature subSig, bool ret = m; } } else { - Optional oc = cls.getSuperclass(); + Optional oc = cls.getSuperclass(); if (oc.isPresent()) { - SootClass c = oc.get(); + ClassType ct = oc.get(); + SootClass c = (SootClass) PTAScene.v().getView().getClass(ct).get(); ret = resolveNonSpecial(c.getType(), subSig); } } diff --git a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java index 2237ee58401..c8bbb7924a0 100644 --- a/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java +++ b/sootup.qilin/src/main/java/qilin/core/builder/CallGraphBuilder.java @@ -18,6 +18,7 @@ package qilin.core.builder; +import java.io.PrintWriter; import java.util.*; import qilin.CoreConfig; import qilin.core.PTA; @@ -44,9 +45,12 @@ import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.JInvokeStmt; import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.Body; import sootup.core.model.SootMethod; import sootup.core.types.ReferenceType; import sootup.core.types.Type; +import sootup.core.types.UnknownType; +import sootup.core.util.printer.JimplePrinter; public class CallGraphBuilder { protected final Map> receiverToSites; @@ -141,6 +145,21 @@ public void initReachableMethods() { } public VarNode getReceiverVarNode(Local receiver, MethodOrMethodContext m) { + if (receiver.getType() == UnknownType.getInstance()) { + System.out.println("why unknown??" + m.method() + ";;" + receiver); + Body body = PTAUtils.getMethodBody(m.method()); + try { + // OutputStream streamOut = new FileOutputStream(m.method().getName() + ".jimple"); + // PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut)); + PrintWriter writerOut = new PrintWriter(System.out); + new JimplePrinter().printTo(body, writerOut); + writerOut.flush(); + writerOut.close(); + // streamOut.close(); + } catch (Exception e) { + System.out.println("Error writing jimple to file "); + } + } LocalVarNode base = pag.makeLocalVarNode(receiver, receiver.getType(), m.method()); return (VarNode) pta.parameterize(base, m.context()); } diff --git a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java index 03809b0ed1f..b4d36f4a6a2 100644 --- a/sootup.qilin/src/main/java/qilin/util/PTAUtils.java +++ b/sootup.qilin/src/main/java/qilin/util/PTAUtils.java @@ -659,8 +659,7 @@ public static boolean isPrimitiveArrayType(Type type) { public static void writeJimple(String parentDir, SootClass clz) { PackageName pkgName = clz.getType().getPackageName(); String clzName = clz.getType().getClassName(); - File packageDirectory = - new File( + File packageDirectory = new File( parentDir + File.separator + pkgName.getPackageName().replace(".", File.separator)); try { @@ -817,9 +816,10 @@ public static Set clinitsOf(SootClass cl) { Set ret = new HashSet<>(); Set visit = new HashSet<>(); Queue worklist = new UniqueQueue<>(); - Optional curr = Optional.of(cl); + Optional curr = Optional.of(cl.getType()); while (curr.isPresent()) { - SootClass sc = curr.get(); + ClassType ct = curr.get(); + SootClass sc = (SootClass) PTAScene.v().getView().getClass(ct).get(); worklist.add(sc); curr = sc.getSuperclass(); } diff --git a/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k0.java b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k0.java new file mode 100644 index 00000000000..eea4e560f18 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k0.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.cfa; + +import qilin.microben.utils.Assert; + +class CFA1k0 { + static Object id(Object a) { + return a; + } + + public static void main(String[] argv) { + Object o1 = new Object(); + Object o2 = new Object(); + Object v1 = id(o1); + Object v2 = id(o2); + Assert.notAlias(v1, v2); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k1.java b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k1.java new file mode 100644 index 00000000000..653ab5d391f --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k1.java @@ -0,0 +1,45 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.cfa; + +import qilin.microben.utils.Assert; + +public class CFA1k1 { + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + bar(o1); + bar(o2); + } + + static void bar(Object o) { + Object o5 = new Object(); + Object v5 = id(o5); + Assert.notAlias(v5, o); + id2(o); + } + + static Object id(Object o) { + return o; + } + + static Object id2(Object o) { + return id(o); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k2.java b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k2.java new file mode 100644 index 00000000000..85a1e129de1 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA1k2.java @@ -0,0 +1,50 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.cfa; + +import qilin.microben.utils.Assert; + +class CFA1k2 { + static class A { + Object id(Object a) { + return a; + } + + Object id2(Object a) { + return id(a); + } + } + + static class A2 extends A { + Object id(Object a) { + return a; + } + } + + public static void main(String[] argv) { + A a1 = new A(); // A1 + A a2 = new A2(); // A2 + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object v1 = a1.id2(o1); + Object v2 = a2.id2(o2); + Assert.notAlias(v1, v2); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA2k.java b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA2k.java new file mode 100644 index 00000000000..bc4c0f0504c --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/cfa/CFA2k.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.cfa; + +import qilin.microben.utils.Assert; + +class CFA2k { + static Object id(Object a) { + return a; + } + + static Object id2(Object a) { + return id(a); + } + + public static void main(String[] argv) { + Object o1 = new Object(); + Object o2 = new Object(); + Object v1 = id2(o1); + Object v2 = id2(o2); + Assert.notAlias(v1, v2); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/cfa/log.txt b/sootup.qilin/src/test/java/qilin/microben/context/cfa/log.txt new file mode 100644 index 00000000000..ba720af9aff --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/cfa/log.txt @@ -0,0 +1,5 @@ +insens-qilin.core: 1 passed, 6 failed. +e-2o: 1 passed, 6 failed. +2c: 7 passed +j-ci: 1 passed, 6 failed. +m-ci: 1 passed, 6 failed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/ArrayList0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/ArrayList0.java new file mode 100644 index 00000000000..494574bd092 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/ArrayList0.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.ArrayList; +import qilin.microben.utils.Assert; + +// need at least 2obj. +public class ArrayList0 { + + public static void main(String[] args) { + ArrayList list1 = new ArrayList<>(); + ArrayList list2 = new ArrayList<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + list1.add(o1); + list1.add(o2); + list2.add(o3); + Object v1 = list1.get(1); + Object v2 = list2.get(0); + Assert.mayAlias(v1, o2); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/HashMap0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/HashMap0.java new file mode 100644 index 00000000000..e21adf8f08b --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/HashMap0.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.HashMap; +import qilin.microben.utils.Assert; + +public class HashMap0 { + public static void main(String[] args) { + HashMap map1 = new HashMap<>(); + HashMap map2 = new HashMap<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + map1.put("first", o1); + map1.put("second", o2); + map2.put("first", o3); + Object v2 = map1.get("second"); + Object v3 = map2.get("first"); + Assert.mayAlias(v2, o2); + Assert.notAlias(v2, v3); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/HashSet0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/HashSet0.java new file mode 100644 index 00000000000..bcf1112b1fb --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/HashSet0.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.HashSet; +import qilin.microben.utils.Assert; + +// at least 3obj could pass this unit tests. +public class HashSet0 { + public static void main(String[] args) { + HashSet set1 = new HashSet<>(); + HashSet set2 = new HashSet<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + set1.add(o1); + set1.add(o2); + set2.add(o3); + Object v2 = set1.iterator().next(); + Object v3 = set2.iterator().next(); + Assert.mayAlias(v2, o1); + Assert.notAlias(v3, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/HashTable0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/HashTable0.java new file mode 100644 index 00000000000..0a52de78112 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/HashTable0.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.Hashtable; +import qilin.microben.utils.Assert; + +public class HashTable0 { + public static void main(String[] args) { + Hashtable ht1 = new Hashtable<>(); + Hashtable ht2 = new Hashtable<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + ht1.put("first", o1); + ht1.put("second", o2); + ht2.put("first", o3); + Object v1 = ht1.get("first"); + Object v3 = ht2.get("first"); + Assert.mayAlias(v1, o2); + Assert.notAlias(v1, v3); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/LinkedList0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/LinkedList0.java new file mode 100644 index 00000000000..bfd6d84418b --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/LinkedList0.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.LinkedList; +import qilin.microben.utils.Assert; + +// need at least 2obj. +public class LinkedList0 { + public static void main(String[] args) { + LinkedList list1 = new LinkedList<>(); + LinkedList list2 = new LinkedList<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + list1.add(o1); + list1.add(o2); + list2.add(o3); + Object v1 = list1.get(1); + Object v2 = list2.get(0); + Assert.mayAlias(v1, o2); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/PriorityQueue0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/PriorityQueue0.java new file mode 100644 index 00000000000..a16508b3b29 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/PriorityQueue0.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.PriorityQueue; +import qilin.microben.utils.Assert; + +public class PriorityQueue0 { + public static void main(String[] args) { + PriorityQueue queue1 = new PriorityQueue<>(); + PriorityQueue queue2 = new PriorityQueue<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + queue1.add(o1); + queue1.add(o2); + queue2.add(o3); + Object v1 = queue1.poll(); + Object v3 = queue2.poll(); + Assert.mayAlias(v1, o2); + Assert.notAlias(v1, v3); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/Stack0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/Stack0.java new file mode 100644 index 00000000000..66da935c390 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/Stack0.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.Stack; +import qilin.microben.utils.Assert; + +public class Stack0 { + public static void main(String[] args) { + Stack s1 = new Stack<>(); + Stack s2 = new Stack<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + s1.push(o1); + s2.push(o2); + s2.push(o3); + Object v1 = s1.pop(); + Object v2 = s2.pop(); + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/TreeMap0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/TreeMap0.java new file mode 100644 index 00000000000..54d98bfe20b --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/TreeMap0.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.Map; +import java.util.TreeMap; +import qilin.microben.utils.Assert; + +public class TreeMap0 { + public static void main(String[] args) { + Map map1 = new TreeMap<>(); + Map map2 = new TreeMap<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + map1.put("first", o1); + map1.put("second", o2); + map2.put("first", o3); + Object v2 = map1.get("second"); + Object v3 = map2.get("first"); + Assert.mayAlias(v2, o2); + Assert.notAlias(v2, v3); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/TreeSet0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/TreeSet0.java new file mode 100644 index 00000000000..24eb1ed2d9c --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/TreeSet0.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.TreeSet; +import qilin.microben.utils.Assert; + +public class TreeSet0 { + public static void main(String[] args) { + TreeSet set1 = new TreeSet<>(); + TreeSet set2 = new TreeSet<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + set1.add(o1); + set1.add(o2); + set2.add(o3); + Object v2 = set1.iterator().next(); + Object v3 = set2.iterator().next(); + Assert.mayAlias(v2, o1); + Assert.notAlias(v3, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/Vector0.java b/sootup.qilin/src/test/java/qilin/microben/context/collections/Vector0.java new file mode 100644 index 00000000000..2f716080c96 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/Vector0.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.collections; + +import java.util.Vector; +import qilin.microben.utils.Assert; + +public class Vector0 { + public static void main(String[] args) { + Vector list1 = new Vector<>(); + Vector list2 = new Vector<>(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + list1.add(o1); + list1.add(o2); + list2.add(o3); + Object v1 = list1.get(1); + Object v2 = list2.get(0); + Assert.mayAlias(v1, o2); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/collections/log.txt b/sootup.qilin/src/test/java/qilin/microben/context/collections/log.txt new file mode 100644 index 00000000000..b98da874382 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/collections/log.txt @@ -0,0 +1,4 @@ +insens-qilin.core: 7 passed, 1 failed. +e-2o: 7 passed, 1 failed. +j-ci: 7 passed, 1 failed. +m-ci: 7 passed, 1 failed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb0.java b/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb0.java new file mode 100644 index 00000000000..1c956e866dd --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb0.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.hyb; + +import qilin.microben.utils.Assert; + +public class Hyb0 { + static class A { + static Object id(Object p) { + return p; + } + } + + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object v1 = A.id(o1); + Object v2 = A.id(o2); + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb1.java b/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb1.java new file mode 100644 index 00000000000..04df489a986 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb1.java @@ -0,0 +1,47 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.hyb; + +import qilin.microben.utils.Assert; + +public class Hyb1 { + static Object id(Object p) { + return p; + } + + static class A { + Object wid(Object q) { + return id(q); + } + + Object xid(Object r) { + return id(r); + } + } + + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + A a = new A(); + Object v1 = a.wid(o1); + Object v2 = a.xid(o2); + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb2.java b/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb2.java new file mode 100644 index 00000000000..dd8c1531222 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/hyb/Hyb2.java @@ -0,0 +1,52 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.hyb; + +import qilin.microben.utils.Assert; + +public class Hyb2 { + static class A { + Object f; + } + + static class B { + A foo(Object p) { + A a = create(); + a.f = p; + return a; + } + } + + static A create() { + return new A(); + } + + public static void main(String[] args) { + B b1 = new B(); // B1; + B b2 = new B(); // B2; + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + A a1 = b1.foo(o1); + A a2 = b2.foo(o2); + Object v1 = a1.f; + Object v2 = a2.f; + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k0.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k0.java new file mode 100644 index 00000000000..3c9a56b3b21 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k0.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +class OBJ1k0 { + static class A { + Object id(Object a) { + return a; + } + + Object id2(Object a) { + return id(a); + } + + Object id3(Object a) { + return id2(a); + } + } + + public static void main(String[] argv) { + A a1 = new A(); // A1 + A a2 = new A(); // A2 + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object v1 = a1.id3(o1); + Object v2 = a2.id3(o2); + Assert.notAlias(v1, v2); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k1.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k1.java new file mode 100644 index 00000000000..41b7e4efabb --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k1.java @@ -0,0 +1,54 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +public class OBJ1k1 { + static class A { + Object f; + + A(Object p) { + this.f = p; + } + + Object getF() { + return this.f; + } + } + + static class B { + Object getF(A a) { + return a.getF(); + } + } + + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + A a1 = new A(o1); // A1 + A a2 = new A(o2); // A2 + B b1 = new B(); // B1 + B b2 = new B(); // B2 + Object v1 = b1.getF(a1); + Object v2 = b2.getF(a2); + Assert.notAlias(v1, v2); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k2.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k2.java new file mode 100644 index 00000000000..3571d962689 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k2.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +class OBJ1k2 { + static class A { + Object id2(I i, Object a) { + return i.id(a); + } + } + + static class I { + Object id(Object a) { + return a; + } + } + + public static void main(String[] argv) { + A a1 = new A(); // A1 + A a2 = new A(); // A2 + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + I i1 = new I(); // I1 + I i2 = new I(); // I2 + Object v3 = a1.id2(i1, o1); + Object v4 = a2.id2(i2, o2); + Assert.mayAlias(v3, o1); + Assert.notAlias(v3, v4); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k3.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k3.java new file mode 100644 index 00000000000..8b0d078c7bd --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k3.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +public class OBJ1k3 { + static class A { + Object id(Object p) { + return p; + } + } + + static A f = new A(); + static A g = new A(); + + public static void main(String[] args) { + Object v1 = f.id(new Object()); + Object v2 = g.id(new Object()); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k4.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k4.java new file mode 100644 index 00000000000..31734ac170e --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k4.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +public class OBJ1k4 { + static class A { + Object f; + + public Object getF() { + return f; + } + + public void setF(Object f) { + this.f = f; + } + } + + public static void main(String[] args) { + A a1 = new A(); + A a2 = new A(); + Object o1 = new Object(); + Object o2 = new Object(); + a1.setF(o1); + a2.setF(o2); + Object v1 = a1.getF(); + Object v2 = a2.getF(); + Assert.notAlias(v1, v2); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k5.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k5.java new file mode 100644 index 00000000000..46e68d2cb90 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ1k5.java @@ -0,0 +1,45 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +public class OBJ1k5 { + static Object id(Object p) { + return p; + } + + static class A { + public Object foo() { + return id(new Object()); + } + + public Object bar() { + return id(new Object()); + } + } + + public static void main(String[] args) { + A a1 = new A(); + A a2 = new A(); + Object v1 = a1.foo(); + Object v2 = a2.bar(); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k0.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k0.java new file mode 100644 index 00000000000..a7b555f5803 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k0.java @@ -0,0 +1,47 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +public class OBJ2k0 { + static class A { + Object foo(Object o) { + B b = new B(); + return b.id(o); + } + } + + static class B { + Object id(Object o) { + return o; + } + } + + public static void main(String[] args) { + A a1 = new A(); // A1 + A a2 = new A(); // A2 + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object v1 = a1.foo(o1); + Object v2 = a2.foo(o2); + Assert.notAlias(v1, v2); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k1.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k1.java new file mode 100644 index 00000000000..78ef7468fef --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k1.java @@ -0,0 +1,48 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +public class OBJ2k1 { + static class B { + Object f; + } + + static class A { + B create() { + return new B(); // B + } + } + + public static void main(String[] args) { + A a1 = new A(); // A1 + A a2 = new A(); // A2 + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + B b1 = a1.create(); + B b2 = a2.create(); + b1.f = o1; + b2.f = o2; + Object w1 = b1.f; + Object w2 = b2.f; + Assert.notAlias(w1, w2); + Assert.mayAlias(w1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k2.java b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k2.java new file mode 100644 index 00000000000..c7a3de54bdb --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/OBJ2k2.java @@ -0,0 +1,54 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.obj; + +import qilin.microben.utils.Assert; + +public class OBJ2k2 { + static class A { + Object f; + + A(Object p) { + this.f = p; + } + + Object getF() { + return this.f; + } + } + + static class B { + A create(Object q) { + return new A(q); + } + } + + public static void main(String[] args) { + B b1 = new B(); + B b2 = new B(); + Object o1 = new Object(); + Object o2 = new Object(); + A a1 = b1.create(o1); + A a2 = b2.create(o2); + Object v1 = a1.getF(); + Object v2 = a2.getF(); + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/obj/log.txt b/sootup.qilin/src/test/java/qilin/microben/context/obj/log.txt new file mode 100644 index 00000000000..bbbd5b7cf91 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/obj/log.txt @@ -0,0 +1,5 @@ +insens-qilin.core: 12 passed, 17 failed. +j-ci: 12 passed, 17 failed. +m-ci: 12 passed, 17 failed. +e-2o: 29 passed. +2c: 26 passed, 3 failed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/context/type/Type1k0.java b/sootup.qilin/src/test/java/qilin/microben/context/type/Type1k0.java new file mode 100644 index 00000000000..897e7ae0bf0 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/type/Type1k0.java @@ -0,0 +1,57 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.type; + +import qilin.microben.utils.Assert; + +/* + * 1Type uses declaring type, not the reciever type. + * */ +public class Type1k0 { + static class A { + Object id(Object p) { + return p; + } + } + + static class B { + A create() { + return new A(); // A1 + } + } + + static class C { + A create() { + return new A(); // A2 + } + } + + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + B b = new B(); // B + C c = new C(); // C + A a1 = b.create(); + A a2 = c.create(); + Object v1 = a1.id(o1); + Object v2 = a2.id(o2); + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/context/type/Type2k0.java b/sootup.qilin/src/test/java/qilin/microben/context/type/Type2k0.java new file mode 100644 index 00000000000..f035a82cd3f --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/context/type/Type2k0.java @@ -0,0 +1,66 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.context.type; + +import qilin.microben.utils.Assert; + +public class Type2k0 { + static class A { + Object id(Object q) { + return q; + } + } + + static class B { + A create1() { + return new A(); + } + + A create2() { + return new A(); + } + } + + static class C { + Object foo(Object p) { + B b1 = new B(); // B1 + A a1 = b1.create1(); + return a1.id(p); + } + } + + static class D { + Object bar(Object o) { + B b2 = new B(); // B2 + A a2 = b2.create2(); + return a2.id(o); + } + } + + public static void main(String[] args) { + C c = new C(); + D d = new D(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object v1 = c.foo(o1); + Object v2 = d.bar(o2); + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayCopy.java b/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayCopy.java new file mode 100644 index 00000000000..b960527ae8e --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayCopy.java @@ -0,0 +1,35 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.array; + +import qilin.microben.utils.Assert; + +public class ArrayCopy { + public static void main(String[] ps) { + Object[] xs = new Object[5]; + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + xs[0] = o1; + xs[1] = o2; + Object[] ys = new Object[5]; + System.arraycopy(xs, 0, ys, 0, 2); + Assert.mayAlias(o1, ys[0]); + Assert.mayAlias(o2, xs[0]); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayElemTypeFiltering.java b/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayElemTypeFiltering.java new file mode 100644 index 00000000000..0cfbe8027ed --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayElemTypeFiltering.java @@ -0,0 +1,46 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.array; + +import qilin.microben.utils.Assert; + +public class ArrayElemTypeFiltering { + interface I {} + + static class G implements I {} + + static class H implements I {} + + public static void main(String[] ps) { + I[] array = new G[10]; + G g = new G(); + H h = new H(); + array[0] = g; + array[1] = h; + I i = array[0]; + Assert.notAlias(i, h); + Assert.mayAlias(i, g); + I[] array2 = new I[10]; + array2[0] = g; + array2[1] = h; + I i2 = array2[0]; + Assert.mayAlias(i2, h); + Assert.mayAlias(i2, g); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayIndex.java b/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayIndex.java new file mode 100644 index 00000000000..e9b7099ed55 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/array/ArrayIndex.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.array; + +import qilin.microben.utils.Assert; + +public class ArrayIndex { + public static void main(String[] ps) { + Object[] t = new Object[5]; + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + t[0] = o1; + t[1] = o2; + Assert.mayAlias(t[1], o1); + /* + * all array elements are collapsed as one field, i.e., arr. + * */ + Assert.mayAlias(t[1], o2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/array/MultiArrayComplex.java b/sootup.qilin/src/test/java/qilin/microben/core/array/MultiArrayComplex.java new file mode 100644 index 00000000000..d8abc9f3387 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/array/MultiArrayComplex.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.array; + +import qilin.microben.utils.Assert; + +public class MultiArrayComplex { + public static void main(String[] ps) { + Object[][][] xs = new Object[5][5][5]; + Object[] subarray = new Object[5]; + xs[1][1] = subarray; + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + xs[1][1][1] = o1; + subarray[1] = o2; + /* + * current pointer analyses do not distinguish array index. + * */ + Assert.mayAlias(subarray[1], o1); + Assert.mayAlias(xs[1][1][1], o2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/array/MultiArraySimple.java b/sootup.qilin/src/test/java/qilin/microben/core/array/MultiArraySimple.java new file mode 100644 index 00000000000..9e5e700c686 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/array/MultiArraySimple.java @@ -0,0 +1,30 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.array; + +import qilin.microben.utils.Assert; + +public class MultiArraySimple { + public static void main(String[] ps) { + Object[][][] xs = new Object[5][5][5]; + Object o = new Object(); + xs[1][1][1] = o; + Assert.mayAlias(xs[1][1][1], o); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/CastFail.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/CastFail.java new file mode 100644 index 00000000000..57d4d554cb4 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/CastFail.java @@ -0,0 +1,32 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class CastFail { + public static void main(String[] ps) { + castfail(5); + } + + public static void castfail(Object o) { + String s = (String) o; + Assert.notAlias(s, o); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/CastSucc.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/CastSucc.java new file mode 100644 index 00000000000..197db9245e8 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/CastSucc.java @@ -0,0 +1,29 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class CastSucc { + public static void main(String[] ps) { + Object o = "Hi"; + String s = (String) o; + Assert.mayAlias(s, o); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/InterAssign.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/InterAssign.java new file mode 100644 index 00000000000..3fc42bab09c --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/InterAssign.java @@ -0,0 +1,43 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class InterAssign { + static class A { + Object f; + } + + public static void main(String[] args) { + A a = new A(); + A b = new A(); + b.f = new Object(); + InterAssign m2 = new InterAssign(); + m2.alloc(a, b); + + Object x = a.f; + Object y = b.f; + Assert.mayAlias(x, y); + } + + public void alloc(A x, A y) { + x.f = y.f; + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/NullPointer.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/NullPointer.java new file mode 100644 index 00000000000..badf7e88aab --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/NullPointer.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +/* + * Currently, null is not a pointer value. As a result, the points-to set of both a and b are empty. + * Thus, they are not alias. + * */ +public class NullPointer { + public static void main(String[] args) { + Object a = getNull(); + Object b = a; + Assert.notAlias(b, a); + } + + static Object getNull() { + return null; + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/Receiver2This.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/Receiver2This.java new file mode 100644 index 00000000000..7b18fd6e41e --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/Receiver2This.java @@ -0,0 +1,50 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +/* + * Note that there is no explicit PAG edge from receiver variable to this^{callee} due to the virtual dispatch. + * */ +public class Receiver2This { + static class A { + void foo(Object o) { + Assert.notAlias(this, o); + } + } + + static class B extends A { + void foo(Object o) { + Assert.mayAlias(this, o); + } + } + + static void test(A a, Object b) { + a.foo(b); + } + + public static void main(String[] args) { + A a1 = new A(); // A + A a2 = new B(); // B + a1.foo(a2); + test(a1, a2); + test(a2, a2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/Recursion.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/Recursion.java new file mode 100644 index 00000000000..232ff06ddfc --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/Recursion.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class Recursion { + static class A { + A next = new A(); + + void foo() { + this.next.foo(); + A nn = this.next.next; + Assert.mayAlias(nn, this); + } + } + + public static void main(String[] args) { + A a = new A(); + a.foo(); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue0.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue0.java new file mode 100644 index 00000000000..bfcee1e5ff5 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue0.java @@ -0,0 +1,35 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class ReturnValue0 { + static Object a, b; + + static Object foo() { + a = new Object(); + return a; + } + + public static void main(String[] args) { + b = foo(); + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue1.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue1.java new file mode 100644 index 00000000000..a507a432bf3 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue1.java @@ -0,0 +1,33 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class ReturnValue1 { + public static Object id(Object x) { + return x; + } + + public static void main(String[] args) { + Object a = new Object(); // O1 + Object b = id(a); + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue2.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue2.java new file mode 100644 index 00000000000..06b593326ef --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue2.java @@ -0,0 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class ReturnValue2 { + public static void main(String[] args) { + Object a = new Object(); + ReturnValue2 x = new ReturnValue2(); + Object v = x.id(a); + Assert.mayAlias(a, v); + } + + public Object id(Object p) { + return p; + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue3.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue3.java new file mode 100644 index 00000000000..8608573a266 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/ReturnValue3.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class ReturnValue3 { + static class A { + Object f; + } + + public static Object id(A x) { + Object b = new Object(); + x.f = b; + return b; + } + + public static void main(String[] args) { + A a = new A(); + Object b = id(a); + Object x = a.f; + Assert.mayAlias(b, x); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/SimpleAssign.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/SimpleAssign.java new file mode 100644 index 00000000000..713f07cf4ff --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/SimpleAssign.java @@ -0,0 +1,29 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class SimpleAssign { + public static void main(String[] argv) { + Object a = new Object(); + Object b = a; + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/assign/StaticParameter.java b/sootup.qilin/src/test/java/qilin/microben/core/assign/StaticParameter.java new file mode 100644 index 00000000000..b2dbe2b1a98 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/assign/StaticParameter.java @@ -0,0 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.assign; + +import qilin.microben.utils.Assert; + +public class StaticParameter { + static Object o; + + static void foo(Object a) { + Assert.mayAlias(a, o); + } + + public static void main(String[] args) { + o = new Object(); + foo(o); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/call/StaticCall.java b/sootup.qilin/src/test/java/qilin/microben/core/call/StaticCall.java new file mode 100644 index 00000000000..58076fb37ed --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/call/StaticCall.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.call; + +import qilin.microben.utils.Assert; + +public class StaticCall { + static void foo() { + bar(); + } + + static void bar() { + Object o = new Object(); + Assert.mayAlias(o, o); + } + + public static void main(String[] args) { + foo(); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall0.java b/sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall0.java new file mode 100644 index 00000000000..667950f48e2 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall0.java @@ -0,0 +1,51 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.call; + +import qilin.microben.utils.Assert; + +/* + * To check whether virtual dispatch is correct. + * */ +public class VirtualCall0 { + interface IA { + void foo(Object p); + } + + static class A1 implements IA { + @Override + public void foo(Object p) { + Assert.notAlias(this, p); + } + } + + static class A2 implements IA { + @Override + public void foo(Object p) { + Assert.mayAlias(this, p); + } + } + + public static void main(String[] args) { + IA a1 = new A1(); + IA a2 = new A2(); + a1.foo(a2); + a2.foo(a2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall1.java b/sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall1.java new file mode 100644 index 00000000000..684d5ae67e8 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/call/VirtualCall1.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.call; + +import qilin.microben.utils.Assert; + +public class VirtualCall1 { + static class A1 { + public void foo(Object p) { + Assert.notAlias(this, p); + } + } + + static class A2 extends A1 {} + + public static void main(String[] args) { + A1 a1 = new A2(); + A1 a2 = new A2(); + a1.foo(a2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitNewExpr.java b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitNewExpr.java new file mode 100644 index 00000000000..a1720ecc0b8 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitNewExpr.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.clinit; + +import qilin.microben.utils.Assert; + +/* + * When creating Object A, its () will be triggered by JVM. + * When you run this program, it will output "hello" and "hello2". + * */ +public class ClinitNewExpr { + static class A { + public static Object field = new Object(); + + static { + System.out.println("hello"); + Assert.mayAlias(field, field); + } + } + + public static void main(String[] ps) { + A a = new A(); + System.out.println("hello2" + a); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticCall.java b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticCall.java new file mode 100644 index 00000000000..fb36745c2c9 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticCall.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.clinit; + +import qilin.microben.utils.Assert; + +public class ClinitStaticCall { + static class A { + static Object a = new Object(); + + static void foo() {} + + static { + Assert.mayAlias(a, a); + System.out.println("hello"); + } + } + + public static void main(String[] args) { + A.foo(); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticLoad.java b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticLoad.java new file mode 100644 index 00000000000..d075b76dde2 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticLoad.java @@ -0,0 +1,38 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.clinit; + +import qilin.microben.utils.Assert; + +public class ClinitStaticLoad { + static class A { + static Object o = new Object(); + + static { + Assert.mayAlias(o, o); + System.out.println("hello"); + } + } + + public static void main(String[] args) { + Object o = new Object(); + Object v = A.o; + Assert.notAlias(o, v); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticStore.java b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticStore.java new file mode 100644 index 00000000000..49e39f5d3e0 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/clinit/ClinitStaticStore.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.clinit; + +import qilin.microben.utils.Assert; + +public class ClinitStaticStore { + static class A { + static Object f; + static Object o = new Object(); + + static { + Assert.notAlias(o, f); + System.out.println("hello"); + } + } + + public static void main(String[] args) { + A.f = new Object(); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/exception/ExceptionChain.java b/sootup.qilin/src/test/java/qilin/microben/core/exception/ExceptionChain.java new file mode 100644 index 00000000000..8d8e5c62621 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/exception/ExceptionChain.java @@ -0,0 +1,54 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.exception; + +import qilin.microben.utils.Assert; + +public class ExceptionChain { + Exception t1; + Exception t2; + + void foo(int x) { + try { + if (x <= 10) { + try { + t1 = new ArithmeticException(); + throw t1; + } catch (ArithmeticException ex) { + Assert.mayAlias(t1, ex); + Assert.notAlias(ex, t2); + } + } else { + t2 = new ClassCastException(); + throw t2; + } + } catch (ClassCastException e) { + Assert.notAlias(e, t1); + Assert.mayAlias(e, t2); + } catch (Exception ey) { + Assert.notAlias(ey, t1); + Assert.notAlias(ey, t2); + } + } + + public static void main(String[] args) { + ExceptionChain ec = new ExceptionChain(); + ec.foo(args.length); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/exception/MethodThrow.java b/sootup.qilin/src/test/java/qilin/microben/core/exception/MethodThrow.java new file mode 100644 index 00000000000..8da668dd8c0 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/exception/MethodThrow.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.exception; + +import qilin.microben.utils.Assert; + +public class MethodThrow { + static class A { + static RuntimeException f; + + void foo() { + f = new RuntimeException(); + throw f; + } + } + + public static void main(String[] args) { + try { + A a = new A(); + a.foo(); + } catch (Exception e) { + Assert.mayAlias(A.f, e); + } + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/exception/SimpleException.java b/sootup.qilin/src/test/java/qilin/microben/core/exception/SimpleException.java new file mode 100644 index 00000000000..c92f9b23649 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/exception/SimpleException.java @@ -0,0 +1,35 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.exception; + +import qilin.microben.utils.Assert; + +public class SimpleException { + static Exception exp = null; + + public static void main(String[] args) { + try { + exp = new RuntimeException(); + throw exp; + } catch (Exception e) { + System.out.println("Hello"); + Assert.mayAlias(exp, e); + } + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/exception/log.txt b/sootup.qilin/src/test/java/qilin/microben/core/exception/log.txt new file mode 100644 index 00000000000..ca693ed5d99 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/exception/log.txt @@ -0,0 +1,4 @@ +insens-qilin.core: 1 passed. +e-2o: 1 passed. +j-ci: 1 passed. +m-ci: 1 passed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity1.java b/sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity1.java new file mode 100644 index 00000000000..592a97b00fd --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity1.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.field; + +import qilin.microben.utils.Assert; + +public class FieldSensitivity1 { + static class A { + Object f; + Object g; + + A(Object o1, Object o2) { + this.f = o1; + this.g = o2; + } + } + + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + A a = new A(o1, o2); + Assert.notAlias(a.f, o2); + Assert.mayAlias(a.g, o2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity2.java b/sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity2.java new file mode 100644 index 00000000000..3db239b7d03 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/field/FieldSensitivity2.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.field; + +import qilin.microben.utils.Assert; + +public class FieldSensitivity2 { + static class A { + static Object f; + static Object g; + } + + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + A.f = o1; + A.g = o2; + Assert.notAlias(A.f, o2); + Assert.mayAlias(A.g, o2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/field/InstanceLoad.java b/sootup.qilin/src/test/java/qilin/microben/core/field/InstanceLoad.java new file mode 100644 index 00000000000..6316a3b139e --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/field/InstanceLoad.java @@ -0,0 +1,31 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.field; + +import qilin.microben.utils.Assert; + +public class InstanceLoad { + Object a = new Object(); + + public static void main(String[] args) { + InstanceLoad o = new InstanceLoad(); + Object a = o.a; + Assert.mayAlias(a, o.a); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/field/InstanceStore.java b/sootup.qilin/src/test/java/qilin/microben/core/field/InstanceStore.java new file mode 100644 index 00000000000..9cc8b695374 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/field/InstanceStore.java @@ -0,0 +1,32 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.field; + +import qilin.microben.utils.Assert; + +public class InstanceStore { + Object a; + + public static void main(String[] args) { + InstanceStore i = new InstanceStore(); + Object o = new Object(); + i.a = o; + Assert.mayAlias(i.a, o); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/global/StaticLoad.java b/sootup.qilin/src/test/java/qilin/microben/core/global/StaticLoad.java new file mode 100644 index 00000000000..54531a21b58 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/global/StaticLoad.java @@ -0,0 +1,30 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.global; + +import qilin.microben.utils.Assert; + +public class StaticLoad { + static Object a = new Object(); + + public static void main(String[] args) { + Object b = a; + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/global/StaticStore.java b/sootup.qilin/src/test/java/qilin/microben/core/global/StaticStore.java new file mode 100644 index 00000000000..5ac64abc56e --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/global/StaticStore.java @@ -0,0 +1,31 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.global; + +import qilin.microben.utils.Assert; + +public class StaticStore { + static Object a; + + public static void main(String[] args) { + Object o = new Object(); + a = o; + Assert.mayAlias(a, o); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/global/StringConstant.java b/sootup.qilin/src/test/java/qilin/microben/core/global/StringConstant.java new file mode 100644 index 00000000000..9a21fb4c188 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/global/StringConstant.java @@ -0,0 +1,31 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.global; + +import qilin.microben.utils.Assert; + +public class StringConstant { + public static void main(String[] argv) { + foo("abc"); + } + + static void foo(String s) { + Assert.mayAlias(s, "abc"); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/log.txt b/sootup.qilin/src/test/java/qilin/microben/core/log.txt new file mode 100644 index 00000000000..db376d0ed58 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/log.txt @@ -0,0 +1,4 @@ +e-2o: 54 passed. +insens-qilin.core: 54 passed. +m-ci: 54 passed. +j-ci: 53 passed, 1 failed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/ArrayCopy.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/ArrayCopy.java new file mode 100644 index 00000000000..a208fc4b4f0 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/ArrayCopy.java @@ -0,0 +1,29 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import qilin.microben.utils.Assert; + +public class ArrayCopy { + public static void main(String[] args) { + Object[] src = new Object[] {new Object()}, dest = new Object[1]; + System.arraycopy(src, 0, dest, 0, 1); + Assert.mayAlias(src[0], dest[0]); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/CurrentThread.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/CurrentThread.java new file mode 100644 index 00000000000..e651f73f24b --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/CurrentThread.java @@ -0,0 +1,59 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import qilin.microben.utils.Assert; + +public class CurrentThread { + static Object t; + + static class A extends Thread { + Object f; + + A(Object p) { + this.f = p; + } + + @Override + public void run() { + Assert.mayAlias(f, t); + bar(); + } + + public void bar() { + Thread thr = Thread.currentThread(); + Assert.mayAlias(thr, this); + System.out.println(thr + ";;" + this); + } + } + + public static void main(String[] args) { + Object o = new Object(); + A a = new A(o); + t = o; + a.start(); // run() will be invoked indirectly. + Thread thr = Thread.currentThread(); + /* + * Currently, the currentThread will point to all runnable thread whose run() is invoked. + * It could not distinguish the exact current thread. + * */ + Assert.notAlias(thr, a); + System.out.println(thr + ";;" + a); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/Finalize.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/Finalize.java new file mode 100644 index 00000000000..fdbcbc84a5a --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/Finalize.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import qilin.microben.utils.Assert; + +/* + * finalize() is invoked by JVM indirectly. + * */ +public class Finalize { + + @Override + protected void finalize() { + Object o = new Object(); + Assert.mayAlias(o, o); + } + + public static void main(String[] args) { + new Finalize(); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/ObjectClone.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/ObjectClone.java new file mode 100644 index 00000000000..743944fe353 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/ObjectClone.java @@ -0,0 +1,29 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import qilin.microben.utils.Assert; + +public class ObjectClone { + public static void main(String[] args) throws CloneNotSupportedException { + ObjectClone a = new ObjectClone(); + Object b = a.clone(); + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions0.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions0.java new file mode 100644 index 00000000000..f2dbbb92499 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions0.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import qilin.microben.utils.Assert; + +public class PrivilegedActions0 { + public static Object o1; + + public static void main(String[] ps) { + Object t1 = AccessController.doPrivileged(new A()); + Assert.mayAlias(t1, o1); + } + + static class A implements PrivilegedAction { + public Object run() { + o1 = new Object(); + return o1; + } + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions1.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions1.java new file mode 100644 index 00000000000..d0e9b3d6c61 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions1.java @@ -0,0 +1,41 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import qilin.microben.utils.Assert; + +public class PrivilegedActions1 { + public static Object o1; + + public static void main(String[] ps) { + AccessControlContext acc = AccessController.getContext(); + Object t1 = AccessController.doPrivileged(new A(), acc); + Assert.mayAlias(o1, t1); + } + + static class A implements PrivilegedAction { + public Object run() { + o1 = new Object(); + return o1; + } + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions2.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions2.java new file mode 100644 index 00000000000..d1bbdc803fa --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/PrivilegedActions2.java @@ -0,0 +1,53 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import qilin.microben.utils.Assert; + +public class PrivilegedActions2 { + + public static void main(String[] args) { + PrivilegedActions2 p1 = new PrivilegedActions2(); + PrivilegedActions2 p2 = new PrivilegedActions2(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object v1 = p1.getSystemProperty(o1); + Object v2 = p2.getSystemProperty(o2); + Assert.notAlias(v1, v2); + Assert.mayAlias(o1, v1); + } + + Object getSystemProperty(final Object propName) { + return AccessController.doPrivileged(new MyPrivilegedAction(propName)); + } + + static class MyPrivilegedAction implements PrivilegedAction { + Object propName; + + public MyPrivilegedAction(Object propName) { + this.propName = propName; + } + + public Object run() { + return propName; + } + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/RefArrayGet.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/RefArrayGet.java new file mode 100644 index 00000000000..50db22d8106 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/RefArrayGet.java @@ -0,0 +1,35 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.lang.reflect.Array; +import qilin.microben.utils.Assert; + +public class RefArrayGet { + public static void main(String[] args) { + Object[] data = new Object[10]; + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + data[0] = o1; + Object v1 = Array.get(data, 0); + System.out.println(o1 + ";;" + v1); + Assert.mayAlias(o1, v1); + Assert.notAlias(o2, v1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/RefArraySet.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/RefArraySet.java new file mode 100644 index 00000000000..9ee22e781c4 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/RefArraySet.java @@ -0,0 +1,35 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.lang.reflect.Array; +import qilin.microben.utils.Assert; + +public class RefArraySet { + public static void main(String[] args) { + Object[] data = new Object[10]; + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Array.set(data, 0, o1); + Object v1 = data[0]; + System.out.println(o1 + ";;" + v1); + Assert.mayAlias(o1, v1); + Assert.notAlias(o2, v1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemErr.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemErr.java new file mode 100644 index 00000000000..d14bbaf0fcb --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemErr.java @@ -0,0 +1,31 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.io.FileNotFoundException; +import java.io.PrintStream; +import qilin.microben.utils.Assert; + +public class SystemErr { + public static void main(String[] args) throws FileNotFoundException { + PrintStream err = new PrintStream(""); + System.setErr(err); + Assert.mayAlias(err, System.err); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemIn.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemIn.java new file mode 100644 index 00000000000..067ca7b1316 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemIn.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.io.InputStream; +import qilin.microben.utils.Assert; + +public class SystemIn { + public static void main(String[] args) { + InputStream in = + new InputStream() { + @Override + public int read() { + return 0; + } + }; + System.setIn(in); + Assert.mayAlias(in, System.in); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemOut.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemOut.java new file mode 100644 index 00000000000..1221f2800d9 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/SystemOut.java @@ -0,0 +1,31 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import java.io.FileNotFoundException; +import java.io.PrintStream; +import qilin.microben.utils.Assert; + +public class SystemOut { + public static void main(String[] args) throws FileNotFoundException { + PrintStream out = new PrintStream(""); + System.setOut(out); + Assert.mayAlias(out, System.out); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/TreadRun.java b/sootup.qilin/src/test/java/qilin/microben/core/natives/TreadRun.java new file mode 100644 index 00000000000..32f2abf5e15 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/TreadRun.java @@ -0,0 +1,45 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.natives; + +import qilin.microben.utils.Assert; + +public class TreadRun { + static Object t; + + static class A extends Thread { + Object f; + + A(Object p) { + this.f = p; + } + + @Override + public void run() { + Assert.mayAlias(f, t); + } + } + + public static void main(String[] args) { + Object o = new Object(); + A a = new A(o); + t = o; + a.start(); // run() will be invoked indirectly. + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/natives/log.txt b/sootup.qilin/src/test/java/qilin/microben/core/natives/log.txt new file mode 100644 index 00000000000..a17f25e3e97 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/natives/log.txt @@ -0,0 +1,4 @@ +insens-qilin.core: 7 passed. +j-ci: 7 passed. +m-ci: 7 passed. +e-2o: 7 passed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/ArrayNewInstance.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ArrayNewInstance.java new file mode 100644 index 00000000000..f4cd0797c4d --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ArrayNewInstance.java @@ -0,0 +1,30 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import java.lang.reflect.Array; +import qilin.microben.utils.Assert; + +public class ArrayNewInstance { + public static void main(String[] args) { + Object array = Array.newInstance(Integer.TYPE, 10); + int[] arrayCast = (int[]) array; + Assert.mayAlias(array, arrayCast); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName.java new file mode 100644 index 00000000000..f92aa0bd906 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName.java @@ -0,0 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +public class ClassForName { + public static void main(String[] args) throws Exception { + String realClassName = "qilin.microben.core.reflog.ClassForName"; + Class c = Class.forName(realClassName); + String realClassName2 = "qilin.microben.core.reflog.ClassForName"; + Class c2 = Class.forName(realClassName2); + String realClassName3 = "java.lang.Object"; + Class c3 = Class.forName(realClassName3); + Assert.mayAlias(c, c2); + Assert.notAlias(c, c3); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName1.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName1.java new file mode 100644 index 00000000000..c029731526f --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassForName1.java @@ -0,0 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +public class ClassForName1 { + public static void main(String[] args) throws Exception { + String realClassName = "qilin.microben.core.reflog.ClassForName1"; + Class c = Class.forName(realClassName, true, ClassLoader.getSystemClassLoader()); + String realClassName2 = "qilin.microben.core.reflog.ClassForName1"; + Class c2 = Class.forName(realClassName2, true, ClassLoader.getSystemClassLoader()); + String realClassName3 = "java.lang.Object"; + Class c3 = Class.forName(realClassName3, true, ClassLoader.getSystemClassLoader()); + Assert.mayAlias(c, c2); + Assert.notAlias(c, c3); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassNewInstance.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassNewInstance.java new file mode 100644 index 00000000000..084c5f9e1af --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ClassNewInstance.java @@ -0,0 +1,29 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +/** to test, ClassNewInstance.log file should be put under the same directory */ +public class ClassNewInstance { + public static void main(String[] args) throws Exception { + Object a = ClassNewInstance.class.newInstance(); + Assert.mayAlias(a, a); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/ConstructorNewInstance.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ConstructorNewInstance.java new file mode 100644 index 00000000000..e8221f1dab8 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/ConstructorNewInstance.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +/** to test, ConstrucorNewInstance.log file should be put under the same directory */ +public class ConstructorNewInstance { + Object f; + + public ConstructorNewInstance(Object f) { + this.f = f; + } + + public static void main(String[] args) throws Exception { + Object f = new Object(); + ConstructorNewInstance a = + ConstructorNewInstance.class.getConstructor(Object.class).newInstance(f); + Assert.mayAlias(f, a.f); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/DoopRefBug.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/DoopRefBug.java new file mode 100644 index 00000000000..9d9a815a074 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/DoopRefBug.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import java.lang.reflect.Field; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathConstants; +import qilin.microben.utils.Assert; + +public class DoopRefBug { + public static void main(String[] args) throws Exception { + String realClassName = "javax.xml.xpath.XPathConstants"; + Class c = Class.forName(realClassName); + String fieldName = "STRING"; + Field f = c.getField(fieldName); + Object o = f.get(null); + QName S = XPathConstants.STRING; + Assert.mayAlias(o, S); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGet.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGet.java new file mode 100644 index 00000000000..655ad465803 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGet.java @@ -0,0 +1,33 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +public class FieldGet { + public Object f; + + public static void main(String[] args) throws Exception { + FieldGet fg = new FieldGet(); + Object c = new Object(); + fg.f = c; + Object d = FieldGet.class.getField("f").get(fg); + Assert.mayAlias(c, d); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGetStatic.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGetStatic.java new file mode 100644 index 00000000000..4b0a2a1344e --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldGetStatic.java @@ -0,0 +1,32 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +public class FieldGetStatic { + public static Object f; + + public static void main(String[] args) throws Exception { + Object a = new Object(); + FieldGetStatic.f = a; + Object b = FieldGetStatic.class.getField("f").get(null); + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSet.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSet.java new file mode 100644 index 00000000000..7acffe86e9c --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSet.java @@ -0,0 +1,37 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +public class FieldSet { + public Object f; + + public static void main(String[] args) throws Exception { + FieldSet fs1 = new FieldSet(); + FieldSet fs2 = new FieldSet(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + FieldSet.class.getField("f").set(fs1, o1); + FieldSet.class.getField("f").set(fs2, o2); + Object v1 = fs1.f; + Assert.notAlias(o2, v1); + Assert.mayAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSetStatic.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSetStatic.java new file mode 100644 index 00000000000..b3aa36ed3b7 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/FieldSetStatic.java @@ -0,0 +1,32 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +public class FieldSetStatic { + public static Object f; + + public static void main(String[] args) throws Exception { + Object a = new Object(); + FieldSetStatic.class.getField("f").set(null, a); + Object b = f; + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvoke.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvoke.java new file mode 100644 index 00000000000..412bd95f85f --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvoke.java @@ -0,0 +1,40 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +public class MethodInvoke { + public static void main(String[] args) throws Exception { + Object c = new Object(); + Object d = + MethodInvoke.class.getMethod("id", Object.class).invoke(new MethodInvokeInstance(), c); + Assert.mayAlias(c, d); + } + + public Object id(Object a) { + return null; + } + + static class MethodInvokeInstance extends MethodInvoke { + public Object id(Object a) { + return a; + } + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvokeStatic.java b/sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvokeStatic.java new file mode 100644 index 00000000000..05f0ec63fc3 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/MethodInvokeStatic.java @@ -0,0 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.core.reflog; + +import qilin.microben.utils.Assert; + +/** to test, MethodInvokeStatic.log file should be put under the same directory */ +public class MethodInvokeStatic { + public static Object id(Object a) { + return a; + } + + public static void main(String[] args) throws Exception { + Object a = new Object(); + Object b = MethodInvokeStatic.class.getMethod("id", Object.class).invoke(null, a); + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/core/reflog/log.txt b/sootup.qilin/src/test/java/qilin/microben/core/reflog/log.txt new file mode 100644 index 00000000000..5ebbacf21a9 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/core/reflog/log.txt @@ -0,0 +1 @@ +m-ci: 10 passed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/flowsens/Branching1.java b/sootup.qilin/src/test/java/qilin/microben/flowsens/Branching1.java new file mode 100644 index 00000000000..b0e27ad1da2 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/flowsens/Branching1.java @@ -0,0 +1,36 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.flowsens; + +import qilin.microben.utils.Assert; + +/* + * @testcase Branching1 + * @description Condition. a and b alias on one path, not on the other + */ +public class Branching1 { + public static void main(String[] args) { + Object a = new Object(); + Object b = new Object(); + if (args.length > 2) { + a = b; + } + Assert.mayAlias(a, b); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/flowsens/FlowSens0.java b/sootup.qilin/src/test/java/qilin/microben/flowsens/FlowSens0.java new file mode 100644 index 00000000000..48935c1594f --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/flowsens/FlowSens0.java @@ -0,0 +1,45 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.flowsens; + +import qilin.microben.utils.Assert; + +public class FlowSens0 { + static class A { + Object f; + } + + public static void main(String[] args) { + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + A a1 = new A(); // A1 + A a2 = new A(); // A2 + a1.f = o1; + a2.f = o2; + Object v1 = a1.f; + Object v2 = a2.f; + Assert.mayAlias(v1, o1); + Assert.notAlias(v1, v2); + a1.f = o3; + Object v3 = a1.f; + Assert.mayAlias(v3, o3); + Assert.notAlias(v3, v1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/flowsens/InstanceOf0.java b/sootup.qilin/src/test/java/qilin/microben/flowsens/InstanceOf0.java new file mode 100644 index 00000000000..23c8c4a8581 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/flowsens/InstanceOf0.java @@ -0,0 +1,44 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.flowsens; + +import qilin.microben.utils.Assert; + +public class InstanceOf0 { + static class A {} + + static class B {} + + static Object o1, o2; + + static void foo(Object p) { + if (p instanceof A) { + Assert.mayAlias(p, o1); + } else { + Assert.notAlias(p, o1); + } + } + + public static void main(String[] args) { + o1 = new A(); + o2 = new B(); + foo(o1); + foo(o2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/flowsens/Loops.java b/sootup.qilin/src/test/java/qilin/microben/flowsens/Loops.java new file mode 100644 index 00000000000..3f664848d3a --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/flowsens/Loops.java @@ -0,0 +1,43 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.flowsens; + +import qilin.microben.utils.Assert; + +public class Loops { + public static class N { + public N next; + + public N() { + next = new N(); + } + } + + public static void main(String[] args) { + N node = new N(); + int i = 0; + while (i < 10) { + node = node.next; + i++; + } + N o = node.next; + N p = node.next.next; + Assert.mayAlias(o, p); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate1.java b/sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate1.java new file mode 100644 index 00000000000..859703b2434 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate1.java @@ -0,0 +1,39 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.flowsens; + +import qilin.microben.utils.Assert; + +public class StrongUpdate1 { + static class A { + Object f; + } + + public static void main(String[] args) { + A a1 = new A(); + A a2 = a1; + Object o1 = new Object(); + Object o2 = new Object(); + a2.f = o1; + a1.f = o2; + Object v1 = a2.f; + Assert.mayAlias(v1, o2); + Assert.notAlias(v1, o1); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate2.java b/sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate2.java new file mode 100644 index 00000000000..7208ffb6c1b --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/flowsens/StrongUpdate2.java @@ -0,0 +1,43 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.flowsens; + +import qilin.microben.utils.Assert; + +// need flow-sensitivity. +public class StrongUpdate2 { + static StrongUpdate2 v; + Object f, g; + + public static void main(String[] args) { + StrongUpdate2 v1 = new StrongUpdate2(); + StrongUpdate2 v2 = new StrongUpdate2(); + Object o1 = new Object(); // O1 + Object o2 = new Object(); // O2 + Object o3 = new Object(); // O3 + v1.f = o1; + v2.f = o2; + v1.g = o3; + v = v1; + v = v2; // strong update pointer. + v.g = v.f; + Assert.notAlias(v1.g, v2.g); + Assert.mayAlias(v2.g, o2); + } +} diff --git a/sootup.qilin/src/test/java/qilin/microben/flowsens/log.txt b/sootup.qilin/src/test/java/qilin/microben/flowsens/log.txt new file mode 100644 index 00000000000..d2f1521e6eb --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/flowsens/log.txt @@ -0,0 +1,4 @@ +insens-qilin.core: 1 passed, 2 failed. +j-ci: 1 passed, 2 failed. +m-ci: 1 passed, 2 failed. +e-2o: 1 passed, 2 failed. \ No newline at end of file diff --git a/sootup.qilin/src/test/java/qilin/microben/utils/Assert.java b/sootup.qilin/src/test/java/qilin/microben/utils/Assert.java new file mode 100644 index 00000000000..f6c8e17cfa6 --- /dev/null +++ b/sootup.qilin/src/test/java/qilin/microben/utils/Assert.java @@ -0,0 +1,34 @@ +/* Qilin - a Java Pointer Analysis Framework + * Copyright (C) 2021-2030 Qilin developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3.0 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + */ + +package qilin.microben.utils; + +public class Assert { + // dummy methods for testee + public static void call(Object... o) { + // to prevent the compiler to prune the Object + } + + public static void mayAlias(Object a, Object b) { + // to be detected by Analyzer + } + + public static void notAlias(Object a, Object b) { + // to be detected by Analyzer + } +} diff --git a/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java index 9c55fb920f2..f3575e87de7 100644 --- a/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java +++ b/sootup.qilin/src/test/java/qilin/test/util/JunitTests.java @@ -44,25 +44,20 @@ public static void setUp() throws IOException { File rootDir = new File("../"); File testDir = new File( - rootDir, - "qilin.microben" - + File.separator - + "build" - + File.separator - + "classes" - + File.separator - + "java" - + File.separator - + "main"); + rootDir, "sootup.qilin" + File.separator + "target" + File.separator + "test-classes"); appPath = testDir.getCanonicalPath(); System.out.println("APP_PATH:" + appPath); File refLogDir = new File( rootDir, - "qilin.microben" + "sootup.qilin" + File.separator + "src" + File.separator + + "test" + + File.separator + + "java" + + File.separator + "qilin" + File.separator + "microben" From caf2617f3c387c5243b50f964d1886072e11ff71 Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Mon, 25 Sep 2023 09:56:08 +1000 Subject: [PATCH 031/145] upgrade sootup to revision 7ed3a82 (latest version) --- CITATION.cff | 9 + README.md | 18 +- docs/SootUpLogo.svg | 25 + docs/announce.md | 2 + docs/call-graph-construction.md | 14 +- docs/faq.md | 54 ++ docs/getting-started.md | 55 +- docs/icon.svg | 24 + docs/img/favicon.ico | Bin 0 -> 228414 bytes docs/index.md | 104 +--- docs/installation.md | 89 ++- docs/jimple.md | 5 +- docs/tools.md | 4 + docs/whatsnew.md | 66 +++ mkdocs.yml | 27 +- pom.xml | 102 +--- .../AugEvalFunctionTest/A.java | 5 + .../AugEvalFunctionDemos.java | 97 +++ .../AugEvalFunctionTest/B.java | 3 + .../ByteCodeHierarchyTest/src/Class1.java | 10 + .../ByteCodeHierarchyTest/src/Class2.java | 17 + .../ByteCodeHierarchyTest/src/Class3.java | 16 + .../ByteCodeHierarchyTest/src/Class4.java | 20 + .../src/RootInterface1.java | 3 + .../src/RootInterface2.java | 3 + .../ByteCodeHierarchyTest/src/Runner.java | 11 + .../src/SubInterface1.java | 3 + .../CastCounterTest/CastCounterDemos.java | 15 + .../CastCounterTest/Sub1.java | 2 + .../CastCounterTest/Sub2.java | 2 + .../CastCounterTest/Super1.java | 6 + .../CastCounterTest/Super2.java | 3 + .../java-miniapps/MiniApp.jar | Bin 4316 -> 4612 bytes .../java-miniapps/src/junkclass | 1 + .../requires_exports/jar/modb.jar | Bin 1074 -> 1243 bytes .../requires_exports/src/modb/pkgb/junkclass | 1 + .../binary/InterfaceVisibleAnnotation.class | Bin 0 -> 394 bytes .../java6/binary/MyInnerAnnotation.class | Bin 0 -> 356 bytes .../java6/binary/MyOuterAnnotation.class | Bin 0 -> 344 bytes .../binary/MySecondInnerAnnotation.class | Bin 0 -> 331 bytes .../java6/binary/NestedAnnotation.class | Bin 0 -> 396 bytes .../java6/binary/VisibleAnnotation.class | Bin 0 -> 279 bytes .../java6/binary/VisibleClassAnnotation.class | Bin 0 -> 388 bytes .../java6/source/NestedAnnotation.java | 23 + .../java6/source/VisibleAnnotation.java | 19 + .../wala-tests/FakeJava.java | 1 + sootup.analysis/pom.xml | 14 +- .../icfg/AbstractJimpleBasedICFG.java | 2 +- .../interprocedural/icfg/CGEdgeUtil.java | 2 +- .../interprocedural/icfg/ICFGDotExporter.java | 128 ++++ .../icfg/JimpleBasedInterproceduralCFG.java | 45 +- .../icfg/ICFGDotExporterTest.java | 306 ++++++++++ .../interprocedural/ifds/CGEdgeUtilTest.java | 560 ++++++++++++++++++ .../ifds/IFDSTaintAnalysisProblem.java | 10 +- .../ifds/IFDSTaintAnalysisTest.java | 6 +- .../ifds/IFDSTaintTestSetUp.java | 2 +- .../src/test/resources/callgraph/Example.java | 21 + .../icfg/source/ICFGArrayListExample.java | 9 + .../resources/icfg/source/ICFGExample.java | 27 + .../resources/icfg/source/ICFGExample2.java | 22 + .../icfg/source/ICFGInterfaceExample.java | 30 + sootup.callgraph/pom.xml | 14 +- .../callgraph/AbstractCallGraphAlgorithm.java | 247 ++++++-- .../main/java/sootup/callgraph/CallGraph.java | 13 +- .../ClassHierarchyAnalysisAlgorithm.java | 52 +- .../sootup/callgraph/GraphBasedCallGraph.java | 150 +++-- .../InstantiateClassValueVisitor.java | 64 ++ .../callgraph/RapidTypeAnalysisAlgorithm.java | 142 +++-- .../sootup/callgraph/CallGraphTestBase.java | 366 ++++++++++-- .../ClassHierarchyAnalysisAlgorithmTest.java | 211 ++++++- .../callgraph/DefaultEntryPointTest.java | 358 ----------- .../InstantiateClassValueVisitorTest.java | 217 +++++++ .../RapidTypeAnalysisAlgorithmTest.java | 235 +++++++- .../source/AbstractMethod1.java | 16 + .../source/AbstractMethod2.java | 20 + .../source/AbstractMethod3.java | 19 + .../source/ClinitCallConstructor.java | 28 + .../source/ClinitCallEntryPoint.java | 10 + .../source/ClinitCallProcessed.java | 14 + .../source/ClinitCallStaticField.java | 19 + .../source/ClinitCallStaticMethodCall.java | 19 + .../source/ClinitCallSuperConstructor.java | 17 + .../binary/ConcreteCallSuperClass.java | 16 + .../ConcreteCall/source/ConcreteCall.java | 12 + .../source/ConcreteCallDefaultInterface.java | 16 + .../ConcreteCallDefaultSubInterface.java | 22 + ...reteCallSuperClassDefaultSubInterface.java | 22 + ...eteCallSuperClassWithDefaultInterface.java | 22 + .../{Example1.java => source/Example2.java} | 6 +- .../InterfaceMethod/{ => binary}/J8DIM6.java | 5 +- .../InterfaceMethod/{ => source}/J8DIM1.java | 0 .../InterfaceMethod/{ => source}/J8DIM2.java | 0 .../InterfaceMethod/{ => source}/J8DIM3.java | 0 .../InterfaceMethod/{ => source}/J8DIM4.java | 0 .../InterfaceMethod/{ => source}/J8DIM5.java | 0 .../InterfaceMethod/{ => source}/J8SIM.java | 0 .../resources/callgraph/Misc/Example1.java | 27 - .../callgraph/Misc/{ => source}/AddClass.java | 0 .../callgraph/Misc/source/Example1.java | 37 ++ .../Misc/{ => source}/HelloWorld.java | 0 .../Misc/{ => source}/RecursiveCall.java | 0 .../RecursiveRevisitedMethod.java | 0 .../Misc/{ => source}/RevisitedMethod.java | 0 .../Misc/{ => source}/SingleMethod.java | 0 .../NoMainMethod/{ => source}/Example1.java | 0 .../NonVirtualCall/{ => source}/NVC1.java | 0 .../NonVirtualCall/{ => source}/NVC2.java | 0 .../NonVirtualCall/{ => source}/NVC3.java | 0 .../NonVirtualCall/{ => source}/NVC4.java | 0 .../NonVirtualCall/{ => source}/NVC5.java | 0 .../RTA/binary/ClinitInstantiateClasses.java | 20 + .../RTA/binary/LaterInstantiatedClass.java | 17 + .../{ => source}/VirtualCall1.java | 0 .../{ => source}/VirtualCall2.java | 0 .../{ => source}/VirtualCall3.java | 0 .../{ => source}/VirtualCall4.java | 0 .../test/resources/callgraph/jimple/A.jimple | 15 - sootup.core/pom.xml | 2 +- .../src/main/java/sootup/core/Language.java | 6 + .../src/main/java/sootup/core/Project.java | 35 +- .../java/sootup/core/cache/ClassCache.java | 21 + .../java/sootup/core/cache/FullCache.java | 40 ++ .../main/java/sootup/core/cache/LRUCache.java | 58 ++ .../sootup/core/cache/MutableClassCache.java | 17 + .../sootup/core/cache/MutableFullCache.java | 21 + .../cache/provider/ClassCacheProvider.java | 11 + .../cache/provider/FullCacheProvider.java | 14 + .../core/cache/provider/LRUCacheProvider.java | 26 + .../provider/MutableFullCacheProvider.java | 14 + .../java/sootup/core/frontend/BodySource.java | 5 +- .../sootup/core/frontend/ClassProvider.java | 6 +- .../core/frontend/OverridingBodySource.java | 4 +- .../core/frontend/OverridingClassSource.java | 10 +- .../sootup/core/frontend/SootClassSource.java | 4 +- .../sootup/core/graph/BackwardsStmtGraph.java | 4 +- .../java/sootup/core/graph/BasicBlock.java | 2 +- .../core/graph/ForwardingBasicBlock.java | 5 +- .../core/graph/ForwardingStmtGraph.java | 4 +- .../core/graph/ImmutableBasicBlock.java | 3 +- .../core/graph/ImmutableBlockStmtGraph.java | 7 +- .../sootup/core/graph/MutableBasicBlock.java | 16 +- .../core/graph/MutableBlockStmtGraph.java | 16 +- .../sootup/core/graph/MutableStmtGraph.java | 50 +- .../java/sootup/core/graph/StmtGraph.java | 27 +- .../StmtGraphBlockIterator.java | 10 +- .../inputlocation/AnalysisInputLocation.java | 4 +- .../inputlocation/ClassLoadingOptions.java | 5 - .../inputlocation/EagerInputLocation.java | 14 +- .../sootup/core/inputlocation/FileType.java | 5 + .../main/java/sootup/core/jimple/Jimple.java | 2 +- .../jimple/basic/FullStmtPositionInfo.java | 94 +++ .../java/sootup/core/jimple/basic/Local.java | 58 +- .../jimple/basic/NoPositionInformation.java | 6 +- .../jimple/basic/SimpleStmtPositionInfo.java | 64 ++ .../core/jimple/basic/StmtPositionInfo.java | 94 +-- .../jimple/common/constant/ClassConstant.java | 5 +- .../common/expr/AbstractFloatBinopExpr.java | 2 +- .../common/expr/AbstractIntLongBinopExpr.java | 2 +- .../common/expr/JDynamicInvokeExpr.java | 3 +- .../core/jimple/common/expr/JNegExpr.java | 17 +- .../core/jimple/common/expr/JNewExpr.java | 5 +- .../common/expr/JNewMultiArrayExpr.java | 2 +- .../core/jimple/common/expr/JShlExpr.java | 4 +- .../core/jimple/common/expr/JShrExpr.java | 4 +- .../core/jimple/common/expr/JUshrExpr.java | 4 +- .../core/jimple/common/ref/JArrayRef.java | 44 +- .../core/jimple/common/ref/JFieldRef.java | 3 + .../common/stmt/AbstractDefinitionStmt.java | 15 +- .../core/jimple/common/stmt/JAssignStmt.java | 22 + .../jimple/common/stmt/JIdentityStmt.java | 5 + .../sootup/core/jimple/common/stmt/Stmt.java | 22 +- .../jimple/visitor/AbstractExprVisitor.java | 5 + .../jimple/visitor/AbstractValueVisitor.java | 5 + .../jimple/visitor/ReplaceUseExprVisitor.java | 2 +- .../jimple/visitor/ReplaceUseRefVisitor.java | 9 +- .../jimple/visitor/ReplaceUseStmtVisitor.java | 34 +- .../src/main/java/sootup/core/model/Body.java | 147 ++++- .../java/sootup/core/model/BodyUtils.java | 166 ------ .../java/sootup/core/model/ClassModifier.java | 168 ++++++ .../java/sootup/core/model/FieldModifier.java | 146 +++++ .../java/sootup/core/model/FullPosition.java | 66 +++ .../java/sootup/core/model/LinePosition.java | 29 + .../{Modifier.java => MethodModifier.java} | 79 +-- .../main/java/sootup/core/model/Position.java | 88 +-- .../java/sootup/core/model/SootClass.java | 24 +- .../sootup/core/model/SootClassMember.java | 44 +- .../java/sootup/core/model/SootField.java | 66 ++- .../java/sootup/core/model/SootMethod.java | 70 ++- .../sootup/core/signatures/PackageName.java | 6 + .../core/transform/BodyInterceptor.java | 9 +- .../typehierarchy/MethodDispatchResolver.java | 183 +++++- .../typehierarchy/MutableTypeHierarchy.java | 2 +- .../core/typehierarchy/TypeHierarchy.java | 52 +- .../core/typehierarchy/ViewTypeHierarchy.java | 101 +++- .../java/sootup/core/types/ArrayType.java | 13 +- .../java/sootup/core/types/ClassType.java | 8 + .../java/sootup/core/types/PrimitiveType.java | 20 +- .../src/main/java/sootup/core/types/Type.java | 56 +- .../java/sootup/core/util/DotExporter.java | 48 +- .../main/java/sootup/core/util/PathUtils.java | 2 +- .../src/main/java/sootup/core/util/Utils.java | 19 +- .../core/util/printer/JimplePrinter.java | 33 +- .../core/validation/CheckInitValidator.java | 3 +- .../core/validation/LocalsValidator.java | 43 +- .../java/sootup/core/views/AbstractView.java | 16 - .../src/main/java/sootup/core/views/View.java | 65 +- .../core/graph/MutableBlockStmtGraphTest.java | 38 +- sootup.examples/pom.xml | 24 +- .../examples/basicSetup/BasicSetup.java | 4 +- .../bodyInterceptor/BodyInterceptor.java | 22 +- .../examples/callgraph/CallgraphExample.java | 7 +- .../classhierarchy/ClassHierarchy.java | 2 +- .../mutatingSootClass/MutatingSootClass.java | 5 +- .../lib/dex-tools-2.2-SNAPSHOT.jar | Bin 5775839 -> 0 bytes sootup.java.bytecode/pom.xml | 25 +- .../frontend/AsmAnnotationClassSource.java | 21 +- .../bytecode/frontend/AsmClassSource.java | 25 +- .../frontend/AsmJavaClassProvider.java | 59 +- .../bytecode/frontend/AsmMethodSource.java | 306 +++++----- .../java/bytecode/frontend/AsmUtil.java | 135 +++-- .../java/bytecode/frontend/OperandStack.java | 10 +- .../java/bytecode/frontend/StackFrame.java | 25 +- .../java/bytecode/frontend/StmtContainer.java | 19 +- .../JavaClassPathAnalysisInputLocation.java | 2 +- .../JavaModulePathAnalysisInputLocation.java | 19 +- .../JrtFileSystemAnalysisInputLocation.java | 65 +- .../bytecode/inputlocation/ModuleFinder.java | 14 +- .../PathBasedAnalysisInputLocation.java | 135 ++--- .../bytecode/interceptors/Aggregator.java | 6 +- .../BytecodeBodyInterceptors.java | 27 +- .../interceptors/CastAndReturnInliner.java | 5 +- .../interceptors/ConditionalBranchFolder.java | 5 +- .../ConstantPropagatorAndFolder.java | 9 +- .../bytecode/interceptors/CopyPropagator.java | 10 +- .../DeadAssignmentEliminator.java | 20 +- .../interceptors/EmptySwitchEliminator.java | 11 +- .../interceptors/LocalLivenessAnalyser.java | 2 +- .../interceptors/LocalNameStandardizer.java | 129 +--- .../bytecode/interceptors/LocalPacker.java | 9 +- .../bytecode/interceptors/LocalSplitter.java | 40 +- .../bytecode/interceptors/NopEliminator.java | 5 +- .../StaticSingleAssignmentFormer.java | 9 +- .../bytecode/interceptors/TrapTightener.java | 3 +- .../bytecode/interceptors/TypeAssigner.java | 31 +- .../UnreachableCodeEliminator.java | 5 +- .../interceptors/UnusedLocalEliminator.java | 3 +- .../typeresolving/AugEvalFunction.java | 273 +++++++++ .../typeresolving/BytecodeHierarchy.java | 261 ++++++++ .../typeresolving/CastCounter.java | 177 ++++++ .../typeresolving/PrimitiveHierarchy.java | 166 ++++++ .../typeresolving/StmtLocalPair.java | 49 ++ .../typeresolving/TypeChecker.java | 335 +++++++++++ .../typeresolving/TypePromotionVisitor.java | 144 +++++ .../typeresolving/TypeResolver.java | 301 ++++++++++ .../interceptors/typeresolving/Typing.java | 114 ++++ .../typeresolving/types/AugIntegerTypes.java | 104 ++++ .../typeresolving/types/BottomType.java | 37 +- .../typeresolving/types/WeakObjectType.java | 54 ++ .../bytecode/RuntimeJarConversionTests.java | 6 +- .../java/sootup/java/bytecode/Soot1577.java | 4 +- .../java/sootup/java/bytecode/Soot1580.java | 4 +- .../frontend/AsmMethodSourceTest.java | 2 +- .../java/bytecode/frontend/AsmUtilTest.java | 216 +++++++ .../bytecode/frontend/JavaModuleViewTest.java | 45 +- .../AnalysisInputLocationTest.java | 29 +- ...vaModulePathAnalysisInputLocationTest.java | 12 +- ...rtFileSystemAnalysisInputLocationTest.java | 4 +- .../JrtFileSystemNamespaceTest.java | 1 - .../PathBasedAnalysisInputLocationTest.java | 100 ++-- .../bytecode/interceptors/AggregatorTest.java | 4 +- .../bytecode/interceptors/AssertUtils.java | 16 +- .../CastAndReturnInlinerTest.java | 4 +- .../ConditionalBranchFolderTest.java | 6 +- .../ConstantPropagatorAndFolderTest.java | 4 +- .../interceptors/CopyPropagatorTest.java | 6 +- .../DeadAssignmentEliminatorTest.java | 8 +- .../EmptySwitchEliminatorTest.java | 2 +- .../LocalNameStandardizerTest.java | 4 +- .../interceptors/LocalPackerTest.java | 4 +- .../interceptors/LocalSplitterTest.java | 79 +-- .../interceptors/NopEliminatorTest.java | 8 +- .../StaticSingleAssignmentFormerTest.java | 4 +- .../interceptors/TrapTightenerTest.java | 8 +- .../UnreachableCodeEliminatorTest.java | 20 +- .../UnusedLocalEliminatorTest.java | 4 +- .../typeresolving/AugEvalFunctionTest.java | 390 ++++++++++++ .../typeresolving/BytecodeHierarchyTest.java | 207 +++++++ .../typeresolving/CastCounterTest.java | 161 +++++ .../typeresolving/PrimitiveHierarchyTest.java | 103 ++++ .../typeresolving/TypeAssignerTest.java | 73 +++ .../typeresolving/TypeAssignerTestSuite.java | 62 ++ .../typeresolving/TypeResolverTest.java | 77 +++ .../MinimalBytecodeTestSuiteBase.java | 17 +- .../java11/TypeInferenceLambdaTest.java | 2 +- .../java14/SwitchExprWithYieldTest.java | 4 +- .../java6/AnnotationLibraryTest.java | 4 +- .../java6/DeclareFieldTest.java | 20 +- .../java6/NestedAnnotationTest.java | 56 ++ .../java6/PublicClassTest.java | 4 +- .../java6/TransientVariableTest.java | 4 +- .../java6/VisibleAnnotationTest.java | 26 + .../java6/VolatileVariableTest.java | 9 +- .../java8/MethodAcceptingLamExprTest.java | 2 +- .../java8/RepeatingAnnotationsTest.java | 4 +- .../java9/DynamicInvokeTest.java | 2 +- sootup.java.core/pom.xml | 4 +- .../java/core/JavaAnnotationSootMethod.java | 4 +- .../java/core/JavaIdentifierFactory.java | 49 +- .../core/JavaModuleIdentifierFactory.java | 46 +- .../sootup/java/core/JavaModuleProject.java | 21 +- .../java/sootup/java/core/JavaProject.java | 42 +- .../java/sootup/java/core/JavaSootClass.java | 2 +- .../java/sootup/java/core/JavaSootField.java | 12 +- .../java/sootup/java/core/JavaSootMethod.java | 6 +- .../java/core/OverridingJavaClassSource.java | 12 +- .../java/core/jimple/basic/JavaLocal.java | 11 - .../sootup/java/core/language/JavaJimple.java | 6 + .../java/core/language/JavaLanguage.java | 3 +- .../core/signatures/ModulePackageName.java | 4 +- .../sootup/java/core/types/JavaClassType.java | 8 +- .../java/core/views/JavaModuleView.java | 53 +- .../java/sootup/java/core/views/JavaView.java | 97 ++- .../java/core/views/MutableJavaView.java | 15 +- .../core/jimple/common/ref/JFieldRefTest.java | 19 +- .../jimple/common/stmt/JInvokeStmtTest.java | 4 +- .../java/core/model/SootMethodTest.java | 13 +- .../java/core/printer/JimplePrinterTest.java | 10 +- .../core/printer/LegacyJimplePrinterTest.java | 6 +- .../signatures/JavaIdentifierFactoryTest.java | 6 +- .../JavaModuleIdentifierFactoryTest.java | 2 +- sootup.java.sourcecode/pom.xml | 257 +++++++- .../frontend/InstructionConverter.java | 16 +- .../frontend/WalaIRToJimpleConverter.java | 100 ++-- .../frontend/WalaJavaClassProvider.java | 12 +- .../sourcecode/frontend/WalaSootMethod.java | 6 +- .../JavaSourcePathAnalysisInputLocation.java | 2 +- .../frontend/SwitchConversionTest.java | 111 ++-- .../frontend/WalaJavaClassProviderTest.java | 14 +- .../JavaSourcePathNamespaceTest.java | 36 +- .../MinimalSourceTestSuiteBase.java | 4 +- .../java6/AnnotationLibraryTest.java | 4 +- .../java6/DeclareFieldTest.java | 20 +- .../java6/InfiniteLoopTest.java | 4 +- .../java6/NoModifierClassTest.java | 4 +- .../java6/PublicClassTest.java | 4 +- .../java6/TransientVariableTest.java | 4 +- .../java6/VolatileVariableTest.java | 4 +- .../java8/RepeatingAnnotationsTest.java | 4 +- sootup.jimple.parser/pom.xml | 13 +- .../src/main/antlr4/sootup/jimple/Jimple.g4 | 30 +- .../parser/JimpleAnalysisInputLocation.java | 9 +- .../jimple/parser/JimpleClassProvider.java | 24 +- .../sootup/jimple/parser/JimpleConverter.java | 67 ++- .../jimple/parser/JimpleConverterUtil.java | 16 +- .../sootup/jimple/parser/JimpleProject.java | 46 +- .../java/sootup/jimple/parser/JimpleView.java | 73 ++- .../src/test/java/resources/jimple/A.jimple | 2 +- .../resources/jimple/AbstractClass.jimple | 2 +- .../java/resources/jimple/AccessArrays.jimple | 2 +- .../resources/jimple/AlphaBetaGamma.jimple | 9 + .../jimple/AnonymousClassInsideMethod.jimple | 2 +- .../jimple/AnonymousDiamondOperator.jimple | 2 +- .../resources/jimple/AssertStatement.jimple | 2 +- .../java/resources/jimple/Autoboxing.jimple | 2 +- .../resources/jimple/AutomaticWidening.jimple | 2 +- .../jimple/BinaryLiteralInInt.jimple | 2 +- .../jimple/BitwiseOperationsInt.jimple | 2 +- .../resources/jimple/BooleanOperators.jimple | 2 +- .../resources/jimple/BreakInWhileLoop.jimple | 2 +- .../resources/jimple/CastingInNumTypes.jimple | 2 +- .../java/resources/jimple/CharLiterals.jimple | 2 +- .../jimple/ContinueInWhileLoop.jimple | 2 +- .../resources/jimple/CreateNewInstance.jimple | 2 +- .../jimple/DeclareConstructor.jimple | 2 +- .../resources/jimple/DeclareEnum$Type.jimple | 2 +- .../DeclareEnumWithConstructor$Number.jimple | 2 +- .../java/resources/jimple/DeclareField.jimple | 2 +- .../java/resources/jimple/DeclareFloat.jimple | 2 +- .../DeclareInnerClass$InnerClass.jimple | 2 +- .../resources/jimple/DeclareInnerClass.jimple | 2 +- .../java/resources/jimple/DeclareInt.jimple | 2 +- .../java/resources/jimple/DeclareLong.jimple | 2 +- .../jimple/DefaultMethodInterfaceImpl.jimple | 2 +- .../java/resources/jimple/DoWhileLoop.jimple | 2 +- .../resources/jimple/DynamicInvoke.jimple | 4 +- .../jimple/EdgeCaseDoubleNumber.jimple | 26 + .../resources/jimple/EmptyStatement.jimple | 2 +- .../jimple/EscapeSequencesInString.jimple | 2 +- .../EvaluationOrderWithParentheses.jimple | 2 +- .../java/resources/jimple/FakeJimple.jimple | 1 + .../java/resources/jimple/FinalMethod.jimple | 2 +- .../resources/jimple/FinalVariable.jimple | 2 +- .../java/resources/jimple/ForEachLoop.jimple | 2 +- .../test/java/resources/jimple/ForLoop.jimple | 2 +- .../java/resources/jimple/GenTypeParam.jimple | 2 +- .../jimple/GenericTypeParamOnClass.jimple | 2 +- .../jimple/GenericTypeParamOnMethod.jimple | 2 +- .../resources/jimple/IfElseStatement.jimple | 2 +- .../java/resources/jimple/InfiniteLoop.jimple | 2 +- .../Initialize3DimensionalArrays.jimple | 2 +- .../InitializeArraysWhileDeclaration.jimple | 2 +- .../jimple/InitializeArraysWithIndex.jimple | 2 +- .../InitializeMultidimensionalArrays.jimple | 2 +- .../resources/jimple/InstanceOfCheck.jimple | 2 +- .../jimple/InterfaceImplClass.jimple | 2 +- .../resources/jimple/LabelStatement.jimple | 2 +- .../resources/jimple/LabelledLoopBreak.jimple | 2 +- .../jimple/MethodAcceptingLamExpr.jimple | 4 +- .../jimple/MethodAcceptingVar.jimple | 2 +- .../resources/jimple/MethodOverloading.jimple | 2 +- .../jimple/MethodOverridingSubclass.jimple | 2 +- .../resources/jimple/MethodReference.jimple | 2 +- .../jimple/MethodReturningVar.jimple | 2 +- .../jimple/MultiInterfaceImplClass.jimple | 2 +- .../resources/jimple/MultiTryCatch.jimple | 2 +- .../jimple/NamedClassInsideMethod.jimple | 2 +- .../java/resources/jimple/NativeMethod.jimple | 2 +- .../jimple/NewCodeBlockInMethod.jimple | 2 +- .../resources/jimple/NoModifierClass.jimple | 2 +- .../java/resources/jimple/NullVariable.jimple | 2 +- .../jimple/PrivateMethodInterfaceImpl.jimple | 2 +- .../java/resources/jimple/PublicClass.jimple | 2 +- .../jimple/ReferenceVarDeclaration.jimple | 2 +- .../resources/jimple/ReferencingThis.jimple | 2 +- .../java/resources/jimple/Reflection.jimple | 4 +- .../resources/jimple/StatementEval.jimple | 2 +- .../java/resources/jimple/StaticImport.jimple | 2 +- .../resources/jimple/StaticInitializer.jimple | 2 +- .../java/resources/jimple/StaticMethod.jimple | 2 +- .../jimple/StaticMethodInterfaceImpl.jimple | 2 +- .../jimple/StaticMethodInvocation.jimple | 2 +- .../resources/jimple/StaticVariable.jimple | 2 +- .../jimple/StringConcatenation.jimple | 2 +- .../jimple/StringWithUnicodeChar.jimple | 2 +- .../java/resources/jimple/SubClass.jimple | 2 +- .../resources/jimple/SubTypeValidator.jimple | 86 +++ .../java/resources/jimple/SuperClass.jimple | 2 +- .../jimple/SwitchCaseStatement.jimple | 2 +- .../SwitchCaseStatementWithString.jimple | 2 +- .../jimple/SymbolsAsMethodName.jimple | 2 +- .../resources/jimple/SynchronizedBlock.jimple | 2 +- .../jimple/SynchronizedMethod.jimple | 2 +- .../resources/jimple/TernaryOperator.jimple | 2 +- .../jimple/ThrowExceptionMethod.jimple | 2 +- .../resources/jimple/TransientVariable.jimple | 2 +- .../resources/jimple/TryCatchFinally.jimple | 2 +- .../resources/jimple/TryWithResources.jimple | 2 +- .../jimple/TryWithResourcesConcise.jimple | 2 +- .../resources/jimple/TypeInference.jimple | 2 +- .../java/resources/jimple/UnaryOpInt.jimple | 2 +- .../resources/jimple/UncheckedCast.jimple | 2 +- .../resources/jimple/UnderscoreInInt.jimple | 2 +- .../jimple/VariableDeclaration.jimple | 2 +- .../resources/jimple/VariableShadowing.jimple | 2 +- .../resources/jimple/VirtualMethod.jimple | 2 +- .../resources/jimple/VolatileVariable.jimple | 2 +- .../java/resources/jimple/WhileLoop.jimple | 2 +- ...61\317\201\316\265\317\204\316\267.jimple" | 2 +- .../JimpleAnalysisInputLocationTest.java | 60 +- .../jimple/parser/JimpleConverterTest.java | 64 +- .../javatestsuite/JimpleTestSuiteBase.java | 6 +- .../java6/AlphaBetaGammaTest.java | 25 + .../java6/AnnotationLibraryTest.java | 4 +- .../javatestsuite/java6/DeclareFieldTest.java | 20 +- .../javatestsuite/java6/PublicClassTest.java | 4 +- .../java6/TransientVariableTest.java | 4 +- .../java6/VolatileVariableTest.java | 9 +- .../java8/MethodAcceptingLamExprTest.java | 2 +- .../java8/RepeatingAnnotationsTest.java | 4 +- .../java9/DynamicInvokeTest.java | 2 +- sootup.report/pom.xml | 28 +- sootup.tests/pom.xml | 22 +- .../java/sootup/tests/SimpleSootClient.java | 2 +- .../src/test/java/sootup/tests/CacheTest.java | 76 +++ .../test/java/sootup/tests/CallGraphTest.java | 204 ++++++- .../sootup/tests/MutableSootClientTest.java | 10 +- .../tests/ReplaceUseRefVisitorTest.java | 18 +- .../test/java/sootup/tests/WitherTest.java | 4 +- .../JavaTypeHierarchyTestBase.java | 2 +- .../typehierarchy/MethodDispatchBase.java | 19 +- .../MethodDispatchResolverTest.java | 103 +++- .../typehierarchy/ViewTypeHierarchyTest.java | 6 +- .../AbstractDispatchTest.java | 20 +- .../AllDispatchTest.java | 46 ++ .../ConcreteDispatchTest.java | 73 ++- .../CovarianceDispatchTest.java | 45 ++ .../AbstractClassInheritanceTest.java | 17 +- .../IncompleteSuperclassTest.java | 31 + .../callgraph/Misc/AbstractClass.java | 3 + .../resources/callgraph/Misc/HelloWorld.java | 9 - .../resources/callgraph/Misc/Interface.java | 5 + .../Misc/InterfaceImplementation.java | 5 + ...InterfaceImplementationNotInstatiated.java | 5 + .../Misc/InterfaceNoImplementation.java | 3 + .../test/resources/callgraph/Misc/Main.java | 11 + .../callgraph/Misc/MethodImplemented.java | 5 + ...thodImplementedInstantiatedInSubClass.java | 5 + .../Misc/SubClassMethodImplemented.java | 5 + .../Misc/SubClassMethodNotImplemented.java | 2 + .../IncompleteSuperclass/SubClassA.java | 3 + .../IncompleteSuperclass/SubClassB.java | 3 + .../AbstractDispatch/A.java | 2 +- .../AbstractDispatch/B.java | 5 +- .../AbstractDispatch/C.java | 2 +- .../methoddispatchresolver/AllDispatch/A.java | 7 + .../AllDispatch/AbstractClass.java | 6 + .../methoddispatchresolver/AllDispatch/B.java | 5 + .../methoddispatchresolver/AllDispatch/C.java | 8 + .../ConcreteDispatch/A.java | 2 +- .../ConcreteDispatch/C.java | 3 + .../ConcreteDispatch/D.java | 3 + .../ConcreteDispatch/I.java | 7 + .../ConcreteDispatch/J.java | 10 + .../CovarianceDispatch/Subclass.java | 8 + .../CovarianceDispatch/Superclass.java | 8 + 515 files changed, 11728 insertions(+), 3423 deletions(-) create mode 100644 CITATION.cff create mode 100644 docs/SootUpLogo.svg create mode 100644 docs/faq.md create mode 100644 docs/icon.svg create mode 100644 docs/img/favicon.ico create mode 100644 docs/whatsnew.md create mode 100644 shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/A.java create mode 100644 shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/AugEvalFunctionDemos.java create mode 100644 shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/B.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class1.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class2.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class3.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class4.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface1.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface2.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Runner.java create mode 100644 shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/SubInterface1.java create mode 100644 shared-test-resources/TypeResolverTestSuite/CastCounterTest/CastCounterDemos.java create mode 100644 shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub1.java create mode 100644 shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub2.java create mode 100644 shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super1.java create mode 100644 shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super2.java create mode 100644 shared-test-resources/java-miniapps/src/junkclass create mode 100644 shared-test-resources/jigsaw-examples/requires_exports/src/modb/pkgb/junkclass create mode 100644 shared-test-resources/miniTestSuite/java6/binary/InterfaceVisibleAnnotation.class create mode 100644 shared-test-resources/miniTestSuite/java6/binary/MyInnerAnnotation.class create mode 100644 shared-test-resources/miniTestSuite/java6/binary/MyOuterAnnotation.class create mode 100644 shared-test-resources/miniTestSuite/java6/binary/MySecondInnerAnnotation.class create mode 100644 shared-test-resources/miniTestSuite/java6/binary/NestedAnnotation.class create mode 100644 shared-test-resources/miniTestSuite/java6/binary/VisibleAnnotation.class create mode 100644 shared-test-resources/miniTestSuite/java6/binary/VisibleClassAnnotation.class create mode 100644 shared-test-resources/miniTestSuite/java6/source/NestedAnnotation.java create mode 100644 shared-test-resources/miniTestSuite/java6/source/VisibleAnnotation.java create mode 100644 shared-test-resources/wala-tests/FakeJava.java create mode 100644 sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java create mode 100644 sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java create mode 100644 sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/CGEdgeUtilTest.java create mode 100644 sootup.analysis/src/test/resources/callgraph/Example.java create mode 100644 sootup.analysis/src/test/resources/icfg/source/ICFGArrayListExample.java create mode 100644 sootup.analysis/src/test/resources/icfg/source/ICFGExample.java create mode 100644 sootup.analysis/src/test/resources/icfg/source/ICFGExample2.java create mode 100644 sootup.analysis/src/test/resources/icfg/source/ICFGInterfaceExample.java create mode 100644 sootup.callgraph/src/main/java/sootup/callgraph/InstantiateClassValueVisitor.java delete mode 100644 sootup.callgraph/src/test/java/sootup/callgraph/DefaultEntryPointTest.java create mode 100644 sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod1.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod2.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod3.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallConstructor.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallEntryPoint.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallProcessed.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticField.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticMethodCall.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallSuperConstructor.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClass.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCall.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultInterface.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultSubInterface.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassDefaultSubInterface.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassWithDefaultInterface.java rename sootup.callgraph/src/test/resources/callgraph/DefaultEntryPoint/{Example1.java => source/Example2.java} (80%) rename sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/{ => binary}/J8DIM6.java (85%) rename sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/{ => source}/J8DIM1.java (100%) rename sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/{ => source}/J8DIM2.java (100%) rename sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/{ => source}/J8DIM3.java (100%) rename sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/{ => source}/J8DIM4.java (100%) rename sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/{ => source}/J8DIM5.java (100%) rename sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/{ => source}/J8SIM.java (100%) delete mode 100644 sootup.callgraph/src/test/resources/callgraph/Misc/Example1.java rename sootup.callgraph/src/test/resources/callgraph/Misc/{ => source}/AddClass.java (100%) create mode 100644 sootup.callgraph/src/test/resources/callgraph/Misc/source/Example1.java rename sootup.callgraph/src/test/resources/callgraph/Misc/{ => source}/HelloWorld.java (100%) rename sootup.callgraph/src/test/resources/callgraph/Misc/{ => source}/RecursiveCall.java (100%) rename sootup.callgraph/src/test/resources/callgraph/Misc/{ => source}/RecursiveRevisitedMethod.java (100%) rename sootup.callgraph/src/test/resources/callgraph/Misc/{ => source}/RevisitedMethod.java (100%) rename sootup.callgraph/src/test/resources/callgraph/Misc/{ => source}/SingleMethod.java (100%) rename sootup.callgraph/src/test/resources/callgraph/NoMainMethod/{ => source}/Example1.java (100%) rename sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/{ => source}/NVC1.java (100%) rename sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/{ => source}/NVC2.java (100%) rename sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/{ => source}/NVC3.java (100%) rename sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/{ => source}/NVC4.java (100%) rename sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/{ => source}/NVC5.java (100%) create mode 100644 sootup.callgraph/src/test/resources/callgraph/RTA/binary/ClinitInstantiateClasses.java create mode 100644 sootup.callgraph/src/test/resources/callgraph/RTA/binary/LaterInstantiatedClass.java rename sootup.callgraph/src/test/resources/callgraph/VirtualCall/{ => source}/VirtualCall1.java (100%) rename sootup.callgraph/src/test/resources/callgraph/VirtualCall/{ => source}/VirtualCall2.java (100%) rename sootup.callgraph/src/test/resources/callgraph/VirtualCall/{ => source}/VirtualCall3.java (100%) rename sootup.callgraph/src/test/resources/callgraph/VirtualCall/{ => source}/VirtualCall4.java (100%) delete mode 100644 sootup.callgraph/src/test/resources/callgraph/jimple/A.jimple create mode 100644 sootup.core/src/main/java/sootup/core/cache/ClassCache.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/FullCache.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/LRUCache.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/MutableClassCache.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/MutableFullCache.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/provider/ClassCacheProvider.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/provider/FullCacheProvider.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/provider/LRUCacheProvider.java create mode 100644 sootup.core/src/main/java/sootup/core/cache/provider/MutableFullCacheProvider.java rename sootup.core/src/main/java/sootup/core/graph/{iterator => }/StmtGraphBlockIterator.java (96%) create mode 100644 sootup.core/src/main/java/sootup/core/jimple/basic/FullStmtPositionInfo.java create mode 100644 sootup.core/src/main/java/sootup/core/jimple/basic/SimpleStmtPositionInfo.java delete mode 100644 sootup.core/src/main/java/sootup/core/model/BodyUtils.java create mode 100644 sootup.core/src/main/java/sootup/core/model/ClassModifier.java create mode 100644 sootup.core/src/main/java/sootup/core/model/FieldModifier.java create mode 100644 sootup.core/src/main/java/sootup/core/model/FullPosition.java create mode 100644 sootup.core/src/main/java/sootup/core/model/LinePosition.java rename sootup.core/src/main/java/sootup/core/model/{Modifier.java => MethodModifier.java} (65%) delete mode 100644 sootup.java.bytecode/lib/dex-tools-2.2-SNAPSHOT.jar create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/AugEvalFunction.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/BytecodeHierarchy.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/CastCounter.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchy.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/StmtLocalPair.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeChecker.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypePromotionVisitor.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeResolver.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/Typing.java create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/types/AugIntegerTypes.java rename sootup.callgraph/src/main/java/sootup/callgraph/OnDemandClassHierarchyAnalysisAlgorithm.java => sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/types/BottomType.java (54%) create mode 100644 sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/types/WeakObjectType.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/frontend/AsmUtilTest.java delete mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/inputlocation/JrtFileSystemNamespaceTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/AugEvalFunctionTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/BytecodeHierarchyTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/CastCounterTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchyTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/TypeAssignerTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/TypeAssignerTestSuite.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/TypeResolverTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/NestedAnnotationTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/VisibleAnnotationTest.java create mode 100644 sootup.jimple.parser/src/test/java/resources/jimple/AlphaBetaGamma.jimple create mode 100644 sootup.jimple.parser/src/test/java/resources/jimple/EdgeCaseDoubleNumber.jimple create mode 100644 sootup.jimple.parser/src/test/java/resources/jimple/FakeJimple.jimple create mode 100644 sootup.jimple.parser/src/test/java/resources/jimple/SubTypeValidator.jimple create mode 100644 sootup.jimple.parser/src/test/java/sootup/jimple/parser/javatestsuite/java6/AlphaBetaGammaTest.java create mode 100644 sootup.tests/src/test/java/sootup/tests/CacheTest.java create mode 100644 sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/AllDispatchTest.java create mode 100644 sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/CovarianceDispatchTest.java create mode 100644 sootup.tests/src/test/java/sootup/tests/typehierarchy/viewtypehierarchytestcase/IncompleteSuperclassTest.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/AbstractClass.java delete mode 100644 sootup.tests/src/test/resources/callgraph/Misc/HelloWorld.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/Interface.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/InterfaceImplementation.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/InterfaceImplementationNotInstatiated.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/InterfaceNoImplementation.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/Main.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/MethodImplemented.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/MethodImplementedInstantiatedInSubClass.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/SubClassMethodImplemented.java create mode 100644 sootup.tests/src/test/resources/callgraph/Misc/SubClassMethodNotImplemented.java create mode 100644 sootup.tests/src/test/resources/javatypehierarchy/IncompleteSuperclass/SubClassA.java create mode 100644 sootup.tests/src/test/resources/javatypehierarchy/IncompleteSuperclass/SubClassB.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/A.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/AbstractClass.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/B.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/C.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/C.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/D.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/I.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/J.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Subclass.java create mode 100644 sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Superclass.java diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000000..4d30000d111 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,9 @@ +cff-version: 1.2.0 +title: SootUp +message: 'If you use SootUp, please cite it as below.' +type: software +authors: + - given-names: Soot-oss +repository-code: 'https://github.com/soot-oss/SootUp' +version: 1.1.2 +date-released: '2023-06-12' \ No newline at end of file diff --git a/README.md b/README.md index 0d1bc0da787..051d37be1da 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,25 @@ -# SootUp library ![Java CI with Maven](https://github.com/soot-oss/SootUp/workflows/Java%20CI%20with%20Maven/badge.svg?branch=develop) [![codecov](https://codecov.io/gh/soot-oss/SootUp/branch/develop/graph/badge.svg?token=ELA7U7IAWD)](https://codecov.io/gh/soot-oss/SootUp) +

+ +

+ +# SootUp library ![Java CI with Maven](https://github.com/soot-oss/SootUp/workflows/Java%20CI%20with%20Maven/badge.svg?branch=develop) [![codecov](https://codecov.io/gh/soot-oss/SootUp/branch/develop/graph/badge.svg?token=ELA7U7IAWD)](https://codecov.io/gh/soot-oss/SootUp) [![javadoc](https://javadoc.io/badge2/org.soot-oss/sootup.core/javadoc.svg)](https://javadoc.io/doc/org.soot-oss/sootup.core) This is the home of the **SootUp** project. A complete overhaul of the good, old static analysis framework [Soot](https://github.com/soot-oss/soot). ## What is SootUp - Transforms JVM bytecode (and other inputs!) to the intermediate representation Jimple. -- ClassHierarchy generation +- Provides ClassHierarchy generation - CallGraph generation with different algorithms/precisions -- Inter-procedural Data-flow Analysis with the IDE/IFDS framework enabled by [Heros](https://github.com/Sable/heros)) -- Applys/Enables simple transformations on retrieving a methods Body (see BodyInterceptor) +- Inter-procedural Data-flow Analysis with the IDE/IFDS framework enabled by [Heros](https://github.com/Sable/heros) +- Applies/Enables simple transformations on retrieving a methods Body (see BodyInterceptor) - Provides serialization of the Jimple IR. ## Getting started [Documentation](https://soot-oss.github.io/SootUp/) and usage examples are available on Github pages. Check the [Javadocs](https://soot-oss.github.io/SootUp/apidocs). +Do you have questions? Feel free to start a [Discussion](https://github.com/soot-oss/SootUp/discussions). + ## SootUp improvements #### (compared to its predecessor [Soot](https://github.com/soot-oss/soot).) @@ -22,7 +28,7 @@ Check the [Javadocs](https://soot-oss.github.io/SootUp/apidocs). - [x] Enables lazyloading of classes (no interleaved loading of used/dependend classes anymore) - [x] Fail early strategy - input validation while constructing/building objects - [x] Up-to-Date (i.e. Java8!) Sourcecode Frontend -- [x] Full Java 17 Support for Bytecode +- [x] Full Java 21 Support for Bytecode - [x] Multiple Views (Scenes) - [ ] Full-Diff Support for Classes (across different View instances) - [x] Immutable Jimple IR Objects and Graphs @@ -41,7 +47,7 @@ You want to collaborate? Please read our [coding guidelines and the contributors ## Supporters -The development of SootUp is financed by generous support from the German Research Foundation (DFG), +The development of SootUp is financed by generous support from the German Research Foundation (DFG) and the Heinz Nixdorf Institute (HNI). diff --git a/docs/SootUpLogo.svg b/docs/SootUpLogo.svg new file mode 100644 index 00000000000..daa00567f46 --- /dev/null +++ b/docs/SootUpLogo.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/announce.md b/docs/announce.md index e3f41ae7ed4..76ecf8b2fe8 100644 --- a/docs/announce.md +++ b/docs/announce.md @@ -1,3 +1,5 @@ +## Release Announcement + We would like to announce [Soot](https://github.com/soot-oss/soot)’s successor, SootUp. Over more than 20 years, Soot has become one of the world’s most popular academic tool for Java and Android analysis and instrumentation. We thank all of you who have used and contributed to it over the years! It was your feedback and your contributions that helped it grow into such a versatile tool! diff --git a/docs/call-graph-construction.md b/docs/call-graph-construction.md index 12ac867bded..60bc3d93b40 100644 --- a/docs/call-graph-construction.md +++ b/docs/call-graph-construction.md @@ -4,7 +4,7 @@ A call graph shows the method calling relationship of a program. It is a directe SootUp contains several call graph construction algorithms. Below, we show how you can use each of these. ## Creating the Type Hierarchy -All the call graph construction algorithms require a type hierarchy for resolving method calls based of sub typing relationship. +All the call graph construction algorithms require the view to access the type hierarchy for resolving method calls based of sub typing relationship. Below, we show how to create a type hierarchy: === "SootUp" @@ -24,9 +24,7 @@ Below, we show how to create a type hierarchy: System.getProperty("java.home") + "/lib/rt.jar")) .build(); - JavaView view = project.createFullView(); - - ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); + JavaView view = project.createView(); ``` === "Soot" @@ -84,12 +82,12 @@ You can construct a call graph with CHA as follows: ```java CallGraphAlgorithm cha = - new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); + new ClassHierarchyAnalysisAlgorithm(view); CallGraph cg = cha.initialize(Collections.singletonList(entryMethodSignature)); - cg.callsFrom(entryMethodSignature).forEach(System.out::println); + System.out.println(cg); ``` === "Soot" @@ -113,12 +111,12 @@ You can construct a call graph with RTA as follows: ```java CallGraphAlgorithm rta = - new RapidTypeAnalysisAlgorithm(view, typeHierarchy); + new RapidTypeAnalysisAlgorithm(view); CallGraph cg = rta.initialize(Collections.singletonList(entryMethodSignature)); - cg.callsFrom(entryMethodSignature).forEach(System.out::println); + System.out.println(cg); ``` === "Soot" diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 00000000000..f9c75c88b54 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,54 @@ +# Frequently Asked Questions + +### How to setup the soot dependency (in Maven, Gradle)? +See [Installation](installation.md). + +### How to retreive a SootClass or SootMethod? +See [Getting Started](getting-started.md). + +### Is there a github template to quickstart into development with SootUp? +Not yet. + +### Error while using the Sourcecodefrontend +Please make sure to use Java8 to execute. + +### Exception: Provider "jrt" not found +```shell +java.lang.ExceptionInInitializerError + at sootup.java.bytecode.inputlocation.JrtFileSystemAnalysisInputLocationTest.getClassSource(JrtFileSystemAnalysisInputLocationTest.java:28) + ... +Caused by: java.nio.file.ProviderNotFoundException: Provider "jrt" not found +``` +To execute SootUp with JavaModules support please make sure you run the code at least the Java9 Runtime. + + +### How to solve a ConcurrentModificationException? +Copy the Iterator into an intermediate Collection. +```java +final StmtGraph stmtGraph = builder.getStmtGraph(); + for (Stmt stmt : Lists.newArrayList(stmtGraph)){ + ... + } +} +``` + +### How can I visualize a StmtGraph? +There exists a tool, that converts a StmtGraph to the Graphviz Dot Language. +```java +DotExporter.buildGraph( stmtgraph ); +``` +or create a convenient link with the exported stmtgraph as HTTP GET Parameter +```java +DotExporter.createUrlToWebeditor( stmtgraph ); +``` + + +### Is there a way to use code exploration and syntax highlighting features in my IDE for .jimple files? +Try [JimpeLsp](https://github.com/swissiety/JimpleLsp). + +### Is there a way to use syntax highlighting of .jimple in my paper, thesis, ...? +Have a look at [LspLexer4Pygments](https://github.com/swissiety/LspLexer4Pygments). + +### How to ... add an entry in this list? i.e. Your question is not answered here? +Feel free to start a [Discussion](https://github.com/soot-oss/SootUp/discussions). + \ No newline at end of file diff --git a/docs/getting-started.md b/docs/getting-started.md index 4aa93b73965..d913d88bd55 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,8 +1,7 @@ -# Getting Started - +# General Usage of SootUp This page walks you through the core data structures, as well as shows how to get started with SootUp. -## Core Data Structures +## The core datastructures Before you get started with the SootUp library, it helps to learn about the following core data structures: - `Project`: defines the outlines of an analysis. SootUp users should first create a `Project` instance. It is the starting point for all operations. @@ -41,10 +40,8 @@ You can use bytecode analysis typically when you do not have access to the sourc !!! example "Create a project to analyze Java bytecode" ~~~java - Path pathToBinary = Paths.get("src/test/resources/BasicSetup/binary"); - AnalysisInputLocation inputLocation = - PathBasedAnalysisInputLocation.createForClassContainer(pathToBinary); + new JavaClassPathAnalysisInputLocation("path2Binary"); JavaLanguage language = new JavaLanguage(8); @@ -54,13 +51,15 @@ You can use bytecode analysis typically when you do not have access to the sourc If you have access to the source code, it is also possible to create a project for analyzing source code. Following example shows how to create project for analyzing Java source code. +!!! info "Experimental" + + The source code frontend is experimental and should only be used for testing purposes. You should compile the code for analysis first and use the bytecode frontend instead. + !!! example "Create a project to analyze Java source code" ~~~java - Path pathToSource = Paths.get("src/test/resources/BasicSetup/source"); - AnalysisInputLocation inputLocation = - new JavaSourcePathAnalysisInputLocation(pathToSource.toString()); + new JavaSourcePathAnalysisInputLocation("path2Source"); JavaLanguage language = new JavaLanguage(8); @@ -73,7 +72,7 @@ If you have a [Jimple](../jimple) file, you can create a project for analyzing j !!! example "Create a project to analyze jimple code" ~~~java - Path pathToJimple = Paths.get("src/test/resources/BasicSetup/jimple"); + Path pathToJimple = Paths.get("path2Jimple"); AnalysisInputLocation inputLocation = new JimpleAnalysisInputLocation(pathToJimple); @@ -89,13 +88,20 @@ If you have a [Jimple](../jimple) file, you can create a project for analyzing j ## Creating a View -It is possible to create different views based on your needs. You can prefer creating a full view, when you are interested in the whole program including all the application code, and the library code; or you can create an on-demand view, when you want to limit your analysis' scope. -You can call different view creation methods on the `project` object. + +To create an analysis view, you can call the `createView()` method on the `project` object: ```java -project.createFullView(); +JavaView view = project.createView(); ``` +By default, whenever a class is retrieved, it will be permanently stored in a cache. +If you do not want retrieved classes to be stored indefinetly, you can instead provide a different `CacheProvider` to the created view. +To for example use an `LRUCache` instead, which stores at most 50 classes, and always replaces the least recently used class by a newly retrieved one, use the following call: + +```java +JavaView view = project.createView(new LRUCacheProvider(50)); +``` ## Retrieving a Class @@ -114,10 +120,13 @@ Let's say the following is the target program that we want to analyze: } - public static void main(String[] var0) { - - System.out.println("Hello World!"); - + public static void main(String[] args) { + HelloWorld hw = new HelloWorld(); + hw.hello(); + } + + public void hello() { + } } @@ -182,7 +191,7 @@ Alternatively, we can also retrieve a `SootMethod` from `SootClass` that contain ## Retrieving the Control-Flow Graph of a Method -Each `SootMethod` contains a Control-Flow Graph (CFG), or as we name here a `StmtGraph`, that is usually used for program analysis. You can retrieve the CFG of a `SootMethod` as follows: +Each `SootMethod` contains a Control-Flow Graph (CFG) which is represented via the `StmtGraph`. This structure is usually used for program analysis. You can retrieve the CFG of a `SootMethod` as follows: !!! example "Retrieving the CFG of a SootMethod" @@ -191,9 +200,8 @@ Each `SootMethod` contains a Control-Flow Graph (CFG), or as we name here a `Stm ``` -You can view all the code used until this point below: -!!! info "All the code used above" +!!! info "Access or Download all of the code used above" [BasicSetup.java](https://github.com/secure-software-engineering/soot-reloaded/blob/develop/sootup.examples/src/test/java/sootup/examples/basicSetup/BasicSetup.java) @@ -204,9 +212,8 @@ Below we show a comparison of the code so far with the same functionality in soo === "SootUp" ``` java - Path pathToBinary = Paths.get("src/test/resources/BasicSetup/binary"); AnalysisInputLocation inputLocation = - PathBasedAnalysisInputLocation.createForClassContainer(pathToBinary); + new JavaClassPathAnalysisInputLocation("path2Binary"); JavaLanguage language = new JavaLanguage(8); @@ -224,7 +231,7 @@ Below we show a comparison of the code so far with the same functionality in soo "main", classType, "void", Collections.singletonList("java.lang.String[]")); - View view = project.createOnDemandView(); + View view = project.createView(); SootClass sootClass = (SootClass) view.getClass(classType).get(); @@ -298,7 +305,7 @@ Below we show a comparison of the code so far with the same functionality in soo ## Creating Different Views 1. Create a full view of all classes found in given analysis input location. ~~~java - project.createFullView(); + project.createView(); ~~~ 2. Create a on-demand view. An on-demand view does not load all classes into the view, but only classes that are specified and their transitive closure. diff --git a/docs/icon.svg b/docs/icon.svg new file mode 100644 index 00000000000..8a7d4883382 --- /dev/null +++ b/docs/icon.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/img/favicon.ico b/docs/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d82a2835422ebdd54c68e62664debb64bbab27c9 GIT binary patch literal 228414 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 Ee?RBzdH?_b literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md index 1b1be97d443..d78d260eda0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,101 +1,37 @@ -# What is SootUp? - -The purpose of the SootUp project is to make [Soot](https://github.com/soot-oss/soot) future-proof. The focus of this project lies on restructuring Soot away from a framework that makes heavy use of singletons, towards a lighter library that can easily be included in other projects. - -# [Click here to read our announcement on the first release of SootUp](announce.md) +# What's SootUp? +SootUp is a complete overhaul of the good, old static analysis framework [Soot](https://github.com/soot-oss/soot). +- Transforms JVM bytecode (and other inputs!) to the intermediate representation Jimple. +- Provides ClassHierarchy generation +- CallGraph generation with different algorithms/precisions +- Inter-procedural Data-flow Analysis with the IDE/IFDS framework enabled by [Heros](https://github.com/Sable/heros) +- Applies/Enables simple transformations on retrieving a methods Body (see BodyInterceptor) +- Provides serialization of the Jimple IR. !!! important SootUp is *not a version update* to Soot, it is instead a *completely new implementation* written from scratch that aims to be a leaner, more extensible equivalent of soot. -## What is new? - -Over the years, Soot has evolved into a powerful framework, which is one of the most widely used tools in the static analysis community. This evolution was guided by the needs of the community and carried out with ad-hoc improvements. As a result, Soot has become a tool that can do many things, but it is heavy and hard to maintain. Below are the features of SootUp, which aims to address Soot's shortcomings. - -### Library by default - -Soot can do many things. It is a library and a stand-alone command-line application. SootUp, on the other hand, is designed to be a core library. It assumes that it is embedded in a client application that owns the thread of control. It can be extended with a command-line interface, included in other software projects as a library, or integrated into IDEs with [JimpleLSP](https://github.com/swissiety/Jimplelsp). - -### Modular Architecture - -SootUp has a modular architecture, which enables its clients to include only the necessary functionality to their applications. Below are its modules: - -??? info "core" - - [core module](https://github.com/soot-oss/SootUp/tree/develop/sootup.core) contains the core building blocks such as the jimple IR, control flow graphs, and frontend interfaces. The rest of the modules build on the core module. - -??? info "java.core" - - [java.core module](https://github.com/soot-oss/SootUp/tree/develop/sootup.java.core) contains parts that are essential for analyzing Java code. - -??? info "java.bytecode" - - [java.bytecode module](https://github.com/soot-oss/SootUp/tree/develop/sootup.java.bytecode) contains the functionality that is necessary for taking as input java bytecode. - -??? info "java.sourcecode" - - [java.sourcecode module](https://github.com/soot-oss/SootUp/tree/develop/sootup.java.sourcecode) contains the functionality that is necessary for taking as input java source code. - -??? info "callgraph" - - [callgraph module](https://github.com/soot-oss/SootUp/tree/develop/sootup.callgraph) contains implementations of common call graph construction algorithms such as **CHA**, **RTA**. A reimplementation of **Spark** pointer analysis framework is in progress. - -??? info "jimple.parser" - - [jimple.parser module](https://github.com/soot-oss/SootUp/tree/develop/sootup.jimple.parser) contains the functionalty that is necessary for taking as input .jimple files. - -??? info "analysis" - - [analysis module](https://github.com/soot-oss/SootUp/tree/develop/sootup.analysis) enables performing interprocedural dataflow analyses. +## Why SootUp? +#### [Click here to read our announcement on the first release of SootUp](announce.md) -### No More Singletons - -Singletons offer a single view of a single program version, which makes it impossible to analyze multiple programs or multiple versions of the same program. SootUp does not make use of singletons such the `Scene` class in the old Soot any more. It enables analyzing multple programs simultaneously. - -### New Source Code Frontend - -Soot's JastAdd-based java frontend is not maintained anymore. In SootUp, we use WALA's well-maintained source code frontend, which will not only allow Soot to analyze Java source code, but also JavaScript and Python. - -### Immutable by Design - -SootUp has been designed with the goal of immutability in mind. This makes sharing objects between several entities easier, because there is no need to worry about unintended changes to other entities. - -#### Withers instead of Setters - -Due to the immutability goal, many classes do not have setters anymore. For example, a `Body` does not have a method `setStmts(List stmts)`. Instead, a method called `withStmts(List stmts)` has been added. This does not modify the original instance, but returns a copy that has different `stmts` than the original instance. This concept of so-called `with`-ers can be found all throughout SootUp. - -!!! example "A simplified example" - - ```java - class Body { - final List stmts; - final List locals; - - Body(List stmts, List locals) { - this.stmts = stmts; - this.locals = locals; - } - - Body withStmts(List stmts) { return new Body(stmts, this.locals); } - Body withLocals(List locals) { return new Body(this.stmts, locals); } - } - ``` - - - -### Intermediate Representation - -Jimple is the only intermediate representation (IR) in SootUp. We changed it slightly to be able to accommodate different programming languages in future. +Over the 20+ years, SootUps predecessor Soot has evolved into a powerful framework, which is one of the most widely used tools in the static analysis community. +This evolution was guided by the needs of the community and carried out with ad-hoc improvements. +As a result, Soot has become a tool that can do a multitude of things, but it is heavy and hard to maintain and comprehend. +So there was the need to clean up the codebase e.g. improve the software architecture, +remove legacy datastructures that weren't in the Java Runtime at the time of Soots creation, +enforce validation to have a sane state, +removing the necessity of arcane knowledge, document it more and more - to make Soot future prove. +So we introduced [Design changes in SootUp](whatsnew.md), which aim to address Soot's shortcomings. +The goal is a lighter library that can easily be understood and maintained to be included in other projects. ### Is this a drop-in replacement for Soot? - Not really. SootUp has a completely new architecture and API, so it is not trivial to update existing projects that build on soot. We recommend using it for greenfield projects. ## Supporters -The development of SootUp is financed by generous support from the German Research Foundation (DFG), +The development of SootUp is financed by generous support from the German Research Foundation (DFG) and the Heinz Nixdorf Institute (HNI).
diff --git a/docs/installation.md b/docs/installation.md index 1a4f7d3cbe4..f561370c6ec 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,4 +1,67 @@ # Installation +## Using the release +SootUp is available in maven central, you can include it in your project as follows. + +Below we only show how you can add the SootUp modules to your project. It is not necessary to add all the modules as dependency. +Depending on your needs you can import only the modules you need. +Take a look at the [Modules](whatsnew.md#modular-architecture) to learn more about which modules you might need. + +### Maven + + Add the following dependency in the ```pom.xml``` file of your project to include all SootUp modules into your project. + +``` + + + org.soot-oss + sootup.core + 1.0.0 + + + org.soot-oss + sootup.java.core + 1.0.0 + + + org.soot-oss + sootup.java.sourcecode + 1.0.0 + + + org.soot-oss + sootup.java.bytecode + 1.0.0 + + + org.soot-oss + sootup.jimple.parser + 1.0.0 + + + org.soot-oss + sootup.callgraph + 1.0.0 + + + org.soot-oss + sootup.analysis + 1.0.0 + + +``` +### Gradle + +Add the following dependency in the ```build.gradle``` file of your project to include all SootUp modules into your project. + +``` +compile "org.soot-oss:sootup.core:1.0.0" +compile "org.soot-oss:sootup.java.core:1.0.0" +compile "org.soot-oss:sootup.java.sourcecode:1.0.0" +compile "org.soot-oss:sootup.java.bytecode:1.0.0" +compile "org.soot-oss:sootup.jimple.parser:1.0.0" +compile "org.soot-oss:sootup.callgraph:1.0.0" +compile "org.soot-oss:sootup.analysis:1.0.0" +``` ## Building from Source Build from source if you'd like to get the most recent changes. @@ -22,29 +85,3 @@ Or if you want to skip unit tests while building: mvn -Dskiptests install ``` -## Using the release -Alternatively you can directly get the release versions. -SootUp is available in maven central, you can include it in your project as follows. - -Below we only show how you can add the ```sootup.core``` module to your project. Depending on your needs you can import other modules too. See [Modules](../#modular-architecture) to learn more about the modules. - -1. Maven: - - Add the following dependency in the ```pom.xml``` file of your project. - -``` - - org.soot-oss - sootup.core - 1.0.0 - -``` - -2. Gradle - -Add the following dependency in the ```build.gradle``` file of your project. - -``` -compile "org.soot-oss:sootup.core:1.0.0" -``` - diff --git a/docs/jimple.md b/docs/jimple.md index 55d1780dac5..f0b0df75972 100644 --- a/docs/jimple.md +++ b/docs/jimple.md @@ -1029,8 +1029,8 @@ They end the execution/flow inside the current method and return (a value) to it virtualinvoke $stack1.("Inside method print"); return; - } - } + } + } /* "return $stack2" is JReturnStmt. "return" is JReturnVoidStmt. @@ -2297,7 +2297,6 @@ Values can be assigned to Locals via JIdentityStmt or JAssignStmt. === "Jimple" ```jimple - public class target.exercise1.DemoClass extends java.lang.Object { public void () diff --git a/docs/tools.md b/docs/tools.md index e69de29bb2d..dc5e297e375 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -0,0 +1,4 @@ +# Who uses SootUp +- [JimpleLsp](https://github.com/swissiety/JimpleLsp) +- Maybe there is more to find via [Github Network Dependents](https://github.com/soot-oss/SootUp/network/dependents) - have a look at the individual modules. +- Your tool is not on this list? Create a PR :-) \ No newline at end of file diff --git a/docs/whatsnew.md b/docs/whatsnew.md new file mode 100644 index 00000000000..f81711acdf2 --- /dev/null +++ b/docs/whatsnew.md @@ -0,0 +1,66 @@ +# What's new in SootUp? + +### Library by default + +While Soot is a library and a stand-alone command-line application. SootUp, on the other hand, is designed to be a core library. +It assumes that it is embedded in a client application that owns the thread of control. +It can be extended with a command-line interface, included in other software projects as a library, or integrated into IDEs with [JimpleLSP](https://github.com/swissiety/Jimplelsp). + +### Modular Architecture + +SootUp has a modular architecture, which enables its clients to include only the necessary functionality to their applications. + +- [core module](https://github.com/soot-oss/SootUp/tree/develop/sootup.core) contains the core building blocks such as the jimple IR, control flow graphs, and frontend interfaces. The rest of the modules build on the core module. +- [java.core module](https://github.com/soot-oss/SootUp/tree/develop/sootup.java.core) contains parts that are essential for analyzing Java code. +- [java.bytecode module](https://github.com/soot-oss/SootUp/tree/develop/sootup.java.bytecode) contains the functionality that is necessary for taking as input java bytecode. +- [java.sourcecode module](https://github.com/soot-oss/SootUp/tree/develop/sootup.java.sourcecode) contains the functionality that is necessary for taking as input java source code. +- [callgraph module](https://github.com/soot-oss/SootUp/tree/develop/sootup.callgraph) contains implementations of common call graph construction algorithms such as **CHA**, **RTA**. A reimplementation of **Spark** pointer analysis framework is in progress. +- [jimple.parser module](https://github.com/soot-oss/SootUp/tree/develop/sootup.jimple.parser) contains the functionalty that is necessary for taking as input .jimple files. +- [analysis module](https://github.com/soot-oss/SootUp/tree/develop/sootup.analysis) enables performing interprocedural dataflow analyses. + +### No More Singletons + +Singletons offer a single view of a single program version, which makes it impossible to analyze multiple programs or multiple versions of the same program. +SootUp does not make use of singletons such the `Scene` class in the old Soot any more. It enables analyzing multple programs simultaneously. + +### New Source Code Frontend + +Soot's JastAdd-based java frontend is not maintained anymore. +In SootUp, we use WALA's well-maintained source code frontend, which will not only allow Soot to analyze Java source code, but also JavaScript and Python. + +### Immutable by Design + +SootUp has been designed with the goal of immutability in mind. +This makes sharing objects between several entities easier, because there is no need to worry about unintended changes to other entities. + +#### Withers instead of Setters + +Due to the goal of immutability, many classes do not have setters anymore. +For example, a `Body` does not have a method `setStmts(List stmts)`. +Instead, a method called `withStmts(List stmts)` has been added. +This does not modify the original instance, but returns a copy of the Body but with the provided `stmts` in its instance. +This concept of so-called `with`-ers can be found all throughout SootUp. + +!!! example "A simplified example" + + ```java + class Body { + final List stmts; + final List locals; + + Body(List stmts, List locals) { + this.stmts = stmts; + this.locals = locals; + } + + Body withStmts(List stmts) { return new Body(stmts, this.locals); } + Body withLocals(List locals) { return new Body(this.stmts, locals); } + } + ``` + + + +### Intermediate Representation + +[Jimple](jimple.md) is the only intermediate representation (IR) in SootUp. We modified it slightly to be able to accommodate different programming languages in the future. + diff --git a/mkdocs.yml b/mkdocs.yml index 3f317e57923..0d6610bfb85 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,19 +5,28 @@ edit_uri: edit/develop/docs/ nav: - Home: index.md - - Installation: installation.md - - Getting started: getting-started.md - - Call Graph Construction: call-graph-construction.md - - Jimple: jimple.md - - Advanced Topics: advanced-topics.md - - Javadocs: /SootUp/apidocs + - How to Start: + - Installation: installation.md + - Getting started: getting-started.md + - General information: + - Design Decisions: whatsnew.md + - Jimple: jimple.md + - Call Graph Construction: call-graph-construction.md + - Advanced Topics: advanced-topics.md + - More information: + - Javadoc: /SootUp/apidocs + - FAQ: faq.md +# - Used by: tools.md # - Analyses: analyses.md -# - About: about.md - theme: + palette: + primary: white name: material - + logo: ./SootUpLogo.svg + favicon: ./icon.svg + features: + - navigation.sections plugins: - tooltips diff --git a/pom.xml b/pom.xml index ebb4b6f33f0..ed7b5e473ac 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ pom org.soot-oss sootup - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT SootUp A new version of Soot with a completely overhauled architecture https://soot-oss.github.io/SootUp @@ -70,7 +70,6 @@ sootup.analysis sootup.examples sootup.report - sootup.qilin @@ -82,19 +81,19 @@ UTF-8 2.22.2 0.8.4 - 0.1.3 - verify - 1.7.25 - 1.7.25 - 25.1-jre - 3.5 - 2.7 - 4.13.1 + 2.0.5 + 2.0.5 + 32.0.1-jre + 3.12.0 + 2.11.0 + 4.13.2 1.7.3 1.7.3 1.6.7 3.2.1 3.1.1 + 2.8.2 + 1.5 true true ${basedir}/target @@ -138,9 +137,6 @@ !false - - none - deploy @@ -152,21 +148,10 @@ - - org.sonatype.plugins - nexus-staging-maven-plugin - ${nexus-staging-maven-plugin.version} - true - - ossrh - https://s01.oss.sonatype.org/ - false - - org.apache.maven.plugins maven-gpg-plugin - 1.5 + ${maven-gpg-plugin.version} sign-artifacts @@ -202,12 +187,6 @@ - - author - true - false - false - @@ -217,59 +196,6 @@ - - org.codehaus.mojo - exec-maven-plugin - 3.0.0 - false - - - install-dex2jar - validate - - exec - - - - - mvn - - install:install-file - -Dfile=sootup.java.bytecode/lib/dex-tools-2.2-SNAPSHOT.jar - -DgroupId=com.googlecode.d2j - -DartifactId=dex-tools - -Dversion=2.2-SNAPSHOT - -Dpackaging=jar - - - - - org.apache.maven.plugins - maven-shade-plugin - 2.3 - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - - - - package - - shade - - - - com.coveo fmt-maven-plugin @@ -364,6 +290,7 @@ -Xmx4096M ${surefireArgLine} ${testcase.groups} + false @@ -458,12 +385,15 @@ - ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots + https://oss.sonatype.org/content/repositories/snapshots + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + diff --git a/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/A.java b/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/A.java new file mode 100644 index 00000000000..99a940acd02 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/A.java @@ -0,0 +1,5 @@ +public class A { + public B method(){ + return new B(); + } +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/AugEvalFunctionDemos.java b/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/AugEvalFunctionDemos.java new file mode 100644 index 00000000000..a01acd4ffc1 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/AugEvalFunctionDemos.java @@ -0,0 +1,97 @@ +import java.util.*; + +public class AugEvalFunctionDemos { + + A field = new A(); + static int count = 0; + static final String constant =" new A()"; + + /*test constants*/ + public void constant(){ + int i = 127; + i = 32111; + i = -129; + double d = 1.0; + String s = "example"; + } + + /*test class constant*/ + public void reflection(){ + Class a = A.class; + } + + /*test condition expression*/ + public void condition(){ + int a = 1; + int b = 1; + boolean c = a < b; + } + + /*test shift expression*/ + public void shift() { + int a = 1; + long b = 1; + long c = b << a; + int d = a << b; + } + + /*test logical expression*/ + public void xor(){ + int a = 1; + int b = 1; + int c = b^a; + long d = 1L; + long e = b^d; + } + + /*test int float binary expression*/ + public void add(){ + int a = 1; + float b = 1; + float c = b + a; + a++; + } + + /*test unitary expression - length*/ + public void length(){ + int[] arr = new int[10]; + int b = arr.length; + } + + /*test instanceof expression*/ + public boolean instanceOf(){ + A a = new A(); + return a instanceof A; + } + + public void newArrayExpr(){ + A[][] arr = new A[3][3]; + A[] a = arr[1]; + } + + public void invokeExpr(){ + A a = new A(); + a.method(); + } + + public void caughtException1(){ + try{ + int c = 1/0; + } catch (ArithmeticException e) { + e.printStackTrace(); + } + } + + public void caughtException2(){ + try { + int a = 1; + }catch(IndexOutOfBoundsException| NumberFormatException e) { + e.printStackTrace(); + } + } + + public void fieldRef(){ + A newField = this.field; + count ++ ; + } +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/B.java b/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/B.java new file mode 100644 index 00000000000..1cdc569c304 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/AugEvalFunctionTest/B.java @@ -0,0 +1,3 @@ +public class B { + +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class1.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class1.java new file mode 100644 index 00000000000..dafbdd95704 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class1.java @@ -0,0 +1,10 @@ +public class Class1 implements RootInterface1, SubInterface1{ + @Override + public void method1(){ + + } + @Override + public void method2(){ + + } +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class2.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class2.java new file mode 100644 index 00000000000..282fe842d09 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class2.java @@ -0,0 +1,17 @@ +public class Class2 extends Class1 implements RootInterface2{ + + @Override + public void method1(){ + + } + + @Override + public void method2(){ + + } + + @Override + public void method3(){ + + } +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class3.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class3.java new file mode 100644 index 00000000000..b8e8c4d4f98 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class3.java @@ -0,0 +1,16 @@ +public class Class3 extends Class2{ + + @Override + public void method1(){ + } + + @Override + public void method2(){ + } + + @Override + public void method3(){ + + } + +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class4.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class4.java new file mode 100644 index 00000000000..c312f214827 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Class4.java @@ -0,0 +1,20 @@ +import java.io.Serializable; + +public class Class4 extends Class2 implements Serializable, Cloneable{ + + @Override + public void method1(){ + + } + + @Override + public void method2(){ + + } + + @Override + public void method3(){ + + } + +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface1.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface1.java new file mode 100644 index 00000000000..6f1a82b133a --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface1.java @@ -0,0 +1,3 @@ +public interface RootInterface1 { + public void method1(); +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface2.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface2.java new file mode 100644 index 00000000000..f63bb7655ed --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/RootInterface2.java @@ -0,0 +1,3 @@ +public interface RootInterface2 { + public void method3(); +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Runner.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Runner.java new file mode 100644 index 00000000000..ca7d9a41602 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/Runner.java @@ -0,0 +1,11 @@ +public class Runner { + public static void main(String[] args){ + RootInterface1 if1 = new Class1(); + SubInterface1 if2 = new Class2(); + RootInterface2 if3 = new Class3(); + + if1.method1(); + if2.method2(); + if3.method3(); + } +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/SubInterface1.java b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/SubInterface1.java new file mode 100644 index 00000000000..4356158ed64 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/ByteCodeHierarchyTest/src/SubInterface1.java @@ -0,0 +1,3 @@ +public interface SubInterface1 extends RootInterface1{ + public void method2(); +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/CastCounterTest/CastCounterDemos.java b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/CastCounterDemos.java new file mode 100644 index 00000000000..a133cc6f40b --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/CastCounterDemos.java @@ -0,0 +1,15 @@ +public class CastCounterDemos { + + public void invokeStmt(){ + Super1 s1 = new Sub1(); + int i = 1; + Sub2 s2 = new Sub2(); + s1.m(i, s2); + } + + public void assignStmt(){ + Super1[] arr = new Super1[10]; + arr[0] = new Sub1(); + Super1 var = arr[2]; + } +} diff --git a/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub1.java b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub1.java new file mode 100644 index 00000000000..2d6fbdba369 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub1.java @@ -0,0 +1,2 @@ +public class Sub1 extends Super1 { +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub2.java b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub2.java new file mode 100644 index 00000000000..356b618a455 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Sub2.java @@ -0,0 +1,2 @@ +public class Sub2 extends Super2 { +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super1.java b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super1.java new file mode 100644 index 00000000000..e34d2aa1ec5 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super1.java @@ -0,0 +1,6 @@ +public class Super1 { + + public void m(int num, Sub2 sub2){ + + } +} \ No newline at end of file diff --git a/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super2.java b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super2.java new file mode 100644 index 00000000000..56e342447e1 --- /dev/null +++ b/shared-test-resources/TypeResolverTestSuite/CastCounterTest/Super2.java @@ -0,0 +1,3 @@ +public class Super2 { + +} \ No newline at end of file diff --git a/shared-test-resources/java-miniapps/MiniApp.jar b/shared-test-resources/java-miniapps/MiniApp.jar index bb7ebf378d97a9b8379ef5939d265c49e513ea0c..64f7fb6d76194ce5a8391ea934a2d2577262902d 100644 GIT binary patch delta 328 zcmcbk*rKu_n6I9hMTCKagM%R_Tqv9Y32*}0S*3Z|$vKI|#k_|cxf%=vm=COfl6`vC zt%QvUMW4P}`7GI7- diff --git a/shared-test-resources/java-miniapps/src/junkclass b/shared-test-resources/java-miniapps/src/junkclass new file mode 100644 index 00000000000..e3bc908497b --- /dev/null +++ b/shared-test-resources/java-miniapps/src/junkclass @@ -0,0 +1 @@ +this is a test file to check if it recognized as class \ No newline at end of file diff --git a/shared-test-resources/jigsaw-examples/requires_exports/jar/modb.jar b/shared-test-resources/jigsaw-examples/requires_exports/jar/modb.jar index 3079df5844ceca92eea3e410699dae387217ecba..154aa390259fc423b67199306763c83d9b9c5536 100644 GIT binary patch delta 322 zcmdnQahr3(Q7$e91`Y;>mPn!S&8rx_8S9x@L>M?YI2dxmg~Az-03VQDke!~SpH-Td zot%?cT+DmOk*mQ#fce1sC)uZG-AdS)Q1t1mmCv%Cdc_ihEgd;uQsOT(G_~(NAFaKl$`~lwV9BSLQi5miqG6UiOZ03m)*9{>OV delta 145 zcmcc3xrt-K(TOZ#ljk!X=3!>xVqoB4VAva3;=l2{H{;|a=6ZDz1`!4h4i1KEDW(42 ztv-Tt7#J8X1F;|wBf!DQ3z$R%0=yZSxEK(IOn%EO#WaU;GAE0n+I~g`hJx($Bz-5n Yb%7 diff --git a/shared-test-resources/jigsaw-examples/requires_exports/src/modb/pkgb/junkclass b/shared-test-resources/jigsaw-examples/requires_exports/src/modb/pkgb/junkclass new file mode 100644 index 00000000000..e3bc908497b --- /dev/null +++ b/shared-test-resources/jigsaw-examples/requires_exports/src/modb/pkgb/junkclass @@ -0,0 +1 @@ +this is a test file to check if it recognized as class \ No newline at end of file diff --git a/shared-test-resources/miniTestSuite/java6/binary/InterfaceVisibleAnnotation.class b/shared-test-resources/miniTestSuite/java6/binary/InterfaceVisibleAnnotation.class new file mode 100644 index 0000000000000000000000000000000000000000..268061e8e0ca1594b45e286170569b50327c529a GIT binary patch literal 394 zcmah_%}N4M6#kBBx6Dd6K}8fUTs9971T7{I)MT21XmuSaV`YGk!Lf2^V|X_iF*dWm33cru*JA!dK$ ze&-+P&|8x&grJhQLE7!dgqw0os`D`iLAJ~9vE`}Qr;BeEP&NG+#vOogAW@UI0u`uD ZKEkooYnkhEJ7F|%inDe531Xb1xdPEha?$_* literal 0 HcmV?d00001 diff --git a/shared-test-resources/miniTestSuite/java6/binary/MyInnerAnnotation.class b/shared-test-resources/miniTestSuite/java6/binary/MyInnerAnnotation.class new file mode 100644 index 0000000000000000000000000000000000000000..0e731724e2874dba054ab1666d2bf62c631f2944 GIT binary patch literal 356 zcmah_%Sr=55Uh@gqtTe;;6Xg-Dd@%h073Ae5XdI7G2SPeCQKN6AUhk_U-OU;@T0_z z2NxvZp&xX0RW<$j^|1x;fSy5v&`+zO2(KSSLbTBZF=!HcE4#6Yx3Wwo^A+dO;E-@t zPwnr1Qd0@%1?NE)e>^=D`o(qYRA) z7ZVc?{YZCJb*BzrAD;l8&{n7r?&4ye2i}dG^FasWox%m7z14diS?%7U`DV*$P`D)Y z%BlXrMcR(5SOZ)KT1%~xDT zg9E~KdbNLimZXIC+WLkG=eKv01Q)S#vb-mBiqKRgkDOQLV#amkMUoGG6@;t2k?7v} z&DC!1In`^z%}&>yFXS9qH9>Sn{~zQzcvo%|H2Lf7Wjr1B0m7bITdza9yuqPnEgWrq P2ge#uwSJ;zSkto~*uh=5 literal 0 HcmV?d00001 diff --git a/shared-test-resources/miniTestSuite/java6/binary/NestedAnnotation.class b/shared-test-resources/miniTestSuite/java6/binary/NestedAnnotation.class new file mode 100644 index 0000000000000000000000000000000000000000..3dc91bd1c87f163fbc21756a49a864a02e2bac1c GIT binary patch literal 396 zcmZutO-lnY6rA*9SJ!H*bq_rV9@T^W0ZOR|f>2wq(tCC{NXj;WO}5aVhMhi^@0-d>B%6=}*Yk!i=Rq6$TTWz!-2-Ghw zXCd}jG*-^5?9LeLrPtO7H12Jt1ll8Q)VN$Es(6t}P9~b#vPji~t{(BO@wyr((0eY8 z*9$e%PSdq*>;$@_r`4qNs@SqO9Hfo;O>OEP|B|eWol33Ab_7mj*Xe%}JImDJ2Tc{>^yw#G4v#{4XnI;RpCpaz}P^Z=Kt@ z=bmoo{dv9sOyD}mz_O7oBZoYpb`m!+JPUmsuKkk?3?V;OTA2yK>h?Sv1w!3ZSLL7O zRO`?Pqe4x{&ceMUxJ#wwD!%wK+6g`(INLCe0y$R+X{4Nk)^eeZ uj1D45%OiAPbA+Ubn?o=bnYDi$$n_tf`%iWl6B%&XQsS9G8I}LG3VZ=(hCj9d literal 0 HcmV?d00001 diff --git a/shared-test-resources/miniTestSuite/java6/binary/VisibleClassAnnotation.class b/shared-test-resources/miniTestSuite/java6/binary/VisibleClassAnnotation.class new file mode 100644 index 0000000000000000000000000000000000000000..bfb84cede2eb99a3192caef6fc0bc0cdab95a92b GIT binary patch literal 388 zcmaiw%Sr<=6o&s(Tch<>K?D&|Ty*I?fFKl^g5af$Q$bv%!(m8C6KOJqzM2akz=x8a zia47A7rFl5mml)={qYIl28RkQ!tsjJSFb`KY7uPN7ZcP4z-2R=YBJnoPNf z3Y&!U`d0t(Nv#sP&%T-$JT#UGM|Cm|y5y_1PB_Ub7tM@+>uV?wF76vEGL9^cch`i@ zLfcAS@Bf32yfwvA1eJ{+^Sg(XaMrBkdR}rA^0GNkEzhJrU%s org.soot-oss sootup - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT @@ -18,7 +18,7 @@ org.soot-oss sootup.java.sourcecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT pom import @@ -29,23 +29,23 @@ org.soot-oss sootup.callgraph - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT de.upb.cs.swt heros - 1.2.3-SNAPSHOT + 1.2.3 org.soot-oss sootup.java.bytecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT test org.soot-oss sootup.java.sourcecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT test @@ -59,4 +59,4 @@ - \ No newline at end of file + diff --git a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/AbstractJimpleBasedICFG.java b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/AbstractJimpleBasedICFG.java index 05b77f30757..367917a71a7 100644 --- a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/AbstractJimpleBasedICFG.java +++ b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/AbstractJimpleBasedICFG.java @@ -216,7 +216,7 @@ public Set getCallsFromWithin(SootMethod m) { public void initializeStmtToOwner(SootMethod m) { if (m.hasBody()) { Body b = m.getBody(); - for (Stmt node : b.getStmtGraph().nodes()) { + for (Stmt node : b.getStmtGraph().getNodes()) { stmtToOwner.put(node, b); } } diff --git a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/CGEdgeUtil.java b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/CGEdgeUtil.java index 6e700f3554c..9b350ced31f 100644 --- a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/CGEdgeUtil.java +++ b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/CGEdgeUtil.java @@ -59,7 +59,7 @@ public static Set> getCallEdges( for (MethodSignature caller : methodSigs) { SootMethod method = view.getMethod(caller).orElse(null); if (method != null && method.hasBody()) { - for (Stmt s : method.getBody().getStmtGraph().nodes()) { + for (Stmt s : method.getBody().getStmtGraph().getNodes()) { if (s.containsInvokeExpr()) { CalleeMethodSignature callee = new CalleeMethodSignature( diff --git a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java new file mode 100644 index 00000000000..036b4dade8e --- /dev/null +++ b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java @@ -0,0 +1,128 @@ +package sootup.analysis.interprocedural.icfg; + +import java.util.*; +import java.util.stream.Collectors; +import sootup.core.graph.BasicBlock; +import sootup.core.graph.StmtGraph; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.MethodSubSignature; +import sootup.core.typehierarchy.MethodDispatchResolver; +import sootup.core.types.VoidType; +import sootup.core.util.DotExporter; +import sootup.core.views.View; + +public class ICFGDotExporter { + + public static String buildICFGGraph( + Map signatureToStmtGraph, View> view) { + final StringBuilder sb = new StringBuilder(); + DotExporter.buildDiGraphObject(sb); + Map calls; + calls = computeCalls(signatureToStmtGraph, view); + for (Map.Entry entry : signatureToStmtGraph.entrySet()) { + String graph = DotExporter.buildGraph(entry.getValue(), true, calls, entry.getKey()); + sb.append(graph + "\n"); + } + sb.append("}"); + return sb.toString(); + } + + /** + * This method finds out all the calls made in the given StmtGraphs, so it can be edged to other + * methods. + */ + public static Map computeCalls( + Map stmtGraphSet, View> view) { + Map calls = new HashMap<>(); + for (StmtGraph stmtGraph : stmtGraphSet.values()) { + Collection> blocks; + try { + blocks = stmtGraph.getBlocksSorted(); + } catch (Exception e) { + blocks = stmtGraph.getBlocks(); + } + for (BasicBlock block : blocks) { + List stmts = block.getStmts(); + for (Stmt stmt : stmts) { + if (stmt.containsInvokeExpr()) { + MethodSignature methodSignature = stmt.getInvokeExpr().getMethodSignature(); + int hashCode = stmt.hashCode(); + calls.put(hashCode, methodSignature); + // compute all the classes that are made to the subclasses as well + connectEdgesToSubClasses(methodSignature, view, calls); + } else if (stmt instanceof JAssignStmt) { + JAssignStmt jAssignStmt = (JAssignStmt) stmt; + Integer currentHashCode = stmt.hashCode(); + if (jAssignStmt.getRightOp() instanceof JNewExpr) { + // if the statement is a new expression, then there will be calls to its static + // initializers (init and clinit), so need to compute calls to them as well + for (MethodSignature methodSignature : stmtGraphSet.keySet()) { + SootMethod clintMethod = + view.getMethod(methodSignature.getDeclClassType().getStaticInitializer()) + .orElse(null); + if (clintMethod != null) { + if (!calls.containsKey(stmt.hashCode())) { + calls.put(stmt.hashCode(), methodSignature); + } else { + MethodSignature secondInitMethodSignature = calls.get(currentHashCode); + currentHashCode = + stmtGraphSet.get(secondInitMethodSignature).getStartingStmt().hashCode(); + calls.put(currentHashCode, methodSignature); + } + } + } + } + } + } + } + } + return calls; + } + + public static Set getMethodSignatureInSubClass( + MethodSignature targetMethodSignature, View> view) { + try { + return MethodDispatchResolver.resolveAllDispatches(view, targetMethodSignature).stream() + .map( + methodSignature -> + MethodDispatchResolver.resolveConcreteDispatch(view, methodSignature)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + } catch (Exception e) { + return null; + } + } + + public static void connectEdgesToSubClasses( + MethodSignature methodSignature, + View> view, + Map calls) { + Set methodSignatureInSubClass = + getMethodSignatureInSubClass(methodSignature, view); + if (methodSignatureInSubClass != null) { + methodSignatureInSubClass.forEach( + subclassmethodSignature -> { + Optional method = view.getMethod(methodSignature); + MethodSignature initMethod = + new MethodSignature( + subclassmethodSignature.getDeclClassType(), + new MethodSubSignature( + "", Collections.emptyList(), VoidType.getInstance())); + if (method.isPresent() + && !subclassmethodSignature.toString().equals(initMethod.toString())) { + if (method.get().hasBody()) { + calls.put( + method.get().getBody().getStmtGraph().getStartingStmt().hashCode(), + subclassmethodSignature); + } + } + }); + } + } +} diff --git a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java index f977c7ab5e5..1e9faa7cc42 100644 --- a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java +++ b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java @@ -39,11 +39,11 @@ import sootup.callgraph.CallGraph; import sootup.callgraph.CallGraphAlgorithm; import sootup.callgraph.ClassHierarchyAnalysisAlgorithm; +import sootup.core.graph.StmtGraph; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.ViewTypeHierarchy; import sootup.core.views.View; import sootup.java.core.views.JavaView; @@ -60,7 +60,7 @@ public class JimpleBasedInterproceduralCFG extends AbstractJimpleBasedICFG { protected static final Logger logger = LoggerFactory.getLogger(JimpleBasedInterproceduralCFG.class); - private MethodSignature mainMethodSignature; + private final MethodSignature mainMethodSignature; protected boolean includeReflectiveCalls; @@ -69,6 +69,7 @@ public class JimpleBasedInterproceduralCFG extends AbstractJimpleBasedICFG { protected CacheLoader> loaderUnitToCallees = new CacheLoader>() { + @Nonnull @Override public Collection load(Stmt stmt) { ArrayList res = new ArrayList<>(); @@ -94,8 +95,9 @@ public Collection load(Stmt stmt) { protected CacheLoader> loaderMethodToCallers = new CacheLoader>() { + @Nonnull @Override - public Collection load(SootMethod method) throws Exception { + public Collection load(SootMethod method) { ArrayList res = new ArrayList<>(); // only retain callers that are explicit call sites or // Thread.start() @@ -110,11 +112,6 @@ public Collection load(SootMethod method) throws Exception { return res; } - /** - * returns SootMethod if accepted, null otherwise - * - * @param methodSignature - */ @Nullable private Stmt filterEdgeAndGetCallerStmt(@Nonnull MethodSignature methodSignature) { Set> callEdges = @@ -152,9 +149,35 @@ public JimpleBasedInterproceduralCFG( initializeStmtToOwner(); } + public String buildICFGGraph(CallGraph callGraph) { + Map signatureToStmtGraph = new LinkedHashMap<>(); + computeAllCalls(mainMethodSignature, signatureToStmtGraph, callGraph); + return ICFGDotExporter.buildICFGGraph(signatureToStmtGraph, view); + } + + public void computeAllCalls( + MethodSignature methodSignature, + Map signatureToStmtGraph, + CallGraph callGraph) { + final Optional methodOpt = view.getMethod(methodSignature); + // return if the methodSignature is already added to the hashMap to avoid stackoverflow error. + if (signatureToStmtGraph.containsKey(methodSignature)) return; + if (methodOpt.isPresent()) { + SootMethod sootMethod = methodOpt.get(); + if (sootMethod.hasBody()) { + StmtGraph stmtGraph = sootMethod.getBody().getStmtGraph(); + signatureToStmtGraph.put(methodSignature, stmtGraph); + } + } + callGraph + .callsFrom(methodSignature) + .forEach( + nextMethodSignature -> + computeAllCalls(nextMethodSignature, signatureToStmtGraph, callGraph)); + } + private CallGraph initCallGraph() { - final ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); - CallGraphAlgorithm cga = new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); + CallGraphAlgorithm cga = new ClassHierarchyAnalysisAlgorithm(view); return cga.initialize(Collections.singletonList(mainMethodSignature)); } @@ -184,7 +207,7 @@ public static Set> getCallEdges( if (methodOpt.isPresent()) { final SootMethod method = methodOpt.get(); if (method.hasBody()) { - for (Stmt s : method.getBody().getStmtGraph().nodes()) { + for (Stmt s : method.getBody().getStmtGraph().getNodes()) { if (s.containsInvokeExpr()) { CalleeMethodSignature callee = new CalleeMethodSignature( diff --git a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java new file mode 100644 index 00000000000..2a009388e75 --- /dev/null +++ b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java @@ -0,0 +1,306 @@ +package sootup.analysis.interprocedural.icfg; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; + +import categories.Java8Test; +import java.util.*; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.analysis.interprocedural.ifds.IFDSTaintTestSetUp; +import sootup.callgraph.CallGraph; +import sootup.callgraph.ClassHierarchyAnalysisAlgorithm; +import sootup.core.graph.StmtGraph; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.JavaProject; +import sootup.java.core.language.JavaLanguage; +import sootup.java.core.types.JavaClassType; +import sootup.java.core.views.JavaView; + +@Category(Java8Test.class) +public class ICFGDotExporterTest extends IFDSTaintTestSetUp { + + public CallGraph loadCallGraph(JavaView view) { + CallGraph cg = + new ClassHierarchyAnalysisAlgorithm(view) + .initialize(Collections.singletonList(entryMethodSignature)); + assertNotNull(cg); + assertTrue( + entryMethodSignature + " is not found in CallGraph", + cg.containsMethod(entryMethodSignature)); + return cg; + } + + @Test + public void ICFGDotExportTest() { + JavaProject javaProject = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .addInputLocation( + new JavaClassPathAnalysisInputLocation("src/test/resources/icfg/binary")) + .build(); + + view = javaProject.createView(); + + JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); + JavaClassType mainClassSignature = identifierFactory.getClassType("ICFGExample"); + + SootClass sc = view.getClass(mainClassSignature).get(); + entryMethod = + sc.getMethods().stream().filter(e -> e.getName().equals("entryPoint")).findFirst().get(); + + entryMethodSignature = entryMethod.getSignature(); + + JimpleBasedInterproceduralCFG icfg = + new JimpleBasedInterproceduralCFG(view, entryMethodSignature, false, false); + CallGraph callGraph = loadCallGraph(view); + String expectedCallGraph = icfg.buildICFGGraph(callGraph); + Digraph digraph = parseDigraph(expectedCallGraph); + Assert.assertEquals(digraph.blocks.length, 5); + // As per the example code, the first block has no invoke calls, so the number of statements and + // edges should be same + Assert.assertEquals(digraph.blocks[0].statements.length, digraph.blocks[0].edges.size()); + // As per the example code, the second block has an invoke call, so the number of edges should + // be same one more than the statements, as one edge is for the invoke call + Assert.assertEquals(digraph.blocks[2].statements.length + 1, digraph.blocks[2].edges.size()); + // compute the edges from the callGraph and compare the edges with the ICFGCallGraph created + Assert.assertEquals( + edgesFromCallGraph(entryMethodSignature, icfg, callGraph), + String.join(" -> ", digraph.blocks[0].edges)); + } + + @Test + public void ICFGDotExportTest2() { + JavaProject javaProject = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .addInputLocation( + new JavaClassPathAnalysisInputLocation("src/test/resources/icfg/binary")) + .build(); + + view = javaProject.createView(); + + JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); + JavaClassType mainClassSignature = identifierFactory.getClassType("ICFGExample2"); + + SootClass sc = view.getClass(mainClassSignature).get(); + entryMethod = + sc.getMethods().stream().filter(e -> e.getName().equals("entryPoint")).findFirst().get(); + + entryMethodSignature = entryMethod.getSignature(); + + JimpleBasedInterproceduralCFG icfg = + new JimpleBasedInterproceduralCFG(view, entryMethodSignature, false, false); + CallGraph callGraph = loadCallGraph(view); + String expectedCallGraph = icfg.buildICFGGraph(callGraph); + Digraph digraph = parseDigraph(expectedCallGraph); + Assert.assertEquals(digraph.blocks.length, 7); + // As per the example code, the first block has no invoke calls, so the number of statements and + // edges should be same + Assert.assertEquals(digraph.blocks[0].statements.length, digraph.blocks[0].edges.size()); + // As per the example code, the second block has an invoke call, so the number of edges should + // be same one more than the statements, as one edge is for the invoke call + Assert.assertEquals(digraph.blocks[2].statements.length + 1, digraph.blocks[2].edges.size()); + // compute the edges from the callGraph and compare the edges with the ICFGCallGraph created + Assert.assertEquals( + edgesFromCallGraph(entryMethodSignature, icfg, callGraph), + String.join(" -> ", digraph.blocks[0].edges)); + } + + @Test + public void ICFGArrayListDotExport() { + JavaProject javaProject = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .addInputLocation( + new JavaClassPathAnalysisInputLocation("src/test/resources/icfg/binary")) + .build(); + + view = javaProject.createView(); + + JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); + JavaClassType mainClassSignature = identifierFactory.getClassType("ICFGArrayListExample"); + + SootClass sc = view.getClass(mainClassSignature).get(); + entryMethod = + sc.getMethods().stream().filter(e -> e.getName().equals("main")).findFirst().get(); + + entryMethodSignature = entryMethod.getSignature(); + + JimpleBasedInterproceduralCFG icfg = + new JimpleBasedInterproceduralCFG(view, entryMethodSignature, false, false); + CallGraph callGraph = loadCallGraph(view); + String expectedCallGraph = icfg.buildICFGGraph(callGraph); + Digraph digraph = parseDigraph(expectedCallGraph); + Assert.assertEquals( + edgesFromCallGraph(entryMethodSignature, icfg, callGraph), + String.join(" -> ", digraph.blocks[0].edges)); + } + + @Test + public void ICFGInterfaceDotExport() { + JavaProject javaProject = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .addInputLocation( + new JavaClassPathAnalysisInputLocation("src/test/resources/icfg/binary")) + .build(); + + view = javaProject.createView(); + + JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); + JavaClassType mainClassSignature = identifierFactory.getClassType("ICFGInterfaceExample"); + + SootClass sc = view.getClass(mainClassSignature).get(); + entryMethod = + sc.getMethods().stream().filter(e -> e.getName().equals("main")).findFirst().get(); + + entryMethodSignature = entryMethod.getSignature(); + + JimpleBasedInterproceduralCFG icfg = + new JimpleBasedInterproceduralCFG(view, entryMethodSignature, false, false); + CallGraph callGraph = loadCallGraph(view); + String expectedCallGraph = icfg.buildICFGGraph(callGraph); + Digraph digraph = parseDigraph(expectedCallGraph); + Assert.assertEquals( + edgesFromCallGraph(entryMethodSignature, icfg, callGraph), + String.join(" -> ", digraph.blocks[0].edges)); + } + + /** Compute the Edges of the given methodSignature from the provided callGraph */ + public String edgesFromCallGraph( + MethodSignature methodSignature, JimpleBasedInterproceduralCFG icfg, CallGraph callGraph) { + Map signatureToStmtGraph = new LinkedHashMap<>(); + icfg.computeAllCalls(methodSignature, signatureToStmtGraph, callGraph); + Map calls; + calls = ICFGDotExporter.computeCalls(signatureToStmtGraph, view); + final Optional methodOpt = view.getMethod(methodSignature); + if (methodOpt.isPresent()) { + SootMethod sootMethod = methodOpt.get(); + if (sootMethod.hasBody()) { + String edges = connectEdges(sootMethod.getBody().getStmts(), methodSignature, calls); + return edges; + } + } + return ""; + } + + /** + * Compute the possible edges which includes the hashcodes of each flowing statement from the + * given statements + * + * @param stmts + * @param methodSignature + * @param calls + * @return + */ + public String connectEdges( + List stmts, MethodSignature methodSignature, Map calls) { + StringBuilder sb = new StringBuilder(); + boolean isAdded = false; + for (Stmt stmt : stmts) { + if (methodSignature != null && calls != null) { + for (Map.Entry entry : calls.entrySet()) { + int key = entry.getKey(); + MethodSignature value = entry.getValue(); + if (methodSignature.equals(value) && !isAdded) { + sb.append(key).append(" -> "); + isAdded = true; + } + } + } + sb.append(stmt.hashCode()).append(" -> "); + } + sb.delete(sb.length() - 4, sb.length()); + return sb.toString(); + } + + /** A POJO class to convert the dot-exported string into java object */ + class Block { + String label; + String[] statements; + + List edges; + + public Block() { + edges = new ArrayList<>(); + } + } + + class Digraph { + Block[] blocks; + } + + public Digraph parseDigraph(String digraphString) { + Digraph digraph = new Digraph(); + Block currentBlock = null; + + String[] lines = digraphString.split("\n"); + for (String line : lines) { + line = line.trim(); + if (line.startsWith("subgraph cluster_")) { + String label = line.split("subgraph cluster_")[1].trim(); + currentBlock = new Block(); + currentBlock.label = label; + digraph.blocks = addBlock(digraph.blocks, currentBlock); + } else if (currentBlock != null && line.contains("label=")) { + String[] splitArray = line.split("="); + String[] newArray = new String[splitArray.length - 1]; + System.arraycopy(splitArray, 1, newArray, 0, splitArray.length - 1); + String join = String.join("", newArray); + String statement = line.split("=")[1].replace("\"", "").trim(); + currentBlock.statements = addStatement(currentBlock.statements, join); + } else if (line.contains("->")) { + String[] arrows = line.split("->"); + for (String arrow : arrows) { + String trimmedArrow = arrow.trim(); + if (!trimmedArrow.isEmpty()) { + currentBlock.edges.add(trimmedArrow); + } + } + } + } + + return digraph; + } + + public static Block[] addBlock(Block[] blocks, Block block) { + if (blocks == null) { + blocks = new Block[1]; + blocks[0] = block; + } else { + Block[] temp = new Block[blocks.length + 1]; + System.arraycopy(blocks, 0, temp, 0, blocks.length); + temp[blocks.length] = block; + blocks = temp; + } + return blocks; + } + + public static String[] addStatement(String[] statements, String statement) { + if (statements == null) { + statements = new String[1]; + statements[0] = statement; + } else { + String[] temp = new String[statements.length + 1]; + System.arraycopy(statements, 0, temp, 0, statements.length); + temp[statements.length] = statement; + statements = temp; + } + return statements; + } +} diff --git a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/CGEdgeUtilTest.java b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/CGEdgeUtilTest.java new file mode 100644 index 00000000000..286a465ff8f --- /dev/null +++ b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/CGEdgeUtilTest.java @@ -0,0 +1,560 @@ +package sootup.analysis.interprocedural.ifds; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; +import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import categories.Java8Test; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import junit.framework.TestCase; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.analysis.interprocedural.icfg.CGEdgeUtil; +import sootup.analysis.interprocedural.icfg.CGEdgeUtil.CallGraphEdgeType; +import sootup.analysis.interprocedural.icfg.CalleeMethodSignature; +import sootup.callgraph.AbstractCallGraphAlgorithm; +import sootup.callgraph.CallGraph; +import sootup.callgraph.RapidTypeAnalysisAlgorithm; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.JimpleComparator; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JDynamicInvokeExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.jimple.visitor.ExprVisitor; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.PackageName; +import sootup.core.types.PrimitiveType; +import sootup.core.types.Type; +import sootup.core.util.printer.StmtPrinter; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.JavaProject; +import sootup.java.core.language.JavaLanguage; +import sootup.java.core.types.JavaClassType; +import sootup.java.core.views.JavaView; +import sootup.java.sourcecode.inputlocation.JavaSourcePathAnalysisInputLocation; + +@Category(Java8Test.class) +public class CGEdgeUtilTest { + + @Test + public void testFindCallGraphEdgeType() { + Type returnType = PrimitiveType.getInt(); + + Local testLocal = new Local("a", returnType); + MethodSignature testMethod = + new MethodSignature( + new JavaClassType("Object", new PackageName("java.lang")), + "test", + Collections.singletonList(PrimitiveType.getInt()), + returnType); + List testParameterList = Collections.singletonList(IntConstant.getInstance(2)); + + JVirtualInvokeExpr jVirtualInvokeExpr = + new JVirtualInvokeExpr(testLocal, testMethod, testParameterList); + assertEquals(CGEdgeUtil.findCallGraphEdgeType(jVirtualInvokeExpr), CallGraphEdgeType.VIRTUAL); + + JSpecialInvokeExpr jSpecialInvokeExpr = + new JSpecialInvokeExpr(testLocal, testMethod, testParameterList); + assertEquals(CGEdgeUtil.findCallGraphEdgeType(jSpecialInvokeExpr), CallGraphEdgeType.SPECIAL); + + JInterfaceInvokeExpr jInterfaceInvokeExpr = + new JInterfaceInvokeExpr(testLocal, testMethod, testParameterList); + assertEquals( + CGEdgeUtil.findCallGraphEdgeType(jInterfaceInvokeExpr), CallGraphEdgeType.INTERFACE); + + JStaticInvokeExpr jStaticInvokeExpr = new JStaticInvokeExpr(testMethod, testParameterList); + assertEquals(CGEdgeUtil.findCallGraphEdgeType(jStaticInvokeExpr), CallGraphEdgeType.STATIC); + + MethodSignature testDynamicMethod = + new MethodSignature( + new JavaClassType( + JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME.substring( + JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME.lastIndexOf(".") + 1), + new PackageName( + JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME.substring( + 0, JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME.lastIndexOf(".")))), + "test", + Collections.singletonList(PrimitiveType.getInt()), + returnType); + JDynamicInvokeExpr jDynamicInvokeExpr = + new JDynamicInvokeExpr(testMethod, testParameterList, testDynamicMethod, testParameterList); + assertEquals(CGEdgeUtil.findCallGraphEdgeType(jDynamicInvokeExpr), CallGraphEdgeType.DYNAMIC); + } + + @Test(expected = RuntimeException.class) + public void testFindCallGraphEdgeTypeError() { + MethodSignature testMethod = + new MethodSignature( + new JavaClassType("Object", new PackageName("java.lang")), + "test", + Collections.singletonList(PrimitiveType.getInt()), + PrimitiveType.getInt()); + Immediate[] testParameterList = {IntConstant.getInstance(2)}; + + AbstractInvokeExpr jNewInvoke = + new AbstractInvokeExpr(testMethod, testParameterList) { + @Override + public void toString(@Nonnull StmtPrinter up) {} + + @Override + public int equivHashCode() { + return 0; + } + + @Override + public boolean equivTo(Object o, @Nonnull JimpleComparator comparator) { + return false; + } + + @Override + public void accept(@Nonnull ExprVisitor exprVisitor) {} + }; + CGEdgeUtil.findCallGraphEdgeType(jNewInvoke); + } + + @Test + public void testGetCallEdges() { + double version = Double.parseDouble(System.getProperty("java.specification.version")); + if (version > 1.8) { + fail("The rt.jar is not available after Java 8. You are using version " + version); + } + + JavaView view = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .addInputLocation( + new JavaSourcePathAnalysisInputLocation("src/test/resources/callgraph/")) + .build() + .createView(); + + JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); + JavaClassType mainClassSignature = identifierFactory.getClassType("example1.Example"); + MethodSignature mainMethodSignature = + identifierFactory.getMethodSignature( + mainClassSignature, "main", "void", Collections.singletonList("java.lang.String[]")); + + SootClass sc = view.getClass(mainClassSignature).orElse(null); + assertNotNull(sc); + SootMethod m = sc.getMethod(mainMethodSignature.getSubSignature()).orElse(null); + assertNotNull(mainMethodSignature + " not found in classloader", m); + + AbstractCallGraphAlgorithm algorithm = new RapidTypeAnalysisAlgorithm(view); + CallGraph cg = algorithm.initialize(Collections.singletonList(mainMethodSignature)); + + assertNotNull(cg); + assertTrue( + mainMethodSignature + " is not found in CallGraph", cg.containsMethod(mainMethodSignature)); + + Set> results = CGEdgeUtil.getCallEdges(view, cg); + assertEquals(results.size(), 6); + + List invokesStmts = + m.getBody().getStmts().stream() + .filter(Stmt::containsInvokeExpr) + .collect(Collectors.toList()); + assertEquals(invokesStmts.size(), 3); + MethodSignature constructorMethodSignature = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.B"), + "", + "void", + Collections.emptyList()); + checkPair( + results, + invokesStmts, + mainMethodSignature, + constructorMethodSignature, + CallGraphEdgeType.SPECIAL, + JSpecialInvokeExpr.class); + MethodSignature staticMethodSignature = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.B"), + "staticDispatch", + "void", + Collections.emptyList()); + checkPair( + results, + invokesStmts, + mainMethodSignature, + staticMethodSignature, + CallGraphEdgeType.STATIC, + JStaticInvokeExpr.class); + MethodSignature virtualMethodSignature = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.A"), + "virtualDispatch", + "void", + Collections.emptyList()); + checkPair( + results, + invokesStmts, + mainMethodSignature, + virtualMethodSignature, + CallGraphEdgeType.VIRTUAL, + JVirtualInvokeExpr.class); + } + + private void checkPair( + Set> results, + List invokesStmts, + MethodSignature key, + MethodSignature valueMethod, + CallGraphEdgeType type, + Class invokeClass) { + Pair virtualCall = + results.stream() + .filter(pair -> pair.getKey().equals(key) && pair.getValue().getEdgeType().equals(type)) + .findAny() + .orElse(null); + assertNotNull(virtualCall); + Stmt virtualStmt = + invokesStmts.stream() + .filter(stmt -> stmt.getInvokeExpr().getClass() == invokeClass) + .findAny() + .orElse(null); + assertNotNull(virtualStmt); + TestCase.assertEquals(virtualCall.getValue().getMethodSignature(), valueMethod); + TestCase.assertEquals(virtualCall.getValue().getSourceStmt(), virtualStmt); + } + + @Test + public void testCallGraphEdgeType() { + CallGraphEdgeType invalidEnum = CallGraphEdgeType.INVALID; + CallGraphEdgeType staticEnum = CallGraphEdgeType.STATIC; + CallGraphEdgeType virtualEnum = CallGraphEdgeType.VIRTUAL; + CallGraphEdgeType interfaceEnum = CallGraphEdgeType.INTERFACE; + CallGraphEdgeType specialEnum = CallGraphEdgeType.SPECIAL; + CallGraphEdgeType dynamicEnum = CallGraphEdgeType.DYNAMIC; + CallGraphEdgeType clinitEnum = CallGraphEdgeType.CLINIT; + CallGraphEdgeType genericFakeEnum = CallGraphEdgeType.GENERIC_FAKE; + CallGraphEdgeType threadEnum = CallGraphEdgeType.THREAD; + CallGraphEdgeType executorEnum = CallGraphEdgeType.EXECUTOR; + CallGraphEdgeType asynctaskEnum = CallGraphEdgeType.ASYNCTASK; + CallGraphEdgeType finalizeEnum = CallGraphEdgeType.FINALIZE; + CallGraphEdgeType handlerEnum = CallGraphEdgeType.HANDLER; + CallGraphEdgeType invokeFinalizeEnum = CallGraphEdgeType.INVOKE_FINALIZE; + CallGraphEdgeType privilegedEnum = CallGraphEdgeType.PRIVILEGED; + CallGraphEdgeType reflInvokeEnum = CallGraphEdgeType.REFL_INVOKE; + CallGraphEdgeType newinstanceEnum = CallGraphEdgeType.NEWINSTANCE; + CallGraphEdgeType refConstrNewinstanceEnum = CallGraphEdgeType.REFL_CONSTR_NEWINSTANCE; + CallGraphEdgeType refClassNewinstanceEnum = CallGraphEdgeType.REFL_CLASS_NEWINSTANCE; + + assertFalse(invalidEnum.isAsyncTask()); + assertFalse(staticEnum.isAsyncTask()); + assertFalse(virtualEnum.isAsyncTask()); + assertFalse(interfaceEnum.isAsyncTask()); + assertFalse(specialEnum.isAsyncTask()); + assertFalse(dynamicEnum.isAsyncTask()); + assertFalse(clinitEnum.isAsyncTask()); + assertFalse(genericFakeEnum.isAsyncTask()); + assertFalse(threadEnum.isAsyncTask()); + assertFalse(executorEnum.isAsyncTask()); + assertTrue(asynctaskEnum.isAsyncTask()); + assertFalse(finalizeEnum.isAsyncTask()); + assertFalse(handlerEnum.isAsyncTask()); + assertFalse(invokeFinalizeEnum.isAsyncTask()); + assertFalse(privilegedEnum.isAsyncTask()); + assertFalse(reflInvokeEnum.isAsyncTask()); + assertFalse(newinstanceEnum.isAsyncTask()); + assertFalse(refConstrNewinstanceEnum.isAsyncTask()); + assertFalse(refClassNewinstanceEnum.isAsyncTask()); + + assertFalse(invalidEnum.isClinit()); + assertFalse(staticEnum.isClinit()); + assertFalse(virtualEnum.isClinit()); + assertFalse(interfaceEnum.isClinit()); + assertFalse(specialEnum.isClinit()); + assertFalse(dynamicEnum.isClinit()); + assertTrue(clinitEnum.isClinit()); + assertFalse(genericFakeEnum.isClinit()); + assertFalse(threadEnum.isClinit()); + assertFalse(executorEnum.isClinit()); + assertFalse(asynctaskEnum.isClinit()); + assertFalse(finalizeEnum.isClinit()); + assertFalse(handlerEnum.isClinit()); + assertFalse(invokeFinalizeEnum.isClinit()); + assertFalse(privilegedEnum.isClinit()); + assertFalse(reflInvokeEnum.isClinit()); + assertFalse(newinstanceEnum.isClinit()); + assertFalse(refConstrNewinstanceEnum.isClinit()); + assertFalse(refClassNewinstanceEnum.isClinit()); + + assertFalse(invalidEnum.isDynamic()); + assertFalse(staticEnum.isDynamic()); + assertFalse(virtualEnum.isDynamic()); + assertFalse(interfaceEnum.isDynamic()); + assertFalse(specialEnum.isDynamic()); + assertTrue(dynamicEnum.isDynamic()); + assertFalse(clinitEnum.isDynamic()); + assertFalse(genericFakeEnum.isDynamic()); + assertFalse(threadEnum.isDynamic()); + assertFalse(executorEnum.isDynamic()); + assertFalse(asynctaskEnum.isDynamic()); + assertFalse(finalizeEnum.isDynamic()); + assertFalse(handlerEnum.isDynamic()); + assertFalse(invokeFinalizeEnum.isDynamic()); + assertFalse(privilegedEnum.isDynamic()); + assertFalse(reflInvokeEnum.isDynamic()); + assertFalse(newinstanceEnum.isDynamic()); + assertFalse(refConstrNewinstanceEnum.isDynamic()); + assertFalse(refClassNewinstanceEnum.isDynamic()); + + assertFalse(invalidEnum.isFake()); + assertFalse(staticEnum.isFake()); + assertFalse(virtualEnum.isFake()); + assertFalse(interfaceEnum.isFake()); + assertFalse(specialEnum.isFake()); + assertFalse(dynamicEnum.isFake()); + assertFalse(clinitEnum.isFake()); + assertTrue(genericFakeEnum.isFake()); + assertTrue(threadEnum.isFake()); + assertTrue(executorEnum.isFake()); + assertTrue(asynctaskEnum.isFake()); + assertFalse(finalizeEnum.isFake()); + assertTrue(handlerEnum.isFake()); + assertFalse(invokeFinalizeEnum.isFake()); + assertTrue(privilegedEnum.isFake()); + assertFalse(reflInvokeEnum.isFake()); + assertFalse(newinstanceEnum.isFake()); + assertFalse(refConstrNewinstanceEnum.isFake()); + assertFalse(refClassNewinstanceEnum.isFake()); + + assertFalse(invalidEnum.isExecutor()); + assertFalse(staticEnum.isExecutor()); + assertFalse(virtualEnum.isExecutor()); + assertFalse(interfaceEnum.isExecutor()); + assertFalse(specialEnum.isExecutor()); + assertFalse(dynamicEnum.isExecutor()); + assertFalse(clinitEnum.isExecutor()); + assertFalse(genericFakeEnum.isExecutor()); + assertFalse(threadEnum.isExecutor()); + assertTrue(executorEnum.isExecutor()); + assertFalse(asynctaskEnum.isExecutor()); + assertFalse(finalizeEnum.isExecutor()); + assertFalse(handlerEnum.isExecutor()); + assertFalse(invokeFinalizeEnum.isExecutor()); + assertFalse(privilegedEnum.isExecutor()); + assertFalse(reflInvokeEnum.isExecutor()); + assertFalse(newinstanceEnum.isExecutor()); + assertFalse(refConstrNewinstanceEnum.isExecutor()); + assertFalse(refClassNewinstanceEnum.isExecutor()); + + assertFalse(invalidEnum.passesParameters()); + assertTrue(staticEnum.passesParameters()); + assertTrue(virtualEnum.passesParameters()); + assertTrue(interfaceEnum.passesParameters()); + assertTrue(specialEnum.passesParameters()); + assertFalse(dynamicEnum.passesParameters()); + assertFalse(clinitEnum.passesParameters()); + assertFalse(genericFakeEnum.passesParameters()); + assertTrue(threadEnum.passesParameters()); + assertTrue(executorEnum.passesParameters()); + assertTrue(asynctaskEnum.passesParameters()); + assertTrue(finalizeEnum.passesParameters()); + assertFalse(handlerEnum.passesParameters()); + assertTrue(invokeFinalizeEnum.passesParameters()); + assertTrue(privilegedEnum.passesParameters()); + assertTrue(reflInvokeEnum.passesParameters()); + assertTrue(newinstanceEnum.passesParameters()); + assertTrue(refConstrNewinstanceEnum.passesParameters()); + assertTrue(refClassNewinstanceEnum.passesParameters()); + + assertFalse(invalidEnum.isExplicit()); + assertTrue(staticEnum.isExplicit()); + assertTrue(virtualEnum.isExplicit()); + assertTrue(interfaceEnum.isExplicit()); + assertTrue(specialEnum.isExplicit()); + assertFalse(dynamicEnum.isExplicit()); + assertFalse(clinitEnum.isExplicit()); + assertFalse(genericFakeEnum.isExplicit()); + assertFalse(threadEnum.isExplicit()); + assertFalse(executorEnum.isExplicit()); + assertFalse(asynctaskEnum.isExplicit()); + assertFalse(finalizeEnum.isExplicit()); + assertFalse(handlerEnum.isExplicit()); + assertFalse(invokeFinalizeEnum.isExplicit()); + assertFalse(privilegedEnum.isExplicit()); + assertFalse(reflInvokeEnum.isExplicit()); + assertFalse(newinstanceEnum.isExplicit()); + assertFalse(refConstrNewinstanceEnum.isExplicit()); + assertFalse(refClassNewinstanceEnum.isExplicit()); + + assertFalse(invalidEnum.isInstance()); + assertFalse(staticEnum.isInstance()); + assertTrue(virtualEnum.isInstance()); + assertTrue(interfaceEnum.isInstance()); + assertTrue(specialEnum.isInstance()); + assertFalse(dynamicEnum.isInstance()); + assertFalse(clinitEnum.isInstance()); + assertFalse(genericFakeEnum.isInstance()); + assertFalse(threadEnum.isInstance()); + assertFalse(executorEnum.isInstance()); + assertFalse(asynctaskEnum.isInstance()); + assertFalse(finalizeEnum.isInstance()); + assertFalse(handlerEnum.isInstance()); + assertFalse(invokeFinalizeEnum.isInstance()); + assertFalse(privilegedEnum.isInstance()); + assertFalse(reflInvokeEnum.isInstance()); + assertFalse(newinstanceEnum.isInstance()); + assertFalse(refConstrNewinstanceEnum.isInstance()); + assertFalse(refClassNewinstanceEnum.isInstance()); + + assertFalse(invalidEnum.isVirtual()); + assertFalse(staticEnum.isVirtual()); + assertTrue(virtualEnum.isVirtual()); + assertFalse(interfaceEnum.isVirtual()); + assertFalse(specialEnum.isVirtual()); + assertFalse(dynamicEnum.isVirtual()); + assertFalse(clinitEnum.isVirtual()); + assertFalse(genericFakeEnum.isVirtual()); + assertFalse(threadEnum.isVirtual()); + assertFalse(executorEnum.isVirtual()); + assertFalse(asynctaskEnum.isVirtual()); + assertFalse(finalizeEnum.isVirtual()); + assertFalse(handlerEnum.isVirtual()); + assertFalse(invokeFinalizeEnum.isVirtual()); + assertFalse(privilegedEnum.isVirtual()); + assertFalse(reflInvokeEnum.isVirtual()); + assertFalse(newinstanceEnum.isVirtual()); + assertFalse(refConstrNewinstanceEnum.isVirtual()); + assertFalse(refClassNewinstanceEnum.isVirtual()); + + assertFalse(invalidEnum.isSpecial()); + assertFalse(staticEnum.isSpecial()); + assertFalse(virtualEnum.isSpecial()); + assertFalse(interfaceEnum.isSpecial()); + assertTrue(specialEnum.isSpecial()); + assertFalse(dynamicEnum.isSpecial()); + assertFalse(clinitEnum.isSpecial()); + assertFalse(genericFakeEnum.isSpecial()); + assertFalse(threadEnum.isSpecial()); + assertFalse(executorEnum.isSpecial()); + assertFalse(asynctaskEnum.isSpecial()); + assertFalse(finalizeEnum.isSpecial()); + assertFalse(handlerEnum.isSpecial()); + assertFalse(invokeFinalizeEnum.isSpecial()); + assertFalse(privilegedEnum.isSpecial()); + assertFalse(reflInvokeEnum.isSpecial()); + assertFalse(newinstanceEnum.isSpecial()); + assertFalse(refConstrNewinstanceEnum.isSpecial()); + assertFalse(refClassNewinstanceEnum.isSpecial()); + + assertFalse(invalidEnum.isStatic()); + assertTrue(staticEnum.isStatic()); + assertFalse(virtualEnum.isStatic()); + assertFalse(interfaceEnum.isStatic()); + assertFalse(specialEnum.isStatic()); + assertFalse(dynamicEnum.isStatic()); + assertFalse(clinitEnum.isStatic()); + assertFalse(genericFakeEnum.isStatic()); + assertFalse(threadEnum.isStatic()); + assertFalse(executorEnum.isStatic()); + assertFalse(asynctaskEnum.isStatic()); + assertFalse(finalizeEnum.isStatic()); + assertFalse(handlerEnum.isStatic()); + assertFalse(invokeFinalizeEnum.isStatic()); + assertFalse(privilegedEnum.isStatic()); + assertFalse(reflInvokeEnum.isStatic()); + assertFalse(newinstanceEnum.isStatic()); + assertFalse(refConstrNewinstanceEnum.isStatic()); + assertFalse(refClassNewinstanceEnum.isStatic()); + + assertFalse(invalidEnum.isThread()); + assertFalse(staticEnum.isThread()); + assertFalse(virtualEnum.isThread()); + assertFalse(interfaceEnum.isThread()); + assertFalse(specialEnum.isThread()); + assertFalse(dynamicEnum.isThread()); + assertFalse(clinitEnum.isThread()); + assertFalse(genericFakeEnum.isThread()); + assertTrue(threadEnum.isThread()); + assertFalse(executorEnum.isThread()); + assertFalse(asynctaskEnum.isThread()); + assertFalse(finalizeEnum.isThread()); + assertFalse(handlerEnum.isThread()); + assertFalse(invokeFinalizeEnum.isThread()); + assertFalse(privilegedEnum.isThread()); + assertFalse(reflInvokeEnum.isThread()); + assertFalse(newinstanceEnum.isThread()); + assertFalse(refConstrNewinstanceEnum.isThread()); + assertFalse(refClassNewinstanceEnum.isThread()); + + assertFalse(invalidEnum.isPrivileged()); + assertFalse(staticEnum.isPrivileged()); + assertFalse(virtualEnum.isPrivileged()); + assertFalse(interfaceEnum.isPrivileged()); + assertFalse(specialEnum.isPrivileged()); + assertFalse(dynamicEnum.isPrivileged()); + assertFalse(clinitEnum.isPrivileged()); + assertFalse(genericFakeEnum.isPrivileged()); + assertFalse(threadEnum.isPrivileged()); + assertFalse(executorEnum.isPrivileged()); + assertFalse(asynctaskEnum.isPrivileged()); + assertFalse(finalizeEnum.isPrivileged()); + assertFalse(handlerEnum.isPrivileged()); + assertFalse(invokeFinalizeEnum.isPrivileged()); + assertTrue(privilegedEnum.isPrivileged()); + assertFalse(reflInvokeEnum.isPrivileged()); + assertFalse(newinstanceEnum.isPrivileged()); + assertFalse(refConstrNewinstanceEnum.isPrivileged()); + assertFalse(refClassNewinstanceEnum.isPrivileged()); + + assertFalse(invalidEnum.isReflection()); + assertFalse(staticEnum.isReflection()); + assertFalse(virtualEnum.isReflection()); + assertFalse(interfaceEnum.isReflection()); + assertFalse(specialEnum.isReflection()); + assertFalse(dynamicEnum.isReflection()); + assertFalse(clinitEnum.isReflection()); + assertFalse(genericFakeEnum.isReflection()); + assertFalse(threadEnum.isReflection()); + assertFalse(executorEnum.isReflection()); + assertFalse(asynctaskEnum.isReflection()); + assertFalse(finalizeEnum.isReflection()); + assertFalse(handlerEnum.isReflection()); + assertFalse(invokeFinalizeEnum.isReflection()); + assertFalse(privilegedEnum.isReflection()); + assertTrue(reflInvokeEnum.isReflection()); + assertFalse(newinstanceEnum.isReflection()); + assertTrue(refConstrNewinstanceEnum.isReflection()); + assertTrue(refClassNewinstanceEnum.isReflection()); + + assertFalse(invalidEnum.isReflInvoke()); + assertFalse(staticEnum.isReflInvoke()); + assertFalse(virtualEnum.isReflInvoke()); + assertFalse(interfaceEnum.isReflInvoke()); + assertFalse(specialEnum.isReflInvoke()); + assertFalse(dynamicEnum.isReflInvoke()); + assertFalse(clinitEnum.isReflInvoke()); + assertFalse(genericFakeEnum.isReflInvoke()); + assertFalse(threadEnum.isReflInvoke()); + assertFalse(executorEnum.isReflInvoke()); + assertFalse(asynctaskEnum.isReflInvoke()); + assertFalse(finalizeEnum.isReflInvoke()); + assertFalse(handlerEnum.isReflInvoke()); + assertFalse(invokeFinalizeEnum.isReflInvoke()); + assertFalse(privilegedEnum.isReflInvoke()); + assertTrue(reflInvokeEnum.isReflInvoke()); + assertFalse(newinstanceEnum.isReflInvoke()); + assertFalse(refConstrNewinstanceEnum.isReflInvoke()); + assertFalse(refClassNewinstanceEnum.isReflInvoke()); + } +} diff --git a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisProblem.java b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisProblem.java index 90c31cbd0e8..4e6ba910147 100644 --- a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisProblem.java +++ b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisProblem.java @@ -112,13 +112,13 @@ FlowFunction getNormalFlow(Stmt curr, Stmt succ) { public Set computeTargets(Value source) { // source = {v.f*} some local and all its fields // Kill T = ... - if (source.equivTo(leftOp)) { + if (source == leftOp) { return Collections.emptySet(); } Set res = new HashSet(); res.add(source); // x = T - if (source.equivTo(rightOp)) { + if (source == rightOp) { res.add(leftOp); } return res; @@ -206,11 +206,11 @@ FlowFunction getReturnFlow( return new FlowFunction() { @Override public Set computeTargets(Value source) { - Set ret = new HashSet(); + Set ret = new HashSet<>(); if (source instanceof JStaticFieldRef) { ret.add(source); } - if (callSite instanceof AbstractDefinitionStmt && source.equivTo(retOp)) { + if (callSite instanceof AbstractDefinitionStmt && source == retOp) { AbstractDefinitionStmt defnStmt = (AbstractDefinitionStmt) callSite; ret.add(defnStmt.getLeftOp()); } @@ -273,7 +273,7 @@ public Set computeTargets(Value source) { Set ret = new HashSet(); ret.add(source); // taint leftOp if base is tainted - if (baseF != null && leftOpF != null && source.equivTo(baseF)) { + if (baseF != null && leftOpF != null && source == baseF) { ret.add(leftOpF); } // taint leftOp if one of the args is tainted diff --git a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisTest.java b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisTest.java index 2d91cb5fce8..f43e33e2296 100644 --- a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisTest.java +++ b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintAnalysisTest.java @@ -57,7 +57,7 @@ Set getResultsAtLastStatement( } if (fact instanceof JInstanceFieldRef) { JInstanceFieldRef ins = (JInstanceFieldRef) fact; - names.add(((Local) ins.getBase()).getName() + "." + ins.getFieldSignature().getName()); + names.add(ins.getBase().getName() + "." + ins.getFieldSignature().getName()); } if (fact instanceof JStaticFieldRef) { JStaticFieldRef stat = (JStaticFieldRef) fact; @@ -100,8 +100,8 @@ public void FunctionTaintPropagated() { JimpleIFDSSolver> analysis = executeStaticAnalysis("FunctionTaintPropagated"); Set result = getResultsAtLastStatement(analysis); - assertTrue(result.contains("l1")); - assertTrue(result.contains("l2")); + assertTrue(result + " is missing an element.", result.contains("l1")); + assertTrue(result + " is missing an element.", result.contains("l2")); } @Test diff --git a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintTestSetUp.java b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintTestSetUp.java index dc4b9a7e0eb..57e091d2445 100644 --- a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintTestSetUp.java +++ b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/ifds/IFDSTaintTestSetUp.java @@ -80,7 +80,7 @@ private void setupSoot(String targetTestClassName) { new JavaClassPathAnalysisInputLocation("src/test/resources/taint/binary")) .build(); - view = javaProject.createOnDemandView(); + view = javaProject.createView(); JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); JavaClassType mainClassSignature = identifierFactory.getClassType(targetTestClassName); diff --git a/sootup.analysis/src/test/resources/callgraph/Example.java b/sootup.analysis/src/test/resources/callgraph/Example.java new file mode 100644 index 00000000000..3c222d17d45 --- /dev/null +++ b/sootup.analysis/src/test/resources/callgraph/Example.java @@ -0,0 +1,21 @@ +package example1; + +class Example { + + public static void main(String[] args) { + A objB = new B(); + B.staticDispatch(); + + objB.virtualDispatch(); + } +} + +class A extends Object { + public void virtualDispatch() { } + public static void staticDispatch() { } +} + +class B extends A { + public void virtualDispatch() { } + public static void staticDispatch() { } +} diff --git a/sootup.analysis/src/test/resources/icfg/source/ICFGArrayListExample.java b/sootup.analysis/src/test/resources/icfg/source/ICFGArrayListExample.java new file mode 100644 index 00000000000..7354e78b681 --- /dev/null +++ b/sootup.analysis/src/test/resources/icfg/source/ICFGArrayListExample.java @@ -0,0 +1,9 @@ +import java.util.ArrayList; +import java.util.List; + +public class ICFGArrayListExample{ + public static List main(String[] args) { + ArrayList arrayList = new ArrayList<>(); + return arrayList; + } +} \ No newline at end of file diff --git a/sootup.analysis/src/test/resources/icfg/source/ICFGExample.java b/sootup.analysis/src/test/resources/icfg/source/ICFGExample.java new file mode 100644 index 00000000000..a180c55706b --- /dev/null +++ b/sootup.analysis/src/test/resources/icfg/source/ICFGExample.java @@ -0,0 +1,27 @@ + +public class ICFGExample { + public ICFGExample() { + } + + private String id(String var1) { + return var1; + } + + private void sink(String var1) { + secondMethod(var1); + } + + private void secondMethod(String var1){ + thirdMethod(var1); + } + + public String thirdMethod(String var1){ + return var1; + } + + public void entryPoint() { + String var1 = "SECRET"; + String var2 = this.id(var1); + this.sink(var2); + } +} \ No newline at end of file diff --git a/sootup.analysis/src/test/resources/icfg/source/ICFGExample2.java b/sootup.analysis/src/test/resources/icfg/source/ICFGExample2.java new file mode 100644 index 00000000000..b61b47b230c --- /dev/null +++ b/sootup.analysis/src/test/resources/icfg/source/ICFGExample2.java @@ -0,0 +1,22 @@ +public class ICFGExample2{ + public ICFGExample2(){ + } + + public void entryPoint(){ + ICFGSuperClass polymorphicObj = new ICFGSubClass(); + polymorphicObj.m(); + } +} + +class ICFGSuperClass { + public void m() { + + } +} + +class ICFGSubClass extends ICFGSuperClass { + @Override + public void m() { + + } +} \ No newline at end of file diff --git a/sootup.analysis/src/test/resources/icfg/source/ICFGInterfaceExample.java b/sootup.analysis/src/test/resources/icfg/source/ICFGInterfaceExample.java new file mode 100644 index 00000000000..16286ea7135 --- /dev/null +++ b/sootup.analysis/src/test/resources/icfg/source/ICFGInterfaceExample.java @@ -0,0 +1,30 @@ +interface MyInterface { + int calculateSum(int a, int b); + void displayMessage(String message); +} + +class MyClass implements MyInterface { + @Override + public int calculateSum(int a, int b) { + return a + b; + } + + @Override + public void displayMessage(String message) { + String string = "The Message to be displayed is " + message; + } +} + +// Main class to demonstrate the interface methods +public class ICFGInterfaceExample { + public static void main(String[] args) { + // Create an instance of MyClass + MyClass myClass = new MyClass(); + + // Call the calculateSum method + int result = myClass.calculateSum(10, 20); + + // Call the displayMessage method + myClass.displayMessage("Hello, Interface!"); + } +} diff --git a/sootup.callgraph/pom.xml b/sootup.callgraph/pom.xml index d46b4d1ec3d..9ff98afc433 100644 --- a/sootup.callgraph/pom.xml +++ b/sootup.callgraph/pom.xml @@ -9,7 +9,7 @@ org.soot-oss sootup - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT @@ -17,7 +17,7 @@ org.soot-oss sootup.java.sourcecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT pom import @@ -28,23 +28,23 @@ org.soot-oss sootup.core - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.java.core - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.java.bytecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT test org.soot-oss sootup.java.sourcecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT test @@ -55,7 +55,7 @@ org.soot-oss sootup.jimple.parser - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT test diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java b/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java index 8307f815be9..eb899f1e0af 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java @@ -4,7 +4,7 @@ * #%L * Soot - a J*va Optimization Framework * %% - * Copyright (C) 2019-2020 Christian Brüggemann, Ben Hermann, Markus Schmidt and others + * Copyright (C) 2019-2022 Christian Brüggemann, Ben Hermann, Markus Schmidt, Jonas Klauke and others * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -28,36 +28,36 @@ import javax.annotation.Nonnull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JStaticInvokeExpr; +import sootup.core.jimple.common.ref.JStaticFieldRef; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Method; import sootup.core.model.SootClass; +import sootup.core.model.SootClassMember; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; import sootup.core.signatures.MethodSubSignature; -import sootup.core.typehierarchy.TypeHierarchy; import sootup.core.types.ClassType; import sootup.core.views.View; import sootup.java.core.JavaIdentifierFactory; import sootup.java.core.types.JavaClassType; /** - * The AbstractCallGraphAlgorithm class is the super class of all call graph algorithmen. It - * provides basic methods used in all call graph algorithm. It is abstract since it has no - * implemented functionality to resolve method calls because it is decided by the applied call graph - * algorithm + * The AbstractCallGraphAlgorithm class is the super class of all call graph algorithm. It provides + * basic methods used in all call graph algorithm. It is abstract since it has no implemented + * functionality to resolve method calls because it is decided by the applied call graph algorithm */ public abstract class AbstractCallGraphAlgorithm implements CallGraphAlgorithm { private static final Logger logger = LoggerFactory.getLogger(AbstractCallGraphAlgorithm.class); @Nonnull protected final View> view; - @Nonnull protected final TypeHierarchy typeHierarchy; - protected AbstractCallGraphAlgorithm( - @Nonnull View> view, @Nonnull TypeHierarchy typeHierarchy) { + protected AbstractCallGraphAlgorithm(@Nonnull View> view) { this.view = view; - this.typeHierarchy = typeHierarchy; } /** @@ -72,20 +72,60 @@ protected AbstractCallGraphAlgorithm( @Nonnull final CallGraph constructCompleteCallGraph( View> view, List entryPoints) { - MutableCallGraph cg = new GraphBasedCallGraph(); + MutableCallGraph cg = initializeCallGraph(); Deque workList = new ArrayDeque<>(entryPoints); Set processed = new HashSet<>(); + // implicit edge from entry point to static initializer + addImplicitEdgesOfEntryPoints(entryPoints, cg, workList); + processWorkList(view, workList, processed, cg); return cg; } + /** + * This method creates the mutable call graph which is used in the call graph algorithm. Overwrite + * it to change the used mutable call graph + * + * @return the initialized call graph used in the call graph algorithm + */ + protected MutableCallGraph initializeCallGraph() { + return new GraphBasedCallGraph(); + } + + /** + * This method adds implicit edges of the entry points of the call graph algorithm. It will add an + * edge to all static initializer of the entry points. + * + * @param entryPoints the entry points of the call graph algorithm + * @param cg the call graph which will save the added implicit edges. + * @param workList the implicit targets will be added to the work list to process in the call + * graph algorithm + */ + protected void addImplicitEdgesOfEntryPoints( + List entryPoints, MutableCallGraph cg, Deque workList) { + entryPoints.forEach( + methodSignature -> { + SootMethod clintMethod = + view.getMethod(methodSignature.getDeclClassType().getStaticInitializer()) + .orElse(null); + if (clintMethod == null) return; + MethodSignature staticInitSig = clintMethod.getSignature(); + if (!cg.containsMethod(methodSignature)) cg.addMethod(methodSignature); + if (!cg.containsMethod(staticInitSig)) cg.addMethod(staticInitSig); + if (!cg.containsCall(methodSignature, staticInitSig)) { + cg.addCall(methodSignature, staticInitSig); + workList.push(staticInitSig); + } + }); + } + /** * Processes all entries in the workList, skipping those present in processed * , adding call edges to the graph. Newly discovered methods are added to the * workList and processed as well. cg is updated accordingly. The method - * postProcessingMethod is called after a method is processed in the worklist. + * postProcessingMethod is called after a method is processed in the workList. * * @param view it contains the classes. * @param workList it contains all method that have to be processed in the call graph generation. @@ -100,23 +140,43 @@ final void processWorkList( MutableCallGraph cg) { while (!workList.isEmpty()) { MethodSignature currentMethodSignature = workList.pop(); + // skip if already processed if (processed.contains(currentMethodSignature)) continue; + // perform pre-processing if needed + preProcessingMethod(view, currentMethodSignature, workList, cg); + + // process the method if (!cg.containsMethod(currentMethodSignature)) cg.addMethod(currentMethodSignature); - Stream invocationTargets = - resolveAllCallsFromSourceMethod(view, currentMethodSignature); - - invocationTargets.forEach( - t -> { - if (!cg.containsMethod(t)) cg.addMethod(t); - if (!cg.containsCall(currentMethodSignature, t)) { - cg.addCall(currentMethodSignature, t); - workList.push(t); - } - }); + // transform the method signature to the actual SootMethod + SootMethod currentMethod = + view.getClass(currentMethodSignature.getDeclClassType()) + .flatMap(c -> c.getMethod(currentMethodSignature.getSubSignature())) + .orElse(null); + + // get all call targets of invocations in the method body + Stream invocationTargets = resolveAllCallsFromSourceMethod(currentMethod); + + // get all call targets of implicit edges in the method body + Stream implicitTargets = + resolveAllImplicitCallsFromSourceMethod(view, currentMethod); + + // save calls in the call graphs + Stream.concat(invocationTargets, implicitTargets) + .forEach( + t -> { + if (!cg.containsMethod(t)) cg.addMethod(t); + if (!cg.containsCall(currentMethodSignature, t)) { + cg.addCall(currentMethodSignature, t); + workList.push(t); + } + }); + + // set method as processed processed.add(currentMethodSignature); + // perform post-processing if needed postProcessingMethod(view, currentMethodSignature, workList, cg); } } @@ -126,27 +186,94 @@ final void processWorkList( * invoke statement in the body of the source method that is implemented in the corresponding call * graph algorithm. * - * @param view it contains all classes. * @param sourceMethod this signature is used to access the statements contained method body of * the specified method * @return a stream containing all resolved callable method signatures by the given source method */ @Nonnull - Stream resolveAllCallsFromSourceMethod( - View> view, MethodSignature sourceMethod) { - SootMethod currentMethodCandidate = - view.getClass(sourceMethod.getDeclClassType()) - .flatMap(c -> c.getMethod(sourceMethod.getSubSignature())) - .orElse(null); - if (currentMethodCandidate == null) return Stream.empty(); - - if (currentMethodCandidate.hasBody()) { - return currentMethodCandidate.getBody().getStmtGraph().nodes().stream() - .filter(Stmt::containsInvokeExpr) - .flatMap(s -> resolveCall(currentMethodCandidate, s.getInvokeExpr())); - } else { - return Stream.empty(); - } + Stream resolveAllCallsFromSourceMethod(SootMethod sourceMethod) { + if (sourceMethod == null || !sourceMethod.hasBody()) return Stream.empty(); + + return sourceMethod.getBody().getStmts().stream() + .filter(Stmt::containsInvokeExpr) + .flatMap(s -> resolveCall(sourceMethod, s.getInvokeExpr())); + } + + /** + * It resolves all implicit calls caused by the given source method + * + * @param view it contains the class data + * @param sourceMethod the inspected source method + * @return a stream containing all method signatures of targets of implicit calls. + */ + @Nonnull + protected Stream resolveAllImplicitCallsFromSourceMethod( + View> view, SootMethod sourceMethod) { + if (sourceMethod == null || !sourceMethod.hasBody()) return Stream.empty(); + + // collect all static initializer calls + Stream staticInitializerStream = + resolveAllStaticInitializerCallsFromSourceMethod(view, sourceMethod); + return staticInitializerStream; + } + + /** + * It resolves all static initializer calls caused by the given source method + * + * @param view it contains the class data + * @param sourceMethod the inspected source method + * @return a stream containing all method signatures of targets of implicit calls. + */ + @Nonnull + protected Stream resolveAllStaticInitializerCallsFromSourceMethod( + View> view, SootMethod sourceMethod) { + if (sourceMethod == null || !sourceMethod.hasBody()) return Stream.empty(); + + Stream.Builder targetsToStaticInitializer = Stream.builder(); + + InstantiateClassValueVisitor instantiateVisitor = new InstantiateClassValueVisitor(); + + sourceMethod + .getBody() + .getStmts() + .forEach( + stmt -> { + // static field usage + if (stmt.containsFieldRef() && stmt.getFieldRef() instanceof JStaticFieldRef) { + targetsToStaticInitializer.add( + stmt.getFieldRef().getFieldSignature().getDeclClassType()); + } + + // constructor calls + if (stmt instanceof JAssignStmt) { + Value rightOp = ((JAssignStmt) stmt).getRightOp(); + instantiateVisitor.init(); + rightOp.accept(instantiateVisitor); + ClassType classType = instantiateVisitor.getResult(); + if (classType != null) { + targetsToStaticInitializer.add(classType); + } + } + + // static method calls + if (stmt.containsInvokeExpr() && stmt.getInvokeExpr() instanceof JStaticInvokeExpr) { + targetsToStaticInitializer.add( + stmt.getInvokeExpr().getMethodSignature().getDeclClassType()); + } + }); + + return targetsToStaticInitializer + .build() + .flatMap( + classType -> + Stream.concat( + Stream.of(classType), + view.getTypeHierarchy().incompleteSuperClassesOf(classType).stream())) + .filter(Objects::nonNull) + .map(classType -> view.getMethod(classType.getStaticInitializer())) + .filter(Optional::isPresent) + .map(Optional::get) + .map(SootClassMember::getSignature); } /** @@ -155,17 +282,17 @@ Stream resolveAllCallsFromSourceMethod( * @param view it contains all classes * @param sig the signature of the searched method * @param the generic type of the searched method object - * @return the found method object, or null if the metod was not found. + * @return the found method object, or null if the method was not found. */ - final T findMethodInHierarchy( + protected final T findMethodInHierarchy( @Nonnull View> view, @Nonnull MethodSignature sig) { Optional> optSc = view.getClass(sig.getDeclClassType()); if (optSc.isPresent()) { SootClass sc = optSc.get(); - List superClasses = typeHierarchy.superClassesOf(sc.getType()); - Set interfaces = typeHierarchy.implementedInterfacesOf(sc.getType()); + List superClasses = view.getTypeHierarchy().superClassesOf(sc.getType()); + Set interfaces = view.getTypeHierarchy().implementedInterfacesOf(sc.getType()); superClasses.addAll(interfaces); for (ClassType superClassType : superClasses) { @@ -191,20 +318,32 @@ final T findMethodInHierarchy( } /** - * This method enables optional post processing of a method in the call graph algorithm + * This method enables optional pre-processing of a method in the call graph algorithm + * + * @param view view + * @param sourceMethod the processed method + * @param workList the current work list that might be extended + * @param cg the current cg that might be extended + */ + protected abstract void preProcessingMethod( + View> view, + MethodSignature sourceMethod, + @Nonnull Deque workList, + @Nonnull MutableCallGraph cg); + + /** + * This method enables optional post-processing of a method in the call graph algorithm * * @param view it contains classes and the type hierarchy. * @param sourceMethod the processed method - * @param workList the current worklist that might be extended + * @param workList the current work list that might be extended * @param cg the current cg that might be extended */ - public void postProcessingMethod( + protected abstract void postProcessingMethod( View> view, MethodSignature sourceMethod, @Nonnull Deque workList, - @Nonnull MutableCallGraph cg) { - // is only implemented if it is needed in the call graph algorithm - } + @Nonnull MutableCallGraph cg); @Nonnull @Override @@ -225,8 +364,9 @@ public CallGraph addClass(@Nonnull CallGraph oldCallGraph, @Nonnull JavaClassTyp processWorkList(view, workList, processed, updated); // Step 2: Add edges from old methods to methods overridden in the new class - List superClasses = typeHierarchy.superClassesOf(classType); - Set implementedInterfaces = typeHierarchy.implementedInterfacesOf(classType); + List superClasses = view.getTypeHierarchy().superClassesOf(classType); + Set implementedInterfaces = + view.getTypeHierarchy().implementedInterfacesOf(classType); Stream superTypes = Stream.concat(superClasses.stream(), implementedInterfaces.stream()); @@ -305,7 +445,7 @@ public MethodSignature findMainMethod() { } /** - * This methods resolves the possible targets of a given invoke expression. The results are + * This method resolves the possible targets of a given invoke expression. The results are * dependable of the applied call graph algorithm. therefore, it is abstract. * * @param method the method object that contains the given invoke expression in the body. @@ -314,5 +454,6 @@ public MethodSignature findMainMethod() { * algorithm. */ @Nonnull - abstract Stream resolveCall(SootMethod method, AbstractInvokeExpr invokeExpr); + protected abstract Stream resolveCall( + SootMethod method, AbstractInvokeExpr invokeExpr); } diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/CallGraph.java b/sootup.callgraph/src/main/java/sootup/callgraph/CallGraph.java index 66dfbfdcfcd..e90694879bb 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/CallGraph.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/CallGraph.java @@ -86,6 +86,9 @@ boolean containsCall( */ int callCount(); + /** This method converts the call graph object into dot format and write it to a string file. */ + String exportAsDot(); + /** * This method copies a call graph. * @@ -93,14 +96,4 @@ boolean containsCall( */ @Nonnull MutableCallGraph copy(); - - /** - * This method exports the call graph in a human-readable string. The String lists all nodes in - * the call graph. For each node it also lists the outgoing and incoming edges. An outgoing edge - * is marked by a "To" and an incoming edge by a "From" The nodes, incoming edges, and outgoing - * edges are sorted in order by the classname, method name, parameter list - * - * @return a string containing all nodes and edges of the call graph. - */ - String toStringSorted(); } diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java b/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java index dd0982061ec..d0f22f5323c 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java @@ -28,12 +28,11 @@ import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JDynamicInvokeExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.model.Modifier; +import sootup.core.model.MethodModifier; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; import sootup.core.typehierarchy.MethodDispatchResolver; -import sootup.core.typehierarchy.TypeHierarchy; import sootup.core.views.View; /** @@ -47,11 +46,9 @@ public class ClassHierarchyAnalysisAlgorithm extends AbstractCallGraphAlgorithm * The constructor of the CHA algorithm. * * @param view it contains the data of the classes and methods - * @param typeHierarchy it contains the hierarchy of all classes to resolve virtual calls */ - public ClassHierarchyAnalysisAlgorithm( - @Nonnull View> view, @Nonnull TypeHierarchy typeHierarchy) { - super(view, typeHierarchy); + public ClassHierarchyAnalysisAlgorithm(@Nonnull View> view) { + super(view); } @Nonnull @@ -92,13 +89,48 @@ protected Stream resolveCall(SootMethod method, AbstractInvokeE .orElseGet(() -> findMethodInHierarchy(view, targetMethodSignature)); if (targetMethod == null - || Modifier.isStatic(targetMethod.getModifiers()) + || MethodModifier.isStatic(targetMethod.getModifiers()) || (invokeExpr instanceof JSpecialInvokeExpr)) { return result; } else { - return Stream.concat( - result, - MethodDispatchResolver.resolveAbstractDispatch(view, targetMethodSignature).stream()); + if (targetMethod.isAbstract()) { + return resolveAllSubClassCallTargets(targetMethodSignature); + } + return MethodDispatchResolver.resolveConcreteDispatch(view, targetMethodSignature) + .map( + methodSignature -> + Stream.concat( + Stream.of(methodSignature), + resolveAllSubClassCallTargets(targetMethodSignature))) + .orElseGet(() -> resolveAllSubClassCallTargets(targetMethodSignature)); } } + + private Stream resolveAllSubClassCallTargets( + MethodSignature targetMethodSignature) { + return MethodDispatchResolver.resolveAllDispatches(view, targetMethodSignature).stream() + .map( + methodSignature -> + MethodDispatchResolver.resolveConcreteDispatch(view, methodSignature)) + .filter(Optional::isPresent) + .map(Optional::get); + } + + @Override + protected void postProcessingMethod( + View> view, + MethodSignature sourceMethod, + @Nonnull Deque workList, + @Nonnull MutableCallGraph cg) { + // do nothing + } + + @Override + protected void preProcessingMethod( + View> view, + MethodSignature sourceMethod, + @Nonnull Deque workList, + @Nonnull MutableCallGraph cg) { + // do nothing + } } diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java index 9e227e7ef90..d6672716bbe 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/GraphBasedCallGraph.java @@ -32,58 +32,66 @@ import org.jgrapht.graph.DefaultDirectedGraph; import sootup.core.signatures.MethodSignature; import sootup.core.signatures.SootClassMemberSignature; -import sootup.java.core.types.JavaClassType; /** This class implements a mutable call graph as a graph. */ -public final class GraphBasedCallGraph implements MutableCallGraph { +public class GraphBasedCallGraph implements MutableCallGraph { /** * This internal class is used to describe a vertex in the graph. The vertex is defined by a * method signature that describes the method. */ - private static class Vertex { + protected static class Vertex { @Nonnull final MethodSignature methodSignature; - private Vertex(@Nonnull MethodSignature methodSignature) { + protected Vertex(@Nonnull MethodSignature methodSignature) { this.methodSignature = methodSignature; } + + @Nonnull + protected MethodSignature getMethodSignature() { + return methodSignature; + } } /** This internal class is used to describe the edge in the graph. */ - private static class Edge {} + protected static class Edge {} @Nonnull private final DefaultDirectedGraph graph; @Nonnull private final Map signatureToVertex; - // TODO: [ms] typeToVertices is not used in a useful way, yet? - @Nonnull private final Map> typeToVertices; /** The constructor of the graph based call graph. it initializes the call graph object. */ - GraphBasedCallGraph() { + public GraphBasedCallGraph() { graph = new DefaultDirectedGraph<>(null, null, false); signatureToVertex = new HashMap<>(); - typeToVertices = new HashMap<>(); } - private GraphBasedCallGraph( + public GraphBasedCallGraph( @Nonnull DefaultDirectedGraph graph, - @Nonnull Map signatureToVertex, - @Nonnull Map> typeToVertices) { + @Nonnull Map signatureToVertex) { this.graph = graph; this.signatureToVertex = signatureToVertex; - this.typeToVertices = typeToVertices; } @Override public void addMethod(@Nonnull MethodSignature calledMethod) { Vertex v = new Vertex(calledMethod); - graph.addVertex(v); - signatureToVertex.put(calledMethod, v); + addMethod(calledMethod, v); + } + + protected void addMethod(@Nonnull MethodSignature calledMethod, Vertex vertex) { + graph.addVertex(vertex); + signatureToVertex.put(calledMethod, vertex); } @Override public void addCall( @Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod) { - graph.addEdge(vertexOf(sourceMethod), vertexOf(targetMethod), new Edge()); + addCall(sourceMethod, targetMethod, new Edge()); + } + + protected void addCall( + @Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod, Edge edge) { + graph.addEdge(vertexOf(sourceMethod), vertexOf(targetMethod), edge); } @Nonnull @@ -129,14 +137,65 @@ public int callCount() { return graph.edgeSet().size(); } + @Override + public String exportAsDot() { + StringBuilder dotFormatBuilder = new StringBuilder(); + // The edgeSet is first sorted with the sourceMethod first and then targetMethod. It is sorted + // by className, then the method name + // and then the parameters. + graph.edgeSet().stream() + .sorted( + Comparator.comparing( + (Edge edge) -> { + Vertex edgeSource = graph.getEdgeSource(edge); + return edgeSource.methodSignature.getDeclClassType().getFullyQualifiedName(); + }) + .thenComparing( + (Edge edge) -> { + Vertex edgeSource = graph.getEdgeSource(edge); + return edgeSource.methodSignature.getName(); + }) + .thenComparing( + (Edge edge) -> { + Vertex edgeSource = graph.getEdgeSource(edge); + return edgeSource.methodSignature.getParameterTypes().toString(); + }) + .thenComparing( + (Edge edge) -> { + Vertex edgeTarget = graph.getEdgeTarget(edge); + return edgeTarget.methodSignature.getDeclClassType().getClassName(); + }) + .thenComparing( + (Edge edge) -> { + Vertex edgeTarget = graph.getEdgeTarget(edge); + return edgeTarget.methodSignature.getName(); + }) + .thenComparing( + (Edge edge) -> { + Vertex edgeTarget = graph.getEdgeTarget(edge); + return edgeTarget.methodSignature.getParameterTypes().toString(); + })) + .forEach( + edge -> { + Vertex sourceVertex = graph.getEdgeSource(edge); + Vertex targetVertex = graph.getEdgeTarget(edge); + dotFormatBuilder + .append("\t") + .append("\"" + sourceVertex.methodSignature + "\"") + .append(" -> ") + .append("\"" + targetVertex.methodSignature + "\"") + .append(";\n"); + }); + + return "strict digraph ObjectGraph {\n" + dotFormatBuilder + "}"; + } + @SuppressWarnings("unchecked") // (graph.clone() preserves generic properties) @Nonnull @Override public MutableCallGraph copy() { return new GraphBasedCallGraph( - (DefaultDirectedGraph) graph.clone(), - new HashMap<>(signatureToVertex), - new HashMap<>(typeToVertices)); + (DefaultDirectedGraph) graph.clone(), new HashMap<>(signatureToVertex)); } /** @@ -146,45 +205,44 @@ public MutableCallGraph copy() { * @return the vertex of the requested method signature. */ @Nonnull - private Vertex vertexOf(@Nonnull MethodSignature method) { + protected Vertex vertexOf(@Nonnull MethodSignature method) { Vertex methodVertex = signatureToVertex.get(method); Preconditions.checkNotNull(methodVertex, "Node for " + method + " has not been added yet"); return methodVertex; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder("GraphBasedCallGraph(" + callCount() + ")"); - if (signatureToVertex.keySet().isEmpty()) { - sb.append(" is empty"); - } else { - sb.append(":\n"); - for (MethodSignature method : signatureToVertex.keySet()) { - sb.append(method.toString()).append(":\n"); - callsFrom(method) - .forEach( - (m) -> { - sb.append("\tto ").append(m).append("\n"); - }); - callsTo(method) - .forEach( - (m) -> { - sb.append("\tfrom ").append(m).append("\n"); - }); - sb.append("\n"); - } - } - return sb.toString(); + @Nonnull + protected DefaultDirectedGraph getGraph() { + return graph; + } + + @Nonnull + protected Map getSignatureToVertex() { + return signatureToVertex; + } + + @Nonnull + protected MethodSignature vertex2MethodSignature(@Nonnull Vertex vertex) { + return vertex.getMethodSignature(); } + /** + * This method exports the call graph in a human-readable string. The String lists all nodes in + * the call graph. For each node it also lists the outgoing and incoming edges. An outgoing edge + * is marked by a "To" and an incoming edge by a "From" The nodes, incoming edges, and outgoing + * edges are sorted in order by the classname, method name, parameter list + * + * @return a string containing all nodes and edges of the call graph. + */ @Override - public String toStringSorted() { + public String toString() { StringBuilder stringBuilder = new StringBuilder("GraphBasedCallGraph(" + callCount() + ")"); - if (signatureToVertex.keySet().isEmpty()) { + Set signatures = signatureToVertex.keySet(); + if (signatures.isEmpty()) { stringBuilder.append(" is empty"); } else { stringBuilder.append(":\n"); - signatureToVertex.keySet().stream() + signatures.stream() .sorted( Comparator.comparing((MethodSignature o) -> o.getDeclClassType().toString()) .thenComparing(SootClassMemberSignature::getName) diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/InstantiateClassValueVisitor.java b/sootup.callgraph/src/main/java/sootup/callgraph/InstantiateClassValueVisitor.java new file mode 100644 index 00000000000..fe22740579b --- /dev/null +++ b/sootup.callgraph/src/main/java/sootup/callgraph/InstantiateClassValueVisitor.java @@ -0,0 +1,64 @@ +package sootup.callgraph; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2023 Jonas Klauke + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import javax.annotation.Nonnull; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JNewMultiArrayExpr; +import sootup.core.jimple.visitor.AbstractValueVisitor; +import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; +import sootup.core.types.Type; + +public class InstantiateClassValueVisitor extends AbstractValueVisitor { + + public void init() { + setResult(null); + } + + @Override + public void caseNewExpr(@Nonnull JNewExpr expr) { + setResult(expr.getType()); + } + + @Override + public void caseNewArrayExpr(@Nonnull JNewArrayExpr expr) { + setResult(findClassTypeInType(expr.getBaseType())); + } + + @Override + public void caseNewMultiArrayExpr(@Nonnull JNewMultiArrayExpr expr) { + setResult(findClassTypeInType(expr.getBaseType())); + } + + private ClassType findClassTypeInType(Type type) { + if (type instanceof ArrayType) { + return findClassTypeInType(((ArrayType) type).getBaseType()); + } + if (type instanceof ClassType) { + return (ClassType) type; + } + return null; + } +} diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java b/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java index cea6161d4fe..69fee270cab 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java @@ -28,13 +28,14 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.expr.JNewExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.model.Modifier; +import sootup.core.jimple.common.stmt.JAssignStmt; +import sootup.core.model.MethodModifier; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; import sootup.core.typehierarchy.MethodDispatchResolver; -import sootup.core.typehierarchy.TypeHierarchy; import sootup.core.types.ClassType; import sootup.core.views.View; @@ -57,41 +58,40 @@ private static class Call { @Nonnull final MethodSignature source; @Nonnull final MethodSignature target; - private Call(@Nonnull MethodSignature source, MethodSignature target) { + private Call(@Nonnull MethodSignature source, @Nonnull MethodSignature target) { this.source = source; this.target = target; } } - @Nonnull private Set instantiatedClasses = new HashSet<>(); - @Nonnull private HashMap> ignoredCalls = new HashMap<>(); - @Nonnull private CallGraph chaGraph; + @Nonnull private Set instantiatedClasses = Collections.emptySet(); + @Nonnull private Map> ignoredCalls = Collections.emptyMap(); /** * The constructor of the RTA algorithm. * * @param view it contains the data of the classes and methods - * @param typeHierarchy it contains the hierarchy of all classes to resolve virtual calls */ - public RapidTypeAnalysisAlgorithm(@Nonnull View view, @Nonnull TypeHierarchy typeHierarchy) { - super(view, typeHierarchy); + public RapidTypeAnalysisAlgorithm(@Nonnull View> view) { + super(view); } @Nonnull @Override public CallGraph initialize() { - ClassHierarchyAnalysisAlgorithm cha = new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); List entryPoints = Collections.singletonList(findMainMethod()); - chaGraph = cha.initialize(entryPoints); - return constructCompleteCallGraph(view, entryPoints); + return initialize(entryPoints); } @Nonnull @Override public CallGraph initialize(@Nonnull List entryPoints) { - ClassHierarchyAnalysisAlgorithm cha = new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); - chaGraph = cha.initialize(entryPoints); - return constructCompleteCallGraph(view, entryPoints); + instantiatedClasses = new HashSet<>(); + ignoredCalls = new HashMap<>(); + CallGraph cg = constructCompleteCallGraph(view, entryPoints); + instantiatedClasses = Collections.emptySet(); + ignoredCalls = Collections.emptyMap(); + return cg; } /** @@ -100,23 +100,19 @@ public CallGraph initialize(@Nonnull List entryPoints) { * * @param method this object contains the method body which is inspected. */ - private void collectInstantiatedClassesInMethod(SootMethod method) { + protected void collectInstantiatedClassesInMethod(SootMethod method) { + if (method == null || method.isAbstract() || method.isNative()) { + return; + } + Set instantiated = - chaGraph.callsFrom(method.getSignature()).stream() - .filter(s -> s.getSubSignature().getName().equals("")) - .map(s -> s.getDeclClassType()) + method.getBody().getStmts().stream() + .filter(stmt -> stmt instanceof JAssignStmt) + .map(stmt -> ((JAssignStmt) stmt).getRightOp()) + .filter(value -> value instanceof JNewExpr) + .map(value -> ((JNewExpr) value).getType()) .collect(Collectors.toSet()); instantiatedClasses.addAll(instantiated); - - // add also found classes' super classes - instantiated.stream() - .map(s -> view.getClass(s)) - .filter(Optional::isPresent) - .map(Optional::get) - .map(s -> s.getSuperclass()) - .filter(s -> s.isPresent()) - .map(s -> s.get()) - .forEach(instantiatedClasses::add); } /** @@ -136,44 +132,92 @@ protected Stream resolveCall(SootMethod method, AbstractInvokeE MethodSignature targetMethodSignature = invokeExpr.getMethodSignature(); Stream result = Stream.of(targetMethodSignature); - if (!chaGraph.containsMethod(method.getSignature())) { - return result; - } - collectInstantiatedClassesInMethod(method); - SootMethod targetMethod = view.getClass(targetMethodSignature.getDeclClassType()) .flatMap(clazz -> clazz.getMethod(targetMethodSignature.getSubSignature())) .orElseGet(() -> findMethodInHierarchy(view, targetMethodSignature)); if (targetMethod == null - || Modifier.isStatic(targetMethod.getModifiers()) + || MethodModifier.isStatic(targetMethod.getModifiers()) || (invokeExpr instanceof JSpecialInvokeExpr)) { return result; } else { Set notInstantiatedCallTargets = Sets.newHashSet(); Set implAndOverrides = - MethodDispatchResolver.resolveAbstractDispatchInClasses( + MethodDispatchResolver.resolveAllDispatchesInClasses( view, targetMethodSignature, instantiatedClasses, notInstantiatedCallTargets); + // the class of the actual method call is instantiated + boolean targetMethodClassIsInstantiated = + instantiatedClasses.contains(targetMethodSignature.getDeclClassType()); + + // add the targetMethod to the ignoredCalls + if (!targetMethodClassIsInstantiated) { + notInstantiatedCallTargets.add(targetMethodSignature); + } + + // save filtered calls to include them later when their class is instantiated notInstantiatedCallTargets.forEach( ignoredMethodSignature -> { - List calls = ignoredCalls.get(ignoredMethodSignature.getDeclClassType()); + ClassType notInstantiatedClass = ignoredMethodSignature.getDeclClassType(); + List calls = ignoredCalls.get(notInstantiatedClass); if (calls == null) { calls = new ArrayList<>(); calls.add(new Call(method.getSignature(), ignoredMethodSignature)); - ignoredCalls.put(ignoredMethodSignature.getDeclClassType(), calls); + ignoredCalls.put(notInstantiatedClass, calls); } else { calls.add(new Call(method.getSignature(), ignoredMethodSignature)); } }); - return Stream.concat(result, implAndOverrides.stream()); + // find the concrete dispatch of all possible dispatches + Set concreteCallTargets = + implAndOverrides.stream() + .map( + methodSignature -> + MethodDispatchResolver.resolveConcreteDispatch(view, methodSignature)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + + // add the concrete of the targetMethod if the class is instantiated + if (targetMethodClassIsInstantiated) { + MethodDispatchResolver.resolveConcreteDispatch(view, targetMethodSignature) + .ifPresent(concreteCallTargets::add); + } + + return concreteCallTargets.stream(); } } /** - * Post processing of a method in the RTA call graph algorithm + * Preprocessing of a method in the RTA call graph algorithm + * + *

Before processing the method, all instantiated types are collected inside the body of the + * sourceMethod. + * + * @param view view + * @param sourceMethod the processed method + * @param workList the current work list + * @param cg the current cg + */ + @Override + protected void preProcessingMethod( + View> view, + MethodSignature sourceMethod, + @Nonnull Deque workList, + @Nonnull MutableCallGraph cg) { + SootMethod method = + view.getClass(sourceMethod.getDeclClassType()) + .flatMap(c -> c.getMethod(sourceMethod.getSubSignature())) + .orElse(null); + if (method == null) return; + + collectInstantiatedClassesInMethod(method); + } + + /** + * Postprocessing of a method in the RTA call graph algorithm * *

RTA has to add previously ignored calls because a found instantiation of a class could * enable a call to a ignored method at a later time. @@ -184,7 +228,7 @@ protected Stream resolveCall(SootMethod method, AbstractInvokeE * @param cg the current cg is extended by new call targets and calls */ @Override - public void postProcessingMethod( + protected void postProcessingMethod( View> view, MethodSignature sourceMethod, @Nonnull Deque workList, @@ -195,14 +239,20 @@ public void postProcessingMethod( if (newEdges != null) { newEdges.forEach( call -> { - if (cg.containsMethod(call.target)) { + MethodSignature concreteTarget = + MethodDispatchResolver.resolveConcreteDispatch(view, call.target) + .orElse(null); + if (concreteTarget == null) { + return; + } + if (cg.containsMethod(concreteTarget)) { // method is already analyzed or is in the work list, simply add the call - cg.addCall(call.source, call.target); + cg.addCall(call.source, concreteTarget); } else { // new target method found that has to be analyzed - cg.addMethod(call.target); - cg.addCall(call.source, call.target); - workList.push(call.target); + cg.addMethod(concreteTarget); + cg.addCall(call.source, concreteTarget); + workList.push(concreteTarget); } }); // can be removed because the instantiated class will be considered in future resolves diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java b/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java index 9f0ee4b2e62..cefcac8de44 100644 --- a/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java +++ b/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java @@ -3,16 +3,11 @@ import static junit.framework.TestCase.*; import java.util.Collections; -import java.util.Optional; import junit.framework.TestCase; -import org.junit.Ignore; import org.junit.Test; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.TypeHierarchy; -import sootup.core.typehierarchy.ViewTypeHierarchy; -import sootup.core.types.ClassType; import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; import sootup.java.core.JavaIdentifierFactory; import sootup.java.core.JavaProject; @@ -24,54 +19,68 @@ public abstract class CallGraphTestBase { private T algorithm; - protected String testDirectory, className; protected JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); protected JavaClassType mainClassSignature; protected MethodSignature mainMethodSignature; - protected abstract T createAlgorithm(JavaView view, TypeHierarchy typeHierarchy); + protected abstract T createAlgorithm(JavaView view); // private static Map viewToClassPath = new HashMap<>(); private JavaView createViewForClassPath(String classPath) { - JavaProject javaProject = + return createViewForClassPath(classPath, true); + } + + private JavaView createViewForClassPath(String classPath, boolean useSourceCodeFrontend) { + JavaProject.JavaProjectBuilder javaProjectBuilder = JavaProject.builder(new JavaLanguage(8)) .addInputLocation( new JavaClassPathAnalysisInputLocation( - System.getProperty("java.home") + "/lib/rt.jar")) - .addInputLocation(new JavaSourcePathAnalysisInputLocation(classPath)) - .build(); - return javaProject.createOnDemandView(); + System.getProperty("java.home") + "/lib/rt.jar")); + if (useSourceCodeFrontend) { + javaProjectBuilder.addInputLocation(new JavaSourcePathAnalysisInputLocation(classPath)); + } else { + javaProjectBuilder.addInputLocation(new JavaClassPathAnalysisInputLocation(classPath)); + } + + return javaProjectBuilder.build().createView(); } CallGraph loadCallGraph(String testDirectory, String className) { + return loadCallGraph(testDirectory, true, className); + } + + CallGraph loadCallGraph(String testDirectory, boolean useSourceCodeFrontend, String className) { double version = Double.parseDouble(System.getProperty("java.specification.version")); if (version > 1.8) { fail("The rt.jar is not available after Java 8. You are using version " + version); } - String classPath = "src/test/resources/callgraph/" + testDirectory; + String classPath = + "src/test/resources/callgraph/" + + testDirectory + + "/" + + (useSourceCodeFrontend ? "source" : "binary"); // JavaView view = viewToClassPath.computeIfAbsent(classPath, this::createViewForClassPath); - JavaView view = createViewForClassPath(classPath); + JavaView view = createViewForClassPath(classPath, useSourceCodeFrontend); mainClassSignature = identifierFactory.getClassType(className); mainMethodSignature = identifierFactory.getMethodSignature( mainClassSignature, "main", "void", Collections.singletonList("java.lang.String[]")); - SootClass sc = view.getClass(mainClassSignature).get(); - Optional m = - (Optional) sc.getMethod(mainMethodSignature.getSubSignature()); - assertTrue(mainMethodSignature + " not found in classloader", m.isPresent()); + SootClass sc = view.getClass(mainClassSignature).orElse(null); + assertNotNull(sc); + SootMethod m = sc.getMethod(mainMethodSignature.getSubSignature()).orElse(null); + assertNotNull(mainMethodSignature + " not found in classloader", m); - final ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); - algorithm = createAlgorithm(view, typeHierarchy); + algorithm = createAlgorithm(view); CallGraph cg = algorithm.initialize(Collections.singletonList(mainMethodSignature)); + assertNotNull(cg); assertTrue( mainMethodSignature + " is not found in CallGraph", cg.containsMethod(mainMethodSignature)); - assertNotNull(cg); return cg; } @@ -120,11 +129,185 @@ public void testRecursiveCall() { assertTrue(cg.containsMethod(mainMethodSignature)); assertTrue(cg.containsMethod(method)); assertFalse(cg.containsMethod(uncalledMethod)); - TestCase.assertEquals(2, cg.getMethodSignatures().size()); + // 2 methods + Object::clinit + Object::registerNatives + TestCase.assertEquals(4, cg.getMethodSignatures().size()); assertTrue(cg.containsCall(mainMethodSignature, mainMethodSignature)); assertTrue(cg.containsCall(mainMethodSignature, method)); - TestCase.assertEquals(2, cg.callsFrom(mainMethodSignature).size()); + // 2 calls +1 clinit calls + TestCase.assertEquals(3, cg.callsFrom(mainMethodSignature).size()); + } + + @Test + public void testConcreteCall() { + CallGraph cg = loadCallGraph("ConcreteCall", "cvc.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvc.Class"), "target", "void", Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testConcreteCallInSuperClass() { + CallGraph cg = loadCallGraph("ConcreteCall", false, "cvcsc.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvcsc.SuperClass"), + "target", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testConcreteCallInSuperClassWithDefaultInterface() { + CallGraph cg = loadCallGraph("ConcreteCall", "cvcscwi.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvcscwi.SuperClass"), + "target", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testConcreteCallInInterface() { + CallGraph cg = loadCallGraph("ConcreteCall", "cvci.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvci.Interface"), + "target", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testConcreteCallInSubInterface() { + CallGraph cg = loadCallGraph("ConcreteCall", "cvcsi.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvcsi.SubInterface"), + "target", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testConcreteCallInSuperClassSubInterface() { + CallGraph cg = loadCallGraph("ConcreteCall", "cvcscsi.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvcscsi.SubInterface"), + "target", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testClinitCallEntryPoint() { + CallGraph cg = loadCallGraph("ClinitCall", "ccep.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccep.Class"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testClinitCallProcessed() { + CallGraph cg = loadCallGraph("ClinitCall", "ccp.Class"); + MethodSignature sourceMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccp.Class"), + "", + "void", + Collections.emptyList()); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccp.Class"), "method", "int", Collections.emptyList()); + assertTrue(cg.containsCall(sourceMethod, targetMethod)); + } + + @Test + public void testClinitCallConstructor() { + CallGraph cg = loadCallGraph("ClinitCall", "ccc.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccc.DirectType"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + MethodSignature arrayMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccc.ArrayType"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, arrayMethod)); + MethodSignature arrayDimMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccc.ArrayDimType"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, arrayDimMethod)); + MethodSignature arrayInArrayMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccc.ArrayInArrayType"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, arrayInArrayMethod)); + } + + @Test + public void testClinitCallSuperConstructor() { + CallGraph cg = loadCallGraph("ClinitCall", "ccsc.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccsc.Clinit"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + MethodSignature targetMethod2 = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccsc.SuperClinit"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod2)); + } + + @Test + public void testClinitStaticMethodCall() { + CallGraph cg = loadCallGraph("ClinitCall", "ccsmc.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccsmc.Clinit"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); + } + + @Test + public void testClinitStaticField() { + CallGraph cg = loadCallGraph("ClinitCall", "ccsf.Class"); + MethodSignature targetMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("ccsf.Clinit"), + "", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); } @Test @@ -220,7 +403,7 @@ public void testVirtualCall2() { MethodSignature targetMethod = identifierFactory.getMethodSignature( - identifierFactory.getClassType("vc2.Class"), "method", "void", Collections.emptyList()); + subClassSig, "method", "void", Collections.emptyList()); assertTrue(cg.containsCall(callMethod, targetMethod)); } @@ -255,10 +438,7 @@ public void testVirtualCall4() { // more precise its: declareClassSig MethodSignature callMethod = identifierFactory.getMethodSignature( - identifierFactory.getClassType("vc4.Interface"), - "method", - "void", - Collections.emptyList()); + identifierFactory.getClassType("vc4.Class"), "method", "void", Collections.emptyList()); assertTrue(cg.containsCall(mainMethodSignature, callMethod)); } @@ -280,7 +460,7 @@ public void testDynamicInterfaceMethod2() { MethodSignature callMethod = identifierFactory.getMethodSignature( - identifierFactory.getClassType("j8dim2.Interface"), + identifierFactory.getClassType("j8dim2.SuperClass"), "method", "void", Collections.emptyList()); @@ -328,10 +508,9 @@ public void testDynamicInterfaceMethod5() { assertTrue(cg.containsCall(mainMethodSignature, compute)); } - @Ignore - // TODO: WALA can't handle this case? + @Test public void testDynamicInterfaceMethod6() { - CallGraph cg = loadCallGraph("InterfaceMethod", "j8dim6.Demo"); + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8dim6.Demo"); MethodSignature combinedInterfaceMethod = identifierFactory.getMethodSignature( @@ -372,17 +551,128 @@ public void testStaticInterfaceMethod() { assertTrue(cg.containsCall(mainMethodSignature, method)); } - /** Ignored because takes too long to analyze whole rt.jar */ - @Ignore - public void testHelloWorld() { - CallGraph cg = loadCallGraph("Misc", "HelloWorld"); + @Test + public void testAbstractMethod() { + CallGraph cg = loadCallGraph("AbstractMethod", "am1.Main"); + + MethodSignature method = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("am1.Class"), "method", "void", Collections.emptyList()); + + MethodSignature abstractMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("am1.AbstractClass"), + "method", + "void", + Collections.emptyList()); + + assertTrue(cg.containsCall(mainMethodSignature, method)); + assertFalse(cg.containsCall(mainMethodSignature, abstractMethod)); + } + + @Test + public void testAbstractMethodInSubClass() { + CallGraph cg = loadCallGraph("AbstractMethod", "am2.Main"); + + MethodSignature method = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("am2.Class"), "method", "void", Collections.emptyList()); + + MethodSignature abstractMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("am2.AbstractClass"), + "method", + "void", + Collections.emptyList()); + MethodSignature superMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("am2.SuperClass"), + "method", + "void", + Collections.emptyList()); + + assertTrue(cg.containsCall(mainMethodSignature, method)); + assertFalse(cg.containsCall(mainMethodSignature, abstractMethod)); - ClassType clazzType = JavaIdentifierFactory.getInstance().getClassType("java.io.PrintStream"); + if (this instanceof ClassHierarchyAnalysisAlgorithmTest) { + assertTrue(cg.containsCall(mainMethodSignature, superMethod)); + } + if (this instanceof RapidTypeAnalysisAlgorithmTest) { + assertFalse(cg.containsCall(mainMethodSignature, superMethod)); + } + } + + @Test + public void testAbstractMethodMissingMethodInSuperclass() { + CallGraph cg = loadCallGraph("AbstractMethod", "am3.Main"); MethodSignature method = identifierFactory.getMethodSignature( - clazzType, "println", "void", Collections.singletonList("java.lang.String")); + identifierFactory.getClassType("am3.Class"), "method", "void", Collections.emptyList()); + + MethodSignature abstractMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("am3.AbstractClass"), + "method", + "void", + Collections.emptyList()); assertTrue(cg.containsCall(mainMethodSignature, method)); + assertFalse(cg.containsCall(mainMethodSignature, abstractMethod)); + } + + @Test + public void testWithoutEntryMethod() { + JavaView view = createViewForClassPath("src/test/resources/callgraph/DefaultEntryPoint"); + + JavaClassType mainClassSignature = identifierFactory.getClassType("example2.Example"); + MethodSignature mainMethodSignature = + identifierFactory.getMethodSignature( + mainClassSignature, "main", "void", Collections.singletonList("java.lang.String[]")); + + CallGraphAlgorithm algorithm = createAlgorithm(view); + CallGraph cg = algorithm.initialize(); + assertTrue( + mainMethodSignature + " is not found in CallGraph", cg.containsMethod(mainMethodSignature)); + assertNotNull(cg); + } + + /** + * Test uses initialize() method to create call graph, but multiple main methods are present in + * input java source files. Expected result is RuntimeException. + */ + @Test + public void testMultipleMainMethod() { + + JavaView view = createViewForClassPath("src/test/resources/callgraph/Misc"); + + CallGraphAlgorithm algorithm = createAlgorithm(view); + try { + algorithm.initialize(); + fail("Runtime Exception not thrown, when multiple main methods are defined."); + } catch (RuntimeException e) { + assertTrue(e.getMessage().startsWith("There are more than 1 main method present")); + } + } + + /** + * Test uses initialize() method to create call graph, but no main method is present in input java + * source files. Expected result is RuntimeException. + */ + @Test + public void testNoMainMethod() { + + JavaView view = createViewForClassPath("src/test/resources/callgraph/NoMainMethod"); + + CallGraphAlgorithm algorithm = createAlgorithm(view); + try { + algorithm.initialize(); + fail("Runtime Exception not thrown, when no main methods are defined."); + } catch (RuntimeException e) { + System.out.println(e.getMessage()); + assertEquals( + e.getMessage(), + "No main method is present in the input programs. initialize() method can be used if only one main method exists in the input program and that should be used as entry point for call graph. \n Please specify entry point as a parameter to initialize method."); + } } } diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java index 16c8b279865..88d8b83677e 100644 --- a/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java +++ b/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java @@ -7,11 +7,10 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.TypeHierarchy; import sootup.java.core.views.JavaView; /** - * Input source examples taken from https://bitbucket.org/delors/jcg/src/master/ + * Input source examples taken from cats * * @author Markus Schmidt */ @@ -22,15 +21,28 @@ public class ClassHierarchyAnalysisAlgorithmTest // TODO: StaticInitializers, Lambdas ? @Override - protected ClassHierarchyAnalysisAlgorithm createAlgorithm( - JavaView view, TypeHierarchy typeHierarchy) { - return new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); + protected ClassHierarchyAnalysisAlgorithm createAlgorithm(JavaView view) { + return new ClassHierarchyAnalysisAlgorithm(view); } + /** + * Testing the call graph generation using CHA on a code example + * + *

In this testcase, the call graph of Example1 in folder {@link callgraph.Misc} is created + * using CHA. The testcase expects a call from main to the constructors of B,C, and E The virtual + * call print is resolved to all subtypes of A, A.print B.print, C.print, D.print and E.print, + * Overall, 8 calls are expected in the main method. the constructor of B is called directly and + * indirectly by C, since B is the super class of C. + */ @Test public void testMiscExample1() { - /** We expect constructors for B and C We expect A.print(), B.print(), C.print(), D.print() */ CallGraph cg = loadCallGraph("Misc", "example1.Example"); + MethodSignature constructorA = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.A"), + "", + "void", + Collections.emptyList()); MethodSignature constructorB = identifierFactory.getMethodSignature( @@ -46,54 +58,195 @@ public void testMiscExample1() { "void", Collections.emptyList()); - MethodSignature methodA = + MethodSignature constructorD = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.D"), + "", + "void", + Collections.emptyList()); + + MethodSignature constructorE = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.E"), + "", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodA = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.A"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodB = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.B"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodC = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.C"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodD = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.D"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodE = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.E"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature staticMethodA = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.A"), - "print", + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); - MethodSignature methodB = + MethodSignature staticMethodB = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.B"), - "print", + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); - MethodSignature methodC = + MethodSignature staticMethodC = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.C"), - "print", + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); - MethodSignature methodD = + MethodSignature staticMethodD = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.D"), - "print", + "staticDispatch", + "void", + Collections.singletonList("java.lang.Object")); + + MethodSignature staticMethodE = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.E"), + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); + MethodSignature clinitObject = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("java.lang.Object"), + "", + "void", + Collections.emptyList()); + + assertFalse(cg.containsCall(mainMethodSignature, constructorA)); assertTrue(cg.containsCall(mainMethodSignature, constructorB)); assertTrue(cg.containsCall(mainMethodSignature, constructorC)); + assertFalse(cg.containsCall(mainMethodSignature, constructorD)); + assertTrue(cg.containsCall(mainMethodSignature, constructorE)); + + assertFalse(cg.containsMethod(staticMethodA)); + assertTrue(cg.containsCall(mainMethodSignature, staticMethodB)); + assertFalse(cg.containsMethod(staticMethodC)); + assertFalse(cg.containsMethod(staticMethodD)); + assertFalse(cg.containsMethod(staticMethodE)); + + assertTrue(cg.containsCall(mainMethodSignature, virtualMethodA)); + assertTrue(cg.containsCall(mainMethodSignature, virtualMethodB)); + assertFalse(cg.containsMethod(virtualMethodC)); + assertTrue(cg.containsCall(mainMethodSignature, virtualMethodD)); + assertTrue(cg.containsCall(mainMethodSignature, virtualMethodE)); - assertTrue(cg.containsCall(mainMethodSignature, methodA)); - assertTrue(cg.containsCall(mainMethodSignature, methodB)); - assertTrue(cg.containsCall(mainMethodSignature, methodC)); - assertTrue(cg.containsCall(mainMethodSignature, methodD)); + assertTrue(cg.containsCall(mainMethodSignature, clinitObject)); - assertEquals(6, cg.callsFrom(mainMethodSignature).size()); + assertEquals(9, cg.callsFrom(mainMethodSignature).size()); - assertEquals(2, cg.callsTo(constructorB).size()); + assertEquals(1, cg.callsTo(constructorB).size()); assertEquals(1, cg.callsTo(constructorC).size()); - assertEquals(1, cg.callsTo(methodA).size()); - assertEquals(1, cg.callsTo(methodB).size()); - assertEquals(1, cg.callsTo(methodC).size()); - assertEquals(1, cg.callsTo(methodD).size()); - - assertEquals(0, cg.callsFrom(methodA).size()); - assertEquals(0, cg.callsFrom(methodB).size()); - assertEquals(0, cg.callsFrom(methodC).size()); - assertEquals(0, cg.callsFrom(methodD).size()); + assertEquals(1, cg.callsTo(constructorE).size()); + assertEquals(1, cg.callsTo(staticMethodB).size()); + assertEquals(1, cg.callsTo(virtualMethodA).size()); + assertEquals(1, cg.callsTo(virtualMethodB).size()); + assertEquals(1, cg.callsTo(virtualMethodD).size()); + assertEquals(1, cg.callsTo(virtualMethodE).size()); + + assertEquals(0, cg.callsFrom(staticMethodB).size()); + assertEquals(0, cg.callsFrom(virtualMethodA).size()); + assertEquals(0, cg.callsFrom(virtualMethodB).size()); + assertEquals(0, cg.callsFrom(virtualMethodD).size()); + assertEquals(0, cg.callsFrom(virtualMethodE).size()); + + assertEquals( + cg.toString().replace("\n", "").replace("\t", ""), + "GraphBasedCallGraph(16):" + + "()>:" + + "to ()>" + + "from ()>" + + "from ()>" + + "from ()>" + + "" + + ":" + + "from " + + "" + + "()>:" + + "to ()>" + + "from " + + "" + + ":" + + "from " + + "" + + ":" + + "from " + + "" + + "()>:" + + "to ()>" + + "from " + + "" + + "()>:" + + "to ()>" + + "from ()>" + + "" + + ":" + + "from " + + "" + + "()>:" + + "to ()>" + + "from " + + "" + + ":" + + "from " + + "" + + ":" + + "to " + + "to ()>" + + "to " + + "to " + + "to ()>" + + "to " + + "to ()>" + + "to " + + "to ()>" + + "" + + "()>:" + + "to ()>" + + "to " + + "from " + + "from ()>" + + "" + + "()>:" + + "from ()>" + + "" + + ":" + + "from ()>"); } } diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/DefaultEntryPointTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/DefaultEntryPointTest.java deleted file mode 100644 index 487fe9e9887..00000000000 --- a/sootup.callgraph/src/test/java/sootup/callgraph/DefaultEntryPointTest.java +++ /dev/null @@ -1,358 +0,0 @@ -package sootup.callgraph; - -import static junit.framework.TestCase.*; - -import java.nio.file.Paths; -import java.util.*; -import org.junit.Test; -import sootup.core.inputlocation.AnalysisInputLocation; -import sootup.core.model.SootClass; -import sootup.core.model.SourceType; -import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.ViewTypeHierarchy; -import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; -import sootup.java.core.JavaIdentifierFactory; -import sootup.java.core.JavaProject; -import sootup.java.core.JavaSootClass; -import sootup.java.core.JavaSootClassSource; -import sootup.java.core.language.JavaLanguage; -import sootup.java.core.types.JavaClassType; -import sootup.java.core.views.JavaView; -import sootup.java.sourcecode.inputlocation.JavaSourcePathAnalysisInputLocation; -import sootup.jimple.parser.JimpleAnalysisInputLocation; -import sootup.jimple.parser.JimpleProject; -import sootup.jimple.parser.JimpleView; - -public class DefaultEntryPointTest { - - /** Method to check java version. */ - private void checkVersion() { - double version = Double.parseDouble(System.getProperty("java.specification.version")); - if (version > 1.8) { - fail("The rt.jar is not available after Java 8. You are using version " + version); - } - } - - /** - * The method returns the view for input java source path and rt.jar file. - * - * @param classPath - The location of java source files. - * @return - Java view - */ - private JavaView getView(String classPath) { - JavaProject javaProject = - JavaProject.builder(new JavaLanguage(8)) - .addInputLocation( - new JavaClassPathAnalysisInputLocation( - System.getProperty("java.home") + "/lib/rt.jar", SourceType.Library)) - .addInputLocation(new JavaSourcePathAnalysisInputLocation(classPath)) - .build(); - return javaProject.createOnDemandView(); - } - - /** - * Test to create call graph for CHA without specifying entry point. It uses main method present - * in input java files as entry point. - */ - @Test - public void CHADefaultEntryPoint() { - checkVersion(); - - JavaView view = getView("src/test/resources/callgraph/DefaultEntryPoint"); - - JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); - - JavaClassType mainClassSignature = identifierFactory.getClassType("example1.Example"); - MethodSignature mainMethodSignature = - identifierFactory.getMethodSignature( - mainClassSignature, "main", "void", Collections.singletonList("java.lang.String[]")); - - ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); - CallGraphAlgorithm algorithm = new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); - CallGraph cg = algorithm.initialize(); - assertTrue( - mainMethodSignature + " is not found in CallGraph", cg.containsMethod(mainMethodSignature)); - assertNotNull(cg); - - MethodSignature constructorB = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.B"), - "", - "void", - Collections.emptyList()); - - MethodSignature constructorC = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.C"), - "", - "void", - Collections.emptyList()); - - MethodSignature methodA = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.A"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - MethodSignature methodB = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.B"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - MethodSignature methodC = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.C"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - MethodSignature methodD = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.D"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - assertTrue(cg.containsCall(mainMethodSignature, constructorB)); - assertTrue(cg.containsCall(mainMethodSignature, constructorC)); - - assertTrue(cg.containsCall(mainMethodSignature, methodA)); - assertTrue(cg.containsCall(mainMethodSignature, methodB)); - assertTrue(cg.containsCall(mainMethodSignature, methodC)); - assertTrue(cg.containsCall(mainMethodSignature, methodD)); - - assertEquals(6, cg.callsFrom(mainMethodSignature).size()); - - assertEquals(2, cg.callsTo(constructorB).size()); - assertEquals(1, cg.callsTo(constructorC).size()); - assertEquals(1, cg.callsTo(methodA).size()); - assertEquals(1, cg.callsTo(methodB).size()); - assertEquals(1, cg.callsTo(methodC).size()); - assertEquals(1, cg.callsTo(methodD).size()); - - assertEquals(0, cg.callsFrom(methodA).size()); - assertEquals(0, cg.callsFrom(methodB).size()); - assertEquals(0, cg.callsFrom(methodC).size()); - assertEquals(0, cg.callsFrom(methodD).size()); - } - - /** - * Test uses initialize() method to create call graph, but multiple main methods are present in - * input java source files. Expected result is RuntimeException. - */ - @Test - public void CHAMultipleMainMethod() { - checkVersion(); - - JavaView view = getView("src/test/resources/callgraph/Misc"); - - ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); - ClassHierarchyAnalysisAlgorithm algorithm = - new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); - try { - algorithm.initialize(); - fail("Runtime Exception not thrown, when multiple main methods are defined."); - } catch (RuntimeException e) { - System.out.println(e.getMessage()); - assertTrue(e.getMessage().startsWith("There are more than 1 main method present")); - } - } - - /** - * Test uses initialize() method to create call graph, but no main method is present in input java - * source files. Expected result is RuntimeException. - */ - @Test - public void CHANoMainMethod() { - checkVersion(); - - JavaView view = getView("src/test/resources/callgraph/NoMainMethod"); - - ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); - ClassHierarchyAnalysisAlgorithm algorithm = - new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); - try { - algorithm.initialize(); - fail("Runtime Exception not thrown, when no main methods are defined."); - } catch (RuntimeException e) { - System.out.println(e.getMessage()); - assertEquals( - e.getMessage(), - "No main method is present in the input programs. initialize() method can be used if only one main method exists in the input program and that should be used as entry point for call graph. \n Please specify entry point as a parameter to initialize method."); - } - } - - /** - * Test to create call graph for RTA without specifying entry point. It uses main method present - * in input java files as entry point. - */ - @Test - public void RTADefaultEntryPoint() { - checkVersion(); - - JavaView view = getView("src/test/resources/callgraph/DefaultEntryPoint"); - - JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); - - JavaClassType mainClassSignature = identifierFactory.getClassType("example1.Example"); - MethodSignature mainMethodSignature = - identifierFactory.getMethodSignature( - mainClassSignature, "main", "void", Collections.singletonList("java.lang.String[]")); - - ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); - CallGraphAlgorithm algorithm = new RapidTypeAnalysisAlgorithm(view, typeHierarchy); - CallGraph cg = algorithm.initialize(); - assertTrue( - mainMethodSignature + " is not found in CallGraph", cg.containsMethod(mainMethodSignature)); - assertNotNull(cg); - - MethodSignature constructorB = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.B"), - "", - "void", - Collections.emptyList()); - - MethodSignature constructorC = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.C"), - "", - "void", - Collections.emptyList()); - - MethodSignature methodA = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.A"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - MethodSignature methodB = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.B"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - MethodSignature methodC = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.C"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - MethodSignature methodD = - identifierFactory.getMethodSignature( - identifierFactory.getClassType("example1.D"), - "print", - "void", - Collections.singletonList("java.lang.Object")); - - assertTrue(cg.containsCall(mainMethodSignature, constructorB)); - assertTrue(cg.containsCall(mainMethodSignature, constructorC)); - - assertTrue(cg.containsCall(mainMethodSignature, methodA)); - assertTrue(cg.containsCall(mainMethodSignature, methodB)); - assertTrue(cg.containsCall(mainMethodSignature, methodC)); - assertFalse(cg.containsMethod(methodD)); - - assertEquals(5, cg.callsFrom(mainMethodSignature).size()); - - assertEquals(2, cg.callsTo(constructorB).size()); - assertEquals(1, cg.callsTo(constructorC).size()); - assertEquals(1, cg.callsTo(methodA).size()); - assertEquals(1, cg.callsTo(methodB).size()); - assertEquals(1, cg.callsTo(methodC).size()); - - assertEquals(0, cg.callsFrom(methodA).size()); - assertEquals(0, cg.callsFrom(methodB).size()); - assertEquals(0, cg.callsFrom(methodC).size()); - } - - /** - * Test for JavaSourcePathAnalysisInputLocation. Specifying all input source files with source - * type as Library. Expected - All input classes are of source type Library. - */ - @Test - public void specifyBuiltInInputSourcePath() { - checkVersion(); - - String classPath = "src/test/resources/callgraph/DefaultEntryPoint"; - JavaProject javaProject = - JavaProject.builder(new JavaLanguage(8)) - .addInputLocation( - new JavaSourcePathAnalysisInputLocation(SourceType.Library, classPath)) - .build(); - JavaView view = javaProject.createOnDemandView(); - - Set> classes = - new HashSet<>(); // Set to track the classes to check - for (SootClass aClass : view.getClasses()) { - if (!aClass.isLibraryClass()) { - System.out.println("Found user defined class " + aClass); - classes.add(aClass); - } - } - - assertEquals("User Defined class found, expected none", 0, classes.size()); - } - - /** - * Test for JavaClassPathAnalysisInputLocation. Specifying jar file with source type as Library. - * Expected - All input classes are of source type Library. - */ - @Test - public void specifyBuiltInInputClassPath() { - checkVersion(); - - JavaProject javaProject = - JavaProject.builder(new JavaLanguage(8)) - .addInputLocation( - new JavaClassPathAnalysisInputLocation( - System.getProperty("java.home") + "/lib/rt.jar", SourceType.Library)) - .build(); - JavaView view = javaProject.createOnDemandView(); - - Collection> classes = - new HashSet<>(); // Set to track the classes to check - - for (SootClass aClass : view.getClasses()) { - // System.out.println(aClass.getClassSource().getClassType().isBuiltInClass()); - if (!aClass.isLibraryClass()) { - System.out.println("Found user defined class " + aClass); - classes.add(aClass); - } - } - - assertEquals("User Defined class found, expected none", 0, classes.size()); - } - - /** - * Test for JimpleAnalysisInputLocation. Specifying jimple file with source type as Library. - * Expected - All input classes are of source type Library. - */ - @Test - public void specifyBuiltInInputJimplePath() { - checkVersion(); - - String classPath = "src/test/resources/callgraph/jimple"; - AnalysisInputLocation jimpleInputLocation = - new JimpleAnalysisInputLocation<>(Paths.get(classPath), SourceType.Library); - JimpleView view = new JimpleProject(jimpleInputLocation).createOnDemandView(); - - Collection> classes = new HashSet<>(); // Set to track the classes to check - - for (SootClass aClass : view.getClasses()) { - // System.out.println(aClass.getClassSource().getClassType().isBuiltInClass()); - if (!aClass.isLibraryClass()) { - System.out.println("Found user defined class " + aClass); - classes.add(aClass); - } - } - - assertEquals("User Defined class found, expected none", 0, classes.size()); - } -} diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java new file mode 100644 index 00000000000..7186e18082e --- /dev/null +++ b/sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java @@ -0,0 +1,217 @@ +package sootup.callgraph; + +import static junit.framework.TestCase.*; + +import categories.Java8Test; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.core.IdentifierFactory; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.constant.BooleanConstant; +import sootup.core.jimple.common.constant.ClassConstant; +import sootup.core.jimple.common.constant.DoubleConstant; +import sootup.core.jimple.common.constant.EnumConstant; +import sootup.core.jimple.common.constant.FloatConstant; +import sootup.core.jimple.common.constant.IntConstant; +import sootup.core.jimple.common.constant.LongConstant; +import sootup.core.jimple.common.constant.MethodHandle; +import sootup.core.jimple.common.constant.MethodType; +import sootup.core.jimple.common.constant.StringConstant; +import sootup.core.jimple.common.expr.JAddExpr; +import sootup.core.jimple.common.expr.JAndExpr; +import sootup.core.jimple.common.expr.JCastExpr; +import sootup.core.jimple.common.expr.JCmpExpr; +import sootup.core.jimple.common.expr.JCmpgExpr; +import sootup.core.jimple.common.expr.JCmplExpr; +import sootup.core.jimple.common.expr.JDivExpr; +import sootup.core.jimple.common.expr.JDynamicInvokeExpr; +import sootup.core.jimple.common.expr.JEqExpr; +import sootup.core.jimple.common.expr.JGeExpr; +import sootup.core.jimple.common.expr.JGtExpr; +import sootup.core.jimple.common.expr.JInstanceOfExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; +import sootup.core.jimple.common.expr.JLeExpr; +import sootup.core.jimple.common.expr.JLengthExpr; +import sootup.core.jimple.common.expr.JMulExpr; +import sootup.core.jimple.common.expr.JNeExpr; +import sootup.core.jimple.common.expr.JNegExpr; +import sootup.core.jimple.common.expr.JNewArrayExpr; +import sootup.core.jimple.common.expr.JNewExpr; +import sootup.core.jimple.common.expr.JNewMultiArrayExpr; +import sootup.core.jimple.common.expr.JOrExpr; +import sootup.core.jimple.common.expr.JPhiExpr; +import sootup.core.jimple.common.expr.JRemExpr; +import sootup.core.jimple.common.expr.JShlExpr; +import sootup.core.jimple.common.expr.JShrExpr; +import sootup.core.jimple.common.expr.JSpecialInvokeExpr; +import sootup.core.jimple.common.expr.JSubExpr; +import sootup.core.jimple.common.expr.JUshrExpr; +import sootup.core.jimple.common.expr.JVirtualInvokeExpr; +import sootup.core.jimple.common.expr.JXorExpr; +import sootup.core.jimple.common.ref.JArrayRef; +import sootup.core.jimple.common.ref.JCaughtExceptionRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; +import sootup.core.jimple.common.ref.JParameterRef; +import sootup.core.jimple.common.ref.JStaticFieldRef; +import sootup.core.jimple.common.ref.JThisRef; +import sootup.core.signatures.FieldSignature; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.MethodSubSignature; +import sootup.core.types.ArrayType; +import sootup.core.types.ClassType; +import sootup.core.types.PrimitiveType; +import sootup.core.views.View; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaProject; +import sootup.java.core.JavaSootClass; +import sootup.java.core.language.JavaLanguage; + +@Category(Java8Test.class) +public class InstantiateClassValueVisitorTest { + @Test + public void testVisitor() { + + JavaProject javaProject = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .build(); + View view = javaProject.createView(); + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + + InstantiateClassValueVisitor instantiateVisitor = new InstantiateClassValueVisitor(); + List listWithAllValues = new ArrayList<>(); + fillList(listWithAllValues, view); + List foundClassTypes = new ArrayList<>(); + + for (Value value : listWithAllValues) { + instantiateVisitor.init(); + value.accept(instantiateVisitor); + ClassType classType = instantiateVisitor.getResult(); + if (classType != null) { + foundClassTypes.add(classType); + } + } + + assertFalse(foundClassTypes.isEmpty()); + assertEquals(foundClassTypes.size(), 4); + assertTrue(foundClassTypes.contains(identifierFactory.getClassType("java.lang.Object"))); + assertTrue(foundClassTypes.contains(identifierFactory.getClassType("java.lang.Boolean"))); + assertTrue(foundClassTypes.contains(identifierFactory.getClassType("java.lang.Byte"))); + assertTrue(foundClassTypes.contains(identifierFactory.getClassType("java.lang.Double"))); + assertFalse(foundClassTypes.contains(identifierFactory.getClassType("java.lang.String"))); + } + + private void fillList(List listWithAllValues, View view) { + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + // interesting cases + PrimitiveType charType = identifierFactory.getPrimitiveType("char").orElse(null); + assertNotNull(charType); + + listWithAllValues.add(new JNewExpr(identifierFactory.getClassType("java.lang.Object"))); + + ArrayType charArrayType = new ArrayType(charType, 3); + listWithAllValues.add( + new JNewArrayExpr( + identifierFactory.getClassType("java.lang.Boolean"), + IntConstant.getInstance(3), + identifierFactory)); + listWithAllValues.add( + new JNewArrayExpr( + new ArrayType(identifierFactory.getClassType("java.lang.Byte"), 3), + IntConstant.getInstance(3), + identifierFactory)); + listWithAllValues.add( + new JNewArrayExpr(charType, IntConstant.getInstance(3), identifierFactory)); + listWithAllValues.add( + new JNewArrayExpr(charArrayType, IntConstant.getInstance(3), identifierFactory)); + + listWithAllValues.add( + new JNewMultiArrayExpr( + new ArrayType(identifierFactory.getClassType("java.lang.Double"), 3), + Collections.singletonList(IntConstant.getInstance(3)))); + listWithAllValues.add( + new JNewMultiArrayExpr( + new ArrayType(charType, 3), Collections.singletonList(IntConstant.getInstance(3)))); + + // default cases + ClassType StringClass = identifierFactory.getClassType("java.lang.String"); + MethodSignature toStringMethod = + identifierFactory.getMethodSignature( + StringClass, new MethodSubSignature("toString", Collections.emptyList(), StringClass)); + FieldSignature stringField = new FieldSignature(StringClass, "a", StringClass); + Immediate stringConstant = new StringConstant("String", StringClass); + listWithAllValues.add(BooleanConstant.getInstance(true)); + listWithAllValues.add(DoubleConstant.getInstance(2.5)); + listWithAllValues.add(FloatConstant.getInstance(2.5f)); + listWithAllValues.add(IntConstant.getInstance(3)); + listWithAllValues.add(LongConstant.getInstance(3L)); + listWithAllValues.add(new StringConstant("String", StringClass)); + listWithAllValues.add(new EnumConstant("3", StringClass)); + listWithAllValues.add(new ClassConstant("java/lang/String", StringClass)); + listWithAllValues.add(new MethodHandle(toStringMethod, 3, StringClass)); + listWithAllValues.add(new MethodType(toStringMethod.getSubSignature(), StringClass)); + listWithAllValues.add(new JAddExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JAndExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JCmpExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JCmpgExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JCmplExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JDivExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JEqExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JNeExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JGeExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JGtExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JLeExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JMulExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JOrExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JRemExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JShlExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JShrExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JUshrExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JSubExpr(stringConstant, stringConstant)); + listWithAllValues.add(new JXorExpr(stringConstant, stringConstant)); + listWithAllValues.add( + new JSpecialInvokeExpr( + new Local("a", StringClass), + toStringMethod, + Collections.singletonList(stringConstant))); + listWithAllValues.add( + new JVirtualInvokeExpr( + new Local("a", StringClass), + toStringMethod, + Collections.singletonList(stringConstant))); + listWithAllValues.add( + new JInterfaceInvokeExpr( + new Local("a", StringClass), + toStringMethod, + Collections.singletonList(stringConstant))); + listWithAllValues.add( + new JDynamicInvokeExpr( + toStringMethod, + Collections.singletonList(stringConstant), + new MethodSignature( + identifierFactory.getClassType(JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME), + toStringMethod.getSubSignature()), + Collections.singletonList(stringConstant))); + listWithAllValues.add(new JCastExpr(stringConstant, StringClass)); + listWithAllValues.add(new JInstanceOfExpr(stringConstant, StringClass)); + listWithAllValues.add(new JLengthExpr(stringConstant)); + listWithAllValues.add(new JNegExpr(stringConstant)); + listWithAllValues.add(new JStaticFieldRef(stringField)); + listWithAllValues.add(new JInstanceFieldRef(new Local("a", StringClass), stringField)); + listWithAllValues.add(new JArrayRef(new Local("a", StringClass), stringConstant)); + listWithAllValues.add(new JParameterRef(StringClass, 3)); + listWithAllValues.add(new JCaughtExceptionRef(StringClass)); + listWithAllValues.add(new JThisRef(StringClass)); + listWithAllValues.add(new Local("a", StringClass)); + listWithAllValues.add( + new JPhiExpr(Collections.singletonList(new Local("a", StringClass)), new HashMap<>())); + } +} diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java index 43d383d4104..ef03efc3265 100644 --- a/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java +++ b/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java @@ -7,7 +7,6 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.TypeHierarchy; import sootup.java.core.views.JavaView; /** @author Kadiray Karakaya, Jonas Klauke */ @@ -15,15 +14,30 @@ public class RapidTypeAnalysisAlgorithmTest extends CallGraphTestBase { @Override - protected RapidTypeAnalysisAlgorithm createAlgorithm(JavaView view, TypeHierarchy typeHierarchy) { - return new RapidTypeAnalysisAlgorithm(view, typeHierarchy); + protected RapidTypeAnalysisAlgorithm createAlgorithm(JavaView view) { + return new RapidTypeAnalysisAlgorithm(view); } + /** + * Testing the call graph generation using RTA on a code example + * + *

In this testcase, the call graph of Example1 in folder {@link callgraph.Misc} is created + * using RTA. The testcase expects a call from main to the constructors of B,C, and E The virtual + * call print is resolved to calls to B.print, C.print, and E.print, since the types were + * instantiated. Overall, 6 calls are expected in the main method. the constructor of B is called + * directly and indirectly by C, since B is the super class of C. + */ @Test public void testMiscExample1() { - /** We expect constructors for B and C We expect A.print(), B.print(), C.print() */ CallGraph cg = loadCallGraph("Misc", "example1.Example"); + MethodSignature constructorA = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.A"), + "", + "void", + Collections.emptyList()); + MethodSignature constructorB = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.B"), @@ -38,53 +52,190 @@ public void testMiscExample1() { "void", Collections.emptyList()); - MethodSignature methodA = + MethodSignature constructorD = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.D"), + "", + "void", + Collections.emptyList()); + + MethodSignature constructorE = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.E"), + "", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodA = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.A"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodB = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.B"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodC = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.C"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodD = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.D"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature virtualMethodE = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.E"), + "virtualDispatch", + "void", + Collections.emptyList()); + + MethodSignature staticMethodA = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.A"), - "print", + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); - MethodSignature methodB = + MethodSignature staticMethodB = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.B"), - "print", + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); - MethodSignature methodC = + MethodSignature staticMethodC = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.C"), - "print", + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); - MethodSignature methodD = + MethodSignature staticMethodD = identifierFactory.getMethodSignature( identifierFactory.getClassType("example1.D"), - "print", + "staticDispatch", "void", Collections.singletonList("java.lang.Object")); + MethodSignature staticMethodE = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("example1.E"), + "staticDispatch", + "void", + Collections.singletonList("java.lang.Object")); + + MethodSignature clinitObject = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("java.lang.Object"), + "", + "void", + Collections.emptyList()); + + assertFalse(cg.containsCall(mainMethodSignature, constructorA)); assertTrue(cg.containsCall(mainMethodSignature, constructorB)); assertTrue(cg.containsCall(mainMethodSignature, constructorC)); + assertFalse(cg.containsCall(mainMethodSignature, constructorD)); + assertTrue(cg.containsCall(mainMethodSignature, constructorE)); + + assertFalse(cg.containsMethod(staticMethodA)); + assertTrue(cg.containsCall(mainMethodSignature, staticMethodB)); + assertFalse(cg.containsMethod(staticMethodC)); + assertFalse(cg.containsMethod(staticMethodD)); + assertFalse(cg.containsMethod(staticMethodE)); + + assertFalse(cg.containsMethod(virtualMethodA)); + assertTrue(cg.containsCall(mainMethodSignature, virtualMethodB)); + assertFalse(cg.containsMethod(virtualMethodC)); + assertTrue(cg.containsCall(mainMethodSignature, virtualMethodD)); + assertTrue(cg.containsCall(mainMethodSignature, virtualMethodE)); - assertTrue(cg.containsCall(mainMethodSignature, methodA)); - assertTrue(cg.containsCall(mainMethodSignature, methodB)); - assertTrue(cg.containsCall(mainMethodSignature, methodC)); - assertFalse(cg.containsMethod(methodD)); + assertTrue(cg.containsCall(mainMethodSignature, clinitObject)); - assertEquals(5, cg.callsFrom(mainMethodSignature).size()); + assertEquals(8, cg.callsFrom(mainMethodSignature).size()); - assertEquals(2, cg.callsTo(constructorB).size()); + assertEquals(1, cg.callsTo(constructorB).size()); assertEquals(1, cg.callsTo(constructorC).size()); - assertEquals(1, cg.callsTo(methodA).size()); - assertEquals(1, cg.callsTo(methodB).size()); - assertEquals(1, cg.callsTo(methodC).size()); + assertEquals(1, cg.callsTo(constructorE).size()); + assertEquals(1, cg.callsTo(staticMethodB).size()); + assertEquals(1, cg.callsTo(virtualMethodB).size()); + assertEquals(1, cg.callsTo(virtualMethodD).size()); + assertEquals(1, cg.callsTo(virtualMethodE).size()); - assertEquals(0, cg.callsFrom(methodA).size()); - assertEquals(0, cg.callsFrom(methodB).size()); - assertEquals(0, cg.callsFrom(methodC).size()); + assertEquals(0, cg.callsFrom(staticMethodB).size()); + assertEquals(0, cg.callsFrom(virtualMethodB).size()); + assertEquals(0, cg.callsFrom(virtualMethodD).size()); + assertEquals(0, cg.callsFrom(virtualMethodE).size()); + + assertEquals( + cg.toString().replace("\n", "").replace("\t", ""), + "GraphBasedCallGraph(15):" + + "()>:" + + "to ()>" + + "from ()>" + + "from ()>" + + "from ()>" + + "" + + "()>:" + + "to ()>" + + "from " + + "" + + ":" + + "from " + + "" + + ":" + + "from " + + "" + + "()>:" + + "to ()>" + + "from " + + "" + + "()>:" + + "to ()>" + + "from ()>" + + "" + + ":" + + "from " + + "" + + "()>:" + + "to ()>" + + "from " + + "" + + ":" + + "from " + + "" + + ":" + + "to ()>" + + "to " + + "to " + + "to ()>" + + "to " + + "to ()>" + + "to " + + "to ()>" + + "" + + "()>:" + + "to ()>" + + "to " + + "from " + + "from ()>" + + "" + + "()>:" + + "from ()>" + + "" + + ":" + + "from ()>"); } @Test @@ -118,7 +269,7 @@ public void testRevisitMethod() { "int", Collections.emptyList()); - assertTrue(cg.containsCall(alreadyVisitedMethod, newTargetA)); + assertFalse(cg.containsCall(alreadyVisitedMethod, newTargetA)); assertTrue(cg.containsCall(alreadyVisitedMethod, newTargetB)); assertTrue(cg.containsCall(alreadyVisitedMethod, newTargetC)); } @@ -154,8 +305,40 @@ public void testRecursiveRevisitMethod() { "int", Collections.emptyList()); - assertTrue(cg.containsCall(alreadyVisitedMethod, newTargetA)); + assertFalse(cg.containsCall(alreadyVisitedMethod, newTargetA)); assertTrue(cg.containsCall(alreadyVisitedMethod, newTargetB)); assertTrue(cg.containsCall(alreadyVisitedMethod, newTargetC)); } + + @Test + public void testInstantiatedClassInClinit() { + CallGraph cg = loadCallGraph("RTA", false, "cic.Class"); + MethodSignature instantiatedClassMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cic.SubClass"), + "method", + "void", + Collections.emptyList()); + + MethodSignature nonInstantiatedClassMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cic.SuperClass"), + "method", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, instantiatedClassMethod)); + assertFalse(cg.containsCall(mainMethodSignature, nonInstantiatedClassMethod)); + } + + @Test + public void testLaterInstantiatedClass() { + CallGraph cg = loadCallGraph("RTA", false, "lic.Class"); + MethodSignature instantiatedClassMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("lic.InstantiatedClass"), + "method", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, instantiatedClassMethod)); + } } diff --git a/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod1.java b/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod1.java new file mode 100644 index 00000000000..888e78f32b1 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod1.java @@ -0,0 +1,16 @@ +package am1; + +class Main { + public static void main(String[] args){ + AbstractClass a = new Class(); + a.method(); + } +} + +abstract class AbstractClass { + public abstract void method(); +} +class Class extends AbstractClass{ + public void method(){ + } +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod2.java b/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod2.java new file mode 100644 index 00000000000..0a426f7e931 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod2.java @@ -0,0 +1,20 @@ +package am2; + +class Main { + public static void main(String[] args){ + SuperClass a = new Class(); + a.method(); + } +} + +class SuperClass { + public void method(){ + } +} +abstract class AbstractClass extends SuperClass{ + public abstract void method(); +} +class Class extends AbstractClass{ + public void method(){ + } +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod3.java b/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod3.java new file mode 100644 index 00000000000..de8477c5ea2 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/AbstractMethod/source/AbstractMethod3.java @@ -0,0 +1,19 @@ +package am3; + +class Main { + public static void main(String[] args){ + SuperClass a = new Class(); + a.method(); + } +} + +abstract class SuperClass { + public abstract void method(); +} +abstract class AbstractClass extends SuperClass{ + +} +class Class extends AbstractClass{ + public void method(){ + } +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallConstructor.java b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallConstructor.java new file mode 100644 index 00000000000..7cc435465c0 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallConstructor.java @@ -0,0 +1,28 @@ +// ccm/Class.java +package ccc; + +class Class { + + public static void main(String[] args){ + DirectType a=new DirectType(); + int[] b= new int[5]; + ArrayType[] c =new ArrayType[5]; + ArrayDimType[][] d= new ArrayDimType[2][4]; + ArrayInArrayType[][] e= new ArrayInArrayType[2][]; + } +} + +class DirectType { + static int a=3; +} + +class ArrayType { + static int a=3; +} + +class ArrayDimType { + static int a=3; +} +class ArrayInArrayType { + static int a=3; +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallEntryPoint.java b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallEntryPoint.java new file mode 100644 index 00000000000..b0647a995b9 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallEntryPoint.java @@ -0,0 +1,10 @@ +// ccm/Class.java +package ccep; + +class Class { + + static int a=3; + + public static void main(String[] args){ + } +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallProcessed.java b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallProcessed.java new file mode 100644 index 00000000000..cb1a3b16400 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallProcessed.java @@ -0,0 +1,14 @@ +// ccm/Class.java +package ccp; + +class Class { + + static int a=method(); + + public static void main(String[] args){ + } + + public static int method(){ + return 3; + } +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticField.java b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticField.java new file mode 100644 index 00000000000..fd0d014adce --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticField.java @@ -0,0 +1,19 @@ +// ccm/Class.java +package ccsf; + +class Class { + + public static void main(String[] args){ + int b=Clinit.a; + } +} + +class Clinit { + + static int a=3; + + public static void method(){ + + } + +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticMethodCall.java b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticMethodCall.java new file mode 100644 index 00000000000..43d6575cce2 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallStaticMethodCall.java @@ -0,0 +1,19 @@ +// ccm/Class.java +package ccsmc; + +class Class { + + public static void main(String[] args){ + Clinit.method(); + } +} + +class Clinit { + + static int a=3; + + public static void method(){ + + } + +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallSuperConstructor.java b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallSuperConstructor.java new file mode 100644 index 00000000000..2599409f122 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ClinitCall/source/ClinitCallSuperConstructor.java @@ -0,0 +1,17 @@ +// ccm/Class.java +package ccsc; + +class Class { + + public static void main(String[] args){ + Clinit c=new Clinit(); + } +} + +class Clinit extends SuperClinit{ + static int a=3; +} + +class SuperClinit { + static int b=3; +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClass.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClass.java new file mode 100644 index 00000000000..ce9d64874bf --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClass.java @@ -0,0 +1,16 @@ +// cvc/Class.java +package cvcsc; + +class Class extends SuperClass{ + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} + +class SuperClass { + + public void target(){ } + +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCall.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCall.java new file mode 100644 index 00000000000..403b997c6c5 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCall.java @@ -0,0 +1,12 @@ +// cvc/Class.java +package cvc; + +class Class { + + public void target(){ } + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultInterface.java new file mode 100644 index 00000000000..9db1421d553 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultInterface.java @@ -0,0 +1,16 @@ +// cvci/Class.java +package cvci; + +class Class implements Interface{ + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} + +interface Interface { + + default void target(){ } + +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultSubInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultSubInterface.java new file mode 100644 index 00000000000..afaca67bf79 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultSubInterface.java @@ -0,0 +1,22 @@ +// cvci/Class.java +package cvcsi; + +class Class implements SubInterface{ + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} + +interface Interface { + + default void target(){ } + +} + +interface SubInterface extends Interface { + + default void target(){ } + +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassDefaultSubInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassDefaultSubInterface.java new file mode 100644 index 00000000000..0e32385085a --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassDefaultSubInterface.java @@ -0,0 +1,22 @@ +// cvc/Class.java +package cvcscsi; + +class Class extends SuperClass implements Interface{ + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} + +class SuperClass implements SubInterface { + +} + +interface Interface { + default void target(){} +} + +interface SubInterface extends Interface { + default void target(){} +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassWithDefaultInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassWithDefaultInterface.java new file mode 100644 index 00000000000..f16a278fdb8 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassWithDefaultInterface.java @@ -0,0 +1,22 @@ +// cvc/Class.java +package cvcscwi; + +class Class extends SuperClass implements Interface{ + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} + +class SuperClass { + + public void target(){ } + +} + +class Interface { + + default void target(){ } + +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/DefaultEntryPoint/Example1.java b/sootup.callgraph/src/test/resources/callgraph/DefaultEntryPoint/source/Example2.java similarity index 80% rename from sootup.callgraph/src/test/resources/callgraph/DefaultEntryPoint/Example1.java rename to sootup.callgraph/src/test/resources/callgraph/DefaultEntryPoint/source/Example2.java index 98ecdb857a6..554ef1f70dc 100644 --- a/sootup.callgraph/src/test/resources/callgraph/DefaultEntryPoint/Example1.java +++ b/sootup.callgraph/src/test/resources/callgraph/DefaultEntryPoint/source/Example2.java @@ -1,4 +1,4 @@ -package example1; +package example2; class Example { @@ -21,7 +21,3 @@ public void print(Object o) { } class C extends B { public void print(Object o) { } } - -class D extends A { - public void print(Object o) { } -} diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM6.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM6.java similarity index 85% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM6.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM6.java index ec2a879ca7e..60c93ed10e2 100644 --- a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM6.java +++ b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM6.java @@ -30,8 +30,7 @@ interface CombinedInterface extends SomeInterface, AnotherInterface { @DirectCall(name = "method", line = 33, resolvedTargets = "Lj8dim/AnotherInterface;") })*/ default void method() { - // TODO: WALA can't handle the following lines - // SomeInterface.super.method(); - // AnotherInterface.super.method(); + SomeInterface.super.method(); + AnotherInterface.super.method(); } } diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM1.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM1.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM1.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM1.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM2.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM2.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM2.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM2.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM3.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM3.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM3.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM3.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM4.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM4.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM4.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM4.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM5.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM5.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8DIM5.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM5.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8SIM.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8SIM.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/J8SIM.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8SIM.java diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/Example1.java b/sootup.callgraph/src/test/resources/callgraph/Misc/Example1.java deleted file mode 100644 index 98ecdb857a6..00000000000 --- a/sootup.callgraph/src/test/resources/callgraph/Misc/Example1.java +++ /dev/null @@ -1,27 +0,0 @@ -package example1; - -class Example { - - public static void main(String[] args) { - A objB = new B(); - A objC = new C(); - - objB.print(objC); - } -} - -class A extends Object { - public void print( Object o) { } -} - -class B extends A { - public void print(Object o) { } -} - -class C extends B { - public void print(Object o) { } -} - -class D extends A { - public void print(Object o) { } -} diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/AddClass.java b/sootup.callgraph/src/test/resources/callgraph/Misc/source/AddClass.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/Misc/AddClass.java rename to sootup.callgraph/src/test/resources/callgraph/Misc/source/AddClass.java diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/source/Example1.java b/sootup.callgraph/src/test/resources/callgraph/Misc/source/Example1.java new file mode 100644 index 00000000000..e6f0a4cad66 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/Misc/source/Example1.java @@ -0,0 +1,37 @@ +package example1; + +class Example { + + public static void main(String[] args) { + A objB = new B(); + B.staticDispatch(new C()); + + A objC=new E(); + + objB.virtualDispatch(); + } +} + +class A extends Object { + public void virtualDispatch() { } + public static void staticDispatch( Object o) { } +} + +class B extends A { + public void virtualDispatch() { } + public static void staticDispatch( Object o) { } +} + +class C extends D { + public static void staticDispatch( Object o) { } +} + +class D extends A { + public void virtualDispatch() { } + public static void staticDispatch( Object o) { } +} + +class E extends A { + public void virtualDispatch() { } + public static void staticDispatch( Object o) { } +} diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/HelloWorld.java b/sootup.callgraph/src/test/resources/callgraph/Misc/source/HelloWorld.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/Misc/HelloWorld.java rename to sootup.callgraph/src/test/resources/callgraph/Misc/source/HelloWorld.java diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/RecursiveCall.java b/sootup.callgraph/src/test/resources/callgraph/Misc/source/RecursiveCall.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/Misc/RecursiveCall.java rename to sootup.callgraph/src/test/resources/callgraph/Misc/source/RecursiveCall.java diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/RecursiveRevisitedMethod.java b/sootup.callgraph/src/test/resources/callgraph/Misc/source/RecursiveRevisitedMethod.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/Misc/RecursiveRevisitedMethod.java rename to sootup.callgraph/src/test/resources/callgraph/Misc/source/RecursiveRevisitedMethod.java diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/RevisitedMethod.java b/sootup.callgraph/src/test/resources/callgraph/Misc/source/RevisitedMethod.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/Misc/RevisitedMethod.java rename to sootup.callgraph/src/test/resources/callgraph/Misc/source/RevisitedMethod.java diff --git a/sootup.callgraph/src/test/resources/callgraph/Misc/SingleMethod.java b/sootup.callgraph/src/test/resources/callgraph/Misc/source/SingleMethod.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/Misc/SingleMethod.java rename to sootup.callgraph/src/test/resources/callgraph/Misc/source/SingleMethod.java diff --git a/sootup.callgraph/src/test/resources/callgraph/NoMainMethod/Example1.java b/sootup.callgraph/src/test/resources/callgraph/NoMainMethod/source/Example1.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/NoMainMethod/Example1.java rename to sootup.callgraph/src/test/resources/callgraph/NoMainMethod/source/Example1.java diff --git a/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC1.java b/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC1.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC1.java rename to sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC1.java diff --git a/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC2.java b/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC2.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC2.java rename to sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC2.java diff --git a/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC3.java b/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC3.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC3.java rename to sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC3.java diff --git a/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC4.java b/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC4.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC4.java rename to sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC4.java diff --git a/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC5.java b/sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC5.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/NVC5.java rename to sootup.callgraph/src/test/resources/callgraph/NonVirtualCall/source/NVC5.java diff --git a/sootup.callgraph/src/test/resources/callgraph/RTA/binary/ClinitInstantiateClasses.java b/sootup.callgraph/src/test/resources/callgraph/RTA/binary/ClinitInstantiateClasses.java new file mode 100644 index 00000000000..b83a41e4fad --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/RTA/binary/ClinitInstantiateClasses.java @@ -0,0 +1,20 @@ +// ccm/Class.java +package cic; + +class Class { + + static SuperClass sc= new SubClass(); + public static void main(String[] args){ + sc.method(); + } +} + +class SuperClass { + public void method() { + } +} + +class SubClass extends SuperClass { + public void method() { + } +} diff --git a/sootup.callgraph/src/test/resources/callgraph/RTA/binary/LaterInstantiatedClass.java b/sootup.callgraph/src/test/resources/callgraph/RTA/binary/LaterInstantiatedClass.java new file mode 100644 index 00000000000..5b159982ae2 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/RTA/binary/LaterInstantiatedClass.java @@ -0,0 +1,17 @@ +// ccm/Class.java +package lic; + +class Class { + + public static void main(String[] args){ + later().method(); + } + public static InstantiatedClass later(){ + return new InstantiatedClass(); + } +} + +class InstantiatedClass { + public void method() { + } +} diff --git a/sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall1.java b/sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall1.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall1.java rename to sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall1.java diff --git a/sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall2.java b/sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall2.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall2.java rename to sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall2.java diff --git a/sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall3.java b/sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall3.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall3.java rename to sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall3.java diff --git a/sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall4.java b/sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall4.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/VirtualCall/VirtualCall4.java rename to sootup.callgraph/src/test/resources/callgraph/VirtualCall/source/VirtualCall4.java diff --git a/sootup.callgraph/src/test/resources/callgraph/jimple/A.jimple b/sootup.callgraph/src/test/resources/callgraph/jimple/A.jimple deleted file mode 100644 index 815b1e4b005..00000000000 --- a/sootup.callgraph/src/test/resources/callgraph/jimple/A.jimple +++ /dev/null @@ -1,15 +0,0 @@ -abstract synchronized class A extends java.lang.Object -{ - abstract void a(); - void () - { - unknown l0; - - l0 := @this: A; - - specialinvoke l0.()>(); - - return; - } -} - diff --git a/sootup.core/pom.xml b/sootup.core/pom.xml index 03c355c4b65..925ecb3e244 100644 --- a/sootup.core/pom.xml +++ b/sootup.core/pom.xml @@ -16,6 +16,6 @@ org.soot-oss sootup - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT diff --git a/sootup.core/src/main/java/sootup/core/Language.java b/sootup.core/src/main/java/sootup/core/Language.java index 50c588d8708..62dbf1204af 100644 --- a/sootup.core/src/main/java/sootup/core/Language.java +++ b/sootup.core/src/main/java/sootup/core/Language.java @@ -27,9 +27,15 @@ * @author Markus Schmidt */ public abstract class Language { + public abstract String getName(); public abstract int getVersion(); public abstract IdentifierFactory getIdentifierFactory(); + + @Override + public String toString() { + return getName() + " " + getVersion(); + } } diff --git a/sootup.core/src/main/java/sootup/core/Project.java b/sootup.core/src/main/java/sootup/core/Project.java index ea24a5b5ada..a771fd45e5b 100644 --- a/sootup.core/src/main/java/sootup/core/Project.java +++ b/sootup.core/src/main/java/sootup/core/Project.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.function.Function; import javax.annotation.Nonnull; +import sootup.core.cache.provider.ClassCacheProvider; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.inputlocation.ClassLoadingOptions; import sootup.core.model.SootClass; @@ -42,8 +43,6 @@ */ public abstract class Project, V extends View>> { - @Nonnull private final IdentifierFactory identifierFactory; - @Nonnull private final List> inputLocations; @Nonnull private final SourceTypeSpecifier sourceTypeSpecifier; @Nonnull private final Language language; @@ -58,11 +57,7 @@ public Project( @Nonnull Language language, @Nonnull AnalysisInputLocation inputLocation, @Nonnull SourceTypeSpecifier sourceTypeSpecifier) { - this( - language, - Collections.singletonList(inputLocation), - language.getIdentifierFactory(), - sourceTypeSpecifier); + this(language, Collections.singletonList(inputLocation), sourceTypeSpecifier); } /** @@ -70,13 +65,11 @@ public Project( * * @param language the language * @param inputLocations the input locations - * @param identifierFactory the identifier factory * @param sourceTypeSpecifier the source type specifier */ public Project( @Nonnull Language language, @Nonnull List> inputLocations, - @Nonnull IdentifierFactory identifierFactory, @Nonnull SourceTypeSpecifier sourceTypeSpecifier) { this.language = language; List> unmodifiableInputLocations = @@ -84,7 +77,6 @@ public Project( this.sourceTypeSpecifier = sourceTypeSpecifier; this.inputLocations = unmodifiableInputLocations; - this.identifierFactory = identifierFactory; } public void validate() { @@ -105,7 +97,7 @@ public List> getInputLocations() { @Nonnull public IdentifierFactory getIdentifierFactory() { - return this.identifierFactory; + return language.getIdentifierFactory(); } @Nonnull @@ -119,22 +111,29 @@ public Language getLanguage() { } /** - * Create a complete view from everything in all provided input locations. + * Create a view with a default cache. * - * @return A complete view on the provided code + * @return A view on the provided code */ @Nonnull - public abstract V createFullView(); + public abstract V createView(); /** - * Creates an on-demand View that uses the default {@link ClassLoadingOptions} of each frontend. + * Create a view with a provided cache. + * + * @return A view on the provided code */ @Nonnull - public abstract V createOnDemandView(); + public abstract V createView(@Nonnull ClassCacheProvider cacheProvider); + + /** + * Creates an on-demand View that uses the default {@link ClassLoadingOptions} of each frontend. + */ - /** Creates an on-demand View with custom {@link ClassLoadingOptions}. */ + /** Creates a View with custom {@link ClassLoadingOptions}. */ @Nonnull - public abstract V createOnDemandView( + public abstract V createView( + @Nonnull ClassCacheProvider cacheProvider, @Nonnull Function, ClassLoadingOptions> classLoadingOptionsSpecifier); diff --git a/sootup.core/src/main/java/sootup/core/cache/ClassCache.java b/sootup.core/src/main/java/sootup/core/cache/ClassCache.java new file mode 100644 index 00000000000..0c8c6a14aa0 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/ClassCache.java @@ -0,0 +1,21 @@ +package sootup.core.cache; + +import java.util.Collection; +import javax.annotation.Nonnull; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; + +/** Interface for different caching strategies of resolved classes. */ +public interface ClassCache> { + + S getClass(ClassType classType); + + @Nonnull + Collection getClasses(); + + void putClass(ClassType classType, S sootClass); + + boolean hasClass(ClassType classType); + + int size(); +} diff --git a/sootup.core/src/main/java/sootup/core/cache/FullCache.java b/sootup.core/src/main/java/sootup/core/cache/FullCache.java new file mode 100644 index 00000000000..517707ad097 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/FullCache.java @@ -0,0 +1,40 @@ +package sootup.core.cache; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nonnull; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; + +/** Cache that stores any class that has been resolved. */ +public class FullCache> implements ClassCache { + + protected final Map cache = new HashMap<>(); + + @Override + public synchronized S getClass(ClassType classType) { + return cache.get(classType); + } + + @Nonnull + @Override + public synchronized Collection getClasses() { + return cache.values(); + } + + @Override + public void putClass(ClassType classType, S sootClass) { + cache.putIfAbsent(classType, sootClass); + } + + @Override + public boolean hasClass(ClassType classType) { + return cache.containsKey(classType); + } + + @Override + public int size() { + return cache.size(); + } +} diff --git a/sootup.core/src/main/java/sootup/core/cache/LRUCache.java b/sootup.core/src/main/java/sootup/core/cache/LRUCache.java new file mode 100644 index 00000000000..52decf4eb12 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/LRUCache.java @@ -0,0 +1,58 @@ +package sootup.core.cache; + +import java.util.*; +import javax.annotation.Nonnull; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; + +/** + * Cache that implements a least recently used strategy. If the amount of stored classes exceeds a + * specified amount, the lest recently used class will be overwritten. + */ +public class LRUCache> implements ClassCache { + private final int cacheSize; + private final Map cache = new HashMap<>(); + private final LinkedList accessOrder = new LinkedList<>(); + + public LRUCache(int cacheSize) { + this.cacheSize = cacheSize; + } + + @Override + public synchronized S getClass(ClassType classType) { + S sootClass = cache.get(classType); + if (sootClass != null) { + accessOrder.remove(classType); + accessOrder.addFirst(classType); + } + + return sootClass; + } + + @Nonnull + @Override + public synchronized Collection getClasses() { + return cache.values(); + } + + @Override + public void putClass(ClassType classType, S sootClass) { + if (accessOrder.size() >= cacheSize) { + ClassType leastAccessed = accessOrder.removeLast(); + cache.remove(leastAccessed); + } + + accessOrder.addFirst(classType); + cache.putIfAbsent(classType, sootClass); + } + + @Override + public boolean hasClass(ClassType classType) { + return cache.containsKey(classType); + } + + @Override + public int size() { + return cache.size(); + } +} diff --git a/sootup.core/src/main/java/sootup/core/cache/MutableClassCache.java b/sootup.core/src/main/java/sootup/core/cache/MutableClassCache.java new file mode 100644 index 00000000000..e51bfab492e --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/MutableClassCache.java @@ -0,0 +1,17 @@ +package sootup.core.cache; + +import javax.annotation.Nonnull; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; + +/** Interface for caches which are mutable and allow classes to be removed from. */ +public interface MutableClassCache> extends ClassCache { + S removeClass(ClassType classType); + + default S replaceClass( + @Nonnull ClassType oldType, @Nonnull ClassType newType, @Nonnull S newClass) { + S oldClass = removeClass(oldType); + putClass(newType, newClass); + return oldClass; + } +} diff --git a/sootup.core/src/main/java/sootup/core/cache/MutableFullCache.java b/sootup.core/src/main/java/sootup/core/cache/MutableFullCache.java new file mode 100644 index 00000000000..cf45f656eaf --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/MutableFullCache.java @@ -0,0 +1,21 @@ +package sootup.core.cache; + +import javax.annotation.Nonnull; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; + +/** + * Mutable version of the {@link FullCache} that additionally allows for a removal of cached + * classes. + */ +public class MutableFullCache> extends FullCache + implements MutableClassCache { + + @Override + public S removeClass(@Nonnull ClassType classType) { + if (this.hasClass(classType)) { + return cache.remove(classType); + } + return null; + } +} diff --git a/sootup.core/src/main/java/sootup/core/cache/provider/ClassCacheProvider.java b/sootup.core/src/main/java/sootup/core/cache/provider/ClassCacheProvider.java new file mode 100644 index 00000000000..a053c6b2c03 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/provider/ClassCacheProvider.java @@ -0,0 +1,11 @@ +package sootup.core.cache.provider; + +import sootup.core.cache.ClassCache; +import sootup.core.model.SootClass; + +/** Interface for cache providers. */ +public interface ClassCacheProvider> { + + /** Create and return a new cache object. */ + ClassCache createCache(); +} diff --git a/sootup.core/src/main/java/sootup/core/cache/provider/FullCacheProvider.java b/sootup.core/src/main/java/sootup/core/cache/provider/FullCacheProvider.java new file mode 100644 index 00000000000..e2b344f4381 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/provider/FullCacheProvider.java @@ -0,0 +1,14 @@ +package sootup.core.cache.provider; + +import sootup.core.cache.ClassCache; +import sootup.core.cache.FullCache; +import sootup.core.model.SootClass; + +/** Provides a new {@link FullCache} object. */ +public class FullCacheProvider> implements ClassCacheProvider { + + @Override + public ClassCache createCache() { + return new FullCache(); + } +} diff --git a/sootup.core/src/main/java/sootup/core/cache/provider/LRUCacheProvider.java b/sootup.core/src/main/java/sootup/core/cache/provider/LRUCacheProvider.java new file mode 100644 index 00000000000..0e14ac01d5d --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/provider/LRUCacheProvider.java @@ -0,0 +1,26 @@ +package sootup.core.cache.provider; + +import sootup.core.cache.ClassCache; +import sootup.core.cache.LRUCache; +import sootup.core.model.SootClass; + +/** Provides a new {@link LRUCache} object. */ +public class LRUCacheProvider> implements ClassCacheProvider { + private final int cacheSize; + + /** Create a new LRUCacheProvider that returns a {@link LRUCache} with a default size of 100. */ + public LRUCacheProvider() { + this(100); + } + + /** Create a new LRUCacheProvider that returns a {@link LRUCache} with the specified size. */ + public LRUCacheProvider(int cacheSize) { + if (cacheSize < 1) throw new IllegalArgumentException("Cache size has to be at least 1"); + this.cacheSize = cacheSize; + } + + @Override + public ClassCache createCache() { + return new LRUCache<>(cacheSize); + } +} diff --git a/sootup.core/src/main/java/sootup/core/cache/provider/MutableFullCacheProvider.java b/sootup.core/src/main/java/sootup/core/cache/provider/MutableFullCacheProvider.java new file mode 100644 index 00000000000..c8b11a88f30 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/cache/provider/MutableFullCacheProvider.java @@ -0,0 +1,14 @@ +package sootup.core.cache.provider; + +import sootup.core.cache.ClassCache; +import sootup.core.cache.MutableFullCache; +import sootup.core.model.SootClass; + +/** Provides a new {@link MutableFullCache} object. */ +public class MutableFullCacheProvider> implements ClassCacheProvider { + + @Override + public ClassCache createCache() { + return new MutableFullCache<>(); + } +} diff --git a/sootup.core/src/main/java/sootup/core/frontend/BodySource.java b/sootup.core/src/main/java/sootup/core/frontend/BodySource.java index 21d33bc3968..914e186335f 100644 --- a/sootup.core/src/main/java/sootup/core/frontend/BodySource.java +++ b/sootup.core/src/main/java/sootup/core/frontend/BodySource.java @@ -24,7 +24,7 @@ import java.io.IOException; import javax.annotation.Nonnull; import sootup.core.model.Body; -import sootup.core.model.Modifier; +import sootup.core.model.MethodModifier; import sootup.core.signatures.MethodSignature; /** @@ -40,7 +40,8 @@ public interface BodySource { * body accordingly. */ @Nonnull - Body resolveBody(@Nonnull Iterable modifiers) throws ResolveException, IOException; + Body resolveBody(@Nonnull Iterable modifiers) + throws ResolveException, IOException; /** @return returns the default value of the Annotation for this method */ Object resolveAnnotationsDefaultValue(); diff --git a/sootup.core/src/main/java/sootup/core/frontend/ClassProvider.java b/sootup.core/src/main/java/sootup/core/frontend/ClassProvider.java index 60f352d9be2..99a67c278f0 100644 --- a/sootup.core/src/main/java/sootup/core/frontend/ClassProvider.java +++ b/sootup.core/src/main/java/sootup/core/frontend/ClassProvider.java @@ -22,9 +22,9 @@ */ import java.nio.file.Path; +import java.util.Optional; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.inputlocation.FileType; -import sootup.core.model.AbstractClass; import sootup.core.model.SootClass; import sootup.core.types.ClassType; @@ -34,9 +34,9 @@ * * @author Manuel Benz */ -public interface ClassProvider>> { +public interface ClassProvider>> { - AbstractClassSource createClassSource( + Optional> createClassSource( AnalysisInputLocation> inputLocation, Path sourcePath, ClassType classSignature); diff --git a/sootup.core/src/main/java/sootup/core/frontend/OverridingBodySource.java b/sootup.core/src/main/java/sootup/core/frontend/OverridingBodySource.java index 6e6b5dc2026..3dd69a97aaa 100644 --- a/sootup.core/src/main/java/sootup/core/frontend/OverridingBodySource.java +++ b/sootup.core/src/main/java/sootup/core/frontend/OverridingBodySource.java @@ -24,7 +24,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import sootup.core.model.Body; -import sootup.core.model.Modifier; +import sootup.core.model.MethodModifier; import sootup.core.signatures.MethodSignature; /** @author Hasitha Rajapakse */ @@ -68,7 +68,7 @@ public OverridingBodySource(@Nonnull MethodSignature methodSignature, @Nonnull B @Nonnull @Override - public Body resolveBody(@Nonnull Iterable modifiers) throws IOException { + public Body resolveBody(@Nonnull Iterable modifiers) throws IOException { return body != null ? body : delegate.resolveBody(modifiers); } diff --git a/sootup.core/src/main/java/sootup/core/frontend/OverridingClassSource.java b/sootup.core/src/main/java/sootup/core/frontend/OverridingClassSource.java index 1dc98c25676..84fbe45cc3d 100644 --- a/sootup.core/src/main/java/sootup/core/frontend/OverridingClassSource.java +++ b/sootup.core/src/main/java/sootup/core/frontend/OverridingClassSource.java @@ -53,7 +53,7 @@ public class OverridingClassSource extends SootClassSource { @Nullable private final Collection overriddenSootMethods; @Nullable private final Collection overriddenSootFields; - @Nullable private final Set overriddenModifiers; + @Nullable private final Set overriddenModifiers; @Nullable private final Set overriddenInterfaces; @Nullable private final Optional overriddenSuperclass; @Nullable private final Optional overriddenOuterClass; @@ -76,7 +76,7 @@ public OverridingClassSource(@Nonnull SootClassSource delegate) { private OverridingClassSource( @Nullable Collection overriddenSootMethods, @Nullable Collection overriddenSootFields, - @Nullable Set overriddenModifiers, + @Nullable Set overriddenModifiers, @Nullable Set overriddenInterfaces, @Nullable Optional overriddenSuperclass, @Nullable Optional overriddenOuterClass, @@ -97,7 +97,7 @@ private OverridingClassSource( public OverridingClassSource( @Nonnull Set sootMethods, @Nonnull Set sootFields, - @Nonnull EnumSet modifiers, + @Nonnull EnumSet modifiers, @Nonnull Set interfaces, @Nonnull ClassType superClass, @Nonnull ClassType outerClass, @@ -131,7 +131,7 @@ public Collection resolveFields() throws ResolveException { @Nonnull @Override - public Set resolveModifiers() { + public Set resolveModifiers() { return overriddenModifiers != null ? overriddenModifiers : delegate.resolveModifiers(); } @@ -261,7 +261,7 @@ public OverridingClassSource withFields(@Nonnull Collection overridde } @Nonnull - public OverridingClassSource withModifiers(@Nonnull Set overriddenModifiers) { + public OverridingClassSource withModifiers(@Nonnull Set overriddenModifiers) { return new OverridingClassSource( overriddenSootMethods, overriddenSootFields, diff --git a/sootup.core/src/main/java/sootup/core/frontend/SootClassSource.java b/sootup.core/src/main/java/sootup/core/frontend/SootClassSource.java index 426e9bc057d..087161feca0 100644 --- a/sootup.core/src/main/java/sootup/core/frontend/SootClassSource.java +++ b/sootup.core/src/main/java/sootup/core/frontend/SootClassSource.java @@ -28,7 +28,7 @@ import java.util.Set; import javax.annotation.Nonnull; import sootup.core.inputlocation.AnalysisInputLocation; -import sootup.core.model.Modifier; +import sootup.core.model.ClassModifier; import sootup.core.model.Position; import sootup.core.model.SootClass; import sootup.core.model.SootField; @@ -78,7 +78,7 @@ protected SootClassSource(SootClassSource delegate) { /** Reads from the source to retrieve its modifiers. This may be an expensive operation. */ @Nonnull - public abstract Set resolveModifiers(); + public abstract Set resolveModifiers(); /** * Reads from the source to retrieve its directly implemented interfaces. This may be an expensive diff --git a/sootup.core/src/main/java/sootup/core/graph/BackwardsStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/BackwardsStmtGraph.java index 60654dc1ff1..2cf8a7bca2f 100644 --- a/sootup.core/src/main/java/sootup/core/graph/BackwardsStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/BackwardsStmtGraph.java @@ -45,8 +45,8 @@ public List getStartingStmts() { @Nonnull @Override - public Collection nodes() { - return Collections.unmodifiableCollection(backingGraph.nodes()); + public Collection getNodes() { + return Collections.unmodifiableCollection(backingGraph.getNodes()); } @Override diff --git a/sootup.core/src/main/java/sootup/core/graph/BasicBlock.java b/sootup.core/src/main/java/sootup/core/graph/BasicBlock.java index 3cf86535dbc..b27d188b2c3 100644 --- a/sootup.core/src/main/java/sootup/core/graph/BasicBlock.java +++ b/sootup.core/src/main/java/sootup/core/graph/BasicBlock.java @@ -14,7 +14,7 @@ public interface BasicBlock> { @Nonnull List getSuccessors(); - List getExceptionalPredecessors(); + Map getExceptionalPredecessors(); @Nonnull Map getExceptionalSuccessors(); diff --git a/sootup.core/src/main/java/sootup/core/graph/ForwardingBasicBlock.java b/sootup.core/src/main/java/sootup/core/graph/ForwardingBasicBlock.java index bd061431063..9c6a00c4778 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ForwardingBasicBlock.java +++ b/sootup.core/src/main/java/sootup/core/graph/ForwardingBasicBlock.java @@ -30,7 +30,7 @@ */ public class ForwardingBasicBlock> implements BasicBlock { - private final V backingBlock; + @Nonnull private final V backingBlock; ForwardingBasicBlock(@Nonnull V block) { backingBlock = block; @@ -48,8 +48,9 @@ public List getSuccessors() { return backingBlock.getSuccessors(); } + @Nonnull @Override - public List getExceptionalPredecessors() { + public Map getExceptionalPredecessors() { return backingBlock.getExceptionalPredecessors(); } diff --git a/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java index b0ac3dedcd0..e23f7f35f6b 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java @@ -59,8 +59,8 @@ public BasicBlock getBlockOf(@Nonnull Stmt stmt) { @Nonnull @Override - public Collection nodes() { - return backingGraph.nodes(); + public Collection getNodes() { + return backingGraph.getNodes(); } @Nonnull diff --git a/sootup.core/src/main/java/sootup/core/graph/ImmutableBasicBlock.java b/sootup.core/src/main/java/sootup/core/graph/ImmutableBasicBlock.java index eab66389d8e..2cb3c57a337 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ImmutableBasicBlock.java +++ b/sootup.core/src/main/java/sootup/core/graph/ImmutableBasicBlock.java @@ -22,7 +22,8 @@ public List getSuccessors() { } @Override - public List getExceptionalPredecessors() { + @Nonnull + public Map getExceptionalPredecessors() { throw new UnsupportedOperationException("not implemented"); } diff --git a/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java index 3aba9e7b697..7354ca426d8 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java @@ -46,7 +46,7 @@ public BasicBlock getBlockOf(@Nonnull Stmt stmt) { @Nonnull @Override - public List nodes() { + public List getNodes() { int size = 0; for (ImmutableBasicBlock block : blocks) { size += block.getStmtCount(); @@ -178,8 +178,9 @@ public List getSuccessors() { } @Override - public List getExceptionalPredecessors() { - return null; + @Nonnull + public Map getExceptionalPredecessors() { + throw new UnsupportedOperationException("not implemented yet"); } @Nonnull diff --git a/sootup.core/src/main/java/sootup/core/graph/MutableBasicBlock.java b/sootup.core/src/main/java/sootup/core/graph/MutableBasicBlock.java index 894b4afc2f3..3a06ccdab49 100644 --- a/sootup.core/src/main/java/sootup/core/graph/MutableBasicBlock.java +++ b/sootup.core/src/main/java/sootup/core/graph/MutableBasicBlock.java @@ -128,8 +128,20 @@ public List getSuccessors() { } @Override - public List getExceptionalPredecessors() { - throw new UnsupportedOperationException("not implemented."); + public Map getExceptionalPredecessors() { + final HashMap excPreds = new HashMap<>(); + getPredecessors() + .forEach( + (pb) -> { + pb.getExceptionalSuccessors() + .forEach( + (exceptionType, handlerBlock) -> { + if (this == handlerBlock) { + excPreds.put(exceptionType, pb); + } + }); + }); + return excPreds; } @Nonnull diff --git a/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java index c1f1dc9d23f..285170c3033 100644 --- a/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java @@ -814,10 +814,10 @@ public void validateBlocks() { } /** + * @param beforeStmt the Stmt which succeeds the inserted Stmts (its NOT preceeding as this + * simplifies the handling of BranchingStmts) * @param stmts can only allow fallsthrough Stmts except for the last Stmt in the List there is a * single BranchingStmt allowed! - * @param beforeStmt the Stmt which succeeds the inserted Stmts (its not preceeding as this - * simplifies the handling of BranchingStmts) */ public void insertBefore( @Nonnull Stmt beforeStmt, @@ -827,6 +827,10 @@ public void insertBefore( return; } final MutableBasicBlock block = stmtToBlock.get(beforeStmt); + if (block == null) { + throw new IllegalArgumentException( + "beforeStmt '" + beforeStmt + "' does not exists in this StmtGraph."); + } if (block.getHead() == beforeStmt) { // insert before a Stmt that is at the beginning of a Block? -> new block, reconnect, try to // merge blocks - performance hint: if exceptionMap equals the current blocks exception and @@ -1071,7 +1075,11 @@ public BasicBlock getStartingStmtBlock() { @Override @Nullable public BasicBlock getBlockOf(@Nonnull Stmt stmt) { - return new ForwardingBasicBlock<>(stmtToBlock.get(stmt)); + final MutableBasicBlock mutableBasicBlock = stmtToBlock.get(stmt); + if (mutableBasicBlock == null) { + throw new IllegalArgumentException("stmt '" + stmt + "' does not exist in this StmtGraph!"); + } + return new ForwardingBasicBlock<>(mutableBasicBlock); } @Nonnull @@ -1093,7 +1101,7 @@ public void setStartingStmt(@Nonnull Stmt startingStmt) { @Nonnull @Override - public Set nodes() { + public Set getNodes() { return stmtToBlock.keySet(); } diff --git a/sootup.core/src/main/java/sootup/core/graph/MutableStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/MutableStmtGraph.java index 27911c0fad5..278b27a6143 100644 --- a/sootup.core/src/main/java/sootup/core/graph/MutableStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/MutableStmtGraph.java @@ -20,6 +20,7 @@ * . * #L% */ + import java.util.*; import javax.annotation.Nonnull; import sootup.core.jimple.common.stmt.Stmt; @@ -37,21 +38,27 @@ public abstract class MutableStmtGraph extends StmtGraph { public abstract void setStartingStmt(@Nonnull Stmt firstStmt); - public void addNode(@Nonnull Stmt node) { - addNode(node, Collections.emptyMap()); + /** inserts a "stmt" into the StmtGraph */ + public void addNode(@Nonnull Stmt stmt) { + addNode(stmt, Collections.emptyMap()); } - public abstract void addNode(@Nonnull Stmt node, @Nonnull Map traps); + /** inserts a "stmt" with exceptional flows "traps" into the StmtGraph */ + public abstract void addNode(@Nonnull Stmt stmt, @Nonnull Map traps); - // maybe refactor addBlock into MutableBlockStmtGraph.. + /** creates a whole BasicBlock with the details from the parameters */ public abstract void addBlock(@Nonnull List stmts, @Nonnull Map traps); + /** + * creates a whole BasicBlock which contains the sequence of (n-1)*fallsthrough()-stmt + optional + * a non-fallsthrough() stmt at the end of the list + */ public void addBlock(@Nonnull List stmts) { addBlock(stmts, Collections.emptyMap()); } /** - * Modification of nodes (without manipulating any flows; possible assigned exceptional flows stay + * Modification of stmts (without manipulating any flows; possible assigned exceptional flows stay * the same as well) */ public abstract void replaceNode(@Nonnull Stmt oldStmt, @Nonnull Stmt newStmt); @@ -61,28 +68,47 @@ public abstract void insertBefore( @Nonnull List stmts, @Nonnull Map exceptionMap); - public void insertBefore(@Nonnull Stmt beforeStmt, @Nonnull Stmt stmt) { - insertBefore(beforeStmt, Collections.singletonList(stmt), Collections.emptyMap()); + /** + * inserts the "newStmt" before the position of "beforeStmt" i.e. + * newStmt.successors().contains(beforeStmt) will be true + */ + public void insertBefore(@Nonnull Stmt beforeStmt, @Nonnull Stmt newStmt) { + insertBefore(beforeStmt, Collections.singletonList(newStmt), Collections.emptyMap()); } - public abstract void removeNode(@Nonnull Stmt node); + /** removes "stmt" from the StmtGraph */ + public abstract void removeNode(@Nonnull Stmt stmt); - /** Modifications of unexceptional flows */ + /** + * Modifications of unexceptional flows + * + *

Adds a flow "from" to "to". if at least one of the parameter Stmts is not already in the + * StmtGraph it will be added. if "to" needs to be added to the StmtGraph i.e. "to" is not already + * in the StmtGraph the method assumes "to" has the same exceptional flows as "from". + */ public abstract void putEdge(@Nonnull Stmt from, @Nonnull Stmt to); + /** replaces the current outgoing flows of "from" to "targets" */ public abstract void setEdges(@Nonnull Stmt from, @Nonnull List targets); + /** replaces the current outgoing flows of "from" to each target of "targets" */ public void setEdges(@Nonnull Stmt from, @Nonnull Stmt... targets) { setEdges(from, Arrays.asList(targets)); } + /** removes the current outgoing flows of "from" to "targets" */ public abstract void removeEdge(@Nonnull Stmt from, @Nonnull Stmt to); - /** Modifications of exceptional flows */ - public abstract void clearExceptionalEdges(@Nonnull Stmt node); + /** Modifications of exceptional flows removes all exceptional flows from "stmt" */ + public abstract void clearExceptionalEdges(@Nonnull Stmt stmt); + /** + * Adds an exceptional flow with the type "exception" to a "stmt" which will reach + * "traphandlerStmt" + */ public abstract void addExceptionalEdge( @Nonnull Stmt stmt, @Nonnull ClassType exception, @Nonnull Stmt traphandlerStmt); - public abstract void removeExceptionalEdge(@Nonnull Stmt node, @Nonnull ClassType exception); + /** removes an exceptional flow of the type "exception" flow from "stmt" */ + public abstract void removeExceptionalEdge(@Nonnull Stmt stmt, @Nonnull ClassType exception); } diff --git a/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java index 9a8e0024657..81cbd28b479 100644 --- a/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java @@ -69,7 +69,7 @@ public abstract class StmtGraph> implements Iterable nodes(); + public abstract Collection getNodes(); public List getStmts() { final ArrayList res = new ArrayList<>(); @@ -153,7 +153,7 @@ public int degree(@Nonnull Stmt node) { */ @Nonnull public List getTails() { - return nodes().stream() + return getNodes().stream() .filter(stmt -> stmt.getExpectedSuccessorCount() == 0) .collect(Collectors.toList()); } @@ -176,7 +176,7 @@ public Collection getEntrypoints() { public void validateStmtConnectionsInGraph() { try { - for (Stmt stmt : nodes()) { + for (Stmt stmt : getNodes()) { final List successors = successors(stmt); final int successorCount = successors.size(); @@ -322,8 +322,8 @@ public boolean equals(Object o) { return false; } - Collection nodes = nodes(); - final Collection otherNodes = otherGraph.nodes(); + Collection nodes = getNodes(); + final Collection otherNodes = otherGraph.getNodes(); if (nodes.size() != otherNodes.size()) { return false; } @@ -592,10 +592,19 @@ private void updateFollowingBlocks(BasicBlock currentBlock) { while (true) { final List> itPreds = leaderOfFallsthroughBlocks.getPredecessors(); - if (itPreds.size() != 1) { + + BasicBlock finalLeaderOfFallsthroughBlocks = leaderOfFallsthroughBlocks; + final Optional> fallsthroughPredOpt = + itPreds.stream() + .filter( + b -> + b.getTail().fallsThrough() + && b.getSuccessors().get(0) == finalLeaderOfFallsthroughBlocks) + .findAny(); + if (!fallsthroughPredOpt.isPresent()) { break; } - BasicBlock predecessorBlock = itPreds.get(0); + BasicBlock predecessorBlock = fallsthroughPredOpt.get(); if (predecessorBlock.getTail().fallsThrough() && predecessorBlock.getSuccessors().get(0) == leaderOfFallsthroughBlocks) { leaderOfFallsthroughBlocks = predecessorBlock; @@ -612,7 +621,7 @@ private void updateFollowingBlocks(BasicBlock currentBlock) { // remember branching successors if (tailStmt instanceof JGotoStmt) { if (isReturnBlock) { - nestedBlocks.removeFirstOccurrence(currentBlock.getHead()); + nestedBlocks.removeFirstOccurrence(currentBlock); otherBlocks.addLast(leaderOfFallsthroughBlocks); } else { otherBlocks.addFirst(leaderOfFallsthroughBlocks); @@ -679,7 +688,7 @@ public boolean hasNext() { @Nonnull public Collection getLabeledStmts() { Set stmtList = new HashSet<>(); - for (Stmt stmt : nodes()) { + for (Stmt stmt : getNodes()) { if (stmt instanceof BranchingStmt) { if (stmt instanceof JIfStmt) { // [ms] bounds are validated in Body diff --git a/sootup.core/src/main/java/sootup/core/graph/iterator/StmtGraphBlockIterator.java b/sootup.core/src/main/java/sootup/core/graph/StmtGraphBlockIterator.java similarity index 96% rename from sootup.core/src/main/java/sootup/core/graph/iterator/StmtGraphBlockIterator.java rename to sootup.core/src/main/java/sootup/core/graph/StmtGraphBlockIterator.java index af9d5e458a3..ca5362e39a7 100644 --- a/sootup.core/src/main/java/sootup/core/graph/iterator/StmtGraphBlockIterator.java +++ b/sootup.core/src/main/java/sootup/core/graph/StmtGraphBlockIterator.java @@ -1,4 +1,4 @@ -package sootup.core.graph.iterator; +package sootup.core.graph; /*- * #%L * Soot - a J*va Optimization Framework @@ -24,9 +24,7 @@ import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import sootup.core.graph.StmtGraph; import sootup.core.jimple.basic.Trap; -import sootup.core.jimple.common.stmt.*; import sootup.core.jimple.common.stmt.JGotoStmt; import sootup.core.jimple.common.stmt.JReturnStmt; import sootup.core.jimple.common.stmt.JReturnVoidStmt; @@ -58,7 +56,7 @@ public class StmtGraphBlockIterator implements Iterator { public StmtGraphBlockIterator(@Nonnull StmtGraph graph, @Nonnull List traps) { this.graph = graph; - returnedNodes = new HashSet<>(graph.nodes().size(), 1); + returnedNodes = new HashSet<>(graph.getNodes().size(), 1); Stmt startingStmt = graph.getStartingStmt(); if (startingStmt != null) { returnedNodes.add(startingStmt); @@ -180,10 +178,10 @@ public Stmt next() { public boolean hasNext() { final boolean hasIteratorMoreElements = cachedNextStmt != null; final int returnedSize = returnedNodes.size(); - final int actualSize = graph.nodes().size(); + final int actualSize = graph.getNodes().size(); if (!hasIteratorMoreElements && returnedSize != actualSize) { String info = - graph.nodes().stream() + graph.getNodes().stream() .filter(n -> !returnedNodes.contains(n)) .collect(Collectors.toList()) .toString(); diff --git a/sootup.core/src/main/java/sootup/core/inputlocation/AnalysisInputLocation.java b/sootup.core/src/main/java/sootup/core/inputlocation/AnalysisInputLocation.java index 665ac0deb6f..8c66380901f 100644 --- a/sootup.core/src/main/java/sootup/core/inputlocation/AnalysisInputLocation.java +++ b/sootup.core/src/main/java/sootup/core/inputlocation/AnalysisInputLocation.java @@ -73,7 +73,5 @@ Optional> getClassSource( * @return returns null as source type */ @Nullable - default SourceType getSourceType() { - return null; - } + SourceType getSourceType(); } diff --git a/sootup.core/src/main/java/sootup/core/inputlocation/ClassLoadingOptions.java b/sootup.core/src/main/java/sootup/core/inputlocation/ClassLoadingOptions.java index 933398388fe..c3512ff1d99 100644 --- a/sootup.core/src/main/java/sootup/core/inputlocation/ClassLoadingOptions.java +++ b/sootup.core/src/main/java/sootup/core/inputlocation/ClassLoadingOptions.java @@ -36,11 +36,6 @@ */ public interface ClassLoadingOptions { - /** To get the stored Value */ - default T getValue(ClassLoadingOptionKey key) { - return null; - } - /** * The interceptors are executed in order on each loaded method body, allowing it to be inspected * and manipulated. diff --git a/sootup.core/src/main/java/sootup/core/inputlocation/EagerInputLocation.java b/sootup.core/src/main/java/sootup/core/inputlocation/EagerInputLocation.java index 6f3e32cd3f3..b73010302ee 100644 --- a/sootup.core/src/main/java/sootup/core/inputlocation/EagerInputLocation.java +++ b/sootup.core/src/main/java/sootup/core/inputlocation/EagerInputLocation.java @@ -30,6 +30,7 @@ import sootup.core.frontend.AbstractClassSource; import sootup.core.frontend.SootClassSource; import sootup.core.model.SootClass; +import sootup.core.model.SourceType; import sootup.core.types.ClassType; import sootup.core.views.View; @@ -41,14 +42,17 @@ public class EagerInputLocation>> implements AnalysisInputLocation { + @Nonnull protected final SourceType sourceType; @Nonnull private final Map> map; /** not useful for retrieval of classes via view. remove inputlocation from sootclass? */ public EagerInputLocation() { - map = Collections.emptyMap(); + this(Collections.emptyMap(), SourceType.Application); } - public EagerInputLocation(@Nonnull Map> map) { + public EagerInputLocation( + @Nonnull Map> map, @Nonnull SourceType sourceType) { + this.sourceType = sourceType; this.map = ImmutableMap.copyOf(map); } @@ -66,6 +70,12 @@ public Collection> getClassSources(@Nullable Vi return map.values(); } + @Nonnull + @Override + public SourceType getSourceType() { + return sourceType; + } + @Override public int hashCode() { return map.hashCode(); diff --git a/sootup.core/src/main/java/sootup/core/inputlocation/FileType.java b/sootup.core/src/main/java/sootup/core/inputlocation/FileType.java index 06e5f3c9852..67fb9267614 100644 --- a/sootup.core/src/main/java/sootup/core/inputlocation/FileType.java +++ b/sootup.core/src/main/java/sootup/core/inputlocation/FileType.java @@ -47,6 +47,11 @@ public enum FileType { this.extension = fileExtension; } + @Nonnull + public String getExtensionWithDot() { + return "." + extension; + } + @Nonnull public String getExtension() { return extension; diff --git a/sootup.core/src/main/java/sootup/core/jimple/Jimple.java b/sootup.core/src/main/java/sootup/core/jimple/Jimple.java index 656f07de92f..35eda4a4ccb 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/Jimple.java +++ b/sootup.core/src/main/java/sootup/core/jimple/Jimple.java @@ -576,7 +576,7 @@ public static JInstanceFieldRef newInstanceFieldRef(Local base, FieldSignature f /** Constructs a ArrayRef(Local, Immediate) grammar chunk. */ public JArrayRef newArrayRef(Local base, Immediate index) { - return new JArrayRef(base, index, getIdentifierFactory()); + return new JArrayRef(base, index); } /** Constructs a CaughtExceptionRef() grammar chunk. */ diff --git a/sootup.core/src/main/java/sootup/core/jimple/basic/FullStmtPositionInfo.java b/sootup.core/src/main/java/sootup/core/jimple/basic/FullStmtPositionInfo.java new file mode 100644 index 00000000000..98dab8e2641 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/jimple/basic/FullStmtPositionInfo.java @@ -0,0 +1,94 @@ +package sootup.core.jimple.basic; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2019-2023 Linghui Luo and others + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import javax.annotation.Nonnull; +import sootup.core.model.Position; +import sootup.core.util.Copyable; + +/** + * This class stores position information stored for a statement. line number + information about + * its operands + * + * @author Linghui Luo, Markus Schmidt + */ +public class FullStmtPositionInfo extends SimpleStmtPositionInfo implements Copyable { + @Nonnull protected final Position[] operandPositions; + + /** + * Create an instance from given statement position and operand positions. + * + * @param stmtPosition the position of the statement + * @param operandPositions the operand positions + */ + public FullStmtPositionInfo( + @Nonnull Position stmtPosition, @Nonnull Position[] operandPositions) { + super(stmtPosition); + this.operandPositions = operandPositions; + } + + /** + * Return the position of the statement. + * + * @return the position of the statement + */ + @Nonnull + public Position getStmtPosition() { + return this.stmtPosition; + } + + /** + * Return the precise position of the given operand in the statement. + * + * @param index the operand index + * @return the position of the given operand + */ + public Position getOperandPosition(int index) { + if (index >= 0 && index < this.operandPositions.length) { + return this.operandPositions[index]; + } else { + return NoPositionInformation.getInstance(); + } + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append(super.toString()); + s.append("operands at: "); + for (int i = 0; i < operandPositions.length; i++) { + s.append(i).append(": ").append(operandPositions[i]).append(" "); + } + return s.toString(); + } + + @Nonnull + public StmtPositionInfo withStmtPosition(@Nonnull Position stmtPosition) { + return new FullStmtPositionInfo(stmtPosition, operandPositions); + } + + @Nonnull + public StmtPositionInfo withOperandPositions(@Nonnull Position[] operandPositions) { + return new FullStmtPositionInfo(stmtPosition, operandPositions); + } +} diff --git a/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java b/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java index 73f6cfe74fd..27874dc900d 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java +++ b/sootup.core/src/main/java/sootup/core/jimple/basic/Local.java @@ -22,11 +22,12 @@ * #L% */ -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; import javax.annotation.Nonnull; +import sootup.core.graph.StmtGraph; import sootup.core.jimple.Jimple; +import sootup.core.jimple.common.stmt.AbstractDefinitionStmt; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.jimple.visitor.Acceptor; import sootup.core.jimple.visitor.ImmediateVisitor; import sootup.core.model.Body; @@ -60,10 +61,13 @@ public Local(@Nonnull String name, @Nonnull Type type, @Nonnull Position positio this.position = position; } - // Can be safely suppressed, JimpleComparator performs this check - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + /** Hint: the naming is just an indicator! */ + public boolean isFieldLocal() { + return getName().charAt(0) != '$'; + } + @Override - public boolean equals(Object o) { + public final boolean equals(Object o) { if (!(o instanceof Local)) { return false; } @@ -71,7 +75,7 @@ public boolean equals(Object o) { } @Override - public int hashCode() { + public final int hashCode() { return Objects.hashCode(name); } @@ -119,6 +123,46 @@ public Position getPosition() { return position; } + public List> getDefsOfLocal(List defs) { + List> localDefs = new ArrayList<>(); + for (Stmt stmt : defs) { + if (stmt instanceof AbstractDefinitionStmt + && ((AbstractDefinitionStmt) stmt).getLeftOp().equals(this)) { + localDefs.add((AbstractDefinitionStmt) stmt); + } + } + return localDefs; + } + + /** + * Get all definition-stmts which define the given local used by the given stmt. + * + * @param graph a stmt graph which contains the given stmts. + * @param stmt a stmt which uses the given local. + */ + public List getDefsForLocalUse(StmtGraph graph, Stmt stmt) { + if (!stmt.getUses().contains(this)) { + throw new RuntimeException(stmt + " doesn't use the local " + this); + } + List defStmts = new ArrayList<>(); + Set visited = new HashSet<>(); + + Deque queue = new ArrayDeque<>(); + queue.add(stmt); + while (!queue.isEmpty()) { + Stmt s = queue.removeFirst(); + if (!visited.contains(s)) { + visited.add(s); + if (s instanceof AbstractDefinitionStmt && s.getDefs().get(0).equivTo(this)) { + defStmts.add(s); + } else { + queue.addAll(graph.predecessors(s)); + } + } + } + return defStmts; + } + @Override public void accept(@Nonnull ImmediateVisitor v) { v.caseLocal(this); diff --git a/sootup.core/src/main/java/sootup/core/jimple/basic/NoPositionInformation.java b/sootup.core/src/main/java/sootup/core/jimple/basic/NoPositionInformation.java index 10604059a80..3735d12d48c 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/basic/NoPositionInformation.java +++ b/sootup.core/src/main/java/sootup/core/jimple/basic/NoPositionInformation.java @@ -22,14 +22,14 @@ * #L% */ -import sootup.core.model.Position; +import sootup.core.model.FullPosition; /** * This convenience class represents the case when there is no position information available. * * @author Linghui Luo */ -public class NoPositionInformation extends Position { +public class NoPositionInformation extends FullPosition { private static final NoPositionInformation INSTANCE = new NoPositionInformation(); @@ -43,6 +43,6 @@ public static NoPositionInformation getInstance() { @Override public String toString() { - return "No position info"; + return "NoPositionInformation"; } } diff --git a/sootup.core/src/main/java/sootup/core/jimple/basic/SimpleStmtPositionInfo.java b/sootup.core/src/main/java/sootup/core/jimple/basic/SimpleStmtPositionInfo.java new file mode 100644 index 00000000000..546cbe7a110 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/jimple/basic/SimpleStmtPositionInfo.java @@ -0,0 +1,64 @@ +package sootup.core.jimple.basic; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2019-2020 Markus Schmidt + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import sootup.core.model.LinePosition; +import sootup.core.model.Position; + +/** + * This class stores position information (the line number + first/last column) stored for a + * statement. + * + * @author Markus Schmidt + */ +public class SimpleStmtPositionInfo extends StmtPositionInfo { + + @Nonnull protected final Position stmtPosition; + + public SimpleStmtPositionInfo(@Nonnull Position stmtPosition) { + this.stmtPosition = stmtPosition; + } + + /** + * Create an instance only from line number, this is usually the case from byte code front-end. + * + * @param lineNumber the line number of the statement. + */ + public SimpleStmtPositionInfo(int lineNumber) { + stmtPosition = new LinePosition(lineNumber); + } + + @Nonnull + @Override + public Position getStmtPosition() { + return stmtPosition; + } + + @Nullable + @Override + public Position getOperandPosition(int index) { + return null; + } +} diff --git a/sootup.core/src/main/java/sootup/core/jimple/basic/StmtPositionInfo.java b/sootup.core/src/main/java/sootup/core/jimple/basic/StmtPositionInfo.java index 9d978feed45..769eb1bdf1b 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/basic/StmtPositionInfo.java +++ b/sootup.core/src/main/java/sootup/core/jimple/basic/StmtPositionInfo.java @@ -4,7 +4,7 @@ * #%L * Soot - a J*va Optimization Framework * %% - * Copyright (C) 2019-2020 Linghui Luo and others + * Copyright (C) 2019-2023 Linghui Luo, Markus Schmidt * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as @@ -23,48 +23,43 @@ */ import javax.annotation.Nonnull; +import javax.annotation.Nullable; import sootup.core.model.Position; -import sootup.core.util.Copyable; /** * This class stores position information stored for a statement. * - * @author Linghui Luo + * @author Linghui Luo, Markus Schmidt */ -// TODO: [ms] please redesign it more memory efficient! -> there are a lot of Stmts without any of -// this information available! -public final class StmtPositionInfo implements Copyable { - private final Position stmtPosition; - private final Position[] operandPositions; +public abstract class StmtPositionInfo { + + protected static final StmtPositionInfo NOPOSITION = + new StmtPositionInfo() { + @Nonnull + @Override + public Position getStmtPosition() { + return NoPositionInformation.getInstance(); + } + + @Override + public Position getOperandPosition(int index) { + return NoPositionInformation.getInstance(); + } + + @Override + public String toString() { + return "No StmtPositionnfo"; + } + }; /** * Create an instance with no position information. * * @return an instance with no position information. */ + @Nonnull public static StmtPositionInfo createNoStmtPositionInfo() { - return new StmtPositionInfo(null, null); - } - - /** - * Create an instance only from line number, this is usually the case from byte code front-end. - * - * @param lineNumber the line number of the statement. - */ - public StmtPositionInfo(int lineNumber) { - this.stmtPosition = new Position(lineNumber, -1, lineNumber, -1); - this.operandPositions = null; - } - - /** - * Create an instance from given statement position and operand positions. - * - * @param stmtPosition the position of the statement - * @param operandPositions the operand positions - */ - public StmtPositionInfo(Position stmtPosition, Position[] operandPositions) { - this.stmtPosition = stmtPosition; - this.operandPositions = operandPositions; + return NOPOSITION; } /** @@ -72,13 +67,8 @@ public StmtPositionInfo(Position stmtPosition, Position[] operandPositions) { * * @return the position of the statement */ - public Position getStmtPosition() { - if (this.stmtPosition != null) { - return this.stmtPosition; - } else { - return NoPositionInformation.getInstance(); - } - } + @Nonnull + public abstract Position getStmtPosition(); /** * Return the precise position of the given operand in the statement. @@ -86,37 +76,13 @@ public Position getStmtPosition() { * @param index the operand index * @return the position of the given operand */ - public Position getOperandPosition(int index) { - if (this.operandPositions != null && index >= 0 && index < this.operandPositions.length) { - return this.operandPositions[index]; - } else { - return NoPositionInformation.getInstance(); - } - } + @Nullable + public abstract Position getOperandPosition(int index); @Override public String toString() { StringBuilder s = new StringBuilder(); - s.append("stmtPosition: ").append(getStmtPosition().toString()).append("\n"); - s.append("operandPositions: "); - if (operandPositions != null) { - s.append("\n"); - for (int i = 0; i < operandPositions.length; i++) { - s.append(i).append(": ").append(operandPositions[i]).append(" "); - } - } else { - s.append("No position info"); - } + s.append("stmt at:").append(getStmtPosition()); return s.toString(); } - - @Nonnull - public StmtPositionInfo withStmtPosition(Position stmtPosition) { - return new StmtPositionInfo(stmtPosition, operandPositions); - } - - @Nonnull - public StmtPositionInfo withOperandPositions(Position[] operandPositions) { - return new StmtPositionInfo(stmtPosition, operandPositions); - } } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/constant/ClassConstant.java b/sootup.core/src/main/java/sootup/core/jimple/common/constant/ClassConstant.java index 3dde9e35457..8cc69a74997 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/constant/ClassConstant.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/constant/ClassConstant.java @@ -58,7 +58,8 @@ public class ClassConstant implements Constant { public ClassConstant(@Nonnull String str, @Nonnull Type type) { if (str.contains(".")) { - throw new RuntimeException("ClassConstants must use class names separated by '/', not '.'!"); + throw new IllegalArgumentException( + "ClassConstants must use class names separated by '/', not '.'!"); } this.value = str; this.type = type; @@ -113,7 +114,7 @@ public ClassConstant(@Nonnull String str, @Nonnull Type type) { public boolean isRefType() { return value.startsWith("L") && value.endsWith(";"); } - // TODO: [ms] code is quite like the one in Asmutil.java ? so we can/shall remove it? + // TODO: [ms] code is quite like the one in Asmutil.java ? so we can/shall refactor it? // /** Returns numDimensions. */ // public Type toSootType() { // int numDimensions = 0; diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java index 2861437759b..71383da7037 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java @@ -43,7 +43,7 @@ public Type getType() { Type op1t = op1.getType(); Type op2t = op2.getType(); - if (PrimitiveType.isIntLikeType(op1t) && PrimitiveType.isIntLikeType(op2t)) { + if (Type.isIntLikeType(op1t) && Type.isIntLikeType(op2t)) { return PrimitiveType.getInt(); } else if (op1t.equals(PrimitiveType.getLong()) || op2t.equals(PrimitiveType.getLong())) { return PrimitiveType.getLong(); diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractIntLongBinopExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractIntLongBinopExpr.java index 5c34e77fa22..b6a04d18df3 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractIntLongBinopExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractIntLongBinopExpr.java @@ -43,7 +43,7 @@ public Type getType() { Type op1t = op1.getType(); Type op2t = op2.getType(); - if (PrimitiveType.isIntLikeType(op1t) && PrimitiveType.isIntLikeType(op2t)) { + if (Type.isIntLikeType(op1t) && Type.isIntLikeType(op2t)) { return PrimitiveType.getInt(); } else if (op1t.equals(PrimitiveType.getLong()) || op2t.equals(PrimitiveType.getLong())) { return PrimitiveType.getLong(); diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JDynamicInvokeExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JDynamicInvokeExpr.java index eb199b40f54..d75729fade0 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JDynamicInvokeExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JDynamicInvokeExpr.java @@ -143,7 +143,8 @@ public void toString(@Nonnull StmtPrinter up) { final MethodSubSignature mSubSig = methodSignature.getSubSignature(); // dont print methodname from methodsubsignature in the usual way - up.literal(" " + Jimple.escape(mSubSig.getName()) + " <" + getNamelessSubSig(mSubSig) + ">("); + up.literal( + " \"" + Jimple.escape(mSubSig.getName()) + "\" <" + getNamelessSubSig(mSubSig) + ">("); argsToPrinter(up); up.literal(") "); diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNegExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNegExpr.java index 2043869d9bc..c10ef2d8c0d 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNegExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNegExpr.java @@ -69,17 +69,18 @@ public void toString(@Nonnull StmtPrinter up) { public Type getType() { Value op = getOp(); - if (op.getType().equals(PrimitiveType.getInt()) - || op.getType().equals(PrimitiveType.getByte()) - || op.getType().equals(PrimitiveType.getShort()) - || op.getType().equals(PrimitiveType.getBoolean()) - || op.getType().equals(PrimitiveType.getChar())) { + // TODO ms: create a TypeVisitor for this -> O(1) + if (op.getType() == PrimitiveType.getInt() + || op.getType() == PrimitiveType.getByte() + || op.getType() == PrimitiveType.getShort() + || op.getType() == PrimitiveType.getBoolean() + || op.getType() == PrimitiveType.getChar()) { return PrimitiveType.getInt(); - } else if (op.getType().equals(PrimitiveType.getLong())) { + } else if (op.getType() == PrimitiveType.getLong()) { return PrimitiveType.getLong(); - } else if (op.getType().equals(PrimitiveType.getDouble())) { + } else if (op.getType() == PrimitiveType.getDouble()) { return PrimitiveType.getDouble(); - } else if (op.getType().equals(PrimitiveType.getFloat())) { + } else if (op.getType() == PrimitiveType.getFloat()) { return PrimitiveType.getFloat(); } else { return UnknownType.getInstance(); diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewExpr.java index 7af5ad946a4..2a8bad17cfb 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewExpr.java @@ -30,7 +30,6 @@ import sootup.core.jimple.basic.Value; import sootup.core.jimple.visitor.ExprVisitor; import sootup.core.types.ClassType; -import sootup.core.types.ReferenceType; import sootup.core.util.Copyable; import sootup.core.util.printer.StmtPrinter; @@ -56,7 +55,7 @@ public int equivHashCode() { @Override public String toString() { - return Jimple.NEW + " " + type.toString(); + return Jimple.NEW + " " + type; } @Override @@ -68,7 +67,7 @@ public void toString(@Nonnull StmtPrinter up) { @Nonnull @Override - public ReferenceType getType() { + public ClassType getType() { return type; } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java index acbea747fe9..1be30ab14ce 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JNewMultiArrayExpr.java @@ -106,7 +106,7 @@ public ArrayType getBaseType() { return baseType; } - public Immediate getSize(@Nonnull int index) { + public Value getSize(@Nonnull int index) { return sizes.get(index); } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShlExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShlExpr.java index e2452930f42..96ecfb5503c 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShlExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShlExpr.java @@ -55,11 +55,11 @@ public Type getType() { Value op1 = getOp1(); Value op2 = getOp2(); - if (!PrimitiveType.isIntLikeType(op2.getType())) { + if (!Type.isIntLikeType(op2.getType())) { return UnknownType.getInstance(); } - if (PrimitiveType.isIntLikeType(op1.getType())) { + if (Type.isIntLikeType(op1.getType())) { return PrimitiveType.getInt(); } if (op1.getType().equals(PrimitiveType.getLong())) { diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShrExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShrExpr.java index 372baa0a6e3..ee1030496ae 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShrExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JShrExpr.java @@ -55,11 +55,11 @@ public Type getType() { Value op1 = getOp1(); Value op2 = getOp2(); - if (!PrimitiveType.isIntLikeType(op2.getType())) { + if (!Type.isIntLikeType(op2.getType())) { return UnknownType.getInstance(); } - if (PrimitiveType.isIntLikeType(op1.getType())) { + if (Type.isIntLikeType(op1.getType())) { return PrimitiveType.getInt(); } if (op1.getType().equals(PrimitiveType.getLong())) { diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java index 8edaa8fb966..01e9c2d2153 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java @@ -54,11 +54,11 @@ public Type getType() { Value op1 = getOp1(); Value op2 = getOp2(); - if (PrimitiveType.isIntLikeType(op2.getType())) { + if (Type.isIntLikeType(op2.getType())) { return UnknownType.getInstance(); } - if (PrimitiveType.isIntLikeType(op1.getType())) { + if (Type.isIntLikeType(op1.getType())) { return PrimitiveType.getInt(); } if (op1.getType().equals(PrimitiveType.getLong())) { diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/ref/JArrayRef.java b/sootup.core/src/main/java/sootup/core/jimple/common/ref/JArrayRef.java index 803ac979b91..ed5db22889e 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/ref/JArrayRef.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/ref/JArrayRef.java @@ -25,16 +25,12 @@ import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; -import sootup.core.IdentifierFactory; import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.JimpleComparator; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.visitor.RefVisitor; -import sootup.core.types.ArrayType; -import sootup.core.types.NullType; import sootup.core.types.Type; -import sootup.core.types.UnknownType; import sootup.core.util.Copyable; import sootup.core.util.printer.StmtPrinter; @@ -42,42 +38,10 @@ public final class JArrayRef implements ConcreteRef, Copyable { private final Local base; private final Immediate index; - private final IdentifierFactory identifierFactory; - public JArrayRef( - @Nonnull Local base, @Nonnull Immediate index, @Nonnull IdentifierFactory identifierFactory) { + public JArrayRef(@Nonnull Local base, @Nonnull Immediate index) { this.base = base; this.index = index; - this.identifierFactory = identifierFactory; - } - - private Type determineType(@Nonnull IdentifierFactory identifierFactory) { - Type type = base.getType(); - - if (type.equals(UnknownType.getInstance())) { - return UnknownType.getInstance(); - } else if (type.equals(NullType.getInstance())) { - return NullType.getInstance(); - } else { - // use makeArrayType on non-array type references when they propagate to this point. - // kludge, most likely not correct. - // may stop spark from complaining when it gets passed phantoms. - // ideally I'd want to find out just how they manage to get this far. - ArrayType arrayType; - if (type instanceof ArrayType) { - arrayType = (ArrayType) type; - } else { - arrayType = identifierFactory.getArrayType(type, 1); - } - - // FIXME: [JMP] Should unwrapping not be done by the `ArrayType` itself? - if (arrayType.getDimension() == 1) { - return arrayType.getBaseType(); - } else { - return identifierFactory.getArrayType( - arrayType.getBaseType(), arrayType.getDimension() - 1); - } - } } @Override @@ -127,7 +91,7 @@ public List getUses() { @Override @Nonnull public Type getType() { - return determineType(identifierFactory); + return base.getType(); } @Override @@ -137,11 +101,11 @@ public void accept(@Nonnull RefVisitor v) { @Nonnull public JArrayRef withBase(@Nonnull Local base) { - return new JArrayRef(base, getIndex(), identifierFactory); + return new JArrayRef(base, getIndex()); } @Nonnull public JArrayRef withIndex(@Nonnull Immediate index) { - return new JArrayRef(getBase(), index, identifierFactory); + return new JArrayRef(getBase(), index); } } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/ref/JFieldRef.java b/sootup.core/src/main/java/sootup/core/jimple/common/ref/JFieldRef.java index e2f327bf3a1..8e3d2c4e996 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/ref/JFieldRef.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/ref/JFieldRef.java @@ -51,4 +51,7 @@ public boolean equals(JFieldRef ref) { } return this.getFieldSignature().equals(ref.getFieldSignature()); } + + @Nonnull + public abstract JFieldRef withFieldSignature(@Nonnull FieldSignature fieldSignature); } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/AbstractDefinitionStmt.java b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/AbstractDefinitionStmt.java index f074424e7af..86b6a1de640 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/AbstractDefinitionStmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/AbstractDefinitionStmt.java @@ -23,9 +23,9 @@ */ import java.util.ArrayList; -import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; +import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; import sootup.core.types.Type; @@ -60,15 +60,20 @@ public Type getType() { @Override @Nonnull public List getDefs() { - return Collections.singletonList(leftOp); + final List defs = new ArrayList<>(); + defs.add(leftOp); + return defs; } @Override @Nonnull public final List getUses() { - List list = new ArrayList<>(leftOp.getUses()); + final List defsuses = leftOp.getUses(); + final List uses = rightOp.getUses(); + List list = new ArrayList<>(defsuses.size() + uses.size() + 1); + list.addAll(defsuses); list.add(rightOp); - list.addAll(rightOp.getUses()); + list.addAll(uses); return list; } @@ -81,4 +86,6 @@ public boolean fallsThrough() { public boolean branches() { return false; } + + public abstract Stmt withNewDef(@Nonnull Local newLocal); } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java index c5bdafcdb12..389f13edb12 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java @@ -29,6 +29,7 @@ import sootup.core.jimple.common.ref.ConcreteRef; import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JFieldRef; +import sootup.core.jimple.common.ref.JInstanceFieldRef; import sootup.core.jimple.visitor.StmtVisitor; import sootup.core.util.Copyable; import sootup.core.util.printer.StmtPrinter; @@ -210,4 +211,25 @@ public JAssignStmt withRValue(@Nonnull N rValue) { public JAssignStmt withPositionInfo(@Nonnull StmtPositionInfo positionInfo) { return new JAssignStmt<>(getLeftOp(), getRightOp(), positionInfo); } + + @Override + public Stmt withNewDef(@Nonnull Local newLocal) { + // "ReplaceDefVisitor" + final Value leftOp = getLeftOp(); + Value newVal; + if (leftOp instanceof ConcreteRef) { + if (leftOp instanceof JArrayRef) { + newVal = ((JArrayRef) leftOp).withBase(newLocal); + } else if (leftOp instanceof JInstanceFieldRef) { + newVal = ((JInstanceFieldRef) leftOp).withBase(newLocal); + } else { + // JStaticFieldRef -> do nothing + return this; + } + } else { + // its a Local.. + newVal = newLocal; + } + return withVariable(newVal); + } } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JIdentityStmt.java b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JIdentityStmt.java index 233422ac988..2497b433b05 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JIdentityStmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JIdentityStmt.java @@ -80,4 +80,9 @@ public JIdentityStmt withIdentityValue(@Nonnull N ide public JIdentityStmt withPositionInfo(@Nonnull StmtPositionInfo positionInfo) { return new JIdentityStmt<>(getLeftOp(), getRightOp(), positionInfo); } + + @Override + public Stmt withNewDef(@Nonnull Local newLocal) { + return withLocal(newLocal); + } } diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/Stmt.java b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/Stmt.java index 9c610d96f3b..4e53d63e3ff 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/Stmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/Stmt.java @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import sootup.core.jimple.basic.EquivTo; import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; @@ -33,6 +34,7 @@ import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JFieldRef; import sootup.core.jimple.visitor.Acceptor; +import sootup.core.jimple.visitor.ReplaceUseStmtVisitor; import sootup.core.jimple.visitor.StmtVisitor; import sootup.core.util.Copyable; import sootup.core.util.printer.StmtPrinter; @@ -54,8 +56,10 @@ public List getUses() { return Collections.emptyList(); } - /** Returns a list of Values defined in this Stmt. */ - // TODO: [ms] naming/signature its just a single Def..always. + /** + * Returns a list of Values defined in this Stmt. There are languages which allow multiple return + * types/assignments so we return a List + */ @Nonnull public List getDefs() { return Collections.emptyList(); @@ -136,4 +140,18 @@ public JFieldRef getFieldRef() { public StmtPositionInfo getPositionInfo() { return positionInfo; } + + /** + * Use newUse to replace the oldUse in oldStmt. + * + * @param oldUse a Value in the useList of oldStmt. + * @param newUse a Value is to replace oldUse + * @return a new Stmt with newUse + */ + @Nullable + public Stmt withNewUse(@Nonnull Value oldUse, @Nonnull Value newUse) { + ReplaceUseStmtVisitor visitor = new ReplaceUseStmtVisitor(oldUse, newUse); + accept(visitor); + return visitor.getResult(); + } } diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractExprVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractExprVisitor.java index e9c3e720813..847b2c3bd2f 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractExprVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractExprVisitor.java @@ -187,6 +187,11 @@ public void caseNegExpr(@Nonnull JNegExpr expr) { defaultCaseExpr(expr); } + @Override + public void casePhiExpr(@Nonnull JPhiExpr expr) { + defaultCaseExpr(expr); + } + @Override public void defaultCaseExpr(@Nonnull Expr expr) {} } diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractValueVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractValueVisitor.java index db55fd60a00..f72e15ab648 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractValueVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/AbstractValueVisitor.java @@ -275,6 +275,11 @@ public void caseLocal(@Nonnull Local local) { defaultCaseValue(local); } + @Override + public void casePhiExpr(JPhiExpr expr) { + defaultCaseValue(expr); + } + @Override public void defaultCaseValue(@Nonnull Value v) {} } diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseExprVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseExprVisitor.java index 0678f5688b0..175a2b834c8 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseExprVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseExprVisitor.java @@ -489,7 +489,7 @@ public void caseNegExpr(@Nonnull JNegExpr expr) { } @Override - public void casePhiExpr(JPhiExpr v) { + public void casePhiExpr(@Nonnull JPhiExpr v) { if (this.phiBlock != null && newUse instanceof Local && v.getArgs().contains(oldUse) diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseRefVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseRefVisitor.java index 244d5cebfd2..ed1365334a2 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseRefVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseRefVisitor.java @@ -52,7 +52,7 @@ public void caseInstanceFieldRef(@Nonnull JInstanceFieldRef ref) { if (ref.getBase() == oldUse) { setResult(ref.withBase((Local) newUse)); } else { - errorHandler(ref); + setResult(ref); } } @@ -63,7 +63,7 @@ public void caseArrayRef(@Nonnull JArrayRef ref) { } else if (ref.getIndex() == oldUse) { setResult(ref.withIndex((Immediate) newUse)); } else { - errorHandler(ref); + setResult(ref); } } @@ -71,9 +71,4 @@ public void caseArrayRef(@Nonnull JArrayRef ref) { public void defaultCaseRef(@Nonnull Ref ref) { setResult(ref); } - - public void errorHandler(@Nonnull Ref ref) { - throw new IllegalArgumentException( - "The given oldUse which should be replaced is not a current use of " + ref + "!"); - } } diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java index 1f3c3c8afc3..b81defbdeb3 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java @@ -28,7 +28,7 @@ import sootup.core.jimple.common.expr.AbstractConditionExpr; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.Expr; -import sootup.core.jimple.common.ref.Ref; +import sootup.core.jimple.common.ref.*; import sootup.core.jimple.common.stmt.*; import sootup.core.jimple.javabytecode.stmt.*; @@ -70,13 +70,23 @@ public void caseInvokeStmt(@Nonnull JInvokeStmt stmt) { @Override public void caseAssignStmt(@Nonnull JAssignStmt stmt) { - Value rValue = stmt.getRightOp(); + // uses on the def side.. + final Value leftOp = stmt.getLeftOp(); + if (leftOp instanceof Ref) { + refVisitor.init(oldUse, newUse); + ((Ref) leftOp).accept(refVisitor); + if (refVisitor.getResult() != leftOp) { + setResult(stmt.withVariable(refVisitor.getResult())); + } + } + + // rhs + Value rValue = stmt.getRightOp(); if (rValue instanceof Immediate) { if (rValue == oldUse) { setResult(stmt.withRValue(newUse)); } - } else if (rValue instanceof Ref) { if (rValue == oldUse) { setResult(stmt.withRValue(newUse)); @@ -87,21 +97,19 @@ public void caseAssignStmt(@Nonnull JAssignStmt stmt) { setResult(stmt.withRValue(refVisitor.getResult())); } } - } else if (rValue instanceof Expr) { - exprVisitor.init(oldUse, newUse); ((Expr) rValue).accept(exprVisitor); if (exprVisitor.getResult() != rValue) { setResult(stmt.withRValue(exprVisitor.getResult())); } } else { - errorHandler(stmt); + setResult(stmt); } } @Override - public void caseIdentityStmt(@Nonnull JIdentityStmt stmt) { + public void caseIdentityStmt(@Nonnull JIdentityStmt stmt) { defaultCaseStmt(stmt); } @@ -123,12 +131,12 @@ public void caseGotoStmt(@Nonnull JGotoStmt stmt) { @Override public void caseIfStmt(@Nonnull JIfStmt stmt) { Expr conditionExpr = stmt.getCondition(); - exprVisitor.init((Immediate) oldUse, (Immediate) newUse); + exprVisitor.init(oldUse, newUse); conditionExpr.accept(exprVisitor); if (exprVisitor.getResult() != conditionExpr) { setResult(stmt.withCondition((AbstractConditionExpr) exprVisitor.getResult())); } else { - errorHandler(stmt); + setResult(stmt); } } @@ -165,12 +173,4 @@ public void caseThrowStmt(@Nonnull JThrowStmt stmt) { public void defaultCaseStmt(@Nonnull Stmt stmt) { setResult(stmt); } - - public void errorHandler(@Nonnull Stmt stmt) { - defaultCaseStmt(stmt); - /* - throw new IllegalArgumentException( - "The given oldUse '"+ oldUse +"' which should be replaced is not a current use of " + stmt + "!"); - */ - } } diff --git a/sootup.core/src/main/java/sootup/core/model/Body.java b/sootup.core/src/main/java/sootup/core/model/Body.java index 2c3d5defd82..09886d27961 100644 --- a/sootup.core/src/main/java/sootup/core/model/Body.java +++ b/sootup.core/src/main/java/sootup/core/model/Body.java @@ -30,8 +30,7 @@ import javax.annotation.Nullable; import sootup.core.graph.*; import sootup.core.jimple.basic.*; -import sootup.core.jimple.common.ref.JParameterRef; -import sootup.core.jimple.common.ref.JThisRef; +import sootup.core.jimple.common.ref.*; import sootup.core.jimple.common.stmt.*; import sootup.core.signatures.MethodSignature; import sootup.core.types.Type; @@ -98,7 +97,7 @@ private Body( * @return The this local */ public static Local getThisLocal(StmtGraph stmtGraph) { - for (Stmt stmt : stmtGraph.nodes()) { + for (Stmt stmt : stmtGraph.getNodes()) { if (stmt instanceof JIdentityStmt && ((JIdentityStmt) stmt).getRightOp() instanceof JThisRef) { return (Local) ((JIdentityStmt) stmt).getLeftOp(); @@ -131,18 +130,18 @@ private void runValidation(BodyValidator validator) { } /** Verifies that a Value is not used in more than one place. */ - public void validateValues() { - runValidation(new ValuesValidator()); - } + // TODO: #535 implement validator public void validateValues() { runValidation(new + // ValuesValidator());} /** Verifies that each Local of getUsesAndDefs() is in this body's locals Chain. */ - public void validateLocals() { - runValidation(new LocalsValidator()); - } + // TODO: #535 implement validator public void validateLocals() {runValidation(new + // LocalsValidator());} /** Verifies that each use in this Body has a def. */ - public void validateUses() { - runValidation(new UsesValidator()); + // TODO: #535 implement validator public void validateUses() { runValidation(new + // UsesValidator()); } + private void checkInit() { + runValidation(new CheckInitValidator()); } /** Returns a backed chain of the locals declared in this Body. */ @@ -216,7 +215,7 @@ public Collection getParameterLocals() { final List retVal = new ArrayList<>(); // TODO: [ms] performance: don't iterate over all stmt -> lazy vs freedom/error tolerance -> use // fixed index positions at the beginning? - for (Stmt u : graph.nodes()) { + for (Stmt u : graph.getNodes()) { if (u instanceof JIdentityStmt) { JIdentityStmt idStmt = (JIdentityStmt) u; if (idStmt.getRightOp() instanceof JParameterRef) { @@ -241,7 +240,7 @@ public Collection getParameterLocals() { */ @Nonnull public List getStmts() { - final ArrayList stmts = new ArrayList<>(graph.nodes().size()); + final ArrayList stmts = new ArrayList<>(graph.getNodes().size()); for (Stmt stmt : graph) { stmts.add(stmt); } @@ -254,10 +253,6 @@ public StmtGraph getStmtGraph() { return graph; } - private void checkInit() { - runValidation(new CheckInitValidator()); - } - /** {@inheritDoc} */ @Override public String toString() { @@ -312,7 +307,7 @@ public Stmt getFirstNonIdentityStmt() { public Collection getUses() { ArrayList useList = new ArrayList<>(); - for (Stmt stmt : graph.nodes()) { + for (Stmt stmt : graph.getNodes()) { useList.addAll(stmt.getUses()); } return useList; @@ -327,7 +322,7 @@ public Collection getUses() { public Collection getDefs() { ArrayList defList = new ArrayList<>(); - for (Stmt stmt : graph.nodes()) { + for (Stmt stmt : graph.getNodes()) { defList.addAll(stmt.getDefs()); } return defList; @@ -346,7 +341,7 @@ public static BodyBuilder builder(@Nonnull MutableStmtGraph graph) { return new BodyBuilder(graph); } - public static BodyBuilder builder(@Nonnull Body body, Set modifiers) { + public static BodyBuilder builder(@Nonnull Body body, Set modifiers) { return new BodyBuilder(body, modifiers); } @@ -371,7 +366,7 @@ public static BodyBuilder builder(@Nonnull Body body, Set modifiers) { public static class BodyBuilder { @Nonnull private Set locals = new LinkedHashSet<>(); @Nonnull private final LocalGenerator localGen = new LocalGenerator(locals); - @Nonnull private Set modifiers = Collections.emptySet(); + @Nonnull private Set modifiers = Collections.emptySet(); @Nullable private Position position = null; @Nonnull private final MutableStmtGraph graph; @@ -387,10 +382,10 @@ public static class BodyBuilder { this.graph = graph; } - BodyBuilder(@Nonnull Body body, @Nonnull Set modifiers) { + BodyBuilder(@Nonnull Body body, @Nonnull Set modifiers) { setModifiers(modifiers); setMethodSignature(body.getMethodSignature()); - setLocals(body.getLocals()); + setLocals(new LinkedHashSet<>(body.getLocals())); setPosition(body.getPosition()); graph = new MutableBlockStmtGraph(body.getStmtGraph()); } @@ -400,9 +395,10 @@ public MutableStmtGraph getStmtGraph() { return graph; } + /* Gets an ordered copy of the Stmts in the StmtGraph */ @Nonnull public List getStmts() { - cachedLinearizedStmts = Lists.newArrayList(graph); + cachedLinearizedStmts = graph.getStmts(); return cachedLinearizedStmts; } @@ -435,6 +431,35 @@ public BodyBuilder addLocal(@Nonnull Local local) { return this; } + public void replaceLocal(@Nonnull Local oldLocal, @Nonnull Local newLocal) { + if (!locals.contains(oldLocal)) { + throw new RuntimeException("The given old local: '" + oldLocal + "' is not in the body!"); + } else { + for (Stmt currStmt : Lists.newArrayList(getStmtGraph().getNodes())) { + final Stmt stmt = currStmt; + if (currStmt.getUses().contains(oldLocal)) { + final Stmt newStmt = currStmt.withNewUse(oldLocal, newLocal); + if (newStmt != null) { + currStmt = newStmt; + } + } + final List defs = currStmt.getDefs(); + for (Value def : defs) { + if (def == oldLocal || def.getUses().contains(oldLocal)) { + if (currStmt instanceof AbstractDefinitionStmt) { + currStmt = ((AbstractDefinitionStmt) currStmt).withNewDef(newLocal); + } + } + } + if (stmt != currStmt) { + getStmtGraph().replaceNode(stmt, currStmt); + } + } + locals.remove(oldLocal); + locals.add(newLocal); + } + } + /** replace the oldStmt with newStmt in stmtGraph and branches */ @Nonnull public BodyBuilder replaceStmt(@Nonnull Stmt oldStmt, @Nonnull Stmt newStmt) { @@ -456,6 +481,15 @@ public BodyBuilder clearExceptionEdgesOf(@Nonnull Stmt stmt) { return this; } + /* + * Note: if there is a stmt branching to successor this is not updated to the new stmt + * */ + @Nonnull + public BodyBuilder insertBefore(@Nonnull Stmt beforeStmt, Stmt newstmt) { + graph.insertBefore(beforeStmt, newstmt); + return this; + } + @Nonnull @Deprecated public List getTraps() { @@ -476,18 +510,27 @@ public BodyBuilder removeFlow(@Nonnull Stmt fromStmt, @Nonnull Stmt toStmt) { return this; } - public BodyBuilder setModifiers(@Nonnull Set modifiers) { + public BodyBuilder setModifiers(@Nonnull Set modifiers) { this.modifiers = modifiers; return this; } + @Nullable + public Position getPosition() { + return position; + } + @Nonnull public BodyBuilder setPosition(@Nonnull Position position) { this.position = position; return this; } - public BodyBuilder setMethodSignature(MethodSignature methodSig) { + public MethodSignature getMethodSignature() { + return methodSig; + } + + public BodyBuilder setMethodSignature(@Nonnull MethodSignature methodSig) { this.methodSig = methodSig; return this; } @@ -504,7 +547,7 @@ public Body build() { } final Stmt startingStmt = graph.getStartingStmt(); - final Collection nodes = graph.nodes(); + final Collection nodes = graph.getNodes(); if (nodes.size() > 0 && !nodes.contains(startingStmt)) { // TODO: already handled in MutableBlockStmtGraph.. check the others as well throw new IllegalStateException( @@ -524,7 +567,7 @@ public Body build() { } @Nonnull - public Set getModifiers() { + public Set getModifiers() { return modifiers; } @@ -537,4 +580,52 @@ public String toString() { } } } + + /** + * Collects all defining statements of a Local from a list of statements + * + * @param stmts The searched list of statements + * @return A map of Locals and their using statements + */ + public static Map> collectDefs(Collection stmts) { + Map> allDefs = new HashMap<>(); + for (Stmt stmt : stmts) { + List defs = stmt.getDefs(); + for (Value value : defs) { + if (value instanceof Local) { + Collection localDefs = allDefs.get(value); + if (localDefs == null) { + localDefs = new ArrayList<>(); + } + localDefs.add(stmt); + allDefs.put((Local) value, localDefs); + } + } + } + return allDefs; + } + + /** + * Collects all using statements of a Local from a list of statements + * + * @param stmts The searched list of statements + * @return A map of Locals and their using statements + */ + public static Map> collectUses(List stmts) { + Map> allUses = new HashMap<>(); + for (Stmt stmt : stmts) { + Collection uses = stmt.getUses(); + for (Value value : uses) { + if (value instanceof Local) { + Collection localUses = allUses.get(value); + if (localUses == null) { + localUses = new ArrayList<>(); + } + localUses.add(stmt); + allUses.put((Local) value, localUses); + } + } + } + return allUses; + } } diff --git a/sootup.core/src/main/java/sootup/core/model/BodyUtils.java b/sootup.core/src/main/java/sootup/core/model/BodyUtils.java deleted file mode 100644 index 896906bde5a..00000000000 --- a/sootup.core/src/main/java/sootup/core/model/BodyUtils.java +++ /dev/null @@ -1,166 +0,0 @@ -package sootup.core.model; -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2020 Marcus Nachtigall - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -import java.util.*; -import javax.annotation.Nonnull; -import sootup.core.graph.StmtGraph; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.stmt.AbstractDefinitionStmt; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JIdentityStmt; -import sootup.core.jimple.common.stmt.Stmt; -import sootup.core.jimple.visitor.ReplaceUseStmtVisitor; - -/** - * Util class for the Body - * - * @author Marcus Nachtigall, Zun Wang - */ -public class BodyUtils { - - // TODO: [ms] please refactor into respective classes or at least rename to.. StmtUtils? - - /** - * Collects all defining statements of a Local from a list of statements - * - * @param stmts The searched list of statements - * @return A map of Locals and their using statements - */ - public static Map> collectDefs(List stmts) { - Map> allDefs = new HashMap<>(); - for (Stmt stmt : stmts) { - List defs = stmt.getDefs(); - for (Value value : defs) { - if (value instanceof Local) { - List localDefs = allDefs.get(value); - if (localDefs == null) { - localDefs = new ArrayList<>(); - } - localDefs.add(stmt); - allDefs.put((Local) value, localDefs); - } - } - } - return allDefs; - } - - /** - * Collects all using statements of a Local from a list of statements - * - * @param stmts The searched list of statements - * @return A map of Locals and their using statements - */ - public static Map> collectUses(List stmts) { - Map> allUses = new HashMap<>(); - for (Stmt stmt : stmts) { - List uses = stmt.getUses(); - for (Value value : uses) { - if (value instanceof Local) { - List localUses = allUses.get(value); - if (localUses == null) { - localUses = new ArrayList<>(); - } - localUses.add(stmt); - allUses.put((Local) value, localUses); - } - } - } - return allUses; - } - - public static List getDefsOfLocal(Local local, List defs) { - List localDefs = new ArrayList<>(); - for (Stmt stmt : defs) { - if (stmt instanceof AbstractDefinitionStmt - && ((AbstractDefinitionStmt) stmt).getLeftOp().equals(local)) { - localDefs.add((AbstractDefinitionStmt) stmt); - } - } - return localDefs; - } - - /** - * Get all definition-stmts which define the given local used by the given stmt. - * - * @param graph a stmt graph which contains the given stmts. - * @param use a local that is used by the given stmt. - * @param stmt a stmt which uses the given local. - */ - public static List getDefsForLocalUse(StmtGraph graph, Local use, Stmt stmt) { - if (!stmt.getUses().contains(use)) { - throw new RuntimeException(stmt + " doesn't use the local " + use.toString()); - } - List defStmts = new ArrayList<>(); - Set visited = new HashSet<>(); - - Deque queue = new ArrayDeque<>(); - queue.add(stmt); - while (!queue.isEmpty()) { - Stmt s = queue.removeFirst(); - if (!visited.contains(s)) { - visited.add(s); - if (s instanceof AbstractDefinitionStmt && s.getDefs().get(0).equivTo(use)) { - defStmts.add(s); - } else { - for (Stmt pred : graph.predecessors(s)) { - queue.add(pred); - } - } - } - } - return defStmts; - } - - /** - * Use newUse to replace the oldUse in oldStmt. - * - * @param oldStmt a Stmt that has oldUse. - * @param oldUse a Value in the useList of oldStmt. - * @param newUse a Value is to replace oldUse - * @return a new Stmt with newUse - */ - @Nonnull - public static Stmt withNewUse( - @Nonnull Stmt oldStmt, @Nonnull Value oldUse, @Nonnull Value newUse) { - ReplaceUseStmtVisitor visitor = new ReplaceUseStmtVisitor(oldUse, newUse); - oldStmt.accept(visitor); - return visitor.getResult(); - } - - /** - * Use newDef to replace the definition in oldStmt. - * - * @param oldStmt a Stmt whose def is to be replaced. - * @param newDef a Local to replace definition Local of oldStmt. - * @return a new Stmt with newDef - */ - @Nonnull - public static Stmt withNewDef(@Nonnull Stmt oldStmt, @Nonnull Local newDef) { - if (oldStmt instanceof JAssignStmt) { - return ((JAssignStmt) oldStmt).withVariable(newDef); - } else if (oldStmt instanceof JIdentityStmt) { - return ((JIdentityStmt) oldStmt).withLocal(newDef); - } - throw new RuntimeException("The given stmt must be JAssignStmt or JIdentityStmt!"); - } -} diff --git a/sootup.core/src/main/java/sootup/core/model/ClassModifier.java b/sootup.core/src/main/java/sootup/core/model/ClassModifier.java new file mode 100644 index 00000000000..728cd1a07f3 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/model/ClassModifier.java @@ -0,0 +1,168 @@ +// Incomplete class + +package sootup.core.model; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 1997-2020 Raja Vallee-Rai, Jan Martin Persch, Christian Brüggemann and others + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.EnumSet; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; + +/** + * An Enum that provides static methods and constants to represent and work with with Java modifiers + * (ie public, final,...) Represents Java modifiers that can be packed and combined via EnumSet and + * methods to query these. + */ +public enum ClassModifier { + PUBLIC(0x0001), + PRIVATE(0x0002), + PROTECTED(0x0004), + + STATIC(0x0008), + FINAL(0x0010), + + SUPER(0x0020), + INTERFACE(0x0200), + ABSTRACT(0x0400), + SYNTHETIC(0x1000), + ANNOTATION(0x2000), + ENUM(0x4000), + + MODULE(0x8000); + + private final int bytecode; + + ClassModifier(int i) { + bytecode = i; + } + + public static boolean isAbstract(@Nonnull Set m) { + return m.contains(ABSTRACT); + } + + public static boolean isFinal(@Nonnull Set m) { + return m.contains(FINAL); + } + + public static boolean isInterface(@Nonnull Set m) { + return m.contains(INTERFACE); + } + + public static boolean isPrivate(@Nonnull Set m) { + return m.contains(PRIVATE); + } + + public static boolean isProtected(@Nonnull Set m) { + return m.contains(PROTECTED); + } + + public static boolean isPublic(@Nonnull Set m) { + return m.contains(PUBLIC); + } + + public static boolean isStatic(@Nonnull Set m) { + return m.contains(STATIC); + } + + public static boolean isSuper(@Nonnull Set m) { + return m.contains(SUPER); + } + + public static boolean isAnnotation(@Nonnull Set m) { + return m.contains(ANNOTATION); + } + + public static boolean isEnum(@Nonnull Set m) { + return m.contains(ENUM); + } + + public static boolean isSynthetic(@Nonnull Set m) { + return m.contains(SYNTHETIC); + } + + /** + * Converts the given modifiers to their string representation, in canonical form. + * + * @param m a modifier set + * @return a textual representation of the modifiers. + */ + @Nonnull + public static String toString(@Nonnull Set m) { + StringBuilder builder = new StringBuilder(); + + if (isPublic(m)) { + builder.append("public "); + } else if (isPrivate(m)) { + builder.append("private "); + } else if (isProtected(m)) { + builder.append("protected "); + } + + if (isAbstract(m)) { + builder.append("abstract "); + } + + if (isStatic(m)) { + builder.append("static "); + } + + if (isFinal(m)) { + builder.append("final "); + } + + if (isSuper(m)) { + builder.append("super "); + } + + if (isAnnotation(m)) { + builder.append("annotation "); + } + + if (isEnum(m)) { + builder.append("enum "); + } + + if (isInterface(m)) { + builder.append("interface "); + } + + // trim + final int lastCharPos = builder.length() - 1; + if (lastCharPos > 0) { + builder.setLength(lastCharPos); + } + return builder.toString(); + } + + @Nonnull + // depends on the natural order of the Enums! + public static String toString(@Nonnull EnumSet m) { + return m.stream().map((mod) -> mod.name().toLowerCase()).collect(Collectors.joining(" ")); + } + + /** @return the bytecode of this Modifier. */ + public int getBytecode() { + return bytecode; + } +} diff --git a/sootup.core/src/main/java/sootup/core/model/FieldModifier.java b/sootup.core/src/main/java/sootup/core/model/FieldModifier.java new file mode 100644 index 00000000000..38bc7638d71 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/model/FieldModifier.java @@ -0,0 +1,146 @@ +// Incomplete class + +package sootup.core.model; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 1997-2020 Raja Vallee-Rai, Jan Martin Persch, Christian Brüggemann and others + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.EnumSet; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; + +/** + * An Enum that provides static methods and constants to represent and work with with Java modifiers + * (ie public, final,...) Represents Java modifiers that can be packed and combined via EnumSet and + * methods to query these. + */ +public enum FieldModifier { + PUBLIC(0x0001), + PRIVATE(0x0002), + PROTECTED(0x0004), + STATIC(0x0008), + FINAL(0x0010), + VOLATILE(0x0040), + TRANSIENT(0x0080), + SYNTHETIC(0x1000), + ENUM(0x4000); + + private final int bytecode; + + FieldModifier(int i) { + bytecode = i; + } + + public static boolean isFinal(@Nonnull Set m) { + return m.contains(FINAL); + } + + public static boolean isPrivate(@Nonnull Set m) { + return m.contains(PRIVATE); + } + + public static boolean isProtected(@Nonnull Set m) { + return m.contains(PROTECTED); + } + + public static boolean isPublic(@Nonnull Set m) { + return m.contains(PUBLIC); + } + + public static boolean isStatic(@Nonnull Set m) { + return m.contains(STATIC); + } + + public static boolean isTransient(@Nonnull Set m) { + return m.contains(TRANSIENT); + } + + public static boolean isVolatile(@Nonnull Set m) { + return m.contains(VOLATILE); + } + + public static boolean isEnum(@Nonnull Set m) { + return m.contains(ENUM); + } + + public static boolean isSynthetic(@Nonnull Set m) { + return m.contains(SYNTHETIC); + } + + /** + * Converts the given modifiers to their string representation, in canonical form. + * + * @param m a modifier set + * @return a textual representation of the modifiers. + */ + @Nonnull + public static String toString(@Nonnull Set m) { + StringBuilder builder = new StringBuilder(); + + if (isPublic(m)) { + builder.append("public "); + } else if (isPrivate(m)) { + builder.append("private "); + } else if (isProtected(m)) { + builder.append("protected "); + } + + if (isStatic(m)) { + builder.append("static "); + } + + if (isFinal(m)) { + builder.append("final "); + } + + if (isVolatile(m)) { + builder.append("volatile "); + } + + if (isTransient(m)) { + builder.append("transient "); + } + + if (isEnum(m)) { + builder.append("enum "); + } + + // trim + final int lastCharPos = builder.length() - 1; + if (lastCharPos > 0) { + builder.setLength(lastCharPos); + } + return builder.toString(); + } + + @Nonnull + // depends on the natural order of the Enums! + public static String toString(@Nonnull EnumSet m) { + return m.stream().map((mod) -> mod.name().toLowerCase()).collect(Collectors.joining(" ")); + } + + /** @return the bytecode of this Modifier. */ + public int getBytecode() { + return bytecode; + } +} diff --git a/sootup.core/src/main/java/sootup/core/model/FullPosition.java b/sootup.core/src/main/java/sootup/core/model/FullPosition.java new file mode 100644 index 00000000000..02af2342020 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/model/FullPosition.java @@ -0,0 +1,66 @@ +package sootup.core.model; + +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2019-2020 Markus Schmidt + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Objects; + +/** This class represents Position Information i.e. for IDEs to locate positions in sources. */ +// TODO: [ms] it represents a range - rename? +public class FullPosition extends Position { + private final int firstLine; + private final int firstCol; + private final int lastLine; + private final int lastCol; + + public FullPosition(int firstLine, int firstCol, int lastLine, int lastCol) { + this.firstLine = firstLine; + this.firstCol = firstCol; + this.lastLine = lastLine; + this.lastCol = lastCol; + } + + @Override + public int getFirstLine() { + return firstLine; + } + + @Override + public int getLastLine() { + return lastLine; + } + + @Override + public int getFirstCol() { + return firstCol; + } + + @Override + public int getLastCol() { + return lastCol; + } + + @Override + public int hashCode() { + return Objects.hash(firstLine, firstCol, lastLine, lastCol); + } +} diff --git a/sootup.core/src/main/java/sootup/core/model/LinePosition.java b/sootup.core/src/main/java/sootup/core/model/LinePosition.java new file mode 100644 index 00000000000..624ffa88fb8 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/model/LinePosition.java @@ -0,0 +1,29 @@ +package sootup.core.model; + +public class LinePosition extends Position { + private final int lineNo; + + public LinePosition(int lineNo) { + this.lineNo = lineNo; + } + + @Override + public int getFirstLine() { + return lineNo; + } + + @Override + public int getLastLine() { + return lineNo + 1; + } + + @Override + public int getFirstCol() { + return 0; + } + + @Override + public int getLastCol() { + return -1; + } +} diff --git a/sootup.core/src/main/java/sootup/core/model/Modifier.java b/sootup.core/src/main/java/sootup/core/model/MethodModifier.java similarity index 65% rename from sootup.core/src/main/java/sootup/core/model/Modifier.java rename to sootup.core/src/main/java/sootup/core/model/MethodModifier.java index 97439a0825a..6375d38ef47 100644 --- a/sootup.core/src/main/java/sootup/core/model/Modifier.java +++ b/sootup.core/src/main/java/sootup/core/model/MethodModifier.java @@ -34,102 +34,91 @@ * (ie public, final,...) Represents Java modifiers that can be packed and combined via EnumSet and * methods to query these. */ -public enum Modifier { +public enum MethodModifier { PUBLIC(0x0001), PRIVATE(0x0002), PROTECTED(0x0004), - ABSTRACT(0x0400), STATIC(0x0008), FINAL(0x0010), SYNCHRONIZED(0x0020), + + VARARGS(0x0080), /* VARARGS for methods */ + BRIDGE(0x0040), NATIVE(0x0100), - TRANSIENT(0x0080), /* VARARGS for methods */ - VOLATILE(0x0040), /* BRIDGE for methods */ + ABSTRACT(0x0400), STRICTFP(0x0800), - ANNOTATION(0x2000), - ENUM(0x4000), - INTERFACE(0x0200), - - MODULE(0x8000), // dex specifific modifiers SYNTHETIC(0x1000), + ENUM(0x4000), CONSTRUCTOR(0x10000), DECLARED_SYNCHRONIZED(0x20000); private final int bytecode; - Modifier(int i) { + MethodModifier(int i) { bytecode = i; } - public static boolean isAbstract(@Nonnull Set m) { + public static boolean isAbstract(@Nonnull Set m) { return m.contains(ABSTRACT); } - public static boolean isFinal(@Nonnull Set m) { + public static boolean isFinal(@Nonnull Set m) { return m.contains(FINAL); } - public static boolean isInterface(@Nonnull Set m) { - return m.contains(INTERFACE); - } - - public static boolean isNative(@Nonnull Set m) { + public static boolean isNative(@Nonnull Set m) { return m.contains(NATIVE); } - public static boolean isPrivate(@Nonnull Set m) { + public static boolean isPrivate(@Nonnull Set m) { return m.contains(PRIVATE); } - public static boolean isProtected(@Nonnull Set m) { + public static boolean isProtected(@Nonnull Set m) { return m.contains(PROTECTED); } - public static boolean isPublic(@Nonnull Set m) { + public static boolean isPublic(@Nonnull Set m) { return m.contains(PUBLIC); } - public static boolean isStatic(@Nonnull Set m) { + public static boolean isStatic(@Nonnull Set m) { return m.contains(STATIC); } - public static boolean isSynchronized(@Nonnull Set m) { + public static boolean isSynchronized(@Nonnull Set m) { return m.contains(SYNCHRONIZED); } - public static boolean isTransient(@Nonnull Set m) { - return m.contains(TRANSIENT); + public static boolean isVarargs(@Nonnull Set m) { + return m.contains(VARARGS); } - public static boolean isVolatile(@Nonnull Set m) { - return m.contains(VOLATILE); + public static boolean isBridge(@Nonnull Set m) { + return m.contains(BRIDGE); } - public static boolean isStrictFP(@Nonnull Set m) { + public static boolean isStrictFP(@Nonnull Set m) { return m.contains(STRICTFP); } - public static boolean isAnnotation(@Nonnull Set m) { - return m.contains(ANNOTATION); - } - - public static boolean isEnum(@Nonnull Set m) { + public static boolean isEnum(@Nonnull Set m) { return m.contains(ENUM); } - public static boolean isSynthetic(@Nonnull Set m) { + public static boolean isSynthetic(@Nonnull Set m) { return m.contains(SYNTHETIC); } - public static boolean isConstructor(@Nonnull Set m) { + public static boolean isConstructor(@Nonnull Set m) { return m.contains(CONSTRUCTOR); } - public static boolean isDeclaredSynchronized(@Nonnull Set m) { + public static boolean isDeclaredSynchronized(@Nonnull Set m) { return m.contains(DECLARED_SYNCHRONIZED); } @@ -140,7 +129,7 @@ public static boolean isDeclaredSynchronized(@Nonnull Set m) { * @return a textual representation of the modifiers. */ @Nonnull - public static String toString(@Nonnull Set m) { + public static String toString(@Nonnull Set m) { StringBuilder builder = new StringBuilder(); if (isPublic(m)) { @@ -171,30 +160,22 @@ public static String toString(@Nonnull Set m) { builder.append("native "); } - if (isTransient(m)) { - builder.append("transient "); + if (isBridge(m)) { + builder.append("bridge "); } - if (isVolatile(m)) { - builder.append("volatile "); + if (isVarargs(m)) { + builder.append("varargs "); } if (isStrictFP(m)) { builder.append("strictfp "); } - if (isAnnotation(m)) { - builder.append("annotation "); - } - if (isEnum(m)) { builder.append("enum "); } - if (isInterface(m)) { - builder.append("interface "); - } - // trim final int lastCharPos = builder.length() - 1; if (lastCharPos > 0) { @@ -205,7 +186,7 @@ public static String toString(@Nonnull Set m) { @Nonnull // depends on the natural order of the Enums! - public static String toString(@Nonnull EnumSet m) { + public static String toString(@Nonnull EnumSet m) { return m.stream().map((mod) -> mod.name().toLowerCase()).collect(Collectors.joining(" ")); } diff --git a/sootup.core/src/main/java/sootup/core/model/Position.java b/sootup.core/src/main/java/sootup/core/model/Position.java index a39c0c9ef5a..9a0aa6844e3 100644 --- a/sootup.core/src/main/java/sootup/core/model/Position.java +++ b/sootup.core/src/main/java/sootup/core/model/Position.java @@ -1,70 +1,26 @@ package sootup.core.model; -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2019-2020 Markus Schmidt - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ +import javax.annotation.Nonnull; -import java.util.Objects; +public abstract class Position implements Comparable { + public abstract int getFirstLine(); -/** This class represents Position Information i.e. for IDEs to locate positions in sources. */ -// TODO: [ms] it represents a range - rename? -public class Position implements Comparable { + public abstract int getLastLine(); - private final int firstLine; - private final int firstCol; - private final int lastLine; - private final int lastCol; + public abstract int getFirstCol(); - public Position(int firstLine, int firstCol, int lastLine, int lastCol) { - this.firstLine = firstLine; - this.firstCol = firstCol; - this.lastLine = lastLine; - this.lastCol = lastCol; - } - - public int getFirstLine() { - return firstLine; - } - - public int getLastLine() { - return lastLine; - } - - public int getFirstCol() { - return firstCol; - } - - public int getLastCol() { - return lastCol; - } + public abstract int getLastCol(); + @Override public String toString() { final StringBuilder sb = new StringBuilder(); - sb.append("[").append(firstLine); - if (firstCol >= 0) { - sb.append(":").append(firstCol); + sb.append("[").append(getFirstLine()); + if (getFirstCol() >= 0) { + sb.append(":").append(getFirstCol()); } - sb.append("-").append(lastLine); - if (lastCol >= 0) { - sb.append(":").append(lastCol); + sb.append("-").append(getLastLine()); + if (getLastCol() >= 0) { + sb.append(":").append(getLastCol()); } sb.append("]"); return sb.toString(); @@ -78,24 +34,18 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - Position position = (Position) o; - return firstLine == position.firstLine - && firstCol == position.firstCol - && lastLine == position.lastLine - && lastCol == position.lastCol; - } - - @Override - public int hashCode() { - return Objects.hash(firstLine, firstCol, lastLine, lastCol); + FullPosition position = (FullPosition) o; + return getFirstLine() == position.getFirstLine() + && getFirstCol() == position.getFirstCol() + && getLastLine() == position.getLastLine() + && getLastCol() == position.getLastCol(); } /** * Compares "Positions" by their starting line/column Note: this class has a natural ordering that * is inconsistent with equals */ - @Override - public int compareTo(Position position) { + public int compareTo(@Nonnull Position position) { if (getFirstLine() < position.getFirstLine()) { return -1; } else if (getFirstLine() == position.getFirstLine()) { diff --git a/sootup.core/src/main/java/sootup/core/model/SootClass.java b/sootup.core/src/main/java/sootup/core/model/SootClass.java index f989a8f1f12..afa988069e8 100644 --- a/sootup.core/src/main/java/sootup/core/model/SootClass.java +++ b/sootup.core/src/main/java/sootup/core/model/SootClass.java @@ -106,12 +106,12 @@ public Set getFields() { return this._lazyFields.get(); } - private final Supplier> lazyModifiers = + private final Supplier> lazyModifiers = Suppliers.memoize(classSource::resolveModifiers); /** Returns the modifiers of this class in an immutable set. */ @Nonnull - public Set getModifiers() { + public Set getModifiers() { return lazyModifiers.get(); } @@ -184,17 +184,17 @@ public ClassType getType() { /** Convenience method; returns true if this class is an interface. */ public boolean isInterface() { - return Modifier.isInterface(this.getModifiers()); + return ClassModifier.isInterface(this.getModifiers()); } /** Convenience method; returns true if this class is an enumeration. */ public boolean isEnum() { - return Modifier.isEnum(this.getModifiers()); + return ClassModifier.isEnum(this.getModifiers()); } /** Convenience method; returns true if this class is synchronized. */ - public boolean isSynchronized() { - return Modifier.isSynchronized(this.getModifiers()); + public boolean isSuper() { + return ClassModifier.isSuper(this.getModifiers()); } /** Returns true if this class is not an interface and not abstract. */ @@ -204,7 +204,7 @@ public boolean isConcrete() { /** Convenience method; returns true if this class is public. */ public boolean isPublic() { - return Modifier.isPublic(this.getModifiers()); + return ClassModifier.isPublic(this.getModifiers()); } /** Returns the name of this class. */ @@ -240,27 +240,27 @@ public boolean isPhantomClass() { /** Convenience method returning true if this class is private. */ public boolean isPrivate() { - return Modifier.isPrivate(this.getModifiers()); + return ClassModifier.isPrivate(this.getModifiers()); } /** Convenience method returning true if this class is protected. */ public boolean isProtected() { - return Modifier.isProtected(this.getModifiers()); + return ClassModifier.isProtected(this.getModifiers()); } /** Convenience method returning true if this class is abstract. */ public boolean isAbstract() { - return Modifier.isAbstract(this.getModifiers()); + return ClassModifier.isAbstract(this.getModifiers()); } /** Convenience method returning true if this class is final. */ public boolean isFinal() { - return Modifier.isFinal(this.getModifiers()); + return ClassModifier.isFinal(this.getModifiers()); } /** Convenience method returning true if this class is static. */ public boolean isStatic() { - return Modifier.isStatic(this.getModifiers()); + return ClassModifier.isStatic(this.getModifiers()); } private final Supplier lazyPosition = Suppliers.memoize(classSource::resolvePosition); diff --git a/sootup.core/src/main/java/sootup/core/model/SootClassMember.java b/sootup.core/src/main/java/sootup/core/model/SootClassMember.java index b4a9c4bc9e1..333e7194773 100644 --- a/sootup.core/src/main/java/sootup/core/model/SootClassMember.java +++ b/sootup.core/src/main/java/sootup/core/model/SootClassMember.java @@ -22,13 +22,9 @@ * #L% */ -import com.google.common.collect.ImmutableSet; -import java.util.Objects; -import java.util.Set; import javax.annotation.Nonnull; import sootup.core.signatures.SootClassMemberSignature; import sootup.core.types.ClassType; -import sootup.core.util.ImmutableUtils; /** * Provides methods common to Soot objects belonging to classes, namely SootField and SootMethod. @@ -39,13 +35,11 @@ public abstract class SootClassMember { @Nonnull private final S signature; - @Nonnull private final ImmutableSet modifiers; + @Nonnull private final Position position; - SootClassMember( - @Nonnull S signature, @Nonnull Iterable modifiers, @Nonnull Position position) { + SootClassMember(@Nonnull S signature, @Nonnull Position position) { this.signature = signature; - this.modifiers = ImmutableUtils.immutableEnumSetOf(modifiers); this.position = position; } @@ -56,44 +50,22 @@ public ClassType getDeclaringClassType() { } /** Convenience method returning true if this class member is protected. */ - public boolean isProtected() { - return Modifier.isProtected(this.getModifiers()); - } + public abstract boolean isProtected(); /** Convenience method returning true if this class member is private. */ - public boolean isPrivate() { - return Modifier.isPrivate(this.getModifiers()); - } + public abstract boolean isPrivate(); /** Convenience method returning true if this class member is public. */ - public boolean isPublic() { - return Modifier.isPublic(this.getModifiers()); - } + public abstract boolean isPublic(); /** Convenience method returning true if this class member is static. */ - public boolean isStatic() { - return Modifier.isStatic(this.getModifiers()); - } + public abstract boolean isStatic(); /** Convenience method returning true if this field is final. */ - public boolean isFinal() { - return Modifier.isFinal(this.getModifiers()); - } - - /** - * Gets the modifiers of this class member in an immutable set. - * - * @see Modifier - */ - @Nonnull - public Set getModifiers() { - return modifiers; - } + public abstract boolean isFinal(); /** Returns a hash code for this method consistent with structural equality. */ - public int equivHashCode() { - return Objects.hash(modifiers, signature); - } + public abstract int equivHashCode(); /** Returns the signature of this method. */ @Override diff --git a/sootup.core/src/main/java/sootup/core/model/SootField.java b/sootup.core/src/main/java/sootup/core/model/SootField.java index f3514e4a803..7c45a5eb5de 100644 --- a/sootup.core/src/main/java/sootup/core/model/SootField.java +++ b/sootup.core/src/main/java/sootup/core/model/SootField.java @@ -21,11 +21,15 @@ * #L% */ +import com.google.common.collect.ImmutableSet; import java.util.EnumSet; +import java.util.Objects; +import java.util.Set; import javax.annotation.Nonnull; import sootup.core.jimple.basic.NoPositionInformation; import sootup.core.signatures.FieldSignature; import sootup.core.types.Type; +import sootup.core.util.ImmutableUtils; /** * Soot's counterpart of the source language's field concept. Soot representation of a Java field. @@ -36,12 +40,54 @@ */ public class SootField extends SootClassMember implements Field { + @Nonnull private final ImmutableSet modifiers; /** Constructs a Soot field with the given name, type and modifiers. */ public SootField( @Nonnull FieldSignature signature, - @Nonnull Iterable modifiers, + @Nonnull Iterable modifiers, @Nonnull Position position) { - super(signature, modifiers, position); + super(signature, position); + this.modifiers = ImmutableUtils.immutableEnumSetOf(modifiers); + } + + @Override + public boolean isProtected() { + return FieldModifier.isProtected(this.getModifiers()); + } + + @Override + public boolean isPrivate() { + return FieldModifier.isPrivate(this.getModifiers()); + } + + @Override + public boolean isPublic() { + return FieldModifier.isPublic(this.getModifiers()); + } + + @Override + public boolean isStatic() { + return FieldModifier.isStatic(this.getModifiers()); + } + + @Override + public boolean isFinal() { + return FieldModifier.isFinal(this.getModifiers()); + } + + /** + * Gets the modifiers of this class member in an immutable set. + * + * @see FieldModifier + */ + @Nonnull + public Set getModifiers() { + return modifiers; + } + + @Override + public int equivHashCode() { + return Objects.hash(modifiers, getSignature()); } @Nonnull @@ -54,7 +100,9 @@ private String getOriginalStyleDeclaration() { if (this.getModifiers().isEmpty()) { return this.getSignature().getSubSignature().toString(); } else { - return Modifier.toString(this.getModifiers()) + ' ' + this.getSignature().getSubSignature(); + return FieldModifier.toString(this.getModifiers()) + + ' ' + + this.getSignature().getSubSignature(); } } @@ -69,7 +117,7 @@ public SootField withSignature(@Nonnull FieldSignature signature) { } @Nonnull - public SootField withModifiers(@Nonnull Iterable modifiers) { + public SootField withModifiers(@Nonnull Iterable modifiers) { return new SootField(getSignature(), modifiers, getPosition()); } @@ -90,10 +138,10 @@ public interface SignatureStep { public interface ModifierStep { @Nonnull - BuildStep withModifier(@Nonnull Iterable modifier); + BuildStep withModifier(@Nonnull Iterable modifier); @Nonnull - default BuildStep withModifiers(@Nonnull Modifier first, @Nonnull Modifier... rest) { + default BuildStep withModifiers(@Nonnull FieldModifier first, @Nonnull FieldModifier... rest) { return withModifier(EnumSet.of(first, rest)); } } @@ -113,7 +161,7 @@ public interface BuildStep { public static class SootFieldBuilder implements SignatureStep, ModifierStep, BuildStep { private FieldSignature signature; - private Iterable modifiers; + private Iterable modifiers; private Position position = NoPositionInformation.getInstance(); @Nonnull @@ -122,7 +170,7 @@ protected FieldSignature getSignature() { } @Nonnull - protected Iterable getModifiers() { + protected Iterable getModifiers() { return modifiers; } @@ -140,7 +188,7 @@ public ModifierStep withSignature(@Nonnull FieldSignature signature) { @Override @Nonnull - public BuildStep withModifier(@Nonnull Iterable modifiers) { + public BuildStep withModifier(@Nonnull Iterable modifiers) { this.modifiers = modifiers; return this; } diff --git a/sootup.core/src/main/java/sootup/core/model/SootMethod.java b/sootup.core/src/main/java/sootup/core/model/SootMethod.java index 96c913fae81..ad2ecc7184c 100644 --- a/sootup.core/src/main/java/sootup/core/model/SootMethod.java +++ b/sootup.core/src/main/java/sootup/core/model/SootMethod.java @@ -24,6 +24,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.nio.file.Paths; import java.util.*; @@ -56,6 +57,7 @@ */ public class SootMethod extends SootClassMember implements Method, Copyable { + @Nonnull private final ImmutableSet modifiers; /** * An array of parameter types taken by this SootMethod object, in declaration order. */ @@ -71,13 +73,14 @@ public class SootMethod extends SootClassMember implements Meth public SootMethod( @Nonnull BodySource source, @Nonnull MethodSignature methodSignature, - @Nonnull Iterable modifiers, + @Nonnull Iterable modifiers, @Nonnull Iterable thrownExceptions, @Nonnull Position position) { - super(methodSignature, modifiers, position); + super(methodSignature, position); this.bodySource = source; this.parameterTypes = ImmutableUtils.immutableListOf(methodSignature.getParameterTypes()); + this.modifiers = ImmutableUtils.immutableEnumSetOf(modifiers); this.exceptions = ImmutableUtils.immutableListOf(thrownExceptions); } @@ -99,6 +102,46 @@ private Body lazyBodyInitializer() { } } + @Override + public boolean isProtected() { + return MethodModifier.isProtected(this.getModifiers()); + } + + @Override + public boolean isPrivate() { + return MethodModifier.isPrivate(this.getModifiers()); + } + + @Override + public boolean isPublic() { + return MethodModifier.isPublic(this.getModifiers()); + } + + @Override + public boolean isStatic() { + return MethodModifier.isStatic(this.getModifiers()); + } + + @Override + public boolean isFinal() { + return MethodModifier.isFinal(this.getModifiers()); + } + + /** + * Gets the modifiers of this class member in an immutable set. + * + * @see MethodModifier + */ + @Nonnull + public Set getModifiers() { + return modifiers; + } + + @Override + public int equivHashCode() { + return Objects.hash(modifiers, getSignature()); + } + /** Returns true if this method is not abstract or native, i.e. this method can have a body. */ public boolean isConcrete() { return !isAbstract() && !isNative(); @@ -151,17 +194,17 @@ public List getExceptionSignatures() { /** Convenience method returning true if this method is abstract. */ public boolean isAbstract() { - return Modifier.isAbstract(this.getModifiers()); + return MethodModifier.isAbstract(this.getModifiers()); } /** Convenience method returning true if this method is native. */ public boolean isNative() { - return Modifier.isNative(this.getModifiers()); + return MethodModifier.isNative(this.getModifiers()); } /** Convenience method returning true if this method is synchronized. */ public boolean isSynchronized() { - return Modifier.isSynchronized(this.getModifiers()); + return MethodModifier.isSynchronized(this.getModifiers()); } /** @return yes if this is the main method */ @@ -183,8 +226,8 @@ public boolean isBuiltInMethod() { public void toString(@Nonnull StmtPrinter printer) { // print modifiers - final Set modifiers = getModifiers(); - printer.modifier(Modifier.toString(modifiers)); + final Set modifiers = getModifiers(); + printer.modifier(MethodModifier.toString(modifiers)); if (modifiers.size() != 0) { printer.literal(" "); } @@ -228,7 +271,7 @@ public SootMethod withSource(BodySource source) { } @Nonnull - public SootMethod withModifiers(Iterable modifiers) { + public SootMethod withModifiers(Iterable modifiers) { return new SootMethod( bodySource, getSignature(), modifiers, getExceptionSignatures(), getPosition()); } @@ -271,10 +314,11 @@ public interface SignatureStep { public interface ModifierStep { @Nonnull - ThrownExceptionsStep withModifier(@Nonnull Iterable modifier); + ThrownExceptionsStep withModifier(@Nonnull Iterable modifier); @Nonnull - default ThrownExceptionsStep withModifiers(@Nonnull Modifier first, @Nonnull Modifier... rest) { + default ThrownExceptionsStep withModifiers( + @Nonnull MethodModifier first, @Nonnull MethodModifier... rest) { return withModifier(EnumSet.of(first, rest)); } } @@ -304,13 +348,13 @@ public static class SootMethodBuilder implements MethodSourceStep, SignatureStep, ModifierStep, ThrownExceptionsStep, BuildStep { @Nullable private BodySource source; - @Nonnull private Iterable modifiers = Collections.emptyList(); + @Nonnull private Iterable modifiers = Collections.emptyList(); @Nullable private MethodSignature methodSignature; @Nonnull private Iterable thrownExceptions = Collections.emptyList(); @Nonnull private Position position = NoPositionInformation.getInstance(); @Nonnull - public Iterable getModifiers() { + public Iterable getModifiers() { return modifiers; } @@ -350,7 +394,7 @@ public ModifierStep withSignature(@Nonnull MethodSignature methodSignature) { @Override @Nonnull - public ThrownExceptionsStep withModifier(@Nonnull Iterable modifiers) { + public ThrownExceptionsStep withModifier(@Nonnull Iterable modifiers) { this.modifiers = modifiers; return this; } diff --git a/sootup.core/src/main/java/sootup/core/signatures/PackageName.java b/sootup.core/src/main/java/sootup/core/signatures/PackageName.java index 48e6bfb705a..56cbf6eed14 100644 --- a/sootup.core/src/main/java/sootup/core/signatures/PackageName.java +++ b/sootup.core/src/main/java/sootup/core/signatures/PackageName.java @@ -52,10 +52,16 @@ public PackageName(final String packageName) { /** The name of the package. */ @Nonnull + @Deprecated // "use getName()" public String getPackageName() { return packageName; } + @Nonnull + public String getName() { + return packageName; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/sootup.core/src/main/java/sootup/core/transform/BodyInterceptor.java b/sootup.core/src/main/java/sootup/core/transform/BodyInterceptor.java index 8bb26e1d909..46151724bbe 100644 --- a/sootup.core/src/main/java/sootup/core/transform/BodyInterceptor.java +++ b/sootup.core/src/main/java/sootup/core/transform/BodyInterceptor.java @@ -24,11 +24,9 @@ import javax.annotation.Nonnull; import sootup.core.model.Body; +import sootup.core.views.View; -/** - * @author - * @see #interceptBody(Body.BodyBuilder) - */ +/** @see #interceptBody(Body.BodyBuilder, View) */ public interface BodyInterceptor { /** @@ -36,6 +34,7 @@ public interface BodyInterceptor { * variables. * * @param builder + * @param view */ - void interceptBody(@Nonnull Body.BodyBuilder builder); + void interceptBody(@Nonnull Body.BodyBuilder builder, @Nonnull View view); } diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/MethodDispatchResolver.java b/sootup.core/src/main/java/sootup/core/typehierarchy/MethodDispatchResolver.java index 63458d22a00..16c604ceb09 100644 --- a/sootup.core/src/main/java/sootup/core/typehierarchy/MethodDispatchResolver.java +++ b/sootup.core/src/main/java/sootup/core/typehierarchy/MethodDispatchResolver.java @@ -22,6 +22,9 @@ */ import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -37,6 +40,34 @@ public final class MethodDispatchResolver { private MethodDispatchResolver() {} + /** + * Searches the view for classes that are subtypes of the class contained in the signature. + * returns method signatures to all subtypes. Abstract methods are filtered the returned set can + * contain signatures of not implemented methods. + */ + @Nonnull + public static Set resolveAllDispatches( + View> view, MethodSignature m) { + TypeHierarchy hierarchy = view.getTypeHierarchy(); + + return hierarchy.subtypesOf(m.getDeclClassType()).stream() + .map( + subtype -> + view.getClass(subtype) + .orElseThrow( + () -> + new ResolveException( + "Could not resolve " + subtype + ", but found it in hierarchy."))) + .filter( + sootClass -> { + SootMethod sootMethod = sootClass.getMethod(m.getSubSignature()).orElse(null); + // method is not implemented or not abstract + return sootMethod == null || !sootMethod.isAbstract(); + }) + .map(sootClass -> new MethodSignature(sootClass.getType(), m.getSubSignature())) + .collect(Collectors.toSet()); + } + /** * Searches the view for classes that implement or override the method m and returns * the set of method signatures that a method call could resolve to. @@ -54,8 +85,9 @@ public static Set resolveAbstractDispatch( () -> new ResolveException( "Could not resolve " + subtype + ", but found it in hierarchy."))) - .flatMap(abstractClass -> abstractClass.getMethods().stream()) - .filter(potentialTarget -> canDispatch(m, potentialTarget.getSignature(), hierarchy)) + .map(sootClass -> findConcreteMethodInSootClass(sootClass, m)) + .filter(Optional::isPresent) + .map(Optional::get) .filter(method -> !method.isAbstract()) .map(Method::getSignature) .collect(Collectors.toSet()); @@ -66,7 +98,7 @@ public static Set resolveAbstractDispatch( * the set of method signatures that a method call could resolve to within the given classes. */ @Nonnull - public static Set resolveAbstractDispatchInClasses( + public static Set resolveAllDispatchesInClasses( View> view, MethodSignature m, Set classes) { TypeHierarchy hierarchy = view.getTypeHierarchy(); @@ -79,28 +111,36 @@ public static Set resolveAbstractDispatchInClasses( new ResolveException( "Could not resolve " + subtype + ", but found it in hierarchy."))) .filter(c -> classes.contains(c.getType())) - .flatMap(abstractClass -> abstractClass.getMethods().stream()) - .filter(potentialTarget -> canDispatch(m, potentialTarget.getSignature(), hierarchy)) + .map(sootClass -> findConcreteMethodInSootClass(sootClass, m)) + .filter(Optional::isPresent) + .map(Optional::get) .filter(method -> !method.isAbstract()) .map(Method::getSignature) .collect(Collectors.toSet()); } /** - * Searches the view for classes that implement or override the method m and returns - * the set of method signatures that a method call could resolve to within the given classes. + * Resolves all dispatches of a given call filtered by a set of given classes + * + *

searches the view for classes that can override the method m and returns the + * set of method signatures that a method call could resolve to within the given classes. All + * filtered signatures are added to the given set filteredSignatures. * - * @param filteredSignatures all resolvable method signatures that are not within the given - * classes are added to this set + * @param view it contains all classes and their connections. + * @param m it defines the actual invoked method signature. + * @param classes the set of classes that define possible dispatch targets of method signatures + * @param filteredSignatures the set of method signatures which is filled with filtered method + * signatures in the execution of this method. + * @return a set of method signatures that a method call could resolve to within the given classes */ @Nonnull - public static Set resolveAbstractDispatchInClasses( + public static Set resolveAllDispatchesInClasses( View> view, MethodSignature m, Set classes, Set filteredSignatures) { - Set allSignatures = resolveAbstractDispatch(view, m); + Set allSignatures = resolveAllDispatches(view, m); Set signatureInClasses = Sets.newHashSet(); allSignatures.forEach( methodSignature -> { @@ -128,8 +168,8 @@ public static boolean canDispatch( MethodSignature called, MethodSignature potentialTarget, TypeHierarchy hierarchy) { return called.getName().equals(potentialTarget.getName()) && called.getParameterTypes().equals(potentialTarget.getParameterTypes()) - && (called.getType().equals(potentialTarget.getType()) - || hierarchy.isSubtype(called.getType(), potentialTarget.getType())); + && (called.getType().equals(potentialTarget.getType()) // return types are equal + || hierarchy.isSubtype(called.getType(), potentialTarget.getType())); // covariant } /** @@ -138,11 +178,14 @@ public static boolean canDispatch( * concrete implementation. */ @Nonnull - public static MethodSignature resolveConcreteDispatch( + public static Optional resolveConcreteDispatch( View> view, MethodSignature m) { TypeHierarchy hierarchy = view.getTypeHierarchy(); - ClassType superClassType = m.getDeclClassType(); + SootClass startClass = view.getClass(superClassType).orElse(null); + ArrayList> classesInHierachyOrder = new ArrayList<>(); + + // search concrete method in the class itself and its super classes do { ClassType finalSuperClassType = superClassType; SootClass superClass = @@ -152,26 +195,120 @@ public static MethodSignature resolveConcreteDispatch( new ResolveException( "Did not find class " + finalSuperClassType + " in View")); - SootMethod concreteMethod = - superClass.getMethods().stream() - .filter(potentialTarget -> canDispatch(m, potentialTarget.getSignature(), hierarchy)) - .findAny() - .orElse(null); + classesInHierachyOrder.add(superClass); + + SootMethod concreteMethod = findConcreteMethodInSootClass(superClass, m).orElse(null); if (concreteMethod != null && !concreteMethod.isAbstract()) { - return concreteMethod.getSignature(); + // found method is not abstract + return Optional.of(concreteMethod.getSignature()); + } + if (concreteMethod != null && concreteMethod.isAbstract()) { + if (startClass.isAbstract() + && !startClass.getType().equals(concreteMethod.getDeclaringClassType())) { + // A not implemented method of an abstract class results into an abstract method + return Optional.empty(); + } + // found method is abstract and the startclass is not abstract + throw new ResolveException( + "Could not find concrete method for " + m + " because the method is abstract"); } superClassType = hierarchy.superClassOf(superClassType); } while (superClassType != null); + // No super class contains the implemented method, search the concrete method in interfaces + // first collect all interfaces and super interfaces + List> worklist = + classesInHierachyOrder.stream() + .flatMap(sootClass -> getSootClassesOfInterfaces(view, sootClass).stream()) + .collect(Collectors.toList()); + ArrayList> processedInterface = new ArrayList<>(); + ArrayList possibleDefaultMethods = new ArrayList<>(); + while (!worklist.isEmpty()) { + SootClass currentInterface = worklist.remove(0); + if (processedInterface.contains(currentInterface)) { + // interface was already processed + continue; + } + + // add found default method to possibleDefaultMethods + Optional concreteMethod = + findConcreteMethodInSootClass(currentInterface, m); + concreteMethod.ifPresent(possibleDefaultMethods::add); + + // if no default message is found search the default message in super interfaces + if (!concreteMethod.isPresent()) { + worklist.addAll(getSootClassesOfInterfaces(view, currentInterface)); + } + processedInterface.add(currentInterface); + } + + if (!possibleDefaultMethods.isEmpty()) { + // the interfaces are sorted by hierarchy + possibleDefaultMethods.sort( + (interface1, interface2) -> { + // interface1 is a sub-interface of interface2 + if (hierarchy.isSubtype( + interface2.getDeclaringClassType(), interface1.getDeclaringClassType())) return -1; + // interface1 is a super-interface of interface2 + if (hierarchy.isSubtype( + interface1.getDeclaringClassType(), interface2.getDeclaringClassType())) return 1; + // due to multiple inheritance in interfaces + return 0; + }); + // return the lowest element in the hierarchy + return Optional.of(possibleDefaultMethods.get(0).getSignature()); + } throw new ResolveException("Could not find concrete method for " + m); } + /** + * Returns all SootClasses of interfaces that are implemented in the given SootClass + * + *

returns a list of all SootClass Objects of interfaces that are associated with the given + * sootClass parameter. The ClassTypes of the interfaces are converted to SootClasses and not + * contained Interfaces are filtered. + * + * @param view the view that contains all searched SootClasses + * @param sootClass it contains the interfaces + * @return a list of SootClasses of the interfaces of sootClass + */ + private static List> getSootClassesOfInterfaces( + View> view, SootClass sootClass) { + return sootClass.getInterfaces().stream() + .map(view::getClass) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + } + + /** + * finds the concrete method in a SootClass + * + *

this method returns the concrete method of given method signature in a SootClass. Due to + * covariant, the given method signature can differ from the concrete method at the return type + * The method goes through all methods of the given SootClass and searches for a method which can + * dispatch. + * + * @param sootClass The method is searched in this SootClass + * @param methodSignature the signature of the searched method + * @return an Optional Object that can contain the found concrete method in the given SootClass + */ + private static Optional findConcreteMethodInSootClass( + SootClass sootClass, MethodSignature methodSignature) { + return sootClass.getMethods().stream() + .filter( + potentialTarget -> + methodSignature + .getSubSignature() + .equals(potentialTarget.getSignature().getSubSignature())) + .findAny(); + } + /** * Resolves the actual method called by the specialInvokeExpr that is contained by * container. */ - @Nonnull public static MethodSignature resolveSpecialDispatch( View> view, JSpecialInvokeExpr specialInvokeExpr, @@ -191,7 +328,7 @@ public static MethodSignature resolveSpecialDispatch( if (view.getTypeHierarchy() .isSubtype(container.getDeclClassType(), specialMethodSig.getDeclClassType())) { - return resolveConcreteDispatch(view, specialMethodSig); + return resolveConcreteDispatch(view, specialMethodSig).orElse(null); } return specialMethodSig; diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/MutableTypeHierarchy.java b/sootup.core/src/main/java/sootup/core/typehierarchy/MutableTypeHierarchy.java index 34dc39f06c6..043cbadc2a9 100644 --- a/sootup.core/src/main/java/sootup/core/typehierarchy/MutableTypeHierarchy.java +++ b/sootup.core/src/main/java/sootup/core/typehierarchy/MutableTypeHierarchy.java @@ -31,5 +31,5 @@ public interface MutableTypeHierarchy extends TypeHierarchy { * *

For internal use only. */ - void addType(SootClass sootClass); + void addType(SootClass sootClass); } diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java b/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java index ed1fddefa94..5efed1cff0c 100644 --- a/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java +++ b/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java @@ -20,11 +20,14 @@ * . * #L% */ + import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sootup.core.types.*; import sootup.core.views.View; @@ -37,6 +40,8 @@ */ public interface TypeHierarchy { + Logger logger = LoggerFactory.getLogger(TypeHierarchy.class); + /** * Returns all classes that implement the specified interface. This is transitive: If class * A extends B and B implements interface, then this method will return both A @@ -141,17 +146,21 @@ default boolean isSubtype(@Nonnull Type supertype, @Nonnull Type potentialSubtyp return false; } } else if (supertype instanceof ClassType) { + String supertypeName = ((ClassType) supertype).getFullyQualifiedName(); if (potentialSubtype instanceof ClassType) { - // First condition is a fast path - return supertype.equals(superClassOf((ClassType) potentialSubtype)) + String potentialSubtypeName = ((ClassType) potentialSubtype).getFullyQualifiedName(); + // any potential subtype is a subtype of java.lang.Object except java.lang.Object itself + // superClassOf() check is a fast path + return (supertypeName.equals("java.lang.Object") + && !potentialSubtypeName.equals("java.lang.Object")) + || supertype.equals(superClassOf((ClassType) potentialSubtype)) || superClassesOf((ClassType) potentialSubtype).contains(supertype) || implementedInterfacesOf((ClassType) potentialSubtype).contains(supertype); } else if (potentialSubtype instanceof ArrayType) { // Arrays are subtypes of java.lang.Object, java.io.Serializable and java.lang.Cloneable - String fullyQualifiedName = ((ClassType) supertype).getFullyQualifiedName(); - return fullyQualifiedName.equals("java.lang.Object") - || fullyQualifiedName.equals("java.io.Serializable") - || fullyQualifiedName.equals("java.lang.Cloneable"); + return supertypeName.equals("java.lang.Object") + || supertypeName.equals("java.io.Serializable") + || supertypeName.equals("java.lang.Cloneable"); } else { throw new AssertionError("potentialSubtype has unexpected type"); } @@ -162,7 +171,7 @@ default boolean isSubtype(@Nonnull Type supertype, @Nonnull Type potentialSubtyp /** * Returns all superclasses of classType up to java.lang.Object, which - * will be the last entry in the list. + * will be the last entry in the list. i.e. its ordered from bottom level to top level. */ @Nonnull default List superClassesOf(@Nonnull ClassType classType) { @@ -174,4 +183,33 @@ default List superClassesOf(@Nonnull ClassType classType) { } return superClasses; } + /** + * Returns all superclasses of classType up to java.lang.Object, which + * will be the last entry in the list, or till one of the superclasses is not contained in view. + */ + @Nonnull + default List incompleteSuperClassesOf(@Nonnull ClassType classType) { + List superClasses = new ArrayList<>(); + ClassType currentSuperClass = null; + try { + currentSuperClass = superClassOf(classType); + while (currentSuperClass != null) { + superClasses.add(currentSuperClass); + currentSuperClass = superClassOf(currentSuperClass); + } + } catch (IllegalArgumentException ex) { + logger.warn( + "Could not find " + + (currentSuperClass != null ? currentSuperClass : classType) + + " and stopped there the resolve of superclasses of " + + classType); + } + return superClasses; + } + + Set directlyImplementedInterfacesOf(@Nonnull ClassType type); + + boolean isInterface(@Nonnull ClassType type); + + Set directlyExtendedInterfacesOf(@Nonnull ClassType type); } diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java b/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java index 5a1b8bacf58..f04cbbefaf0 100644 --- a/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java +++ b/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java @@ -36,8 +36,6 @@ import javax.annotation.Nullable; import org.jgrapht.Graph; import org.jgrapht.graph.SimpleDirectedGraph; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import sootup.core.frontend.ResolveException; import sootup.core.model.SootClass; import sootup.core.typehierarchy.ViewTypeHierarchy.ScanResult.Edge; @@ -55,14 +53,12 @@ */ public class ViewTypeHierarchy implements MutableTypeHierarchy { - private static final Logger log = LoggerFactory.getLogger(ViewTypeHierarchy.class); - private final Supplier lazyScanResult = Suppliers.memoize(this::scanView); - @Nonnull private final View view; + @Nonnull private final View> view; /** to allow caching use Typehierarchy.fromView() to get/create the Typehierarchy. */ - public ViewTypeHierarchy(@Nonnull View view) { + public ViewTypeHierarchy(@Nonnull View> view) { this.view = view; } @@ -145,7 +141,7 @@ public Set directSubtypesOf(@Nonnull ClassType type) { } @Nonnull - private List superClassesOf(@Nonnull Vertex classVertex, boolean includingSelf) { + public List superClassesOf(@Nonnull Vertex classVertex, boolean includingSelf) { ScanResult scanResult = lazyScanResult.get(); Graph graph = scanResult.graph; @@ -171,20 +167,82 @@ private List superClassesOf(@Nonnull Vertex classVertex, boolean includi return superClasses; } - private Stream directlyImplementedInterfacesOf(Vertex classVertex) { + public Stream directlyImplementedInterfacesOf(@Nonnull Vertex classVertex) { Graph graph = lazyScanResult.get().graph; return graph.outgoingEdgesOf(classVertex).stream() .filter(edge -> edge.type == EdgeType.ClassDirectlyImplements) .map(graph::getEdgeTarget); } - private Stream directlyExtendedInterfacesOf(Vertex interfaceVertex) { + public Stream directlyExtendedInterfacesOf(@Nonnull Vertex interfaceVertex) { Graph graph = lazyScanResult.get().graph; return graph.outgoingEdgesOf(interfaceVertex).stream() .filter(edge -> edge.type == EdgeType.InterfaceDirectlyExtends) .map(graph::getEdgeTarget); } + public Stream directSuperClassOf(@Nonnull Vertex classVertex) { + Graph graph = lazyScanResult.get().graph; + return graph.outgoingEdgesOf(classVertex).stream() + .filter(edge -> edge.type == EdgeType.ClassDirectlyExtends) + .map(graph::getEdgeTarget); + } + + public Set directlyImplementedInterfacesOf(@Nonnull ClassType classType) { + Vertex vertex = lazyScanResult.get().typeToVertex.get(classType); + if (vertex == null) { + throw new IllegalStateException("Could not find '" + classType + "' in hierarchy."); + } + if (vertex.type != VertexType.Class) { + throw new IllegalArgumentException(classType + " is not a class."); + } + return directlyImplementedInterfacesOf(vertex) + .map(v -> v.javaClassType) + .collect(Collectors.toSet()); + } + + @Nonnull + public Set directlyExtendedInterfacesOf(@Nonnull ClassType interfaceType) { + Vertex vertex = lazyScanResult.get().typeToVertex.get(interfaceType); + if (vertex == null) { + throw new IllegalStateException("Could not find " + interfaceType + " in hierarchy."); + } + if (vertex.type != VertexType.Interface) { + throw new IllegalArgumentException(interfaceType + " is not a class."); + } + return directlyExtendedInterfacesOf(vertex) + .map(v -> v.javaClassType) + .collect(Collectors.toSet()); + } + + /** + * method exists for completeness - superClassOf() / which is basically SootClass.getSuperClass() + * should be more performant. + */ + @Nullable + @Deprecated + public ClassType directSuperClassOf(@Nonnull ClassType classType) { + Vertex vertex = lazyScanResult.get().typeToVertex.get(classType); + if (vertex == null) { + throw new IllegalStateException("Could not find " + classType + " in hierarchy."); + } + Graph graph = lazyScanResult.get().graph; + List list = + graph.outgoingEdgesOf(vertex).stream() + .filter(edge -> edge.type == EdgeType.ClassDirectlyExtends) + .map(graph::getEdgeTarget) + .collect(Collectors.toList()); + + if (list.isEmpty()) { + /* is java.lang.Object */ + return null; + } else if (list.size() > 1) { + throw new RuntimeException(classType + "cannot have multiple superclasses"); + } else { + return list.get(0).javaClassType; + } + } + @Nonnull @Override public Set implementedInterfacesOf(@Nonnull ClassType type) { @@ -192,7 +250,7 @@ public Set implementedInterfacesOf(@Nonnull ClassType type) { Vertex vertex = scanResult.typeToVertex.get(type); if (vertex == null) { - throw new ResolveException("Could not find " + type + " in hierarchy for view " + view); + throw new IllegalStateException("Could not find " + type + " in hierarchy for view " + view); } switch (vertex.type) { @@ -239,6 +297,21 @@ public ClassType superClassOf(@Nonnull ClassType classType) { return sootClassFor(classType).getSuperclass().orElse(null); } + public boolean isInterface(@Nonnull ClassType type) { + Vertex vertex = lazyScanResult.get().typeToVertex.get(type); + if (vertex == null) { + throw new RuntimeException("Could not find " + type + " in hierarchy."); + } + return vertex.type == VertexType.Interface; + } + + public boolean isClass(@Nonnull ClassType type) { + Vertex vertex = lazyScanResult.get().typeToVertex.get(type); + if (vertex == null) { + throw new RuntimeException("Could not find " + type + " in hierarchy."); + } + return vertex.type == VertexType.Class; + } /** * Visits the subgraph of the specified vertex and calls the visitor for * each vertex in the subgraph. If includeSelf is true, the visitor is @@ -282,14 +355,10 @@ private static void visitSubgraph( *

In the graph structure, a type is only connected to its direct subtypes. */ private ScanResult scanView() { - long startNanos = System.nanoTime(); Map typeToVertex = new HashMap<>(); Graph graph = new SimpleDirectedGraph<>(null, null, false); - view.getClasses().stream() - .forEach(sootClass -> addSootClassToGraph(sootClass, typeToVertex, graph)); - double runtimeMs = (System.nanoTime() - startNanos) / 1e6; - log.info("Type hierarchy scan took " + runtimeMs + " ms"); + view.getClasses().forEach(sootClass -> addSootClassToGraph(sootClass, typeToVertex, graph)); return new ScanResult(typeToVertex, graph); } @@ -348,7 +417,7 @@ private SootClass sootClassFor(@Nonnull ClassType classType) { } @Override - public void addType(SootClass sootClass) { + public void addType(@Nonnull SootClass sootClass) { ScanResult scanResult = lazyScanResult.get(); addSootClassToGraph(sootClass, scanResult.typeToVertex, scanResult.graph); } diff --git a/sootup.core/src/main/java/sootup/core/types/ArrayType.java b/sootup.core/src/main/java/sootup/core/types/ArrayType.java index d2f380acab8..4a664a01fb5 100644 --- a/sootup.core/src/main/java/sootup/core/types/ArrayType.java +++ b/sootup.core/src/main/java/sootup/core/types/ArrayType.java @@ -38,6 +38,15 @@ public class ArrayType extends ReferenceType { private final int dimension; public ArrayType(Type baseType, int dimension) { + if (!(baseType instanceof PrimitiveType + || baseType instanceof ClassType + || baseType instanceof NullType)) { + throw new RuntimeException( + "The type: " + baseType + "can not be as a base type of an ArrayType."); + } + if (dimension < 1) { + throw new RuntimeException("The dimension of array type should be at least 1."); + } this.baseType = baseType; this.dimension = dimension; } @@ -84,11 +93,11 @@ public int getDimension() { return dimension; } - public Type getArrayElementType() { + public Type getElementType() { if (dimension > 1) { return new ArrayType(baseType, dimension - 1); } else { - return baseType; + return this.baseType; } } diff --git a/sootup.core/src/main/java/sootup/core/types/ClassType.java b/sootup.core/src/main/java/sootup/core/types/ClassType.java index 4e23121e3e1..e5e598a8d3d 100644 --- a/sootup.core/src/main/java/sootup/core/types/ClassType.java +++ b/sootup.core/src/main/java/sootup/core/types/ClassType.java @@ -22,8 +22,11 @@ * #L% */ +import java.util.Collections; import javax.annotation.Nonnull; import sootup.core.jimple.visitor.TypeVisitor; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.MethodSubSignature; import sootup.core.signatures.PackageName; import sootup.core.signatures.Signature; @@ -57,6 +60,11 @@ public boolean equals(Object o) { return getFullyQualifiedName().equals(((ClassType) o).getFullyQualifiedName()); } + public MethodSignature getStaticInitializer() { + return new MethodSignature( + this, new MethodSubSignature("", Collections.emptyList(), VoidType.getInstance())); + } + @Override public String toString() { return getFullyQualifiedName(); diff --git a/sootup.core/src/main/java/sootup/core/types/PrimitiveType.java b/sootup.core/src/main/java/sootup/core/types/PrimitiveType.java index 0d96a10a8f0..73189e9b50a 100644 --- a/sootup.core/src/main/java/sootup/core/types/PrimitiveType.java +++ b/sootup.core/src/main/java/sootup/core/types/PrimitiveType.java @@ -56,14 +56,6 @@ public String toString() { return name; } - public static boolean isIntLikeType(Type t) { - return t == PrimitiveType.IntType.getInstance() - || t == PrimitiveType.ByteType.getInstance() - || t == PrimitiveType.ShortType.getInstance() - || t == PrimitiveType.CharType.getInstance() - || t == PrimitiveType.BooleanType.getInstance(); - } - @Nonnull public static ByteType getByte() { return ByteType.getInstance(); @@ -104,7 +96,7 @@ public static BooleanType getBoolean() { return BooleanType.getInstance(); } - public static class ByteType extends PrimitiveType { + public static class ByteType extends PrimitiveType.IntType { private static final ByteType INSTANCE = new ByteType(); private ByteType() { @@ -121,7 +113,7 @@ public void accept(@Nonnull TypeVisitor v) { } } - public static class ShortType extends PrimitiveType { + public static class ShortType extends PrimitiveType.IntType { private static final ShortType INSTANCE = new ShortType(); private ShortType() { @@ -145,6 +137,10 @@ public IntType() { super("int"); } + protected IntType(@Nonnull String name) { + super(name); + } + public static IntType getInstance() { return INSTANCE; } @@ -206,7 +202,7 @@ public void accept(@Nonnull TypeVisitor v) { } } - public static class CharType extends PrimitiveType { + public static class CharType extends PrimitiveType.IntType { private static final CharType INSTANCE = new CharType(); private CharType() { @@ -223,7 +219,7 @@ public void accept(@Nonnull TypeVisitor v) { } } - public static class BooleanType extends PrimitiveType { + public static class BooleanType extends PrimitiveType.IntType { private static final BooleanType INSTANCE = new BooleanType(); private BooleanType() { diff --git a/sootup.core/src/main/java/sootup/core/types/Type.java b/sootup.core/src/main/java/sootup/core/types/Type.java index c0f4ff2bce9..5415f91b9bc 100644 --- a/sootup.core/src/main/java/sootup/core/types/Type.java +++ b/sootup.core/src/main/java/sootup/core/types/Type.java @@ -22,8 +22,62 @@ * #L% */ +import javax.annotation.Nonnull; import sootup.core.jimple.visitor.Acceptor; import sootup.core.jimple.visitor.TypeVisitor; /** Represents the signature of a Java type, e.g., a class, a primitive type, void, or null. */ -public abstract class Type implements Acceptor {} +public abstract class Type implements Acceptor { + + public static boolean isObjectLikeType(Type type) { + return type.toString().equals("java.lang.Object") + || type.toString().equals("java.io.Serializable") + || type.toString().equals("java.lang.Cloneable"); + } + + public static boolean isIntLikeType(Type type) { + return type == PrimitiveType.IntType.getInstance() + || type == PrimitiveType.ByteType.getInstance() + || type == PrimitiveType.ShortType.getInstance() + || type == PrimitiveType.CharType.getInstance() + || type == PrimitiveType.BooleanType.getInstance(); + } + + public static boolean isObject(Type type) { + return type.toString().equals("java.lang.Object"); + } + + /** + * This method is used to make an array type for the given type. If the given type is an array + * type, then increase its dimension with given dim + */ + public static ArrayType createArrayType(@Nonnull Type type, int dim) { + if (type instanceof ArrayType) { + return new ArrayType( + ((ArrayType) type).getBaseType(), ((ArrayType) type).getDimension() + dim); + } else { + return new ArrayType(type, dim); + } + } + + public static int getValueBitSize(Type type) { + if (type instanceof PrimitiveType.BooleanType) { + return 1; + } + if (type instanceof PrimitiveType.ByteType) { + return 8; + } + if (type instanceof PrimitiveType.ShortType) { + return 16; + } + if (type instanceof PrimitiveType.IntType || type instanceof PrimitiveType.FloatType) { + return 32; + } + if (type instanceof PrimitiveType.LongType + || type instanceof PrimitiveType.DoubleType + || type instanceof ClassType) { + return 64; + } + return 0; + } +} diff --git a/sootup.core/src/main/java/sootup/core/util/DotExporter.java b/sootup.core/src/main/java/sootup/core/util/DotExporter.java index 6c0b2ae056f..134435c9043 100644 --- a/sootup.core/src/main/java/sootup/core/util/DotExporter.java +++ b/sootup.core/src/main/java/sootup/core/util/DotExporter.java @@ -10,6 +10,7 @@ import sootup.core.graph.StmtGraph; import sootup.core.jimple.common.stmt.*; import sootup.core.jimple.javabytecode.stmt.JSwitchStmt; +import sootup.core.signatures.MethodSignature; import sootup.core.types.ClassType; /** @@ -19,7 +20,11 @@ */ public class DotExporter { - public static String buildGraph(@Nonnull StmtGraph graph) { + public static String buildGraph( + @Nonnull StmtGraph graph, + boolean isICFG, + Map calls, + MethodSignature methodSignature) { // TODO: hint: use edge weight to have a better top->down code like linear layouting with // starting stmt at the top; @@ -27,14 +32,12 @@ public static String buildGraph(@Nonnull StmtGraph graph) { // blocks StringBuilder sb = new StringBuilder(); - sb.append("digraph G {\n") - .append("\tcompound=true\n") - .append("\tlabelloc=b\n") - .append("\tstyle=filled\n") - .append("\tcolor=gray90\n") - .append("\tnode [shape=box,style=filled,color=white]\n") - .append("\tedge [fontsize=10,arrowsize=1.5,fontcolor=grey40]\n") - .append("\tfontsize=10\n\n"); + + boolean isAdded = false; + + if (!isICFG) { + buildDiGraphObject(sb); + } /* entrypoint */ Stmt startingStmt = graph.getStartingStmt(); @@ -86,6 +89,16 @@ public static String buildGraph(@Nonnull StmtGraph graph) { if (stmts.size() > 1) { sb.append("\n\t\t"); for (Stmt stmt : stmts) { + if (methodSignature != null && calls != null) { + for (Map.Entry entry : calls.entrySet()) { + int key = entry.getKey(); + MethodSignature value = entry.getValue(); + if (methodSignature.equals(value) && !isAdded) { + sb.append(key).append(" -> "); + isAdded = true; + } + } + } sb.append(stmt.hashCode()).append(" -> "); } sb.delete(sb.length() - 4, sb.length()); @@ -158,7 +171,8 @@ public static String buildGraph(@Nonnull StmtGraph graph) { sb.append("\n"); } - return sb.append("}").toString(); + if (!isICFG) return sb.append("}").toString(); + else return sb.toString(); } private static String escape(String str) { @@ -166,10 +180,22 @@ private static String escape(String str) { return StringEscapeUtils.escapeXml10(str); } + public static StringBuilder buildDiGraphObject(StringBuilder sb) { + sb.append("digraph G {\n") + .append("\tcompound=true\n") + .append("\tlabelloc=b\n") + .append("\tstyle=filled\n") + .append("\tcolor=gray90\n") + .append("\tnode [shape=box,style=filled,color=white]\n") + .append("\tedge [fontsize=10,arrowsize=1.5,fontcolor=grey40]\n") + .append("\tfontsize=10\n\n"); + return sb; + } + public static String createUrlToWebeditor(@Nonnull StmtGraph graph) { try { return "http://magjac.com/graphviz-visual-editor/?dot=" - + URLEncoder.encode(buildGraph(graph), "UTF-8"); + + URLEncoder.encode(buildGraph(graph, false, null, null), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } diff --git a/sootup.core/src/main/java/sootup/core/util/PathUtils.java b/sootup.core/src/main/java/sootup/core/util/PathUtils.java index 2253e4d7c39..613f2e3088a 100644 --- a/sootup.core/src/main/java/sootup/core/util/PathUtils.java +++ b/sootup.core/src/main/java/sootup/core/util/PathUtils.java @@ -60,7 +60,7 @@ public static boolean hasExtension(@Nonnull Path path, @Nonnull Collection filterJimple(Stream stream) { .collect(Collectors.toCollection(ArrayList::new)); } - public static void printJimpleForTest(SootMethod m) { - System.out.println(printedJimpleToArrayRepresentation(m.getBody())); + public static void generateJimpleForTest(@Nonnull SootMethod m) { + System.out.println(generateJimpleForTest(m.getBody())); } /** Helper for writing tests . */ - public static String printedJimpleToArrayRepresentation(Body b) { + public static String generateJimpleForTest(@Nonnull Body b) { ArrayList arr = filterJimple(Utils.bodyStmtsAsStrings(b).stream()); - return printJimpleStmtsForTest(arr); + return generateJimpleTest(arr); } - public static String printJimpleStmtsForTest(List stmts) { + public static String generateJimpleTest(@Nonnull List stmts) { StringBuilder sb = new StringBuilder(); + + sb.append( + "List actualStmts = Utils.bodyStmtsAsStrings( body );\nAssert.assertEquals(\nStream.of(\n"); + stmts.forEach( item -> sb.append('"') @@ -188,8 +192,11 @@ public static String printJimpleStmtsForTest(List stmts) { .append(',') .append("\n")); if (stmts.size() > 0) { - sb.setLength(sb.length() - 1); + sb.setCharAt(sb.length() - 2, '\n'); } + + sb.append(").collect(Collectors.toList()), actualStmts);"); + return sb.toString(); } } diff --git a/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java b/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java index ff514b5dc4c..648df78ec11 100644 --- a/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java +++ b/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java @@ -24,14 +24,15 @@ import java.io.PrintWriter; import java.util.*; +import java.util.stream.Collectors; import sootup.core.graph.StmtGraph; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Trap; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.Body; +import sootup.core.model.ClassModifier; import sootup.core.model.Field; import sootup.core.model.Method; -import sootup.core.model.Modifier; import sootup.core.model.SootClass; import sootup.core.model.SootField; import sootup.core.model.SootMethod; @@ -135,16 +136,16 @@ public void printTo(SootClass cl, PrintWriter out) { } */ - EnumSet modifiers = EnumSet.copyOf(cl.getModifiers()); + EnumSet modifiers = EnumSet.copyOf(cl.getModifiers()); // remove unwanted modifier combinations - if (cl.isInterface() && Modifier.isAbstract(modifiers)) { - modifiers.remove(Modifier.ABSTRACT); + if (cl.isInterface() && ClassModifier.isAbstract(modifiers)) { + modifiers.remove(ClassModifier.ABSTRACT); } if (modifiers.size() != 0) { - printer.modifier(Modifier.toString(modifiers)); + printer.modifier(ClassModifier.toString(modifiers)); printer.literal(" "); } - if (!Modifier.isInterface(modifiers) && !Modifier.isAnnotation(modifiers)) { + if (!ClassModifier.isInterface(modifiers) && !ClassModifier.isAnnotation(modifiers)) { printer.literal("class "); } @@ -404,25 +405,19 @@ private void printLocalsInBody(Body body, StmtPrinter up) { // group locals by type { for (Local local : body.getLocals()) { - List localList; - - Type t = local.getType(); - - if (typeToLocals.containsKey(t)) { - localList = typeToLocals.get(t); - } else { - localList = new ArrayList<>(); - typeToLocals.put(t, localList); - } - - localList.add(local); + typeToLocals.computeIfAbsent(local.getType(), k -> new ArrayList<>()).add(local); } } // Print locals { - for (Type type : typeToLocals.keySet()) { + final Collection types = + typeToLocals.keySet().stream() + .sorted(Comparator.comparing(Object::toString)) + .collect(Collectors.toList()); + for (Type type : types) { List localList = new ArrayList<>(typeToLocals.get(type)); + localList.sort(Comparator.comparing(Local::getName)); up.typeSignature(type); up.literal(" "); diff --git a/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java b/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java index 962fe3287db..d801585b227 100644 --- a/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/CheckInitValidator.java @@ -30,7 +30,8 @@ public class CheckInitValidator implements BodyValidator { @Override public void validate(Body body, List exception) { - // TODO: check code copied from old soot + // TODO: #535 implement validator + // check code copied from old soot /* * ExceptionalUnitGraph g = new ExceptionalUnitGraph(body, ThrowAnalysisFactory.checkInitThrowAnalysis(), false); * diff --git a/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java b/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java index 2d57b0076e9..dc70ca2eb01 100644 --- a/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java +++ b/sootup.core/src/main/java/sootup/core/validation/LocalsValidator.java @@ -23,32 +23,37 @@ */ import java.util.List; +import java.util.Set; +import javax.annotation.Nonnull; import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; import sootup.core.model.Body; public class LocalsValidator implements BodyValidator { - /** Verifies that each Local of getUseAndDefBoxes() is in this body's locals Chain. */ + /** Verifies that each Local of getUses() and getDefs() belongs to this body's locals. */ @Override - public void validate(Body body, List exception) { - for (Value v : body.getUses()) { - validateLocal(body, v, exception); - } - for (Value v : body.getDefs()) { - validateLocal(body, v, exception); - } - } + public void validate(@Nonnull Body body, @Nonnull List exception) { + final Set locals = body.getLocals(); + + body.getUses() + .parallelStream() + .filter(value -> value instanceof Local && !locals.contains(value)) + .forEach( + value -> + exception.add( + new ValidationException( + value, + "Local not in chain : " + value + " in " + body.getMethodSignature()))); - private void validateLocal(Body body, Value v, List exception) { - Value value; - if ((value = v) instanceof Local) { - if (!body.getLocals().contains(value)) { - exception.add( - new ValidationException( - value, "Local not in chain : " + value + " in " + body.getMethodSignature())); - } - } + body.getDefs() + .parallelStream() + .filter(value -> value instanceof Local && !locals.contains(value)) + .forEach( + value -> + exception.add( + new ValidationException( + value, + "Local not in chain : " + value + " in " + body.getMethodSignature()))); } @Override diff --git a/sootup.core/src/main/java/sootup/core/views/AbstractView.java b/sootup.core/src/main/java/sootup/core/views/AbstractView.java index 4fca873cf45..dc2469f9b9c 100644 --- a/sootup.core/src/main/java/sootup/core/views/AbstractView.java +++ b/sootup.core/src/main/java/sootup/core/views/AbstractView.java @@ -22,8 +22,6 @@ * #L% */ -import java.util.HashMap; -import java.util.Map; import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -47,8 +45,6 @@ public abstract class AbstractView> implements View { @Nonnull private final Project> project; - @Nonnull private final Map, Object> moduleData = new HashMap<>(); - @Nullable private TypeHierarchy typeHierarchy; @Override @@ -105,18 +101,6 @@ public Optional getField(@Nonnull FieldSignature signature) return aClass.get().getField(signature.getSubSignature()); } - @SuppressWarnings("unchecked") // Safe because we only put T in putModuleData - @Override - @Nullable - public K getModuleData(@Nonnull ModuleDataKey key) { - return (K) moduleData.get(key); - } - - @Override - public void putModuleData(@Nonnull ModuleDataKey key, @Nonnull K value) { - moduleData.put(key, value); - } - @Override @Nonnull public Project> getProject() { diff --git a/sootup.core/src/main/java/sootup/core/views/View.java b/sootup.core/src/main/java/sootup/core/views/View.java index c2bd0efdf5d..84f254a5f86 100644 --- a/sootup.core/src/main/java/sootup/core/views/View.java +++ b/sootup.core/src/main/java/sootup/core/views/View.java @@ -25,14 +25,10 @@ import java.util.Collection; import java.util.List; import java.util.Optional; -import java.util.function.Function; -import java.util.function.Supplier; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import sootup.core.IdentifierFactory; import sootup.core.Project; import sootup.core.Scope; -import sootup.core.frontend.ResolveException; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.model.SootClass; import sootup.core.model.SootField; @@ -54,10 +50,7 @@ public interface View { Project getProject(); @Nonnull - List getBodyInterceptors(AnalysisInputLocation inputLocation); - - @Nonnull - List getBodyInterceptors(); + List getBodyInterceptors(AnalysisInputLocation inputLocation); /** Return all classes in the view. */ @Nonnull @@ -93,59 +86,7 @@ public interface View { @Nonnull default T getClassOrThrow(@Nonnull ClassType classType) { return getClass(classType) - .orElseThrow(() -> new ResolveException("Could not find " + classType + " in View.")); - } - - /** @see ModuleDataKey */ - void putModuleData(@Nonnull ModuleDataKey key, @Nonnull K value); - - /** @see ModuleDataKey */ - @Nullable - K getModuleData(@Nonnull ModuleDataKey key); - - /** - * @see java.util.Map#computeIfAbsent(Object, Function) - * @see ModuleDataKey - */ - default K computeModuleDataIfAbsent(@Nonnull ModuleDataKey key, Supplier dataSupplier) { - K moduleData = getModuleData(key); - if (moduleData != null) { - return moduleData; - } - - K computedModuleData = dataSupplier.get(); - putModuleData(key, computedModuleData); - return computedModuleData; + .orElseThrow( + () -> new IllegalArgumentException("Could not find " + classType + " in View.")); } - - /** - * A key for use with {@link #getModuleData(ModuleDataKey)}, {@link #putModuleData(ModuleDataKey, - * Object)} and {@link #computeModuleDataIfAbsent(ModuleDataKey, Supplier)}. This allows - * additional data to be stored or cached inside a {@link View} and to be retrieved in a type-safe - * manner. A {@link ModuleDataKey} of type T can only be used to store and retrieve - * data of type T. - * - *

Additionally, since it is an abstract class and not an interface, it can be assured that a - * given class can only be a key for a single type, which avoids clashes. - * - *

Example:
- *
- * - *

-   *   class StringDataKey extends ModuleDataKey<String> {
-   *     public static final StringDataKey instance = new StringDataKey();
-   *     private StringDataKey() {}
-   *   }
-   *
-   *   void storeInView(String str, View view) {
-   *     view.putModuleData(StringDataKey.instance, str);
-   *     String retrieved = view.getModuleData(StringDataKey.instance);
-   *   }
-   * 
- * - * @param The type of the stored and retrieved data that is associated with the key - * @author Christian Brüggemann - */ - @SuppressWarnings("unused") // Used in modules - abstract class ModuleDataKey {} } diff --git a/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java b/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java index 2c0b2c4422b..64c9c4bf2e7 100644 --- a/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java +++ b/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java @@ -214,25 +214,25 @@ public void removeStmtConditionalTailBetweenBlocks() { public void modifyStmtToBlockAtTail() { MutableBlockStmtGraph graph = new MutableBlockStmtGraph(); assertEquals(0, graph.getBlocksSorted().size()); - assertEquals(0, graph.nodes().size()); + assertEquals(0, graph.getNodes().size()); graph.addNode(firstNop); graph.setStartingStmt(firstNop); - assertEquals(1, graph.nodes().size()); + assertEquals(1, graph.getNodes().size()); assertEquals(1, graph.getBlocksSorted().size()); assertEquals(1, graph.getBlocksSorted().get(0).getStmts().size()); graph.putEdge(firstNop, secondNop); assertEquals(1, graph.getBlocksSorted().size()); - assertEquals(2, graph.nodes().size()); + assertEquals(2, graph.getNodes().size()); graph.putEdge(secondNop, thirdNop); assertEquals(1, graph.getBlocksSorted().size()); - assertEquals(3, graph.nodes().size()); + assertEquals(3, graph.getNodes().size()); // insert branchingstmt at end graph.putEdge(thirdNop, conditionalStmt); - assertEquals(4, graph.nodes().size()); + assertEquals(4, graph.getNodes().size()); assertEquals(1, graph.getBlocksSorted().size()); assertEquals(0, graph.getBlocksSorted().get(0).getPredecessors().size()); assertEquals(0, graph.getBlocksSorted().get(0).getSuccessors().size()); @@ -263,17 +263,17 @@ public void modifyStmtToBlockAtTail() { graph.removeEdge(conditionalStmt, firstNop); assertEquals(2, graph.getBlocksSorted().size()); - assertEquals(4, graph.nodes().size()); + assertEquals(4, graph.getNodes().size()); graph.removeNode(firstNop); - assertEquals(3, graph.nodes().size()); + assertEquals(3, graph.getNodes().size()); // remove branchingstmt at head graph.removeEdge(conditionalStmt, secondNop); assertEquals(1, graph.getBlocksSorted().size()); - assertEquals(3, graph.nodes().size()); + assertEquals(3, graph.getNodes().size()); graph.removeNode(secondNop); - assertEquals(2, graph.nodes().size()); + assertEquals(2, graph.getNodes().size()); assertEquals(1, graph.getBlocksSorted().size()); } @@ -802,13 +802,13 @@ public void copyOf() { final StmtGraph graph2 = new MutableBlockStmtGraph(graph); assertEquals(graph.getStartingStmt(), graph2.getStartingStmt()); - assertEquals(graph.nodes().size(), graph2.nodes().size()); + assertEquals(graph.getNodes().size(), graph2.getNodes().size()); assertEquals( Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(stmt1, stmt2))), - graph2.nodes()); + graph2.getNodes()); - assertEquals(graph.nodes().size(), graph2.nodes().size()); - for (Stmt node : graph.nodes()) { + assertEquals(graph.getNodes().size(), graph2.getNodes().size()); + for (Stmt node : graph.getNodes()) { assertEquals(graph.predecessors(node), graph2.predecessors(node)); assertEquals(graph.successors(node), graph2.successors(node)); } @@ -862,9 +862,9 @@ public void removeNodeWOEdges() { Stmt stmt = new JNopStmt(StmtPositionInfo.createNoStmtPositionInfo()); MutableStmtGraph graph = new MutableBlockStmtGraph(); graph.addNode(stmt); - assertTrue(graph.nodes().contains(stmt)); + assertTrue(graph.getNodes().contains(stmt)); graph.removeNode(stmt); - assertFalse(graph.nodes().contains(stmt)); + assertFalse(graph.getNodes().contains(stmt)); } @Test @@ -874,12 +874,12 @@ public void removeNodeWOPredecessors() { MutableStmtGraph graph = new MutableBlockStmtGraph(); graph.putEdge(stmt1, stmt2); - assertTrue(graph.nodes().contains(stmt1)); + assertTrue(graph.getNodes().contains(stmt1)); assertEquals(Collections.singletonList(stmt2), graph.successors(stmt1)); assertEquals(Collections.singletonList(stmt1), graph.predecessors(stmt2)); graph.removeNode(stmt1); - assertFalse(graph.nodes().contains(stmt1)); + assertFalse(graph.getNodes().contains(stmt1)); assertTrue(graph.predecessors(stmt2).isEmpty()); try { @@ -898,12 +898,12 @@ public void removeNodeWOSuccessors() { MutableStmtGraph graph = new MutableBlockStmtGraph(); graph.putEdge(stmt1, stmt2); - assertTrue(graph.nodes().contains(stmt2)); + assertTrue(graph.getNodes().contains(stmt2)); assertEquals(Collections.singletonList(stmt2), graph.successors(stmt1)); assertEquals(Collections.singletonList(stmt1), graph.predecessors(stmt2)); graph.removeNode(stmt2); - assertFalse(graph.nodes().contains(stmt2)); + assertFalse(graph.getNodes().contains(stmt2)); try { graph.predecessors(stmt2); fail(); diff --git a/sootup.examples/pom.xml b/sootup.examples/pom.xml index b3e6948cb06..5bc9e88731d 100644 --- a/sootup.examples/pom.xml +++ b/sootup.examples/pom.xml @@ -8,39 +8,39 @@ org.soot-oss sootup - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.callgraph - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.core - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.java.bytecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.java.core - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.java.sourcecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT org.soot-oss sootup.jimple.parser - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT @@ -49,7 +49,7 @@ org.soot-oss sootup.java.sourcecode - 1.0.0-SNAPSHOT + 1.1.2-SNAPSHOT pom import @@ -59,11 +59,11 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - ${nexus-staging-maven-plugin.version} + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} - true + true diff --git a/sootup.examples/src/test/java/sootup/examples/basicSetup/BasicSetup.java b/sootup.examples/src/test/java/sootup/examples/basicSetup/BasicSetup.java index a83c51ad96a..adc4bdc3d56 100644 --- a/sootup.examples/src/test/java/sootup/examples/basicSetup/BasicSetup.java +++ b/sootup.examples/src/test/java/sootup/examples/basicSetup/BasicSetup.java @@ -57,7 +57,7 @@ public void createByteCodeProject() { // from the directory Path pathToBinary = Paths.get("src/test/resources/BasicSetup/binary"); AnalysisInputLocation inputLocation = - new PathBasedAnalysisInputLocation(pathToBinary, null); + PathBasedAnalysisInputLocation.create(pathToBinary, null); // Specify the language of the JavaProject. This is especially relevant for Multi-release jars, // where classes are loaded depending on the language level of the analysis @@ -78,7 +78,7 @@ public void createByteCodeProject() { classType, "main", "void", Collections.singletonList("java.lang.String[]")); // Create a view for project, which allows us to retrieve classes - View view = project.createOnDemandView(); + View view = project.createView(); // Assert that class is present assertTrue(view.getClass(classType).isPresent()); diff --git a/sootup.examples/src/test/java/sootup/examples/bodyInterceptor/BodyInterceptor.java b/sootup.examples/src/test/java/sootup/examples/bodyInterceptor/BodyInterceptor.java index bc23c3f1275..dce04ca15d5 100644 --- a/sootup.examples/src/test/java/sootup/examples/bodyInterceptor/BodyInterceptor.java +++ b/sootup.examples/src/test/java/sootup/examples/bodyInterceptor/BodyInterceptor.java @@ -34,7 +34,7 @@ public void test() { // Create a AnalysisInputLocation, which points to a directory. All class files will be loaded // from the directory AnalysisInputLocation inputLocation = - new PathBasedAnalysisInputLocation( + PathBasedAnalysisInputLocation.create( Paths.get("src/test/resources/BodyInterceptor/binary"), null); // Specify the language of the JavaProject. This is especially relevant for Multi-release jars, @@ -55,16 +55,16 @@ public void test() { // Create a view for project, which allows us to retrieve classes // add class loading options, which can specify body interceptors - JavaView view = - project.createOnDemandView( - analysisInputLocation -> - new ClassLoadingOptions() { - @Nonnull - @Override - public List getBodyInterceptors() { - return Collections.singletonList(new DeadAssignmentEliminator()); - } - }); + JavaView view = project.createView(); + view.configBodyInterceptors( + analysisInputLocation -> + new ClassLoadingOptions() { + @Nonnull + @Override + public List getBodyInterceptors() { + return Collections.singletonList(new DeadAssignmentEliminator()); + } + }); // Assert that class is present assertTrue(view.getClass(classType).isPresent()); diff --git a/sootup.examples/src/test/java/sootup/examples/callgraph/CallgraphExample.java b/sootup.examples/src/test/java/sootup/examples/callgraph/CallgraphExample.java index 7650c799f6b..1c551b0a44d 100644 --- a/sootup.examples/src/test/java/sootup/examples/callgraph/CallgraphExample.java +++ b/sootup.examples/src/test/java/sootup/examples/callgraph/CallgraphExample.java @@ -5,7 +5,6 @@ import sootup.callgraph.CallGraph; import sootup.callgraph.CallGraphAlgorithm; import sootup.callgraph.ClassHierarchyAnalysisAlgorithm; -import sootup.callgraph.RapidTypeAnalysisAlgorithm; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.signatures.MethodSignature; import sootup.core.typehierarchy.ViewTypeHierarchy; @@ -40,7 +39,7 @@ public void test() { System.getProperty("java.home") + "/lib/rt.jar")) // add rt.jar .build(); - JavaView view = project.createFullView(); + JavaView view = project.createView(); // Get a MethodSignature ClassType classTypeA = project.getIdentifierFactory().getClassType("A"); @@ -56,8 +55,8 @@ public void test() { // Create type hierarchy and CHA final ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); System.out.println(typeHierarchy.subclassesOf(classTypeA)); - CallGraphAlgorithm cha = new ClassHierarchyAnalysisAlgorithm(view, typeHierarchy); - cha = new RapidTypeAnalysisAlgorithm(view, typeHierarchy); + CallGraphAlgorithm cha = new ClassHierarchyAnalysisAlgorithm(view); + // Create CG by initializing CHA with entry method(s) CallGraph cg = cha.initialize(Collections.singletonList(entryMethodSignature)); diff --git a/sootup.examples/src/test/java/sootup/examples/classhierarchy/ClassHierarchy.java b/sootup.examples/src/test/java/sootup/examples/classhierarchy/ClassHierarchy.java index b251d916413..408ab93736f 100644 --- a/sootup.examples/src/test/java/sootup/examples/classhierarchy/ClassHierarchy.java +++ b/sootup.examples/src/test/java/sootup/examples/classhierarchy/ClassHierarchy.java @@ -49,7 +49,7 @@ public void test() { System.getProperty("java.home") + "/lib/rt.jar")) // add rt.jar .build(); - JavaView view = project.createOnDemandView(); + JavaView view = project.createView(); // Create type hierarchy final ViewTypeHierarchy typeHierarchy = new ViewTypeHierarchy(view); diff --git a/sootup.examples/src/test/java/sootup/examples/mutatingSootClass/MutatingSootClass.java b/sootup.examples/src/test/java/sootup/examples/mutatingSootClass/MutatingSootClass.java index b4d53636a67..e7dec1c9e10 100644 --- a/sootup.examples/src/test/java/sootup/examples/mutatingSootClass/MutatingSootClass.java +++ b/sootup.examples/src/test/java/sootup/examples/mutatingSootClass/MutatingSootClass.java @@ -43,7 +43,8 @@ public void test() { // Create a AnalysisInputLocation, which points to a directory. All class files will be loaded // from the directory AnalysisInputLocation inputLocation = - new PathBasedAnalysisInputLocation(Paths.get("src/test/resources/BasicSetup/binary"), null); + PathBasedAnalysisInputLocation.create( + Paths.get("src/test/resources/BasicSetup/binary"), null); // Specify the language of the JavaProject. This is especially relevant for Multi-release jars, // where classes are loaded depending on the language level of the analysis @@ -63,7 +64,7 @@ public void test() { classType, "main", "void", Collections.singletonList("java.lang.String[]")); // Create a view for project, which allows us to retrieve classes - JavaView view = project.createOnDemandView(); + JavaView view = project.createView(); // Assert that class is present assertTrue(view.getClass(classType).isPresent()); diff --git a/sootup.java.bytecode/lib/dex-tools-2.2-SNAPSHOT.jar b/sootup.java.bytecode/lib/dex-tools-2.2-SNAPSHOT.jar deleted file mode 100644 index f2bd6580d3b19058fdef459f54083e98ede5faf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5775839 zcmeFXW0Y>cwjQ;&k-@bj$>2v$y^UX-+Sjl*1 zl94r6lKIS~C<6)x0|W#G1*9u+rwa5>0{NHtCqe&HE*;9mf zT(Gys-W}2o{ypX%kK#>(eG7Aggit5c+*;&7Pp8KkTnY!8y>E5Nb z%e?oaD)1l0b*q(_26}zfBZp?fvfnWc`n|93$2IFCjec*RZ}uHMiN1?rO*Q9v0<(NS zM;^UT-|x>AJWgGmC=K=)8jl}ub4T*M{axsHxAinmK3~tzXP3Weymjw&G#-0CcHUm@ zE~GY(W?-Glw0~a#qjbjr&;(i>Te2K&w%m+MOc@|{Jr&)LL$7g_a{BMDL~UxZ@~T7C zbZoMl$|uxzWAyD?aclMCpCF0zEH6~oB2V>qtG4eR$PpUNb?e4DhFf37j`>s)aMutg zim`pjbnM!FYBa8dGW8m2164JvBl;4L8`;%=aui~5^R$_3Pl+6Fr=@GJH9nOW$3!98 zlJh#xekYt@`E-*T2tjK-@+%=-fZUDy!R8`z$jVqUlEF!~cMo zv2NMQP_G5<1SX{QdW>>+&&Gq@ z$+emsR(H1PE34D~EnKE!X0!cqor4*`dHx8edeT?f zO`z<^55%eeI2ii9B+j47QN5%L_i^)ddl&cR2!_VPYg&b!KY8aYdBLww4jHOp*tsLl zE|>vX#nW|7LV@O}hCH9lvCiC?HmixOgxEc}1O43F4`??(oi-}G93yM>2A&8e)`Kaia;m8ha`sKHFTlwYkoqpa5pa)z{4G{jL4|>tmilI9N%asJpb>Eg)s!o$ z;VlnnpBZH!(wFh-9z=zk^^+D+OkI7rtK)Ko_)=b~sk+wkMTh8j;Hj8=6;h?OtG;T( z)1%lhX(_jZQCCY$hzFz`u|+{H{T6Vv&FS8;(V6-j+!Xf5?cD@(7f92%Rsu*^+p@(d z94hh+-t*7^sb(~rmr@xN?>P*`ZZxx9{aJbNCty+qjfBHjD|6NABt{n($9heX{IXz^ zAbsj_k4ZfORnbzFfjGy~c!YZR*4q`X`(qLeQdU1VVt*nKamoQ{=}0`;-8lZg5FLD4 z;Auh{!EM3_=waz#MldJl!xOW>q9`2T*t^xhms0sqoY&cT6#UCM-`G8YBW-^+EDpro z#n>{oX6!cwZ0d#`aL@oltD$!jTl}htuBNrCjbO+fsP5l0<$>|DtHuOmOg&&N6~hR#who96{Cud*lf;#YT3G_?8J?=zCAbt(eie?ln`Ba#Qo=BQhiUh1R?bswPvnTz*k-O66E19&(`Q+#(VB^@jxLi;=txE+dA-#N z-Al8}@{{V7y20m*GssepyQ>zA>nniSWjNd#WtVQ_z%lW;LGWLbtp+Pyl^NYoK^q_~O95|lsGwk0k1+=Rw3yA0(O^D=5!+Q;Wz!HV-!W&^*Sw^qg zylx0eUMJfbp0h!M#LHM?&neh~(p1e>7yIcjWy@?ccEwLZG6kq;X&gZzY!n+u%CX&K zawYHPyQ0ZF_qma*{hqPne8F7n&evgr=#-!_J_f(qc{Li3lSsW!eSO89m6f_MjM8UB zfEQ2@xUI^>EHfOllx;5`tVp_0)qR7XFmHxYO{fPHnDUu#puMU|!nNz!UI?oUr^5}R zY4#H5>3Kr6LQ9ah$mA&V?pa84x@&``_FhL!RIU)O0=v#hJo zFNF|-{UR~w&sIySWiBju<)xdf$?FKs@Y89nP5>4}rlwT!i_HgnaYlmpymAcYilyI- zlaF|mal2E^(Biyvp#gI})BS-NN1e|IWJdZSVLL#%$Cwpb0p z&4xpqk|Dann=2nD4-s`~7SRKg?l{KPSq&ypDV;@BHw@@U)7*94mv%eR?}pTia{Zzs z$!?tQXbkK3s(5JvgXX5p6mDzPwj6=sb<>|?N6Xenl;U*y<>Qv3(iW;z!c7@_dQl&H zvR=O*?EN!TKmGlGj^}!O?!O*PQu3RE!^$vYAAjmZTa56yZ65yzE@n0`H}l~ z_xt@NJ?Z`Q|2FskVfk3Tdiy$hpAVRG#OCnw@q!)c^KtQ_+3WA|^KtRGX=y4@ac3PG zL~rL*e{>D05bUqy1>j;WX4kEap1&>Aea7w?Da;D$J{kLAu5ckyb~^<--C#ZBRk>BS z@@+>jF?4v(aNRkv;q?I;Fg;PwWoGs)yH@cL@6S`S!6lUi8h`m?@?Lf(z%VJ*W!U9# z@`O;rn_U%Y)X0aFtzGs?i@aDbQ_cI8D!hMZoujaFT|6ac5yo^B_lpxGj*39O;|<@Z ze!JFs%I2M*TLZ{u+_Do8;=tLPb|=?dl?7*xH=y5mz&q4fj~O5jBIz3q1)7Pnk9o#f z!Qgtt56amI$ST4+|EBm%KX7HNY`!-tny1A>yNUmZz6_OuZ_2+TSSTQzmFT)Y&U7o2C`sVm(hZ3<5^bttJ4i4~^{e|7YwsVzL2_CksAT8!yH$SL z>~-$>)z3IX-`bYB!%Im-l6`&7-H9?L|7*rIcuh6+)6!j4;EkGqhlemw?ZOE7*%koWJM)3ufAM(mFrHv#BZiJqb{Zc zF(6k%vvW&|vwZ})&Ct8g<`?2lyn7vkMkdPNIpW(57j&9$vM-gK9BQ^qJOG6uuJqwCeJU-zu=6+3M@=NdhNX!#Vb#LtD zDWeh>udsjygC4qnS%-cEaTD1*MHrBbugjRf-M(61oBja*PpaTw-g@*kKJe*36hR;` z5D@CWrwZg1RR8hU|K+Tk%`Zrg2qHlMe2DHC7h?!;mM@CJ#zIIu(Jo3%8>nvAd+8Br_&V<9G#+Y z5g1e=&=}njhAOml5(zdZ+Uc-Wi+&fbt%E6#9XQH9SOp1!FA!lEmIDbA8Od0>$Nv0$ z@0Qo`*Z1)i2T;P2dt;zD*REq@P!7BOmL>CQex)ip58RwO$D-EB)wf{uk>s;qKIOOl z>|<|*v)V=N$}N*-4|gh@exdT4b?TGZbNGu%b1j%QpmTynt)5c6hEtI%WJgXV3!7eQ zW=`;8G@&)#m@0A}kq}QNI5V4E!k@evvMz&1poHe~;rTjVe2vzuuZoe>-I;26pQ_vj#uPk)s<{eX*>dMLEGi0`|Zo0Kjvhiebxc5-EiseuL2mq zQZy_K=$j&G2E%=w07sDLElyf&Oz~q#PFD7Ddd+cc5u;;T-WG>rym=Kc8n*(){*q0c zIRYj7^}6?AXlet+uP4mE5+Z#p?q6azhr^-UBVxMD6@MGWE3FsJgwuuGbc>>^H92}U zoZ`%5?0?)kL-CFp;f{|K{^JLLw+v?E3JwIs_7D5W@c+h!{<{UmsTcIzorw%3r7vw@{}-TLlrh z5u$6ziog~=47E2ke!u9pIeQ4UN?fUsK{5xzC_j5=i|@9 zRf{7wW0lDk6jq?xG8$W??J9N6Ho@s5%a;7pr76C_qQxe5Zt~~%F`ht@JUOK-T}59x zfgBBLxpgZGR2Nlvx>;Y5VtFl{(dc6s@5rU2v2K>Ku@-qj6#1Lft@B)Javqt5X0EzG z9f7u9t893iOt1OHcBu44yy{Tvus2Lfk^Q2ovIaydGyw&ZaFRUkG?>T+Omk-~_<5BH z6`A}_OCSceBDG5D^x5gPsII9a;$@1s^vx3O9!>#;c|{szxSN6rIVG(;EOYx&G8}jb z+_&`dk(bI`Wq2&wGTh#DNW4uswaA!Rb$PVAqb!FkHV?9nY3|}9Ha2!F9rNwfB@DI= zmIXjyuQ+BG|%Mx?O%Nw%RzI3NRful*8qylzAey>)6E_(KUV z6bmCAE))$7Kk#t)kKR5)F^;{!P7x)Sy`$D6TI*Mqt@`Ayj7JlEg4BZ6g4iA{bH{3Q z^>xxGI(zGB3l1ONn|CKp;my1RGD6I_W>4eHyy!AG(oVw|uY1%85%dWMj0p8gMqk|D z)9(a9*M=aXO=;Yh+Td?Cu>Vyw2WI?34M< zDE(5Lrv{g{q9P(eJFy0iDHEI_E)?DlN0CZNE*0!U?DaeHI|w2H(T~)$0jMMODy*J| zbtn+<-&OGQzRvkR%4MfMt-kF2{Cs={v+VboyZ>A2;D7lLNdO*%atg+`pD=~A9i2zG zj?}};4A$dXlN-53Xf&?I_c2u9c^=+FxDN4SlWh^<;gua3!A}hR!pn^R!XGsa3?CSHAU-O#W<(iI9>ddw8n~hrlGlNOMrO{N6ME^hj8I1sk0y zd&sgpyyZGEW(+5t(~#D^eFe(GhI0bp*oi)6eg(kEBRl+-t2M|9i;aI5Snml^A#d6m zX@kk)%uK!3IE%2-lzXKco6cBm*qWM@6UG;%GK1xXrN;cg{J>Pb?AV2mQCz?Re1@~y zxD6bmIq9oAG)80BIUUZHE0FbA!N{GqWECrK;VRCc>CIlCm_K0R>R%Sl;y~($XFP5;7)I5v0;qX%hw2svYq}2E z5Txst0NOmYXUSKd^$o{e{Rj;fu3R13GZzrz9L(KPBRTkvRPODE+~0e{7wWk6=XZAO zyM_}xP9^XhT#hVzMk73SfG+quS7fvwmj{`8Pm{^R(|CI(@+6>B5vp9gem2Asy z^>1H2O~j-A1_N)MJXG^$O1woCI6kOE6CXHFU(L2-;Uyikgev>VzC|^Er z(7vRPIVAQ~JE=rj`p}zqRtCgU-&QRf1}(BE%`pB{<}F_Eu;+?pN4*jSwOZO^uHdxd z^K{0s@W@>9d`*4})4-y6Q^9{{)g$x`e7|i!JykEw zA%&WI^qh`+H7(gqX&c(!S?ib&b8U`yT z+7~g0Gn7o|0U=5iIXQF>-B(JF+~(A*K>4jG?L-^3yxibHsra8f{fY{T1B8>rDKyV1 z_v%Smz3(PFeVbO&wAbn{Gx~><)`K2aOYYFJk}<|DowIxJNxulc%v9?hDqhx$z6fuxJr~0O-DQ^HLL-_vF!kvQ_Dt zV8KYI*NQL<#4l7EjMTNlW*UxZUX#NcE?;r_>qqD-a2#lhupDK);eWYVm=cSWqjtx-yQ4Y3m85Tmm~m8LWSg*jioN% zd?5<1UZMS~NsAZnSxT?>0kGRb704%7oePt)#F?eX`%VJn4^YyspC~^?hZ@}ear+mq zbdPTc0}k~sR%>Z$OMCZ_pB3=}M+)5Eu|LcAK>iKK46*)ZPq-!fSr+msyp&v^^~q_s zhFi<;PJHk^NX*(eOIMyq{pFy(DZgh+L9=Rlg(N@>E9ey?&njiAbH7DK(NGK)!%#5v zG{eeaa~iLPiMRgfE^Hwbm(X)FNn_yWs4%z?==0Y8n(bqmSr2RdrHtifwi>78 zAzsDmPz+h&&3rjl$x*@|``)}4!GXJgU8LL3a#2gDg416cGctPEeG$P5&38H1*SU@B zs?kl+K<%P-&t4VdnqD-3C5X`$Sg42z+C?S;w=70cG8Eg4WfmiZ7I9%5Ia!n_iYYS2 zs0W9MCP=sxUa5jf3Lw|RqY@`6?I5ePwf9F2OX=p6j$IzJOsa`tGOneM$2hi3b#Y_T zmt7nc)srn2qj?bRr>B6`HX+@?aJ~e<`_{x%9bs|5wg-xZ#tU=mp+#DCbE+p^Rhw2+J#x*SM$|ro7YItpX%FV8i;Rzu} zyX}o074Ndj&900&8S@8+ji=^_gN)loxaj%6Bxg_g4=f0XW5SLK>)|QbK%i^8z9R82 zAL4szMDPK^5fp%L#1dFwhTKDm>w5TXhH=@N57`}z!VY`tMLyL`l7R5TvJWkLc()H=u8iT~;g;IvcTV{J06A4n1gl1#xRkr`#YZLl8w4d9d z9fQPeE-x32l(xeIfncMt(?s5FcbhTe%(C|O+{n4DHD)W{SSd%f^WL0Z-kKgA23amz zFt~kwa4v+Vj~qacgy>`M;IQmIJzHNl6=r3d))}lJrYR}hl1iw>znr)whBS8}j+h%IjmPa5Od={(NNUKE}KYVz`lJ*@N^(Z@c#h!tUw*B+_zG4a?awRpH^QTO&r za-YIV{pYMK!4R95*5E`ZD3vc>;_93=ZDtMfrK7TPhhypk(6;>Xu_}?k+QEoJDw_(E zuvmoVSTjC`ODr(?ty7osP~1RO=0 zn6gFK9~yzZ+7&LI>!|CYV^6MQAebHoSdld?XNxp>&;33M7FeQeGqM`HrMUTJejwL8 z%Vsh)uqM({!SvAzSuF#4Hl9B`BpuARaT|wc0bhlH|6FjaY*Om%`Iz24ogU@^j}SDS z{>9b5!wC8OyBynckBh>i#^YIeAc5T_&V8paCWPZOPg8%sAo)`HTejgDK)K%+EHF0C zvlI+cg1>(%a|b725&wu?kX)7zm{<_WL}l!sZ^YQ~f_KYK($^J4@9VYm5?tHE^qF`84o3>U$Bp?KX zV%u;#=Q#W78M5XL%XNjYaY#fO#dQmU5+i*PPgnFHnOY+&2Rxp(7=VmiRFcI}pP0@$ zvl*SMrbhob$076*x9cBowa7oTqd)T8UdZ6An&9_Q1r6pkkxVb}){@HDwd0Y4(+0c*dRyeW;YhOyq5~X@=2GJApUvWx z7E~Gl)W>22EJ9TA$YJ9MrHZdf0CDwM3n{dNW451<8>4TC+E)~FVd9#CVUBcD&anzI z1e6?JoguC+>@&9`Tvy6N1F|Jp71$$gU(KN$XH;qm(Wu)JF$Uhw>Vn4WMVior4)*ze9znC=bX%ct2|?hB#C zltK+CZwc*}s<3`y$z$4P>e8ZSU_;8Zzah>^z-%PA^yplUF<1yYqV&9ES zRpe_T&#(i(-~rT6QP3lyrDWm{Fs4jHu%UY}3lv)-&+r48lAj4~0mk;w&L1ETG0L*iBjAOv`;FRI`j8T#hG1OuwGI=s@wP%aNpzMj zs<7L!*5z`dw@XnwN>cW8u~TYQmrW8zw)JB1t>v0jEd<`B+RC-EY1RJ-mFDf}90dP& z#@M_cBD_4CQ@1wwal24`afeZBUpiUIwo+{o#-vV%;8n@7Qte4tjT4oyp;eqe1%A5q z=BZXE7g&EyN9*Z%dYMMsXZTCkP5`lDd`GF8kWwcqQ8P^N+i0Sc9AGP#Y#6~NCM;ox za4B*PVI(T2EF_OL zJKo7&QKfwJN{64KVX(#Cx}G7L(K%zxzJi|jR84pW7(%`ZwWEGV zrk_f=6s4Rhu4w0xdq=!URP<;PQ8J?anxy7YG@~F+ZJM<8$doHDvQBlJI<@GyqwvNh zom#x4>rv;U-uGpla=zs3)A7bBvKSuIw@36`x&0-hznL{`)4Y!Oy=pfp&Z9rf!2M{( zK%K)XQ!Jt(PyZVC^lI?ZiX0)oC3Om}PUD^quGT%D31Z|?@fYmRJR#BW5cWkytgAlwg3o(M*CA7L>}q9G#84?C}P zhip4$6ioRj^5Gogu`!h?PwgUCq3$JrY27s+)k)^C$OT1B4j5a);k{$@_x@a9ZzTMJ z_(sTM^Arlfya#%ELx->dC{HgOU}dfsxj^Otw4I)UT|rHTo{oSm zp!A9Xu*2xMg%E(bV8n>CyWQx+=Dbf+7-m{&`e zQ90tox2|TA(o50D%)m#_z{k&|O`J9xyX*|E1v)^bkCxIHFUy!L-)25Z{q2PmeP$!g zK+d?r%(x=Vz(v}6CvjytzAztOnu{&TL6_j5iMLnB`(4Y~ee~~gGH3Vyk+J9|?Aw#x zxgu5<;%W+fB)@t)-@Tmt2r)H0baj7!c6PrxxxpS?7W3G3?wFUXL1j<`uSup*82?KM z|4WdpX(r(!s>T5=#!7PeUJq4Lk|Ka?<&QKS{a`=+5QOlPiR;QJ!B5s3ru-(7a*wEQ zhAf@RPo(lWG~a?GOpZ8YVaDH21-)0virSyD1$M5KOqYn{cP^bwEg6&KQkP9W7E8({ zi_b_IlX}2viZ1SaG)?N1o=3SlwT-?$i<&qAxew+Q>LtaDVKB{lRiaOl?lxWx zB2sD)pSI?ltxKMeQlWVBCzV?!pHgGy>g3J2q*pTh#NdS9D{GguA(e2(=7i(H`>m%} z>5p^XCGkcLoL3Hx-2T0DNcJy|D&;P%w3(jOt_OR!{$35cbe*-l2mimlwQ3C0kZV26 zrTwLM9?m`QLi}a^DLk}&r}8oeT{%ZX=d>m#G3g+0(PsI+zmJj~v_T&1X0#soW^mqu zPAT4+PU+vW%zFL_@ax=m^b!v=`;rW_`O*Y5;-v~`rJMlUD7@vkC4yWjNo&KVu5l}D z)!CQnXjCJt!>Tp^)#irVtMAsi)8MO9sODeKSTkCGQR{Xaz_A?7od_)V4;hJrTAm(~ zCJQc2#THV&lp_s3S=C8RPBiz!|CVkl4VJxX0kD_Rj;AdcXWGcT!!vLc7oYQx-#4i6 ze3O&Ex-ox;1%M({><7-CWhe384fdSr9X6~E#P$184KBBM1ktIn5twNeE2aNQ=B#3a z>$Fq_+JW8-hD4Qx-{(`JMQ9xF=Qok4Y0??kUiThUA;WhT;$1H!kac+n6p6pw?@bqQ6e zEHNBrO{QBcK2>YO82s*nrsvn`10J0;r14 zLY8<0r!vn)C>uQm@{)csTc!-Wid~!HoF#ZkTC93lA;m_%uXA-Bf_zno%GE*Z zm6VdL{4-Lnz5SB=y2cJSKk4#)R_r{?&{opzyj3?(ex`0+ze*0Cl|oa+cC5S|)w5&8 zbEo``c}0!Q;jS*v8MkHd+a48fpKYZA(jqc=JZn)YFfB)r#z(d)Zj3WQ$s@Mj;KeYK zZtB%0SpB#)!`XIK+?xJyTL@0g7wkrR%ymgAC4Ib7a*4ha!eg^OHjf?iiHb7>-DOr{ zx%tvCeK@f-JDkd6p)MUzf;N=D8}Di*>LG1gB*v?8rv}%d-@AYD^dXBH@P1_(Aja9G zSv&go8uN7tFQ>MeanQpN-sy;!HCKM6dZA9;XrXo(=E{q+8?%0m{LtK`DqPiyV+A+9 zM-|JxSR0Ok#`%%H8^Nv0IjrJ2bWOLUt0HEMsasTL)p{iAnpv@|9(}r^cUHHs=UUs5 zs#_kXj2?r!%DZrzx^A&Oip|=bah^8ix{7y7x7co#Jt}dV5O1|Trh?+TRhtrT344sj zYTl8bTgGO^Eyl+hhDra6u*L;+-l56Jp>5#(_*XOpK_!#DIN2*PP{Ck@s*Xrm!O;1M z+N435>8d+Pc3{_8 za6at^g~$6-wu^5XOPo*61E9!5NUPQM$=_oNC_%lwJeZU~;yLEaAsaV1;z(6j%{G;>HgtM8u0duX^@qFD`kmq;r}Evp#T!=_ zwW>cox_Nla%@LnLT5Qj%KX%o?z<@B=o?LaytzTAOC)rm7${x-@c^~t4@&^Dt2}Y>f z8;nA6h4(Kftul{c+BWn{rCvC=MY5SZP*n1DQo&cdDB)gv=6WNPd1f2$3qs-_KmV|N z*1l5eFpS491}v}HxovoN6UttOW?(byoLM=iVz)9gpi3^rORvTn%)ui4aQ(|PaRN6| zhQPjK10Z~S%49Hgm0;v@u=v>_t?-F{uKSf%qlKi3Kk=xCBCE0pBeDoMPL&~UIypoe z#V2=#b7TV9JB`_F%CFAvtsJ6jW+y@GjXNJdg40ZLlMd+F7{Z*nSKLr`el|sH|(a4yScvxGAvrpErYKnn>M)eS!>Z z$#)SB3($E$=;Ti{bT2GF2>)XUuh24l>=PLXh@1ZZLllnrzyFAFlkMS}y4D@>vQgm+ z3Jg+Q3;{JK3=(R*keEdVnv#_$3sXoz42=XO1y`g~EM8WnWCDz9U8||sL@GW;kCW!Y zI}try)n1uv&voap;QJ`wY4N+~me8Z_Bf{p-qyNI)PRqW7`Q28^=|fvV{x)6cq*90H z=-n9M?h)U;1c%-i^t*+OFYp`6E6gj-E5rq8KX^ZAKO_Q30Pr`=C;Tf90P&z;a3GK{ zkT9qqumCz52u%>2RS*(x5R7&Zyb~Dl0Ni#E5)KFg#A=YpkdYBg5;7cQByc3~aPV*t zc`#`Z>fqObC@qh&X80AeJF5BLWtpEKodnJZL3l`ED<6UkPs2!FCds8Bu3aw_|PB{A`sCaV?zW* zkW>(+LbzX$)Pd55^o)p^h`GSI(7E8Mz-xl=jX;&)mx11f#EnpzaI8Qwfn|cEjc}GA z*+CcwwuR`L2(7?0foX%(hHQ-xny|H?^T6}q^PuyP+d;5_ut70_2nWUoCFyj zGtsxWs)^{_92IA$&u*WYWyNIYV6v@muy3qctjp;qZ)qE-XzXWW+bM-|3zR}_P_@Ou z%fZ`KPzmD-6zL*+6TqvD4mygc_?eD1ga55-$_9^1g+t)jSZ7V&Xk{NnEox}3D|e^* zn=EgULc&`%N26_X^@!^zz^6Fi?OaLL&}C)jXQShHHA>D#V`KSjsA6aG_z+$$Cid4Z zCg+N_Y(hD|CG9*7)AnBHzQ68TNxwBMBQ*ov2~0nEO>?F77tOM6cd@&ZzlfiSUSnHZ z*P6QiP@_iBM&L#eM_}Jz&Y+GU1ArZX0HAL~d_@P?9Pk}*3_1k81R(|@1|i^$T|4U2ldnhKMSnkRgJJ-j^^U-RX zhfZ~yj7sIwLUymLs_JKJXfl6$ct4GnJVvGLHk9(S%OQ#X*_W+~ME)`I{5+W(p0cU0 zwbBieC!J8pB>cV`&##4YkYZF?6X7QI1t+ zv&wd13)^eQh{9MInSFw+b~HK>BQ0Zkmr7*gXZOz%AyoRTW>i&-#Le$i4+Rl=M>b4q zkal~*PCc3j+w)Ave9lOxuwaNw3nc-6Qc0;+YnhHVU*=hqfen6gWtU!?wPeM6lDJS< z?VOJT&%5ds4uGCxXeeQ^0Dm-ol?zV85SKBYZ+tD;Niq~ui_Cr_^(s{-!yz4u2&{2L zQ#g(SgRKTxYR)ox3OtD@`Nk4oaWiJs8FX-{H^4W_Mi2+j}-*+y!AY8l<{c^e*u^{IwT)!jLL;9+K>TOb zj=#bgV)KqzF5IQ8wr0^hxZ`#IHCON4qmSDKoF`4hlnH0b zUy__RW}-LLp9gF-o_p*vFv34<1~4=Jz68A$IdXmjYk+?;3D8vw^jCg=$6P9CsRm3J zzkmGG;HLD|TUp;*YPK@NmKDMsAg0vL`^n6 zoUI_rKMyfpFq#MlEZ7oLNV)^EQz-U0l%#?a14K z_hd)CSj>IB{?O}@jjM5I)g+IM4j=cShjYKn; zd}1zn7kqLH=f0l>hJ_57#bI31KP`O!v_OWi#I&d-w*bPW=972Xr?hg9N3zDYgr~GT zNy#mw>?=-a=c$fok8J6_4@e?>9h1HZb6p-dk5PMQ{-k}~Ay)Fb2D-eH39JkQia@0i zuonZufz2Xfu{7N;kbV>Hdwzf8E)+E1e^TKt>^mI4sc_^MaOivgQYOg5ucbyz8=d|< ztVRg{GYAI$GI_6|Movvfhm^@x5O8GKn;#P`_>`=8qeE^%lwJKoP0h{iBEKN6wxmt^E& zOQ^WUaK}4z(e>V`muMy8G2snU(bZB}w=mY6h@Y&T9=R@(8=-CJ`bR97i(TEsP(L#to zIPDMSi}jHN7}=Bs^R z6-*027K|5yELs%86pRZX3TFB7`NRAmcq6_5(g*prP2>Da`fbu8wp%5D*4uqby0KU�FY4)7L)Cb)k+K1hr+6TTj>Cf(q?L*TW<;T^V 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

wQUN5lZh}_^lPC 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

XK={)WTtr!O;{Q@xb9yqq%G%*(rJ>-&H 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
    (55rNb;MyyK?<-5~Bor4ObX!S_f`! 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%0DJbQg*vXexA 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�`b~ZrP1aHU3AXKHf*(8if{--{*li&OVBx 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

    |zQ{+EYVXl9wu$>05P3ljvYD&DS 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 z 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 z z@xh^iOSM}9Iq)?v-fu5-8Ytkx54S2Ngnm+FmK*-A zSUuYq13s;39ygGVA}i$UEL${bo$hIEdukU-DfBLLmh(Yn=TOs31Op=pYDN$e?QF}- zO4Etcusu&^XE`m0E)bbvZ0Gejmaw#^gmk8Ls& zOlaiYVRmghwHi=)XX~z~XV+2@bX{E%j7}D4UUWJu=` z#x=SDhN!J}+QaC9L|um6aZ!u6Es4rHrri-%j^mh z^#M>++h?6PKhs@ZKDNdRkzeZb&`RVFRV7e6_&z1SF%EtrzXKb z<)#9*#KNe7l3Lb>b|&T?vjEkT?M3zHj5`w@tnYWy(d4k2b%!O6in#NcH)%ms$7-jA z$z`y+_FR_+s&E4L5A(E5rj&DDq^yl?K#R zda%v1rF*6-gDI(f)(27}*g5LVX3Y4rf`tJpvsXq${$!0!m>tBJjZ0FEoZ~~K7!6b6 zamPIR`=ppW7Nbc;71N}avZ0AotodueZ`eAhl?p!`nMXfu)^Z;&7>v^5oD;ETBx5j1 zCHT|7;C)bs`zS3XSkTdt<#t8HoPx+?5~+Ef-B3evJJ)&y(50mlbR#=r6c_Gb1XPP% z+oA@{)fivCA+rhxVwm5_DRG+2WXoT-BBGk}Xx4s>x z5!AyBRVCjfA7JS+ht7tZqj2;B*fUdAnLC$T*wjtv15!=Ul)iies0`3S+D_j&M2jrW za)?zq={_qqR(Gb;T1@B0PC7RJOxjN|54t*KAQ3R>#VF~vNfQiSw2UMWS_6ly?;Bi` z8Alfy;GtZ*JDxAvP3)x|X&e=EiCkmXf1wZPkqNY)ILTXjaoEW&KPQJ2=nS^j;j1ke z^DecwTAtaunYpN-vQm{&lOh>qL<*Tny-vc(nPWK;9%qd#T#l6%;h4wM-11voU3TQ4 zBsa<)&;jY&_0{T*XHH z6DYqphbc)|OE_c8O1YM!4#;bM4?47|Vc~r~8s^H~LI(=v^C_O6I>^;iY^gYSfa(z$F!hP|7$j+&(0?pcj z_1VzR`;;2u^U*S_m~#ltbArY7)RlV4v)Ghl$DLjbCB#6~&)Sj4a6)~2O;x61G-UQh z1fe^{yKxz#k}@Oz^fS$#roSIZkMfkZ%-?^s$lAB!Eodocu^4Zu z<#uJCJ_@a|PL5|CUb;&TRqhQdjY$huByBa~cEZgM^(;bj`Is2f;e^-Sus#(lnobz=*J#^k!7bJ zSNL6^A~fHjs<$2yv=M|W@a0Hzbh6nC)Quqokl|b4ygq=y2nF+|2T|$*zn7095A5P3 z%mp$MAqiBeu?#mX$#kQ$XH)<*nw&gHT3#@yMyZR&?j`&=Lw1cd9g6H{2$AMbS}|_B;hB=v>uL`1aR%$ zj?`Yk|J^{DV1F+I{P%9@9~MHXhP@_^R7x~aK znyIP%YTbFDty4Nf^sC@&?Z+zNpFGpXa_;hrqtA*m&op>pVJpR*2G>mg!}ghO*Q3kN zhbPD1plu`0GequLl_sgMJ?%0lr6L(U|&V35K7yM z9Am2blXvG2qx9_TafdLAVDI7zwH7p0)URCW_=rH`j`+1>5bz z=nnPsiiksr0EtF+yFQ|9TqzONUeMX|dyu7rfwGp>_&}dxd=AMfbZNk7g{YC_Pzw zub?WUKfL?%t(GvT>>5Ne_U*0Ba_RYAslqGulrcHM3(~ z$6q(1uu69!8ojveCspi8-zzR3BTsf`v;4Wt`=)fO*nGIt>48 zn3z)*eb4HlZM1sIfa#IqI@mm^KHR;w$VK%!8Q>&68oRGS(qSyl#^02j6O8Y z*J9)vO3kv~3U68JT1HqB(kE^7a=_EfZSqS{VV!^oh30J*-v{&p!iUDlWs3;$4V8it zAD|pwL0tH5V72&|JzX1!tZVt%_BsD@(u#-cR$FuceB7EzpAoN-7Bki{;ecKe#8{}fJ!*AjS zj^imm#TtSVFS8kVrJE}wh~mV zsRS;KWl_B0^bCU4DXnk_Uj6Aj2cyO!|C*mkRaq7~`>&GAdZ)h0q|4wk+eJ}eM(ofcou+?PvfGZjtoEvPs|t9) z&@xfM-r1>uVV1{E6YCjVPflS494WZGWNbz+gQAif%AB>v9}WN zZ&iJ+jl%FQpJ<7Bx=KYhg8H8q7o6O?u_Y*U|9Ef*+sT2pDP34rc4UIeixY`kel<5Xx@%Qg*kRS z+o34~(%to%Oxqk`y8x>D&S>IQB+b8}MA-g#0W+F|z;i`g4Gb7$G6kL6aWl?Kj*A~Q zVwnxD2mg|;Xog4kOj%VDCW}P=S&G|cjSE8()_gHQ$HMTA*gT_XN^$;%Y_g1r^9r5p zNMzR~Y_x~em$2OLlyNRYpTj-4BA5h;6&dQkRey)&ZBIb#u;z-JbcA4%$35wDXs^(U zzt2$)=igLnuaNouVa=Vx(k7aO=qdf!M=JkEDt7#!U2Ij)P-YOZH(AhYKqeV7Y6YVu24mXVYgXC}j%cgYtI?<{U7}7{EYyxo>-!X7irW7ou z0!5kYkKWSV0Z`pDWQ>a&QN9*S*Zpnuq%tXj5zUNVZW`UA*FXV#%7{KJYySJ4|FC>; zU%xQ^HPM>*@0vaTKsQP?Z2x8X_-*aXCZe20vpI;tL~@6h*(jt9jbxeLJ=4@u-G*dg0U#h-z8~VBYPyPqLKR@@-1GBBnogip= zT%P$t)YrdP#cg>U_Tu8q|L(i!GhChiaaJ7g&%H+6FRj}t1TbO^f0Ue{=mlpx#8s3$ zGnDA326a+(*9kY4WeNj`1eixlZiMjfTwZr0T;$ku(QmFC)R8akSg82)GGP|CG>8$z zaO>wA^UQ%jbkn~(mF^&m7IV1>oop`GbGIiF#;wczK6myy%SSgpeBz_Bv>!BK--7`X%Np8o9jR6z1-Mm=!Z zp0cd%O@H=KQqfzNn*uE7TfC5?DlzL0RI@B4@CljpQA+df6w(tgi~acw?fCX)yh{fz zJW3Do@LV(@bd~u&f6wx#W)lCj|7Cyasn5cw&lwVB)<&rLv%Zj4nW1((X~Uz#L3aJ8 zndJT}*is3fp_=LXuR>d4;)VGrJ&+Lo9gL*&+CmjhPjsjkZ?oJRWhw5PFi`r0^N3YOg2F2IaQJB2hE|(G zT<;N=Tl9%XJHDF{IV%j`3#s^#o|%xm;a`(HNjKbl>Sji-qU(I8y;R(y6X%d)MX$YS z13g2lXQ)%+Ias^AA|T`G(rjVf?4Uvpp`fB?Z6`QB;(z z8ceAOY?QX?$?ap<&DKai3FMNjO$9qfyHE@8HyN*x$rAu(haO>2-UdBD)Bi zq~098JA4d4GD&`N(yDDzl!4ZhpAaP`+_lZ{h7sapUZ z>`AhhaiHdm{$e`kHnmH{aEc6P6PuQ)eWLmxuFRuag#s&o&$lHZL4$G4ir84>U-B>e zun=yyU)-!@l0=A=^S4#qzhYDvJkynj)@Z`NG1H5^Waw+yVEMB5g7!&tqsXUwWS_wQ z+oOg4TJ~Q2UQj*%zNq2-zgGvP&HmXTRCjRwzVA0T(=fJkH~(kMrKYd=KVcR5cG@!F zFd7GjyVj4)qthXal^XE}2axOuz#CBq>x2pp z+17)pk*3gdq8ygRml~sdX6;UACMkd==(0H=CDe_2Fz5c#mg%xQ*g*;zePt>;C^em| zS2|l9n-4IYyeX90v<*A2kOjI}rP>v5IzjJG9dU~tVj^ji?B(SAo#f$u@YJC1K^`s(~hhyd&Pc2z(YNd&+FFtIk8Vq5#C{Wb>h1 zU+{{b`tn(>99BylEW6#kYZ#Fnp~c)L?&x$~;k{~s1~qbeOgW!f+*HtCJT~0#@dtJC zrR32NR$->j4V1~v53-znc+W>xLy1?eR#AahCTDtrc>o9$3_Yb^eTH$mWiH@z?UW32 zn6uj0rk6&_EeaWC6hHY0xSqaHI7H_F2nQE_#y1)L8*T0kWxG5Ml^Nm^LsFF=7ZP{K} z)Va21HiQkJKXoK75C^3P6C8U6*E!;nSyl=SX{az!>5`Od%fMu(i{x=YJv8TK#XyEE z8G#GE&*+r&ncSr1KfFpNV11H}Z-;CU`*ef+ErrPQOx@r5reD~_mam}cIL5+L;|~xN zpW%%0x^A2h=%o`=ZL&Lp_tXXyCQ>pizV}`y? zq?&Q7!xXrU(?8_UO+p6zaPkuHnf}C0s80VWVUza7-^_ENJuDquNg%&m^O|G(m)b5aUlh8P#fHsEMCs! zV5T%21A1zU$E-%FxYaLu^^>C77NiJY+l4Cqn$^Y2>e|{`*$Wb6=_`LnizI0XiobdD zu1Qay2cMoFm)&2yclVKRgb)o8Xpk7D^{BE=)iICUjfD9c&e>5jRnIx7G!E{&9)6o+ z*^oI6JFo}=>%_L6FcoVL)~qP1csV7 z@RVgc33vi@Z2mOgXX+JvuLs8;Gz3m2ao^080wqB*IRcDeNwfP3KCNTU8+vShig?Fr zuk|1mKH_-FgByHG!Mvo|d6Cx`x!={hzBE0Gqc^Sge~R&aQVL!MjQMp?VFpcnVwmc< z@uJ1{eAdc@Ds(BeNH?5=S1VeFLlT(^8|v8SvkAJ z3`b3qP0CQ7(_f(liP+0vtX3IuVbxRQT#QNh$y5$yL&?aO#4g|)V#1w0Y~-#zSg9KM zMrcwjitB(D$_H5~9Y%_aHt5jlIn+^b+-z57iFeYc!snIJg-8JBwW$Uk0fg+uSibC(FxnG&8pI)hW31Azo~Qb1F)1(uNAR0V#qVHd zTkr?-Tb2)4k|@W57*8jNGIBqKazuh)KX8{Fv(7eGW3~uv za0))G1w6$5F6OY%Gvajl;9}-wWQ4)a;v5smFUM&Ccrt8bY|93@MJ11R17R(mMHuB2 z4L@>|SCK~pqQRRQo>~@FjwIC&D%wqO-pIKAA z65iD+*~W>%4Co@C8s5RM8;<_VugH7P6TIM`qVeTA78_Q%5H45cFB3x%NH-W#{8R2c+Gs)CYMWC2H`zrGMfohEPon$JM#hO|GJ86Y_n z4{e##|05K-*d_*$zby_=*eA*UjwU#N?OL;R4g0P#P=9R;kKd*>;Apnj`kV{cnz$sq zP67z-D&iOn=dYx=z1uv)8tjyn?$o=SJBqLvt1Zl3S2?|K2^8+I6KCd(W#c&XPvHmv zaM`-zINM4Q$8^wRAw04`zT!C9-$B3rUNgSy4*Y6U7|`V^GZ7kC<6^M+O$N6~O!rw| zRS3wy+6{mNfEJ^O!n2v2p$!Ry< zLWVQ%1`Q$b#f6?1i9QdgSK5eRmiTKolliN*$?IrT(#AcUCk#85?)(b+7I(~xiLpU) z?hDqrx=G(eJIQ|22#17;Fstf{$K|oNexj09?RpogRmLv0z)Ed)Jf%Q3g>Mw=LVk`B zj3BtRT~Zs0EF;3;>4QNJ2et9ukY_!aF0ZUs{ZEudgm%rTrx=VR<+@+8J-cbiQz==Gvh&e|}&N&PPl+!T?U*ZV&!I+ck2|nvn%vR%ykIkWlRm-Ha zwUnBLF>@MFgHh2v6Oo`{2Tna#fs-vSZm2rnnGp=_?-5`BaN$kT1}|BJ0Uts}ZD$0* zyO@im=jAiL08nn;PJl#0CmevVJr+eoRM&}j( zVLDI3GWd(}RbnfDEKejD_O#pCq`@ZXlo3)+)wFhdhBxFG$7TESkPyyJd;ig`aBgT} zRIShlrsn&T!8gE^x7o!28HI^|?B1Jmco(H+mBTMWhW=uz;}JA~c^q#!p(^wnQd**J zOPM-PSE)nGK}=Jq#c*gU>n6SVT1qsI-lKpVXJr@pVb6@8InMwGwj=Y|_I9j+a2|}KU(9TE3*i0)|!w3^PXvV}xSB_~{3|$2|?KCC$QX+n9LKNtG zPxR6i1tdZuYP>Q--rnIm-@%Ug_y{cu#j- z#o5PjtD<3UkW)+rOVhpDak4iCHQ~7y#o+GCy-qm227mYbmB2Nijcl3`kBSn7Ia3{k zP_wWzTu*fD`Yj-wxF5Fp2&ij*P_`J++IfLLnPxk20MRjVzOH-uGhSJ(*O)>Wchwgii#Z-Munz1y3qBU=Ws?c7;k}FUHQ*qaMWyLpC-w8%+Pks#gR{p z!o|j%#{AiLMtX)AB~B#r&KyrcR~$Q47}H5lU`MNqRC1XqL&XzA=ci%d9d^28hdEHF zQ%&cN`v`+rHMn@(^54IFxj- zG9Gb7)wPJecq$^WO^Vlx-qXLKaVi-Z_VZV>%1uYAC{?m#JKuCpU9&T>RARjoZBIX$ zJ0ZqpIAdayI#tb+P+8TxTyYFm!64|#6LStW$8HTz}ZFR!S@9r3E6>iwho$Ok=`)8}F% zP{UnZD?WR+1hom}yhs<)4SFwR@HP-l7qTao;kw<#e(@6>(9auN7+s*L$6VuTdUqT)am)zcl=5V$ z0iEHT0)?m7$xqc8hnWq;2P%w>Y&o_eO`DcHF<4r5m1Ys2{t|K;$&x`E3!2uBIeG)b zNZt{1&q_(Bw9EvFuz=y(^=udsY!_`WQoO&Rem28qJnV(-Zx*LV33;Ep4aL4Mc~&O z0UH9571~#hTi>RZu(fAiqQC0PF-_*>@L*ZueY~3!;|RzY=qKzqDfe?} z0y%t*2BVV3} zlk1sdVG>S3h*q6+cS+ZMMGJ(5fe~s%67$j3En{6P~8CUlHCaJiaPTFM)tVE5LNv{pQ&!ZZkTuX1}P&Hn>MT= zzR;#9BNb8eiStPECstuZ!Y#gm-%U~Ign_+3mvJ$NC^fS}1Gut&O%ub=o60*t{51RRRvq?GYc9;U% zS?P>s2X?E|ub{ABZ#>B>I}p6d!hjh&FIO_{;T)cc$l2WzI%TWk$(5{TH9tQM5!MKRqh6+!1#4tHLC*7BVp zEQUKe{KUWTY0YDYB$~XJvL#c~*-l3Ab9T(;#*WfCIXG~vGN^&cy~}*9Y8s#8%7z1H z@z^vVW7&mG?f+(|gT zH-?=RZbr2qv?xk#OIw!E6KzJ)MAbxDBBrLbe^p}^-vFhU*5ZnmhIJfRqrWG$-j&73 z8@Qt|XmCOZ!RQG-qW4RE#<_9d#U12~bVS~w=n?fxeMhe?Rkef zqJPhLhQ3kVwH%zefrb5D@`}FpKx)3T#P&nE2fLEy z3kb8)6dGsA#iWs_=T|^Dth+-dJaza$foeueTRXm{MgwSCS3r1FbfGpQ+E2-j!dBsl z$A|O?%oTYP$R-`T2FF{oYSL@$@h;wvvWFHA+%TV^H5EKCV~9knXvSlPb$<=n{+J zs9YI;t&qmT?4BIWOzWk72LczGSf-lJ1B(8noUV_xYZ>gKiiI#M!7yt1xvrNI9B?i0?jh^W?5jFIw*x=rE)M zGMvngYzm_VMWYk2O*4c@tupcaii4smdV0q480(kAB0XVk*1t<5d|4{WzHt|sGTyc# zG#Uy84k!=)a+PZ0B{r#Q56mGZxF)}ce!{OZH`ZUDV_mc@!{^}}`k{2!M9b(GYhsp8 zwaMq%&mlx^oUahC8aHbCdVDA3`NmpS&tpON+>Y|q@H0g|P?r7HC9rF|E+CUKv+~Ip z{e%45Sek7^3B9%7L%Uzew^9C~P;G*2~9f@#;SV{y^6cjQ9GU={Zo1@RRBuJ2McYx*y6W9{sIuUukIF?t3 zt7tEG@JG*GP}8)A`SeNCw0bHxV!FG6+F=g$8D9M)x9%dhM&_NAw&hQjqwEPDNm|$G zRQI^=-;8H9G_DLO?g*NPd^(HVYMFQR=DD#jIR`JbS*FX>2PE7uoV#2efnWSQQH&E0 zJ}~jp*kAuK%d&hvr7)ld0>U!{0wViAHNn4iKsO(>mzwz8!UpS|1qGsu5C}AMDDOTI z5|aoQSpra^QwCUqsPm{?QX(0uB?VqlMMMXIm!VgX*PyOY1`*WmZta=>ZrBmcSz~o4 zZBeh`!qrsv*nXJV)7uwe=4oBP!b3+@byamIVUM5Pk^vAFc^p?k8X|duxDi&69SAp= z3-mrRmI6_JFBAwVG#V0?xDi`WG87ukyBQ_fEwh5yH^&{D5hVdgXl580OVJ1*Aav60THB8!h#SF! zS1?ux99eDE8=ZZI+$=A5hH~Fc1Y`L{L<9r5X?c2vXkShwZTUqzv<*tz#xfsCMLuF} znm_a}l8Wt-d#D#Q_u6zivWlWqNG>PJE@{cw^bGN!Vh0ow6p9r^LryOY2rYCCi4#N6 z0@yUElfZ-i-ah6vY^4XXbZ43kCNFXgX_9P(2X)ZI@kxHpyGsB#e_PV#kJSDp-sgpP z97xrdUmgLu{q?OWdQjW@oY%Oy?-T()bGLT)TW{e9A31n`Z?IH5Yhw_5QoSosvfXt; z*{MBKP}Y!{krR9J8nY8uzgUEA?S-<3))Z1c@$8U@Fp%sEP}Y!|;U{ifg-$@V$K*A0 z?ZAlC5$yw0)=--9Z^?=N_%jB$4bO3c{gKg23Pw;089&=bp!tj;(xP(50iwu-WJk$< zL4*{wSL;W)kf*jhRFbOi?8o_oChls-7n-m3+W+qrHcOMBs=XlfiFTM^`SnrmH4|gg z9cG1JqR;RB(6{FRlh>wx!@@(&+-sySSomFbka|?Fklt*C=I+*t`L)m<(QSQ@D`c+IxcgjyskT0TZ)*!=*E5XQ<-%#&sV~@9n(0EQwAMZ@S+HbMPaetr!C_4mm z-l+s7>_-|Y0)a?-p`k!9N>DYbR{l7K1rPQs^cF%_^^cbD%nV={>I}Mg%hJ;^`6SO4>+kPtDwfhz(Y3miaAo86=5OFB&~ljWr4eVkea%6_GQSWimdPwe zdxsk#ACRdKynnOM^XlW+duE%nSN)_>Z^AU#HIvffwya+H$PU3z8v@s4(n+)$NCiK! zH^ZpSEnYmR;7nU2KE?h6Q>JK)mr90tc?Ixp!MO*U%!|@9z31ZlE>#?{!__aN=#CUV zNiPN02;0rlD) z`)e3=;X->=Pj^vkFWIWAJW*<6DB!nks@=(fjom%C{{5#=@0 z4s|b^7-08kzF7e6|D)_IW9p2eHI4hh4({&mPH}gK;_mKl2X}Xe;_g!14({$yC|aOc zDIId>PBM3rJIT$L?El}7oxRq(*M1(_3ifYuOWzANv>GaY7jANEcraiIk8MYrJ7?y8 zyYD4{<`xNt&e1oL88??sj89GJo6;iAzeR!(*76KeDW220wHlmOtxTO-&P<2?Vr5RP zb;U?e>#JIOdB9Wpk((V3ir)kmE4^?((!R02_&oE=*L$n1D=)rq!# zyM^-D)&1u3S*E&+#DV1v*_`@m<@bqaivCa5#f5P5@BwV}R znb8h6+EvXmAa7!j1GXM5L+i%zamLO`_vbGK36o^an_92cdH2`;h|7dblY*>a8QML$ zAdQ}ut!1hNU5r;0r0ESZ!_{LX(1dVd9F$ zXS~0ae!{G_iz$1%ncs3#<86v@|x%8MRH8FVps6S0| z;>d4}E)mt!CJZZn6Q*+4*$c0J!Ae{XL!$r1ZI-}XK1uo;y<5Pp@8gS$wtJv39F}N< zOon3-Ypf^6a@GgDkwx9v(#oR4)oPD6etG*baE*_-N+HkQZc^m>Fh5l6yYgO1bV~Mu znRa}ff;*+MrR(D~7M+tv6fS4uW15LijE%y?!AadeZAr!+JN&I!%!N#6DJ(Xd+eCK8 zg60j%Zbj6$Tr?%)uh3^OjuCP0QR|Kb$}M6>a&4<_a+DHik|mPaHt5RiXBTY^Hk5u( zJ;k(9DYb0p%aF7IvT`Pa>sO7^@D0zhsC?(&t}MKil=4QS7G7*hEEL`l+amQ&=_{cK z(w1Od)lU#&x8sqSA)(y?u!Rs(YWZn!_?{k2%~Pk|rg0N0?(&XZr!v}S8v8-%*Kls) zPv4zzV)^92wQ z^1s@yb=ZOwrd>6hz|GZ&X6|!+(go}aM!=yO&BeVWyT*pQ8%3{Fo%&fiXRlqd>@Kwd zin<54ms6}t4?i_R9NTWQCOE4yyR|Am#E)MlZ#*~`HRtmd+SgISiNPnbF_oXJvZRR#y zw}MU2uHpFNJ$`)siR9CENPlJChI5>uwH3y5I4brAllzrQ!-6_m!E|BSB-dLqoh6`+ z_Zp-AZSznr@mmR1ooa$PFQvfTFckCldU;M*8ObwOhJF|^V#ynniFfzz2PP}Cs#oc9 zjcbq!Gn}EtYJ5I%!iLl{E__A0-!94B+NVYMNW13x_>*#B>)+pA6xNU(5$2H+c}n-JjHSNdXC@r3MGVS) z)`b?pNm|uOWo!PH!fT{&JxbP1JSi(O1nbBun) z;<*Pp$7u(y)(lfn24k!yJ02>U{t8tqJ(-SNT!Gp#yq3O|WF(8Ba_QK1h3+_WPoO{_ z{EhqP1{-k1o`xn*V76M4Gu-BAd+7jS`eIYj?<}3(yOJ;sMr)?@Y}2fd;Y{_Kiz0ei zS=cic$*wV-_|z`@V(h#=mcg!&F^}?AeN4!%P-S-aab!^uw;-|R$iuHCq>xI+QGz33 zH#)+mWc8~zZEJe32np4xYQn&P;!*5m3269*m z$w*#PDMA~$lR>Cd8oRwt55u$OF1A(c%#@q!57@=q$Lv^h6hUhx?eAZM0|E_Aa+N@i z1kR!vg71yw?ss=7+?;)BoZ$oKc7yFZz;Srs#v4bgZu+mqM z_w`O~B^f!;@V%U^aJ?16rOz__DZvOo!3W~(3`%Bsu>z+!v>b-wQYHFF9Q2JSdc zn=M{7r{LvCRvj#_Ra_`Y%W|G?kke0u~FK7CLiq>11qtYESp7?Tux<*%t z$BTp@jnBAFZ4CBEJYyGpqcJAM#rs!Km{ff;M;b~h?2t+Tlc2HZKWcOBTa5@XZ0Q>pbahy4gZFX9IQD;e59AE~(MLX&N+HTeUKCpzIkO>DH}dC}-Y zLm^2wA;kj>sH9KUl2Ah|v*xyZyQ8MRI9d4a6}{FK8J8rQ{+P0sklZYp>n2xC;?`XSX< z*@Cta73*V&?X3Ec$93QN?TIJUd$hO4N2RYZ7R_c;KoK*D4)xm+<*#N25sadmBTm<3 zR0T7uSna7z8>gaWvLFl5>MQG~xM|qVZ%4>S@6@4<2mwk5giyg1S;3408e`-&e-pL_ zst{0?h%%_mR5N4MqKBhh zYL>9$3onaC*FE#|i{WpJ!tR_Qfh1+kV|%Cc`D(esOL=Ic!}`YguRo_8PJ+o$AB#W-Tr@f}|7itM;lCN1UP0Er zLECXv96be&cK2L80A^f^j2wqPf!;h+X9ybk&k6X)i24lIo)1DALKl5-pnm53H0OZ4d7;qWh?#X-Cj9pLn7lMJJKA{J&Cy_5zs` zY2lwK9RPMzgVMtD?Xq*h%C6`$X~`u;UwG2LnhZQ+Cn83Ir)X(%u$yv8Z<}F3|3bJn zuK}H9mr-|6w8Gp%SjfBNV>jUTuPTDm6MC%ATx)QbckOKfc9iE*7Z&cSW}(&Dsss~s zTh=(sr_#^`x1&DMaZ%BtSHkkDMJr?qNQkjL zW9?`pMZ<;VlF3xIk`?~%Q1yV7XrQ9{*GB&WoFnkLUCKZtUFPN1iXSfVE6vgb#;no? zb7?op(vL+|yRWMx$35I~LDCrR#&vcNc$q08Ibxi*a?ZBFrg=3Od3!)wd@(t&jzyHy zBfiuM@wcf?XpCBcLnUtxz`*rtJ54%I`O-HONC}FDdYW*Q=Vq%6+fEWLf$CL~=CCP+ zQ@(mFl`>DINR2bDG?sCIt9%~h!bHehEzr!LeKNWN5KN7y?H6S?1mS2y9ndN8ZMTZO z^0_ExNqlSXFU`UmX5e3il*fpj_&+jcysT$?IvLV}oqMew7DISkuv9Sv_0$qh?#FU4 zZJh|d@wm%3C|l;T(V#ec0^+%|JU+YUZn8RAw?RYW$s zVLSf)n()+q%ncCF=p^)j&3X|!ZhZ6n>pCDLI z;wV!ZOuon|ZL$k@WTQ?=1B~QOkW7o|ptDQn`O-lSOq-%BC|}U0YMf?coh1OQRKJ!y z>3veS*cQEAcgt`olNts&98(w)zs^*YJWInD`RZ%e`U?U|9Brn#rq(==HnC|v%>3P* zBo^tzy{ZBi=h?61v@~BA99!eBvNK`29q2iR8k{3iRFT0DWWdyOZFqY*k1-1N&S%j)*asmdDp&0)+cbABq@&$Iwm^W)cNRapXyd$ll4 zG&SFs9Z~S0g1LAKl_17xraLsyi?AYbDMk2^io$&4u#93~R_ForI7U?xhONnr zNFwJY1GKS32!HXbz1XTo|3=b|`OV;9Y?gi)u}H82feB_4OpwoOZ3FhjPqc<`Y;UoC90@v34hZ#P z`&rRa--e`L<}+73Od6-&MCKFg{)ldCU=mnVup#-Cl5e#w75UrgboOj8DZ(C z)${xFj)YuYqZc{s0s?VOm?>#D_0hwE>XY@l=ce@&gTsj4SZyL91x-wNFv|74hKtLG z$njdBiKM{`NAQ&^_k$y&%9gQh~BuR*&a_<-mpfG*m|88jOckR+nd2m`p6O9T)oeq>sVF<0W+jh_!OcnF z+2IdAv&HazpVl8BMk0>8wF}j@TVd0=x&YisMj|d!~@{7SFN?_jboaP2*WI+X6 z)^MiTIwc$5G$nqml~aV)egD_Ddgfj<0rR@s{TTCZg+x}VGLC?K8gmi}JG9zG%4szs z45@JNLa+6)GwO%(h%xL3!!Mo4@7*tXQQu!*1c`%@+j72k0dZ{G$A(>6#+Ihy?oNAC3qcT{6dh(rh)`uRIW7iIuNZX^Hrw28n-KVMVp$7qb_|P z=KlF$mBl8aKXYC=CslM9Gv;?doda0eMMYdrsFe=MyrMF?j~u(K2qn}h)^{V>jg{*P zv<15+j7Kzu&%uDJOQ(v2lA5tyjGE_HrOy_DyQ%ItnnchM&U@joO`==rDaLJ-tGV9= zBxrIs;sUWEu1hTNk-~rGOf5=STWQyB-|~hIek{LGZ!=q8N6=VE!c2L^4sIXjUnkQV z)JtFDFUGHLvWtk~Se>rxp0-~TaJFD=pUOdoi|yfz9M4A%AQVZ%-i{y!!qGm=CxZsI zaSNkD?{MSc8;5*+h~*CfkH0$?zVCw+4vD)k_Qq_3(W>4YeTYOxZG|EJ98x;G;tfQo z9PqxR>m5*9MM2jI5?KTux<9_Kx&Z!Ru3v*|)j)VfY$lZm$km0^9B(Ovi1!iE6hJ$%l__R}$kC#k(Yh){$ zGO1hJk4}ymXDx)egwsxpSK-k2j=XyV({bna6Wn#AACU*|xPCZ=AesqW|tb`%;hm&`SlAHGcnx zSd#?pm(Wo9z8z;!R^;nndYG(+khh7dCow0kcbPzCQpT6>a zj`z6J=-$0!c$K`1CUf87L?`r}LFu)g{iQ$deIfAV&C9X7!>d4I1ZBu`+{{aP&gko` zo7LG(0UZ+a6pqIzdG}Oi7=?WeH_STjW{ZZSW^d?VLcPnf0P@>;sH_)f$PrQzytW9b z`pX4d2y2A+00Pb37#r|1LnyUEWzf|qqn zA3PPf$jm8sr3oW?yJjcP@rnl|%I+f)J`YvmG@VFlhfh6nqekaMz%dJu!8p95 z;SJK55_>MNiNGyo^0fwL><&|61@1VZvmTxf_n4rwbH#*)O1hNJ23bmQ=3dQ@E$)u71hRk1L zC#Ft1gb)q*Id(yg&-Q!1i00wC^xKT$hO-rx^&kWPBct( zrV03mpQ1%;Yyc)q!iJqRH5Z6LuS2ElN5A>T6CgEImFlCK{)29Jhk5%5{b{RnP-d`E z?+4?LbWD5$Hq}g=0U}wOe*8Xx!%I!;BwqO9g>Cy0r@LphRsT6#Y9MflhQV%$I@B3b z;5=5`4KTbz#G6Th%!KV*b*cC8pmWSiL#lRwCZtKrR0A=`rhM!G z6~90>)o#i$Qur)YC@xhfDpe>cwJ#*KFZw^$rBEvGf6lTk-IQ{b-cqUkXQ_Rl)V{>j zzR=XZnAE<=|5&#}sh;1RW!+eNRnXV~lkrdwG>)FZxk%|I3J6aZtJV~&qB1pqnscL0 zTgiPIlD!n{IBu?V9TwY;ZZfq<4tAl6HAgB#5m1C~$>$Xm z)Pl5HQ}&Tr82%Nii(O=6wXzs$+ttYtc7O1&J`kyXsgQ>U!|A<~#UB})oZV3?o*GN= z|AWK1b2df%hdS~?e)sG4FyI4vyqNTm;RCI!@E;1{E35igoNHq{>eW@y8U-*+31r5L zAG=EhEtJKLKg>>AZH0DFuInObI7X7b+zJ!BDWTgs^n0N|STQa<9|B$}BUE#jNgs&-4h{Ux*3c!9)=o=5~2@C5Dc%)j$!D?193-TvH$Jx1aIvw4TVB+jf)o?6?nzo?U@g;z46)S?TmED+Uvsbw$xhymf%_jy@-sh zvS{_Z=^Y5mL_HES>g#O}p$>r#y(HFqVteV@nx72bMVjG7$w}vi<)1bb&Xi9CIq>tz zoDHWZ{neoet~h%odc{od+mlQvB_l*B07MFSznHIh6d;Mj$tX25s(4)3PvFM#sEzqG zON59+R66#ArA?Li&xk1kWWDhu^t z?-9%vUBn!g!%G@W)QJSaXo_?fB6&U%^)VQ{=u>o8BzXZuYG!FU+OqO7I$JqHIqyQ% zC0c--wRe#3IV|S$P_Loh)K)D& zfWinAKgTE|8Xj!~Rb;vDxCK~j$8u<0{} z%5Csyb;XZ)A(S^~oy6#n;>{RYHBQp8&7%9|vj17$sHMXx;Ld9Kj@P;$^;Ed~B_(J; z$+VIEZR+n2y!0o}Cy*0ro8`n`_&PDhxiaR5J@GsY*{lkE*Io^ad8PKK15T96NL2a; z%1w$>&&jUFh2`*Qjo0pu0fsJpBAZY#-La;Bu*YTnCOY7W+;?%Ai95S zFLSMBTy=+FM1Sr4FwO3^7#rc;ncF{$NC_%NxU(ud5|^R#sFSd*U4X`8$Yyzz1j z0~V49ep#=oXI>HM>v)^?+y}<>LAN3@Z@!B8-3$t~jFZM)rDg;+b`WgI{uL$v(OV2d zSg(|+B)$KA*|dXQr#F`9jSTb3ll(>R;l?;Nf3rGKQ=z66`vX6xmtY1(tnSOaQ4HkG z*T}CK(EZi?KUFcRZ?W)u)AXqcvl~{#hy|17LZ`iL)4H5RET1{egQL{$` zK3~4Z#hrWJm2W_>#%v!5y9%-tdJlSw_wv|^Gk=H4xq<+Rzz4u7KVkgQ)xRe@uOg8rD50luXCEr(CmNujqq9qYlNo!+cK&*^=puPRLYarD6h zEQ`^iopza@n^Wq*IcXdIZUOqxtD$y-D2q(=A7Z%)mvj}i>x6xagJ%==MQ`5@+X~!3 zAhuwU z9Qf#HqQ5U{>bWY3eu+kL(w4VF!;5mbcsYokv99kv@tKc2@a8u(J_;8_I<`paLMKv6 z^p{P<+FM5IE{`7~4P0k~K7TU)BV74!Z#no+$F#QrHEnHtsg60A{kr0D?wHx7uw2a| zt`zVb{WaD_)5}q_WvYamUmWGf&GQMLB@hb?uY4V8u{rgu>7H3`zNF&LXTKQ0=Qc0~_- zcmI?Uii`du0G>LVB=N!g8QVY5`X$^)9rPvmA4b|~(Sh|ZZ$73E$cfSUx?a8+zu0|U z5Z^Gzm>Q2Hk$KsutF}$ET;5P1OMH~m74OBwD;~L*ym2;iQ7ffxTv;{RHpUvu!WDx3 zmR<4;T=RZ~4vGc+6_DNDw+M7g;?rf`BRo!Y|9N^1wqc=Mq+jyy2Dz!o^; z5w^J#KM#~`zP0=%aoUh$yc5pK0yAZJZU)MA6j1Ew=)S4)k?RhV!M4bc$J?<-YFZ^x z>gTfvyu9cTTs`zy3VXPHgc!efRQZt$D<=Ahid!>JPLxc@SRtP-u5{?sN%?PuV*#@H zCrDy*7_IsS`6lh7V);^$k_z6k&7&h^3KS@vj}gt87IdxUgJ0`dTgr#^GP%CBmJ`yRs}OO00eSm(XKa_h8wG0Dbp>jl)Qt}1>?k)QVIF$i4CZS61afX-V9)TJs2eHl1=U8c-w92jX|NS$Dc=CF_6v_RIN$g#()ILHi2HkpbD%KV@^ zgrJwJ9ACo=4%(<`s!Z4)DiBisJ|h~UE%q4K@@#gX>BaG9?W!N=nM9VcQ&Dz){PjF5 z&B=B7?}O8sZgPRq!gPK;Q-gZppI~L&)z6+~Xjjp2VY;Wi<%S$blv5`ai2~3Zkv(Dw zE--1`fkg#NyO^OUwCq6JX8N1LWJYHGDcM`RL#2HXNl~MmQBm zQLc4KU;0kf&K-S)hUS1irE?6VGGAgdbPiH((YfrWVtSNY?x}JCS3BX)To*+9?Q>H? zW99D84W2h+{&^lZYwdH@l?AH}p30opMC;eai?NI>4Ax-I=VrC#DD(}SfH89W{DR80)hnn{{t3~bF%of5}CSCNjaH2 zTl^ zKdL>{dY-$ztuVic3)&aBKYh%J{0aDx-~YVR`S0PL5yEM7KWqc%=$F&Q4gHBS+98cc z3>I=Ide$6*sbG)P&lDE&UDOM&X-W0+J#Xe(T8%Q-$ENytnK-r#fF(Ra+L-d+Otq@l5i!6fikdD-wK7y8y=F9-g zF0Z%`N>bco1mA0=tV-gLX#iuiGyE^&uzh*Kh>Lpm+D>iW6G!m?fsx#$CZxkz6K?gn2T9N&O;_zE@_!&V$XfOf`~6= z*t`hT^@z*5c{kS_SE&7rQ?h!s*vn}JJq75y(9pwas(TLOK6-r`DwPSS2E2bd40vvp z7xWdEn+VhVjEjaqaSh7NKat<>*pUn3<-0`uHq}6^J2vO8MwC_bvierfu@NH%%XZ>> zEIHP`$oqNqGYDGiNAapFH|Na-it5CM!WTTl8%*_Z%WXuva=J8sR9x)IBRXi~E&3Ma z^WJa9_%*iIp6^b7Q$I~>-F5&I7n^A`Jp#At#rfyc*rSQVdbK1z9? zt3XK*6txfks}dx7zzlFcPI5yIUb?g1d?!Bqzy;hM2?K7CTf}dELWhd3-01{J>fQwl z3zO%YcQ@F>yB{sY*6=Cdk1JQW%;3lx$*QRiA~opf_-j|=un$XOk6gz%Ek}1|CoVcF zRI7ILJltFKx81bW;owBJxcVnq_V#Tdiizn{d1F;;&slP}Z$T6Idl*0_L`=mF(X`&m z6Qy5f$SHUmHlCD&cO#>4owJ%pjw+mn5F~Y`12yR;2!Xr8b2uX%xqpa9X7USx;zGQ7 zwpxHq&*fArk$5eML@Egy_Me`9c!)BGyZ&yU~$CpHpqSn0*B89#- zgb9~9FoRL;bh|w-rl!L#!s*hLzJ;b|8B0{M;4#C^t{gGg>BiPhsx{~4H&L&@C9$=p zWd~1z;=LcXL1qS*hlXL+im7nM5h3*sx??|ALgs7_$~{LMvYV~br{Ox{1#d#%^3ghx ztI+v}ThYv9GY8FasZJYSFf~iTo;#rNv0@jLw!BN2=VIH}Nnq&tfcsE17L7Msyt&RMcNZt;nKtc9|F$3=}?;JEsbx^2_E)plD*hhd~Sj7&j zxg)^f#h0l%ClDz#cX_fl#~taFc4aBAn>EumHsWL6_7Y!38E%rfC8fS{hj5%HRm zn)SRA1wq_z$emt^!4zp&J@W4uQ+G}X|K;oS?(RRhXzV$*`BYK#Vy$;+xti~-3^7k# z<8_AbD7*O=Z2#F2Y2c3u5Ct;waYYP6Zn652T$1bDVhc~c;pyx%`0*7%DqT31#_5kf zj6rM8n@yn)M-8V41EzV1@Wn46wCF3+tH2;OZLta@g89IZL)UP;#()F&NR_)g#Be(A zU+ze(&v!B5*(XQN^Z}(&DkPGTaYd>xRA@yU(bX(Ll84wNBFu53-|nVJjQFFY<7n-M zHQuY(`>mdAU*MZ6XoR@S-r$-*j@By?Rft>={Qo?Wp}7yIe}z&az`>!r(ALZq+dbfG zI*TOaSgxZ{FbuIp=rIAp!X2OV5V^i1wFS$ntRJ#z9oy!{SkuP>xsYjXd5p^V-<^eV zZ`GJZ$_4VvUSA?`4mkCrAKDObZ4hB?=p%iYN-eP}{c4I&xxy#xdLm0#zVNC84Y=5r z6g!t3+d$fj(j>gU;CG4Z#=d2E-EAm1rk8rQC9N$(lAtZZ`9*A9$o(uX6A~F?OkBQx z6l(NKnb2s<0i7!gD0nXtwq@*<_g)b9M2V0Uh?q47SMe24hKrOqy`}q|3k6FW6&DQH zuGFShgMg=;SS5(FcZ*ecaT#3+?8*g-Va;tw%=x;tdbXnx!N)E!?=+biz2A?HO5^CH zjL_}FY)@0fNb%`xbL32uss(MLD!uc$|D-1BGwBKqw?lA;%^5BW zeqEuTC*znY&MZ?y(arZ>P=UssKP_~JL-Lu&x<5BcPfL*hIil#+l)d!Lx;w?oI!Uyk ze%-8qK~ib6X6b}j0IkzRc>ZnWm&BdnphxLL-!v_0{vJJvrIIp+DTn88N`BlQcpsb- zE*$qchelRiXi^@e^Bjy~d|;+jOPnc=+QIRZ8Tkl3M9TM)3-;~7+FeY> za-=s#5+B5ez{!k_dpm~Z>G?m(S1%?*KOihlUL?@#P4IxkqQ$rvdih$vP zfi_~@%xdb|Oz3qEEheLj?X2%uD^s`Eva4m*-%veX)%M@m0+V$77Wt`WkknyRzm)U* z=}Gi@zD_N@>3bb;9{4xIyC3i{n^mL|__0t1;UZ+jJmk*d0Q#|e5RSWZN6~iz$~we$ z8knA4&-O3q{?73X=kCn$jN|Ui`OJH^XL@ss`7QxMq}l3K+%vxyNkhwiPn-Il{cZrV zdr6KIO+7HjXE^Xh6mf+l;y(iA+*K={h;qE+ilmWIEl12#^NANAaKWn$GktnoBFrtm z4LQ*8Q-LtuyJxy{(x_+BOd%O|I5WFlF%z>&ARlrRlba!sa~RD+V-#b%^@htehvhi9 z*!_T+>{FKF*{2*_=CEl~ij{YL)iYBZibJ-F)7hFFIdc|pX$&-+IiE2^o?Lr`yTzRe zAWfgfGoB}_+ZS^UypZrf{grG)T1Xjg^f*UQY#5G&Uk&8$O72}Wx=RaQh>FX$Pj_MG zRW@CsI;_Sl1gW+NEf7B1?Xj$qE(%E4k?r830Bp!%DyY#H#Ak!JiPnY@_IS*aA!Ryga z-nwe*xN37&Okev88t>eNINq}2L0gZu@fQPP{PRU|5SF-@eX`JA1t?$#r@;JCNu
Xt+(hzL(S=jo%TocF@F(h9f3rwAgd2QYee;uU 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 z zVb!Gtb!Fe{J^*E6C5Obv(xnzpwFoVQF-~)*zcJU}3e1 z;Q5j=QH6yCK;^ZcB!%Qm%+dPAva0!dfFZ?%b~|elU=mLBA=!dAX8@}SRHc(&0Ohk& zW=XY``wdFOT+o1o3N7z;`DL(2#>o9tkHZR2e`K{5^<4yK(CwUf4L}uj z7H6#}D9z)jV@pgs{mpYt=bf1qK75SMA zu>}2j;YPX^#FssWXBWh1D)ehqhC^ON2S@0+`${BR$qld&Cl49W4WM?H4*{-J>dTc- zMcR^w9?aEhvKhMG5?Am@oue%PfBa%=s%L-D-{+_Ze7(_S@??hfBFBGhlISaT{Da5z z-MuM*&juH4P)ytu64CXC|d@C!-sFf#g>l}8&Tm+~r=-;TD2Skq1DIEd%`wh8b>6t*j_R-j>yBdSQfj{1wN^frYv~lr#2r>%1>wnQ;{zQ+!<6Cv>M$98Ob5~)%8r5NX^@R-GlG}wzM`Y}t+%Mrju0%VW-i(iHJg1pdPMn!matg_v&OXRQ zqM17yDsu$kXd-a>;5jy=IWh)w5p2TevRwq@AxuXgOc9%VW`sM^OaOS^m-ltR2UEay zj4b<*MR0cH2dyXvR_#L%^#@fX@SGb^H=cH;Wzs8s_yrE8_X|FU_q5Co;6fcC*E%jP zjH>rLci1^6E;D*>5g!TCZ5R4Xb^PYIIR|W{ft}vf)+r9K6Y)MGh~a1Aj58Y|^3ZELW*cquPU#~O zy?#q&6Jwm{qdp%s7xWhcUMBHRT6eHe&kXCYbik;n^f}ew&+WQI+)k5hPb`^ay2RS=qXGdnuQIHb5+Hu29;1DR6JNl4+_pCi%Q;E zMh%)%aB*V@$#6u)mk``BU|8GNMu2OWDYAu@{VS<}L@~cs;%7=>^3%Zn&-1x|MY6?B zN%!+21VbSpH3qT!s8etx|R5`)4bzT9eSY!mq6wkRbO4IGc~Wf z|3$kr%n^66bV$~AD6~KLAbQ5&t-6_-HUQp!NLDK$^G`+S^_?%j5{A@!9FN_^@!slL zSttx4{z^i_D11vcjP_gB1^SyNq<7XqanDo( zlB8*5vQBpv*S(J~>Ic#C7;K+1@4a@e-@RHAdbByek$V9+!3t0r@TtXGv4UY65UK<5 z_Pm-s@%GKpwpxdi*_u5``N0K-BLm%@lm-fu4LG8xR){ERo3J$Q^iEp;{DB{q`jJ2K z@$>P=g+VzRg_DZ44o&}E(ib&4T0)V7hs$V>&Hf26WhiUAxKK2wcEG359SJl?NeGW? zkmO34q#~wjNK~9~wy(4_LGlpg?UfBr_tiT8AtfYRQ^s1emLw@j(5w{`<(jFoIC?1d zp1uq>V_G~+!KKhKh-flPodhSBAssVOR7|3t5HstQi|Yy3IXXMj{C3u+fee-22zPgo zC%d&E|78@mYSuz7?l)+48-_V_B6dFkdJ z;?J4{5!C=B>fD4ucokLZ^1QcnoIWBd<3`+5{O32RWg?XH(xP(X6hl(JK3J?6eYHi9 zW-=$liCN^x31J$D9@F_DBdqw+{30IAfWJI7M~QP6XB7=vxK>>wSwpQNW0kzNN}2xY zc!(-7@XR#z;>FUhT&`J8y}N*n-T? z*C2i17Z1FapAGYoj__`a-;zRX7Q&~@Tq2q)#4TOOj=(v!J;;U7FR^v#_=w-8BYY3L zv}`>5*3t1ujz`p@5%BsP!eYA|!s8;%y~ZzJL|{FkUieQ7xNt;7=K3k;DTSlHAn)J4 z4@~}FBA-11>5?CT#Q<+L_z!SajtHlOcL``OH~`-SF}583jnVvt+c0~C>2$(t>`DUm zvjl9R0S&*#)b_@Vfx1YwTDCr;$e+CPIhPD^?Rr^Mkml zp36FCD?bSoid<{CbVPR*&2jnuZsz)3OWW*@}Nxm(A$p=ynayAFE~a zk2guSC-Wt5xVI=r+08QG*qBl-WA0d)dagsV92D2CNaZb1YN!In$N^?W>y3bveRP6! ztPF4mG)8!h5~0}1u4m_U;p|sngoZ-SiGQ}H&ks;@rKo6B7KF2$HM~nfi!T0Vdv}km zg68!$1*6~d?Z}yt^JHxsRx2niL=V+|dw=r1Ns=K7wu{LR8a=7MHlsOTE zD4mz2S+M0SVEmH2J7)CgS%ey|ofwfB;1VM$SV_|Mcj$DTDr7l?7Dwtvy`W>2@!`j0 zYvWC5QI8_#w$P%8HCCDB!rZ8f#OYoW%P_id_uqznQRP?QI-w{@-j&@mc{<1kIayEbgyntYDdVmH!I?kFP)@azxRxECdD|bpEQ0 zgnhr6Jt|F#bXN4Y=r;)WY8tcSnPiFgCGO$N)t38aAgvz#+J@J)SGL#F+H==8&(}ST zFQ#j?0g!{4X=~Mi#^iZxz;(RpEZJQb*46kZtbJ<=zZf^_;myy2gdK#A#KAkh;Sfpr z?|!!?XRH8Qm{PFgf)nS6#{wfd@wifn9$3c_yYf`&r+KUNLTpXsZ9nmoE<~a#7vC297>Jmwq4F-D>zdrHg&(%IrErPN+J<}}o+N25XX)?J{~yjjU@w;Gh# zjG8q|AQcm9pEZ={$ip(M`MG#?$!AEpL=CG|i#fI0-R1ziO7Wo|>$HB<0c57w{+|){ z;sn>hTQubM@~;+(y<=AEeT!&t&7;u*-j;)wUn3ydwwC(ody*|~&p-Ni<8~~C)Fan$ z6Q~Q8=r!G@p)w_K=eiiBFDW^m$j1sYa|!$Fd(X}q8z=!9&5}AavQ3S)0c6`wOwkY} z`%RP*dUV3Bxl2&N2D5dh;IeG?=$jO0o*WA7PmGmQNM?Q=VRIriAjSnV=@jt;(yC;* z0$d@;cio_UozPFd3bgJ*J1{$p83MnW*kRywKh_V+aLr#IX@*3ww(thw4nel`6bdJJ zUn~fR&$G?p?`W>5^5@?CFl6MVzt^FL?ZUFj@*z#rD%piLabC;T-kF&AA_Qi!B&M4^LHm5eteL>WG7cH>4DlUm*RP$Uofh)25ZS~m;0wR_+60z7XQhR--F(8#wmY+-y_v>Z@c=&+Aqev zH9jt?=B9!hm-ZGXK;s=PKZA3v&z4!>_f*3Jn)gOu8H}`x0#B5zOkneziMSl5csg;B zQ-DvjZxh@{RF2a*;y=ILf$IV9`28I9_y5%&reJDg{||qdmBUZmsJC^3am%?f9xsI% zm7jm%QauqcGDd|JB{2p>JR`>Eu4Q~yZT;GmrFANMbdNvoF7D0m6Up&a^p`6eeYBaj zwO~n7nuN6fOZL0)q51NH_#yjQs50Q$Dh)6}=U{{$Fkt80duOF!c2;7B{u!~>K}+oe z$?0CaP4bhnJRNPASyA{Q`(f{(k>;`r;p~{dNb^=$Cp)+Js3Ehem;+f&JZ0$ZGFKgC zBZFX9%q1yzQ%pSj%T_}UZajI3?D7|PK2UGJ=8A2Ph*w`pF3ho_Jy& zP_DUrvG=Iib1cM+O_sF{*p(1vAG` z%9K`kC;*8!lJ-*6cf>yj5Tt5~2@`Ql>*cHhf4qU`E?mN5)dMhD@&-8#<()q^^na2( z`(emFlAyrARbb<3Z;Tky&xItP30xbP;|@2pk+{aZ8iezRiQ-ALRLt5zN3>S!PeHwq zF0&naz#o&5PmS{~I8e$rxm^$dV>%iL>bqIv9v$R)3#hfwhJAq9_|xyx--aY!C`i3c>|7Erlm&Lqy?^1QL~xp84csN}j1#ko$%b&AbTpxbp4)x+#- zDZBg>p7?{L9rQ9!PJQ?n*HR~<{^59%k-Q{$Q%kTt-3NoAF9aT$bL644&wuIAz`fySUw_Dc z!6^S5C_}-~{wF&4znA(d9=3{0=-*jhTOAov^^}w~v7mgk;E-ay`FHa5`GSD>K&FJ` zENc?=t!vQly+FtX!gcHAx>cRz7?uV}%AT>lvO^+GP0AV-Sx>knS$4$?RX&XiW}s!U zU(;PI8Ajl=L2DjYT*sa}&+pqh+??;j8NZJ9VR1-ZMY)|_Z)m#@`UpAkabw(N!>`F- zvN=6|%mEPDH@yK_2`jM3 zoCIz-v70$b95ZDn2^^rvoHR9`qTJq;xS!GdeFjQ7*I{9)t^O&~fs)qW*TnRO? zugawdIVv;~%Fblzn~0M_2iH-+TH}W^e0%g7nw2V|&Fh-aCd(R%IEqMs#U0d&6yi*s zuwhdO5!6|1qUl~4hgXW3wUkWcqiR@lOb&zD0Ype~mVqHK@#(yb+6#na7|p5VwERO` z%;%ic@$q}Aq~^wTLVLh`9s!?9aS&_8gr{BEn+S!d5Zvjp4<)|R6PMjbAgUH}iv*A< ziCQ0MONU=DBzD@6Q)bKT83R_Em*vltsnVAZN3dQ?{}Ar)RuJdGX=#*awWx123CaUP z)1e_%76r&(hP`AtsjFg$t(SCrE0R^e6ibO|(QBZE3CTwQ0~Vy&V^gJ>#}J~+JvEW=d4_ zRBIP7NF{xc42{k;AA1@lURR7d)mm28W{tmyG~a4D31c;g2y8Zt=qYz{?$oL1eR$g*na&hv zwYX;Cy)@0hgY3=xBMde=Zis(MS}sp!A#4t+lA|a$r348wk>boUU8;#0HKZ6t3R#n< zp;_jA-e;92eQ86r*{7nB9?xpIjYi!OPVl8s@u6Yf)dKlD>g~l?-eNXK6xQq*f+In7 zX}-jv5XZX3um_l&%!#8LWIESxB)P4ok~Ai+cr@hk66F8f_3}%LQ9Lb~oWUVTq(?9X z72YzraSD)#pi-r{U{2{)l(LAV-VimFsKRnCzaEXo^_D`+gD5p^2-PVB6|z=V{B<^> zf-XmCgfxL5GP%I7x>fP|BlBkI`{LwM(W5z=PxXDR? ziDX4k0S?D%myQIot^m18F@nZnjt<~*;WC290?Q@LA#yW8i#(`pRr-09g@O6vV#;KY zB7K3;&eM5zjz=^^%VkriYyZ<8FbsLzCd3GDEBv6G)fp&7v`sRA)fxt1IYl0wqpmY`y^}JfCMfM%z&Zj zsLi(E94@ZA`YK!%jFip|&!ElE`%$8J=p9HDjv1ncXLiAF+4h$}_8s^}8T-|U82<@9 zfuSMK>SBIgrlnFooTZuLP?l_B(!4hYGhg*`8faVSrJgX5)~NB2GWYOBSi5I3&4{f+ zH;|P*yyShj>SOBKNCsu_=37T_xAz;gGdO>N^l|!9M4EVFL4l(^H+vlj%%bNwZb3`X zv|tw789r%Vx=aDXeMMOsq)pP)q8;5}uttzm-w$8>7Af(!o#QhI(g)ocPNv)|KD=BExdbmMCLmh; z>=R^@FI)gl7mVXGw&U{6=3hwG&u&t`faVcpp$V^iH^3GyDy)A8cKHah4=gk(2S2Wr zL<^WftVe+6MGLN1fZer)U$v#dXh_wt(3dUi(=QifHNCykUV*+8+Umw^P2QrMi?<2wq~uq^3XrWd&jot%VEL!Xdi9egn|t~4;NWML=}Lvn|hu1y3_ zBPxk~B|WSWhoa-tLhlLz zNM!GT-j^=mre|n_d0+`A;Eo96AXcycmY8IKk#^gfE)l_gy!P)UTCxgLXdMF&@0VSq z#T_UJ-B(q4+V50bAVhE@`Gv`XRL;4;znXjrWYrBR(=N<+RA9VYiLFLlksGq z3c0z%3`)L!THQaUusoI!)&@>-N`AT4ExeDizJyuMFs1s4NPiUJrNY3eQKvWr@2TfH zMUHTF0ZA(CVMGW_i;ZR_88W#b(w#ssU|3PoHN;58NTxk8i#+xkam(Gaa7pCGjeZ%0 z(8EEr0^%}g^XO4}rxQ8r3ttGfw=N-AfG!A*(v2f9joiTGDx+7H;Eca48(n7FuO zt5RZ1E;C1P8}dSvpN{Ds%2veW#)QeuC&y%uK&gTl5HyoEg#88TB1k*E9E;h$F z+dEh^n5ostk`MOvp<@poUMLL-dFAtEBTtO^IRw^Rur1oQwZJB6QuFxIX^zA84ivqr zx%zh>0Vr0&j$bL)b?cPg-SJ^TvKl5Nn3Bd+AzPmIDq6^V8H0Q#F>bwid!jt3q}kwt zd@@Y6Bn$~f+v0kHpslI=M6fxpaeFb%r6Gs{;uX4g#}S`Tj+br%RI$>qugDOXyVg}0>GIF_{v3+vHDwjz!9#NY|pJE z&ArAUekJ@=G8Y;RR8>p6ubHR9@-?ye9Sr&Ldsd1{G%4PwdH$j40ThI%rZx3U8#J zoJw8|f2g07I_zvKezI>ra5eQXssi=S3fVIbqC7QBk}*No+(R|o`#^U~7;7jw1*d{3 zkoX&MP~0H2e&VDKUjmtG84elFVhw5`vdt*CWF(u&&%dhjrK$h0+OcEHpyqHy)vk*5 zcg?Ov7%Mc(aY>DwEe6XdpLlJIHtB)qA!9|7-SGP>I*GZ+R4d0?np8Hf9CQgKZ2Sxa zy9n)e)?UEPi^+@$;j8}>J`<9YqVt_Jt;ApyUN}U>Yun1)znp{ZO zKD#8c1f3Qo10EG|@2_i@hAWQ9H%3iMek}Q-&&*DO4*#gFbMu1Jb-JuhDToH!g9=Uwgy?`ENESLCL))djW2=)G7Y3~t>yX_hx6LmeusyBVCp%oW;a zWPx5$p~Jua+5xu#-~WQEn57V#T7dXT1N>S`#Vf5{{~5uaWf zY%Nz6oYRwPtTaN>=+#cn0ioFWZ%7UX_3{ zz7-4a+{s~co#ffvd#3Jz4Y+tV#^T(~4LoQ?bsy(lznhYA70$t?eui+bi^G~fgob$k zEjWCLMLqYfoGZY23yT4iWSN&i$1wnpVc^^=$eEkrdLV>!4OjZ`Z_9p?4d&q~nxpY@ zB(AV5GRvde!HJK*-X02P5As*wkWR8Dgw9@c)9F+bJO!<6D-7C z-6UsUyhGqs=ycqnJfAmF#TdLc=>$!}nZ4rB@ReV-=t^_;(>8VU{FENTqU{A3zvtwn zV3q5-w3>f3k8tFh6-71{fQTC>dW%5YWJkKPrC;;3BGh_$|83z~1~w*r6@US$9}BW{ zSYRxdD2X*v}&Wi@eTI7S#%FtQ1mcp_v4UhNKZK8Gyk+2zMx;!@nY)iAT#Egfmw zAXaR2O@`cD<1vLXO-T3yrcg3l_ii6O!&+ceSIjXp%!oRlgo(naUcJZxdX)C>j5Y=f zLb#q+scCLew6Qo{L(>lQCY74iaDDN$g5se(*0Tn@nbJ6Prym`#CvZlBKN*Ul3AyLQN>SnZ+J`OqP8&MEXjjJ~58fU}IM8TZZwZ zkY1d7>Iu`ZWOcV>iCzW)+4;Oe;d5w`afy4q0SJA8fVoNks3F!IG9KiVd8V3@U66{u z6=L}$nw)qSoZ0hlVPNpU>iE-IHp^#%h~%<8DkTxbVm-EZ{-xp)s&v_l6(s?s*@ z>1!t?0}3{3cB_I2r}oV1*|FV{Kf$B|k$r|}#%OwIMxhLrCaZn1x@ZQX^o3~iP#ox# z!H}m_>|3HMX8b4lf~`PQY0~1PakL_lK+efl&ezfDW*pi4w5UiWRRowagOU;@&vVv_ z)*V(E24)+PuT%|5pARL$pY660^1<|3)kR#Y6pV_U)SQk?7?X118&z=^XzgBp+vSGi zPsh*OYTk}@2G>f=C!eZJRGlmtqL$)gpXzw3$MknKY6mj=4b+{1-u0g8W)AcTQY8u~ zoZ*F16S~EKS45cZ1jo6s>ciBy3Jinpv_#umje~KMdyoyO(L7k2Q@|y= zj35R5v@tCb+}w)2eFJ;z*OIilR--ov^w9b7453fN!Yg~EBAd6O|sm|-dp47|S z{8qC5I+Npk7Z^cJd>N) zF_gPno@EJ`rGlwfDE6dINg~m-lQ_K6YlQlh)RlCRs8h-K?KnpgKKUXrbb;%{bIB1ibEE7N_~>H`$&<3CIyOIQjGWk-5UF{N&bQ+7-? zD)%rmy!($vO~cc9S0|=p=TqNs$Q>`5O9V zgY;qPf-!n{Y z$~dE94mYirbcl3dmbMcO2MSmC^@~hB-DUTMA5@w(vBifd={FCw&Pt(+Hj%_J`Rj1Yc+z`7!SytUJMe>TV6wE_f$lwF7TOUl zsA1%F$#4`^h?qrN(x%_1(4Q`B{iiv=c7gH-4t~WZce!6!nwosE-J?P5=HeC=6+)%aqg!GK^rh z51NMZ@aL_zein%2o*IUeH_D@Iv8m?OS{&UqmF-$3ccdCsU<6 zm75<|X?$YzFsmWDCco8-G^r#ucI=_H7@XZK=K?roZ0X}G&Ogv2QIW+flRNL_K=ty- zd;cbptV z#!0SBD~85W-mAJ(#%cVWQF2K|dR9aB=siNyt-UwNy+|&1y+(mvrChdkM%|jizrs614fB6_vRm*Mpysips8D&U)pFH|A0yvY%Z5s1VJi@-ET=iap;ji=! zw$3dmvJcrkDjlR;uV%W*u#y5DY&ppCucKXf%TqFT2U+Ak!mOaI0o-urrkgn8@iLf} zC9_j#@%FO>Cs#Lz?U63m!{iKSe`Oh24OUs~%v>f5z@;Cdk%o>vV$xFO7OtwMyWJ;H zmKJtpFu-~7616`^U_=?HeT6Mm)lk&~tEM=nEn*gR@22tNEIk&=3a<+?Ro=`3DqOt! zLpsg=7!mYCoNE#W;~N6t-y)4W5~B!qGAGBDfJN#PoU>H!eyn3my`eBg>SVr|DmLjl z$i2g$Lxn{)){#d|sT5|h^XvTAP1=!Dtj5U>QC7hiLQNR>_`r=n(@BD50+z9YX##;n zd2EBiVy;;EDhS#kp`!iAa2bShS8&H-{4Sx~Vv4MSJ%r@g`n(8AFm-AOOE7gp2o6~L zo??rvgTV2r=Wqe>sn5Z^Rzfe}*v;ublzOHE9f~Z!h3*LHqI=tY9YK?Ql-Xe2>?rFU zzwNmwjLW{hIzO0w5L>hgoT1l8s4N*8-t~z_DO1Kk_DKGL6r(AhL#Kb*dHG>*d@T?jQ;Bj`4rr3~t5=zB26A5xJoogEvD zD4EXmYtLRY9@B2q_n8S(JKrC#XuX)EB(%N*G9!^Id?1=O|A;&m64 zM^67i1|ZTgJJKpirdjFwh%{K?+IoV47=%e{KE+0noe!E6qGpgDf;*v3Z?3BKrm_18c6|& z-7J{Ezg~8Fnh4uN!xSeL6;%YrXuWLWI8(}gl{MxljCY^o9%|Dm|1x-cCGk;G(b0OD&PuJ35 zV4Aze?!h9{%Jt3PENvTGEtldmcm;3hq=*D9{5)t#C=9Q}w})8U z(mG+f#m-;fy~=nsGs~-H{3)IcDe^bx4Y_#9VGPZDYT^*GcC@kTrh`A12*W1?tmI7+ z%P&7ZZ;wODTPO5m?l5f6tG}n1g0KBR!}Vf^CZ*#vviY!h@#8Wlo`IvDG&17}mUlFc zAAYMg50Uz)IU6rH!1SIH-O=2CQz>HPE=H`sr)NTuo_>8<(*%dH^nb$To9NTDh7AUO zboZhNDn>%2zYyfx$gX%-&!bFyMXw&{82QFv-dBNoVo}|I*#T(_ut!$UbBs4B2$PVc z7$?BO>p*NNc>^M7buS>zfRar#<}eCrWd5ZeePd+TU}P6_3Ids6EsAH>*aGB|@j=fc z^5G3p9VbqyGbo3p#d z>M^pr01%+DTlRqQSHolO;0ENyiV!aMgudeT-!kXGWu^Ims(6qMas9TLxdQ!tU}(Mt zLA-v#@4x`^d%YcY!z2ldb?2%oE9|Of?A{E%+7p94`^qb$l(yiO+mI*PhG0hV+n&)%^8-EA0C`?j2XjH}F3f&F~#7F}EM-uHcWH zfc)PJMgL=r@QTxlJZrDQGqU+C0-~_`$|o(2dON5H#6Zy2*V8!_`Eov>;PwJivha z)YBP?3-(Sz^x>vP_e$*rUZXTFMnBulCf;A`)(Kth@SE9VCwQh%3Y!Of0rO!~C0m^r zaFs*9#tf_~_rX}RFl-VGdebgy91fDx!H!2OJ5mEw9_ID-BbQA<2m<18)nz&QIKE{; z7`5P~?^J!#2lV%BQs}4A+=PtckbPf`ym!@?iW=&Lk!4v=2GP(t6Sc(W*{= zu7v=9xo~yLBRzS>jNfPjtcOtZsiM16K+5DYT84E2itB`1hWyqfhUIsFhrj|cS|945 zIp+6m-ks}HD(-g)sb||CsAi9=nR@Ki#@+vd`Y3wuI%fKLcmO|)If8%x0M(7`ZH)fg z8SbTYt+FVL)I~5FOQa~lr%_QGnhYEyTb|s$I3Ba*FI>B2L}4m1VBId5A}Q_Mtn^jr zUGMGdaK`r5n8@OV!PCjR7}O1T6aTaOch_F_Ja>b=^oA;WIEM%Yh7Hez?EllIdljcYze9!q7xpw5jKnLFmb2OV z1KOV52p`Ost{|bjL_7M`IY;BIsu4TYl<{uN4-=Y zhQp806)0pF+I>u;XVWeCee{PLgVo7*A@Y%K3IGJ=cFdyOk*Fd2khAZ54$D50rO!1X z(k1A&ntmJUK&oKUXW{o`t>lz`%mk127PoM05w;X(T3huub+oo5J;M{qKbOs)gZAsk z?C_r-w4ZMS8!MV0bDq78nIVm#D~-L4Esf(($^3zM|MPu+9wDyTpnv@W!u+?14gY!H ze@Zm}vrdhwNR*ZRBv<-r)p_Un?GEn%%H1JCT<+F>ZVgLfTbPXykIoWj$Fe9C< zC%-w`n-c}apl)T3y^lBVv+lXRcUf)RM25;o2N;T&x|Du9M5@ZS37V9aKgwwr8uiHse3(BlfxF#}DcT6@UYS#0*yX=nh zVg0q$QmG`PKP9%eYHZC%i1j5jX%h)`dck%HoY>YjW9|?Z{U+nfoRHYak=c^|@iUha z#g|h-b9~~;cS2q|#5fXGF-8gWE+}1U94exR$kdrjdrcbmbuUv7zQ!gfvw#9?lPALv z748>~`57eT+Q1AcF-G_9D91G+J%lt%?Fw5(9n&T{J=^OEWQA_Q6v-@g8Djld@?e7s z&XgM(=+;-Z_s-<(7#(Zd^j6zfmdwp6dQMCM+0X7amIp*D=n-9vFc zB1r->UVo>v8t(JcYC}$V(;JA>3g+&`>UN~VVl{2p#n>YIRHMn?CEx`ZWV5689Co%j zIwrX6Mz-7df`Uv+Tk~ic4NX=M<4L7O;^!U7Hg7yK^p(T#zZmZb#xlcFTr<2R{v_w; z_l<89^VE~2O(m@%xlbedH9+xZJx=;J zdS##mF%vOmId#|Zcdzt~RhS$$uK}3w?z5gJjW-21#Jq1D$Iand~cRH?8Zn@mgcH?@i!y1Dk8U z2*HTnlTb{-5ot?@9rg(1%NU4bFE7cNEig(!25uZ?Z6=@=zhCp6mBFd2Na+xmE@t)d z;Rf4%pAt)$J0geZ{~_!hyEB2JZOw}9q+;8)ZQHhO+qTV0DmLHPwryM0ITzjIoO`Uc;?(@piQ0-{bTj|{&ueP`o5(r)``Tj&YM`E7}C3i{Rp0g(AT=75YE^) zRtu6bGWK`@Q0_f6+5yr*hN?+#=DaeSb-_i9{S)}U4zrm%b)yzue!XNq#U1zVnulV6VUgAM>8jV7v*3dGAiQ0$hRm`N1$oWh{&hmWiyINb zLwEyNNTT)%_cObBCy&;QkxGwEKsK+kV8i>q>AlGQM63=imYK**ZMN5PrsD z@R!@X?}R6SP6=L3}nQy`H-H|jxcVYcJrcWFaBcHU>+Y-eq@_confKU19`nncNEqNwFO5c7#T8|4IK*; zUKqpW;OUUhI6wZuo+XWfM-WOW-1*Af6J6K@Z^@63h{hs#)c#R+C$T8aWkee$c;GEa z>bILamtxZ^fmW`-9VjnXT#(p_AtnK>er_dnT5(ZANWyY!6cFT^1rG7%7#-N7>H;TFZhZ8!+Vw0QkqJW`$f zVla3lH{_@3BbM>xr#IwhE5_@|x+;!n$qHS^{Y*`kb(lph2doG$*Lzrs*~9IbDbcNP zjBbP0`{{^QWJpTnd#X~hMo6*v9%y*Ib&7z&ii03;LP;nZ({EZW^I7oi1jnYxvWR7R z%A!ho6Orh)f|?5=+wT(&KKYTZzSlP_;_r)?JbSA(dTQL0QA(98#bTCJ!Ri~>dJ z-)z-!VZ|m3ez79>fg>EqUp!s-VI#gI_mm;UgC2ZQ7Mx7PzQv%C_kiN#0hOl;WjM%+ z;i!%V7qNj-&_3?m4x>KPjNzpT1V%UULrMDCQKe_lhFRfbu?Pujo7jRN1QtAm$p(KFkXoIAI+(5(JsGS z%v?fiA+w4ypGiM@z{AEN?`Vg6$c(TNrTZG$iXq>TreL;?M0Qhw;2$EA7N+oxzdC=! zM0CU0mg3->!PP69+vNTL4c9kCBPP}x+uH(;+n$wlUyUs;y!qNSw z8rXX~9PRuoq6(ovbt{_ARbTXOog*0zTXVM523I&$fjuK%RbBqb%Td~T(m6&^VeRhE zgcb6``eb|w{{5W@xLMRCFD$TPP$0ip8xAkS5|Gur+;t1u0e-BDRpDRE8F*c8kg`!f zFG%fSb7p<`s}tK3?-TbwS6_C{>bsLaJNM<7|F4|-|ERuxMg%H9wU>;g^Z#OJn$@8^ zRF=@b?ad}+$OvgrASEGz`bkJaSOX9lpn!rj8K4XV;DnhH0!dJkptLW7jC8ds)~iC7 zW3_D1sBu{WG_0@om)ED(JC@g%J6hEKs8+51+jKu64S?2{?nRh>o5^B9m@4ocF+$2{&jblHWL}T5kwNJMu|VQlIQdDtLEX*uC3weU@KLOel4mJ zOPiT(OVUx9dzOT{fK(0O7G~u=rxwuxrLIlA>$gi4h=xs4c0b83m;MuF?4`?rF2wLZ&7cQ0cM%cBowIwMOID=aH^G1szVHgN^#z>d58ftA{EY!i zU6W_YlQ#Gz?h4*1RL+A=e$dzk*h2DSPfu|wx=Vf}Jjg@4h7>n%OY zZ`Ane$ZU6KjBtH#jP2GK(SzsEJ2BSr1K}`32pd)w^$*C`soPlN(WTX~l`Fnwg zOr&@|#2~exFh~ssi>yLbp`+k$!CufZvHN2QGHSrF%dRB%kf_CbMxEVTMt$#VgxgK3?b`1RfbvE`l zky`3t_-j_3R$lAt9HZ1P7$J{gVYIjgP{DRTD{R+2U zK0uutytF=9fdx-8i@*cAbh;TIQso%;smC#Vbp!zQiDL_`3*eoYDC79$zV{F_UnAJ| z3w_=@F(O)`mgQ+EjBC`9$*Dr2Q$km_pb{qMVDOm~1C;y<2%c{g^o1}$m}^YJnxo~E zB#4eMiG-3%H%QLCQgQ{*8cHrb-=0}prch43cm}NtX7rI%)-U?OK#6BKFP{0xXtL{= z%dtb$fMT9G7}SFN1MmK*N=mm)O1v@|8&07>;Yo1-GOrhj=5w_~JCr9R+&f^JFOr#a z{KG-y0paEv%jR$8C(fh84;aztO(m4S>uD)x(o)Pxpx%KKgK^fha+3GyM$p7I0cCv7 z4+sO54AjQto54EX2>n|b>kasMRwI`+F}fJJ%^*ENf|1>~bhM*0T#)*}UWp`oYT+GU z2k0C?y{B##TW^!#UEm1Y0?6Bk>7LQ+J7q!c3|Ke!FE0$icQ`%<>24guyHYx(z1KQE zNcu%D1tB9>s*7B(V5`$gWV=?~gE{y_qP`&{2(^kJ@Qv4cI?;6*lDg((sn%pi6!m6_ zd6`*TR@L%)ibc)6N$n%QYhh}2KBc$d>ZC-f?u|&kG>%$B$s9!oLyy;moMRN|$=_6o zq%Dw<;|L@vT{9N-pgXrEHmynIT1nDk7U&+#+Hkxn*qqTDVrLy4yD7Pk#A)A1&GQcx zH_dkE&i53#62eanQe*e5NQSF%WC-ZgjBU<<#$%-Ohz=wulzSC)dH$2lD(LsKl6NlSVpaQVjZ2 zVx?KZSgvHhE17s#z*N{nUEjFO502NzRvOc~mCR>4rt_XOU&HcTp;xwIJGg)vuX8$( z&m4SZkXs?x@9_D_*jFvm2Ct4Cwqd5ob7i5|9IiiOzA#>Sy-_|6E31N}RbMWW>^7^g z>j#{*Z>c-mux&6Q%nc*| zJa#ZNg`1@{zQoqOuxF2J=RDrHo|!y7aZWM6(3u=NfA12Gh>F_-)olXf(`Q<J{mXONsB3_RI8D@&cgNiu~G zZojKCs4=t=>5icg^558i#T19ID zvvZZ~C7v}-_JqwWfN|MSf35Y+7?H^>$J0I$f{4!iUH7b@w$U!M!p*C9qyC}l8FJ~- z9ILuLO{E{p;tIDi*i2E9UsKyioikmBUw5mby|2WC%YV`#r zf3_y{6y*XDdIPw{V1g%b#&0mfC=_&qC1xFsG)w_6Hs+8GW@L<6+I_@uVjVqjm`dnH zI2bLEjDV3S@{E8PE3S+fNtS9vLO-kjomViT@a`meXp~kS4+5-k(}n?9xM?FlMUUDbK(rw$m4+ZS$Y~#zEd+_D&e_A7 zD;7O-L2)pR2{$w&@{ZyNi6uSTfe?L?2oFfwLzW|b%YpPolbYKGVke>~=AtNwecZEa zU8NzC{%}oy%1tjg+heac_Rkl*-ouNN3w_}(5`OLb?)lbUNAYc))OK8W z%kNyDZ}?Wz)t%q?ljV*Hc+AzF*L8kZz5na2`aa)l_UFB0`8CqZ3T!=5>Y zN~WBN%9J^5!j()!#+)%};sl?bId?#rZiwem+UEX%&gfrI8l-!iJ9y~ zh9*OmNn@fkRFXADL>8U7$e@`N)~sPZ)Ogi~dhut~U`Pxuea#S=u5}+8Zl)e!qBCuu z?O{fpS!3i;i>AI|xqM>T7WSq^#^<+HV+bSN)Bw~QcEMs}yg7{w#JxFcJiX$;+l#<- zW`JyjY&Ji32&{&-=cq`=2-nH7S+FMt$8OoC34mekk^n@rc7>4An>t}8(_-mOe?r66 zE#6Y$`LI%dV)A#10sed*YWX?g@>?$5dcn0?dIX1Uy!FGw**6`?dN2oTd-&R!I$;Ag zGCy<1aMd;~vwDB^MRi`zM!H*hq=&g%-!_N!&N{S$yIZu01H4(f)Bzu>n_pPpN&pC! z&FZ~iten|fb*xW0Ksbw!2EZ4KuV}B1)kg(j2Zz7l&>IF(^V)`npj8h+NQ)TtMqDVS z?>rmNP8e0~M~-L4@Q_p{9}6rn`SZBledSbX}-NLp>ynhCh~&v_obV z-HO^KLKL{LWj`y;LA;QD5eo`J3r3qAO>7`Hw08`JA!h2#Ol(myi zU#(R}J$<;&RUJtz&+8eIEDwb7Ik#)xSBwEhA4%mtal66(QQ=iYL7(Phf4u{(+1e_7 zX_3HWQJsaZx(-cGm4#(i+uqhzx45;wBW{x+eaYjk@J|ejsz+$#BPm*}s_T(;Raf&- z4DCBC5)K^N)6#aa&*3<@8_4$R`XungKb%_zTJTW}@ok^EzEZWl@IlQl) zV+NTSy7(E(NK|O|fLorekjfH;>p6~Vubc6g+T9wB0Edc~)uEIo^F72UkB z4hDh?6UX|694yR7cByC!-FBrl z?zujzILK`W{f<2hN$e!w%UeS)I@Hx35&T463e9_2qphkMAdX~U`!JE=bb`?K0FPW7 zGb?mPjFI*X?r4UCC2|>P(WMi;HoLhXS+kjdQ#14z$r9F=(O;XRArrub1+nl^K%|u> zkOItyp+P^u@8uS9K=4;k{OQ}(kIPvLQWHdxz8smhwW~Us20oNMjN_5xchQ7Um`~9Y zF}l@Lh|8R`dx)OZNgb2Fw%I*=vU_IN$e}M;ui-sVGD7AiaI4ncUy%4+ z6v&^&dA3v>2)rS3q~ScVR8b7$1ZeOt+nxgU`Q;@+Mk~bebKbJez>1BXIn0gAfZhY; z#jKnTF=ac9;pyB9_{0Q|{9$vPTZq?UknrN;0Q&^3`prXVm31`8mUm(kNI&_&wM%Q) zm-DOxx826q91vLxvq=0?M2+hJ{5^6A9-t4(uQrtt+W84pcpp6dT|s&!S3}dV%O)x1bQ+o`g@KY;` zU7W+@qS1ceO<|oP$eAl(0KQr~pjyW=gN%z>&UL)FL7a@>Gx*8kQ~?+z^~xHpt3E-W z@K6_7*WC$^Ng(`W{fyW%l{(?Qj16?Ba8dAf&j(N5ykT`5hZOP~CKa@|EH}kCWL)9> zN?N`rOBWR=D0dP)G?c9Hze_s$4Erz5c5d#N(aSikX!@?Z)=kA3g5H632iWjFD1J8q zGZ6)`<)s9!3n<_gpVg-V#le|X21)@aCCU+YU)i6D1Ef6y5y3aKT3B2Ze^cn}-l@;D zMASj@XS&WFUWZrKu`*8r$URlXu*W0lMVy};BYu0Kw5l*N#g>N6VAopv<|zW5oD0v0 zW9C5!VGmq&VgY-usd{-Mbeh*?u(Cw=2}hk zrRExOs#@L@(`}c=V7>wp@1x^1`5KgRL@GNdV9F`+_sFiMlzx|HCEnb)!I-@v}N z^;6EsLuZ1Y^K(u_%RloR(Kz2%E6ektw1+~KJh?1(yx3VJ^8ovaIZiE-f*vi1HDYU;gI|`eIJngMt!|xpA|svC}nD) z*WpgZM6U-)_$giD_rgi|X`c~?@)CY3_vEDhQupPg{$ls$r2caEC#3#@_vobllK1JP z{A6#`Nxf8W)=9l|Z`et_lyBNey|i!KNxjr>-buamZ}uer1nv>Q-0$jXIdV6H@X>Yl zjFoTYLvjYh+jsM!`S31%lr?wD zEj^noY;?&rJ+(=g&f%I^%#=3QrBOE*c41R72e`25n0sh7V0&OiqwH1POErPvg;Sr3mc%m?8gM)V| zT?V2vpz4ZYwgEJ+kPym^>2Ugn@UEfl1_yMCJ2-5YCy+7f6e{G4s9mtf zL3Z)$ASfr-p@q%jhDym3&XCY~g&SkCwUpro=ggkds@?<(#^-?p0ERzh1rTNK-d+V3 zdU=gz2(b4t49)W%=67}&V+ZjAF=fIG3$9`alSK8Jybfg4B$b+E3pCCxoEt9mm(M2I zma{a{Ek}k(EE})t0v-2fRAtslhsvb%CD!d-C)Q{W${7=E*=~RY8|KU{IJt&0Zq2rn z6gfT9;coI}yih1vyz(o=$y&++-0L!rnIfGr;*$*dkg4;|I!Z_65nwaY_D{=v#srlkGBJ;9oZ7dQY@CwvJR4>b_n4MGam?BTCIj zVVgI-$>L*JYIsnkb_y&62Z}UTOz|)LU)X#Sa{Rz@J`rhd_^>15Lyyi9_GLLN@vak4 z4V_pOXQhXwxjt`vdlN$?nWX04ae^HT`b3kR$IpFTxdl-CCOjP0UIu(4!HpSq6ci!x z1ilkU((g1Gx16JW=!EF{MSuK6Uyo*O`~H!1F$N|j%5BfH$3Grg&l?kMOJKGX5M0OR z8M_D3&SbhF@E4;#M#U&zr~XYTEZ-$a@w|r@YBwJgthn73tT1UvkX$l`qCZi%0{RT- z`b1>;q;0$9@O)#G>60(~#UIRk>zonnAMo}nPBB7XfYlqK^$Cr2EB}LDZi&C@EAGF= zsbdV`;v+=0anlWio^WEwke?1RC}wC-T1n2DO&~se3r>3@S)%eEcthW(2rGPLa0soc zb6W#$DAIb+TedoM23peo{*l}m)vr{thcJ9LODW$4V#t0*dywCcdiCM9)YH z!>^7LRuCZ%@g^-7r%#~k4yhg*H#Ekj1Kx`R)r)h8e!_S^(z&Qc(aqS{a!tZ23|pIl zQme5aJVwgP-!iv*A07gyX!$lnW~5cu_HcSXuPV19R9`JXj?uT~!rErlp)1{?+q_lV zVYjljRa?4M`);Q$+*+O3phts@k2&Es0GVkSlJ?REEycRR>GfqANVX!iQiaFS%6@X( zPml$WpimU+_ZfmK9k-}Z7#2un`u&^w;75Z2K{^#`wn8QZO^UBZg{&XTl&MC!tnasJ zhvD_c;ijiBgrHYs(kpYjrC^QA=y^4#W^LKNq~16)++%_!xo|tRKeY{+1_;#}lK5*qz5V9fqw9`m#eOK?CbHBg6i4q<0A{LUHh4FM3#{ zRx;g|2=Dmj#~iem>stxC(G*#gNH%5C4n#8Q^a0IrQ-xX`c-iqKaQhi%nsm&?vG(9G zM{}c<<#EmUgQJxVN+tLr2M5}j;)(Iiu9=iBZuUU!cC=v%cZ|u{i%xDkI=0NnElyi& zD}U>k#Ab-mbzu+<=dXW%GM_8Qmf@3{0VY>tKsBbMHA5xMYhkbST#}#YW7K~9w4o3q z6wf;$n&X|mULig8GkCCa9tl(+=4Ub<49*4Aq3HO^KySdu6#jgk;L~RG4Jdjk(aCA& zBtME9S3uR4^ck>GPciS?1r7@N7^?H=e}{8IhN&tUCo&i)o0CSmwHn{8rckwWYYUkU3>an6!jOBM_u#= z9$lSUYHaryGd8f9IzQyPoBu6}t}XSdw6l_dNq%)|$zIb0^`9G2C|UPc)3LUxuCY@` zF^$$CaWKtMW{OU&v3=65WqgEAeV+_=e8)WrY)tnEU44b@PiRX|aDOs@zC+UN!DU=F z!Ii^zxJ89~eN*lqu<&ssxGogbmQnB`Fsb01R8KJo>q0m$666#Q8wCG!ax1WRv0RG_ zXLiyoXj&ul@G2w6`V|*lsU5&9597sH{ccTSu*LBM>~L}+rN5Z%IsR45f}D8A^?9*= z1A>|Zn1*L(BlPsUk(rjNVPmfxaELF>rL?^OSHF(LF{JcSVNQ$e`|I!UGezwC{Nb5A zL4zQ}3yWXSF?e@dg39z@EYDr#=vmDV-boD*LXx~dxRl;W3Et(3QF3cxYQhP;ehuH%b{LV37k~r+yJUhXfUO!J z^^x?6RsS*rVzUI+0A0OYJgNcKJzWH24Wx5APhtz4Rsy5=y=#=%0ntZ3ODfkXkPhvV z>0^#=5iMc~tV@?DTtH1Cg?=g($pqRVRU`vHqrJmVKK&3{4rrdG7)n|Z!DdLxj_zdgVwtr3qqbdLwx!% z3j*gr=Bu10j6xIYYzX(Y0yO1-gqHAU7QPkW)rL=$!i-(vVH4K6YxD|A7hG2f{3ZMe z-GK%HfUiPrJz#0WKI#9`06{pAT8+PQ0JTKb0~@(D^MLc-mF0oI+3nr+eV6)Fs0@iu zdDufS<@PDN44+9w*n>GDeob;x|0ITx8}#WX|F0Th}x=`mvo2le^XNcwhJ>bG(lhG+#ixkmiGhVKi>68B3=#*FRh! zm%017$2+l#Oq(2T%s(uJI4%B=dS-rgCK9(N>#_*g$M}1Hd84khMny`ODGHy7nz8pZ z&_a)rXANE^%c|@j29bht9i!<>n>xfE2S$M6AH>O=eTu(rA6S+_lznhEL#LJONcX-p ze-)~73`vnWGe)Lyxv2sdh8R)dy@Ww9s3~+8#HYh7+jYgMyE&Z^Wp@YN!zHYIq((>5q z7`!WWjMD;rT_8;f5E$6|Wrda~z)d{!30Moi0%v)$`kDKh%)r+ULd5=bjP+WuO@+z+ z7O|31Em1o!Q~D?HPXt|8UGcPiB}^lb$mEQ#_hZX>+Wq)_W~KKNdY4Fz*kULmES~sw zFPW;zK!wd1DaKf+R(IjHGVH=oMob|T+v$tBJ#U@?O%P6OKw`pAi!FcR*bIZYAwSj7 zxuLz(P!A9!usW6HY`5-3GMhNwW-SR|bgs1}n~F8*Z)_Zs9Fbo0v{xt~Rd>MI(8P3x zi5o#-UWR6`(a{r-fexu%kGq0{0X0hQez+XgSwQBf-yC zRZo||=O8?-D{ltL+U{=Uwlxm>j7KliXKo9bBkgO-!;+*4&@414Yi88FElU^o?9R+z z9o4wVyW)afc18;a>xlQ3991j&9)gs};>>me)Qv*kS$yLMR{V-p7p)d`;Rztj zCSChm!CI3#xmx+@DHDrszd+BRVNz!{@Iv|fFzK!OyHm4T0DbJXV*o=Ref;_AWvJ1h?6VLR!<3b zxI}+$=%q0=zB-=&T{_l+@tF|PlDj20N0zV;w}7q(4rwRQzTOu5I~}r1LA+yixo@T= zJCL_R6t}zck%ee-K^NL3 z^*tEMAb>l)-95Ea9nwGH9acFJX*h<824s-Xawt(D276aQ?WLmTo!+ZEk#^% zhzL>2+T-TOaWBiU+@WxCKW;wXsaX!{R%eoDtHL$wX_2#f@VB$7{sR z7~~4s-w;&&5N#jCYa>y|XcQZ2)vtgU66fMcrb(XkTS7_J190X`N*%Zz>n5uFQE*g;)y;RmGx##@l?smi*DGV;K!sV)DM&qwLTl9lbdT}&cJH+m$W zdiiUX!e5@hOZwtZ2=~w|rbcM`TbpLxF#s=UWtHk8CEo`hM_Baf(s5F1iN)1Xe@jpU z|Dk0`kgtzd5I%Xr{)70>Zzs>WIU~dm56ShTjZOLAzn%XB{};Bmu`xAvv3DY2{9in) z%9PTA0_wM&Hda>I{5^3I5dqkG6EY%Ny+&Y^ar0@>=)jh3Hsz1hP7>2SG+z)x0XEw- zZ#s|kVhaJw-W>YYQ>p0PmU+$0f`P=l&RC<0sA4mqk3Y4if(o{lQmT!v z7{-~Y!%=uZHnY}VG9%qVdjMG2COvzsYU^*8dF?gRV`|GQ-3nHop%p@VXZx_b6Re^A zf_KT&_aDdV<5e-)>h5`+bZf8;r|uxzEU%?TT*DpEQB*Qa#tPQj+%@ed_mTuC{@hP}#jQvfeFi>IeQVY!vWrp?(bLKftAEz`(X_FQJ z?tmum&}zMVQ`H6QR@>1L7gk9$Yz%XZYZFN)wD9a4Z_+5W+Ox+Km})_)s)qmCE*U9P zf|c6Xp_;C@)*8`y`=hf{GqrXRQ8^uE*?L)4gJNsj3gR38cYg9tevm$yoT>I@ zhISsusA=b($`eGGMA^;FfIN)G`AwB7tL@6)bL);)%N3GM#RNc65Z)l#po5$susi7? z+9m*5cpss^=;+LKOYv_E8W`9QAbchu-H%8&kCSgmhq3=}IjFE#m$70A_YNcMyyN6z zv*F6a%ht4R*2^6>xbiWQiJlvNhZ?ii!kB>+Pk4V3yD+;0BYVs(dCm^618(9+c}Dn! zQFKH5$I6|Vggf51BSJ9(AEuiLbl-6fE5Pj><;!2_k#ttN)t3YfQ6S+NkJb5CnHd72 z0zc7fo(j<80v4I@E;YCXuRIr1=@;;>G;oq$$f+vKEo*-yV%0lP;3c7u_$il&Mh??R zxt8B691&(m+CAXI1ozSS={;}90c^(+jXz<4p1*cogeR_gADQl>O9eI=l>i~M2WbG) z)``r#-#W%2s|znN)c}90!k#d6n-KLAWmP^YRE`9b7ykDUN0JMDKqq1ZP5mp=5%=6c zE;*!PUq%+Ekb7E>u*ma9n*8071`KD2aqYi%UjL78#ec~rrvIHyTR+)^_${Zc1+|ASXswzMR0&ztyy;;G`7m2V7HVw(8_a7Ed2YJFOeyj^)*Ll318}{zKha)rgJ3ushj_k09 zsToQ}>jDUNSZ#qpftaXpDGb$vImi!~8kjT;k2cQi^uFbHIxHAv)h#xfo7ErlmD*3b z6X~`SX|9HI%_t!QbW)+L$lL5uDsRLrk0R@LH6y3m{n5Qo!Oi2i=0knD%P-OLk}VP zZk~vcTykId?tY0}xONc^!U&Sa6ccgiOe8SOXi2o&W~&^mLCy&yx-nxW@tjnUSDNnF=nHqyhk$$il40F~+@{xj@ zZ1pkRn47GQ2y3v{*&YEkk!Uqp9*|mhCNYAHGC4?3o%93SzrWWQN2rk= z%7&p;mr|FYa96Yr1e3@AsGuTPz>vV%Z4eRM(;@m!IKFyVp-`3mz6BW0fjj-{C`XUu z5bPG!86DB2?q&*?Y|>+5k*6-SKth5!K{=4eFg)LK95_zwGCx_kw%3xGHpDqs1|fj} zN9F!C@B1TvQ-SRT&InqBqiHQcAnH}3u?|5!eNC*GvmxH_3RWq9C~pvAl2z2t)h6*w z@kWvNNGhORMOVCIYEoP^@eccl${*}2x&kzhFORyhG&BkLTY&*UJ1jzm7p>+WPlZn? zWP(z{pOsfj;z5U>?N(o3xQek*&`tRU_r0VITjP#Nnr?Uz|8?^HYkH3gE@Urj+DsF9 zg|*F5CP8ja-3!^+1QXTd6!r7Jlp?(6Om^IezkU^x{%6+wb0V0|&DM zR|L7UaDAiws(tm@Nzk$jA^6GrO&D?ZDh^|>^=kNwe;^*j1BM^U2;2{A5c*RF|6fVG zf6FaB&?mJY-XKobAKn{{*UW-q~68W6`D_TL}{LlZ|Vru*Hpgm zPRM`3`WGGltoL}Y-eRk`e-D1V3Y5cZ0zXG+B#ju3wGNK>-6>b1Y8Zjli$Omj{UxdR z@RAjeiW*GYC!$QGe5YtO(Ly>m>EJVSNK4UVVvYdkB&BF15m_*8smfI*DVM6JV^RM& zKHKo|)$WTO8z9(DT4=g)S*n-7k5;vbBsJGi!W&epoSimeZBNQhDCO!LPhtjhGiEs_ zJNM2tnU{r@v#jm55%;xLUKoCli^YCjp5Ip7n4hCd5EFFtrOA@voLl@|-nuho-u4wl znR&*&&b^MMO}AK?eu0?F!^*w5-ry*%Z0&2C+$TkrYsS7roUwu$_oT`_S1Up@ue#M- zmqomEwQW&z!6O$-Ze++V+4wsx-@|U`cVHdg^3i-wnZ%;)+0Dig8CQ;O_hsfXDhzkG zc8-Y1M&`5t6E)2!OgLEiiB|t*E8p_QMVN9us4SHRcBGinMY~oNxe(wUpfM2re!8H_o$C?xyxW~#*}(Sj)pFeyT# zhkHC-&HlobXhBS_=;+6hiA*!b$(~tty^8PN*-*cz>q#w3QnDjCk&*Eau+8n-uqF{57{&DrtA0avufda~4gm zW5iRy9|g~Ky9o6+6G)z6NO!SaZa^0D_tAQY9E10h8Rf25PU7ez*WC5_u*LWlo3URq z`sdc^S6m!dYuBiY^&%kiNLIks`lFEs05hX%l`a)s$DJLMqtEVUbW@( z8glHCNPlQc|o2p5Eq?9d_WVdh3 zp8{7L-jlHRLo>>BxielrIRCov&`7A+jHL{xkLiciqB+De{{29{Uj2u`C{m&=o!Fd{ zJE-*Ycy~_9mCJdM9m*q4j55V3s#E8EN7?9{C8Ew~Gv-LO)yyTCJSWGjU8J2!TNIOv zsvHnasx%(rXCO&gZzFG&hoSMaxtKupH?;3t2H*6xQ zjfIgajWX^7!QB$;wNtV9SZjyoSQ4f8w1z_(ZM9J;Y=m7wZM88e>FE~J<{aaR_J%Ns zR7bz!oW)hAyc$vnx#7^3ngielz3J9NU~Q|?=`=4*$_(eAdyc^CJtw_<8Os>jHG>H; z%fE+0+H^@`tk*``Y?8^eQw_suzb(;n7!#}F@}cTw##tY;`BQobcwe#967C-O`tiI(r%bStc|AS?pq-6GTne0SjUpv zu9bR2OQ)08(yB|g((-yJ{M|JXr_v_kvVR_2Gn!c1k6B5HrQlu6lbTg+xlGf8^VfIt zE|y$Rs~EJ2yf7;}8CBP=O$;I3{PAd#9B8?mo4QH$O}oS=X3`0?;UxI5X;;I?PmWJE zl#6;4HMbYEk7(EWnXtnzWjS+);^S`eZ;11m(Fd|t}NKDcinKb z;M7X{GTPm->f5qOkC5{#s+iM2DeR8|Aj2X*kxm;=sTzLF9ITW$&SuNCnR6@G?S28w zdOD(4;sz>Q`p_(>9&|EzI#MG%92T!aY&A37L(kD?Y!s+Lek`JLDo#)B{)0$MW*i&a zRgIC9J&x;&o+>|LZ#d`0_b812fpW?i5nFb|TVy84ciOIXXiM5qIp1gfH%mIZ+%W~) zbX=s|?Z}523oU80!mzA@Gty_c&dMgRRQpLs2nyT_Lub*kQmY9OR2{5M94T?7M2udm zmXR!-M@?Efc>=$-6ySocC75P!8OevpJ5Ho^1kESsHKyWgnO_3A7 z&KX+3kX(8@jLRUMQ*N!!%EcboB$BXc8FN53N+KV5eJ`)KwW-y;%MqCp^h)A%Sft%W zagw3Zn-k9xEJz*iQt9f$K&yw4Ph6Im?aVj6n9YC&?8($&F)Qibuy^j?jYE&8jUSm` z&~_7^ufv`)+32BcWA9Bi=dGO_myb@Ppzv>hqBRE7u6!WARv#YuxSKJ_vc}U&xNFt- zxiB`iLF6@4(1%oic@HFbg*H|^w*1uN6Sq5xFqjOheP3}({<+I~9-J7G#yK|DQzyYf zr&4u|vWyz%P96Hz(Jba+oxO7+${QvfFCTnX@h#u?;TCl-EMDT+^O9DX<7ffH)yOPm zqG%%$Nf>Kp_M0fl?aReWQqF-CW{PFJFP~K}v>QQV>)lcI-~owaVq*QN6OhK@O5^8i z+b$28a4C3vB(u28JYKE}AYQqK(CI?$qGR*b%8}H4MhMm!W6Wyk*N(9xL%MvOsv(|{ z?XzUo?@@Y5lgHBF*3x9d>k&DW`rgEqd5Y9_ zSt+|FC=C%fXC!XsF;>|&z&;s`!ijiiSjhE!&S0B&9_vvUj({4Af=*eFRZ0=E&5R-38jk*^hU?md&#`X0t@T*RcxU+q?{2XP!CO}>UeJER3HAkkDH`jv>%^0Y6r|J#qVu4;(YF*Mv z6*Jr;0KVwnHi*5Uh~hfI3)4NA(brW_V|Y>I(NI>U+LK?pI)lRghJrz@U;cc8kSrh&Pfm zrx3uD;t5t(wXnl_5NcsBex*2e4})INV2B9SoCI zO(p!71JHPEifs0}`gMHQ9?RF3q_;6`aapqBX2@r(EvWy;KxJj_U-RP<*?Uv0;+mL! z7-lMo|BEq#U7sG#Am3(`wIexSn71QtPXP8EiQPcD19RTNs5Oo!i2H%;kGJwQV54nE zvx7~R3)IOdxdHK;x=68iCED9og~o$p(}>p?D#{--+6OMz3b}7*$)&wbtvOLmMJT*!r$q4N~8H= zL(~))0$Tdi*3d#Che24>Cb<1d{pPNxdkLk8v@FRB6;!-0NHxpD4J=g;3mQFKyR<%P zntgqqqFB^uG0-DI`srudrPO7P&x9!<(E0=C!mA7cTB!?YGn^$be=3wJazBWcDIWFv zRa$(5D->Vh48XOs5KrFR%--SOA;+SMH6~F9Kd529H61t>{lwTA z)b_yTCoJ&~bFaKnf8{j(*D^W6-GI}Z;Oe1H*GFF}3Jte-L*(#c%*ZD^3RdAs)$dO% zs4x0|QTC3}wY=N9@0`huZQHhO+s24(W5%{^YsOAyY}>Z&bH(&S&-ia;GIy}P=-S@=p@ff* zx`V#@t&8NQdFUc;K7kM1%9HvtK=2D4RsA{PiD51GOD-nQFO9xxAN^4Cxfh;?&*jzg zx;y4%912RV(kmw7BW)y-?)FLobl|$a-%OT&qeNdTT@-+chSx(XFqVc9d(OcW5U0Y@ z1z%qv@v~5a;hxA^HGS!d(klakFsE=vv8dGATJ^OOv)@Fq*i_Mo zgh}kHe&KQrqi*&X9lgyxP=L+^CUCsh5F$^~WRE&6K!p*`^1#X89RjluNJcTpMI(3& zJTj{eh^G#*y$I8u0}E^)d!6)XSC&)LV0KVmjp1Al3EW4u1I8`*FSWjzX#x}+1}rs+ zwC#S!fYAx_n-{3=3Z*L=tdi>Z8vfR;bgA{DTYQXyqL4c17K3!r)z*+XG!_8$oh6;) z1Ds+_UP%{NhJ0s!sa|=XVW5bm>wV#q@vAJxaM~_jk0T7iqUG4}bX}5D-ZwG&xC?=^ zjaRwU30b||h`(+*Um39929u?(!P$CF-sGZM=K}(_$EYfj1IrSh$=S$gV%V*?#n?j! zi-HwQIj1LjdCS}sM~eP_^#{97UzdUY{#1ZZ;wV4v`hpORpVnlN8BpF}*kolwz9vs` z!LHOqpQu%<%L&n9ZI(b~S7bFryYf@bWe4*_Q1aD2U_Ef?z=WHkdE31eg>Lx5P2=)! z#r%_X>sa6eKGewGJ~oUR1MpMo$P19kHZZ9+>LOD!^HF2s1q%nBzQQF70W{+l9Wfry zlpsSuclw7<)R^709-Fb$_*x1_x)_h%)c(6Np1(wBk8tr{Rnr5VYZ&B%kPy~xwgko79*cCBT8O1_-C4b zhi#4QjxunprIU334>=vvs=;M<1L$XLghWIIWqXYw>Y=@hRhT8;Hz#42He_^N&<)Q#SG$TAbqexnv25bnp`hbL z`k2>Ag7faTF3V_wr^8itp*zolN1z@~S)1`J)=+5osdXx>%$o?TzNTW^E#WP4rvmTxO3L@lPAQip{aZ#V7I~YMa01ECF1>3v zazi^#Qla-wWHmv?sx6Z83&L_m8G_MxUA&kX!mEqKQPT$u;Vybw`9Pua~K52ZuctG^r>#TSQ9&vtXyJ4PY*z5o-ftBUCpQU(yK_ zajedEBU3B=ZN@3sK}33;LGD@zc8dK$sN;Y8YpKWEY4zZ&C;b_xfAa0i3-7R0o*A$6 z@b!%0MpP|5z}bJ-ElC$EI;3@uA1xa&pE;IYwJuW(VAeT`P8dCK5QC|4SHfi=j%g== zo?$Fut6(U1@;Ei>%fIm$8r8jh(Yvs4KO5c&Wl5Zj*bR>9;?2tP@e!XbA%vvN^nnMI zun51|+)uAcEn))Q|8O`&Q73&v^gA*FnHIBz^KbCUMZ%LfKzbbsXUj+EgWtXgq%0td zp6faU=rLt`M{P6Ro9g1n^6(%3*Z~#}^!X$5#YF5y&{#wBdQmCAuaU7T1L0}Dpe>J`W1mwg)!T0yiQ2!aX0eJ#Cc z>OMgNOcW{O&JrrAEFxOycbK1k2zng7=%a`&Dh0Gh`OjM!!`~jXdyv(l`FubB{YDwn zUTfF-Zgj69{Ez!8{uikG$BptYD6MAcq^ySWdD(F}z8`#@p6GXN1vz45<~E<}=TH1w zMrJmhLjG?#8xz||kO65HSj{R}Vseu|P~+lsI7-8fpC&RXvX#4do?yjdlVnkgwf{?Elq=gZck^ScZ0$EPgs%glDSd*>hZH-31qg-(SBX>p`yL(-LZ zwauF`Fw5kfGMu=#eIYfYV||S8q4&5bZ$nO2j|IQZoUCpDzi?Adsti8@ndM$w_dI>1hj;~6>4>(LZh&D5(i0H4OlWK@>+{o$T~;TFl`tcNg?l9z zh9;a=B`v4t%rjacJma#^mO zy}tt%ZAxA^>+Bm_Co3mS&fT1|vcl9c($7{J7D|hy)L>HeQYF){j5A5QLN~JMnN|{u zcA^EM4q*_Kg$T1!x%4`misKciCbFcfTRuT4Q_Sra$N={$vu0$Khv%!RRL(gon9W9D zBc&L6CdF3nbkMJ}9}z684 zU}B%h%!`bNYhh54%Kt)V`5o0h?j)A2ghujLCQ&!7Dk|#(Bg6fo9E(vMdn9#+MaHD0 zcY7qi(z&COV0xrOBVKpaL~+GzP*&1x)uOnzzE3y3DR_9e6UT*sXtEN$mDn3I9P%V= zIfMOJLgU0L^VX?(FkyxTvltq|JS(lKz}b*VO^hujFB-4TgC54EZBtgH-kyo&y3{^D ze`gg*p*4P|kVY2GHTA^r5Gh2ldNr`}E<*vq{Us8ENqh;E^)qyJ3{h*A_mvW6lXeoO zzc#tOt=0&Jx(5i@HBZ39>hf=i)BEt>m>VQumec}+=Y=(dF4ie?3h0z&=n1_S}M@zX)ODgBHLwyQO}B=On+SYffjt zHoI&r0WjIXVd8jYoV+hh=bT&LUyPMKjSll|Hg+*dn9Lz9(9JgHD@95$qjg{OvU)!WjRmG7pr3&#UYCcVl4 zU3c08x5QFKHaGW$YVpA=$X`RzVjUD1#kpX63-hk!B{D8H3v?v~4&@OzWoQS+P=)zq zX&Tl7oOom$UqhO9CxA@*<_$SrDh0f6?<#(1{{+|&`o>I)F{1H2{>?Obl|>KwrGDH3 zsc{C2i3H<94kkw?Owv+K+ol;~9D_B5%tt%cU%k(FM7~+Qj6Rg5AG$T1Tx$nERA3PY z<=KMC0f)w z9#&I`)jWa}x{(ip4NojdB_su;BdPLqMW5E-q_KgU=7RVON8K?*2p)eM0b)UT8}Ga{ zYFb8^9aloVvfW7O?sVOwPC@mmc&X4QM|-3$R2T=0d{8F$O-rGOipJ~M6e%k`>Qc+e zq$rrj0b71td3O~yyr_2j_1LXgve7_&(LJ?<^T4J66*z6MqzgfeBks^MA`1rlvuD+G zJwK0wDKIuv1BM%H#V4p13{hfL1H(2Um5?0>m4jToU^XY{E|ff>>&L&o=pqCzJRImD z3SKK`>Tb)EWP?Dvbo*rXIHWUrC_FmR_>ogHbjosuao}zz`$W@|j*TgfCFnn0)#~!W z`mhF87$V`nM0n8C`p8S1vN$4j?T>uU6I1H2fxJ*tCPwobphQch&w6Ndyzzz&Wuwij z)3b&CKxJQc&7DV8IfLkML{`{yS#tlB``ZZzKj; z_d+1djXF|#{dA`7O&0vM@LTZPF4?R(2Qq_VatNv?xYAZ1=m%D6FSe$pL>F7@JYek!bpwvT^)SZLo?4@Tp=WHt}xslo|crE%ENUu_OoO!H1)W##vs&0-Znct zQ=CY}!N%To#>ZqwBgT7O>1lgkIzdf3(Gzuh1QJeFi`5P&yRR5O_I)LMxk{p5wtz8S zOmPcXrP~-SM{--p?(j8c5ATeuGE7;0O{N6RJo2}a`au-Co5uM2OQGg_pnWJ zW^qs{iE7Xp>NNGH)k3QTJt$ksHGQXj5$D?J36J^wP8vme2sP|IUAH{7bOIxto+i*G zp=0Q|Vs5rJQ57H96W)p8c36wwC```H6{!-h@F&{E&upv)>(4KG@7^zpe(9RvAJu|g z?SgoPevc$Ze+Hm`^-4XnJ??Zb*Yy7h!`O=4k%Z>u4lP4o#`gG(o&8=7K?DU!iWZaS z6Hl_P-fS%qe4rcpXqv=bY|SfUuPWi2I_l1R;se9|8U<+v6$@U<;h~5xVPM|iH=q!l z+XuB$Y#C_b)2YX64CIiZ1NjY*=Cj}M9Nz}K*}A!Q>-SR7b-%8;=O*2A+pn&6>d7(W z57U1c?KYnEsa2va$orboa}y(C;+ZV0B!GDhIsd+4N4an={3)H~7f{&~;`Rx5_kN_F z6Z2;i&p3#0u)rbnSLQz1HbwUNoEy09HiS=!O<#r^=n-$faIHUXVg^ zC)Fb65R4Spqr4-CP&YOK>)o_-ogUV2T z*TNOP-iEst3ri?PgWEMWJ)H1lvOW6Pdw}`NzzXE1Zjm2tj90LA!RC) zmox^U6|ig~nBK3E6}qn=4V4u>j4Y&*iO4-c2qY3Xn8w=1PB#ApC%S&JCXBEOY(2lg zj78;2G(R(OJ90EirEvB~x1)BJGBo~i=WmZj)A?*l6?H>wKinw}!HD|nh%k3* zn$vsb{$P7W8y1q;VrtKTBKE^`c+~E?%ewO1dh&9-t+A!k`S}Mzk7`<|bVwiKSFj*@ zFo7qSAbV(oKLQ86kUTxQAZP&rEFN5szfLcQ7;OFQJp>4!3O#BsqIt`&Jp$$JSZxmN zaI%|3tL$W`sl;s!?vm{ncvXG+(43JiqB?hiP_%<9DS~%wI;p4bSXm#63^hSFl$w#l z2gP^D?&Jw9$W3JVCL__d@t(-vtH$YV3u%j1TFoHeVme)Z`15<2N`5ho!CH(d%ZDaw zp;J23{!P@$RDFB$(#V9kI*oz~P`F!G+hT2b!>e_+V?nwgC}u)Rf)m^hXC`NMQwb>C z%b=0Mx?;5oIV15Nj4k8PkV13Q=gn9Ikv*QaB3g-?B!+8hn3JPVnhF%FT4UQnHECNI zO`Tj799>5;W0CGNM^i`A;*NUtAzdF4{x#YTqjWV94Sl>QYmGmVHhL+oDD`BSOfVEA zVQ^g&(Vl4#Kv1PkO(>eb9O7}up7g+>d8;48ddivKfsBoEt*N1ek6O{aF^?<(7Xnm) zx@-Xd5NX^@{tUAsaRR)Ohm&l;seOvgI!hsS6tU|grF zxMd-pJr*9aPQ(T-j0T}L@UdLI%e5>ntMZOIq{3{F;EzNpyPL?rVZC3TkMR`8gwox& zM(JYE?(eGH5wTU_2InhZtCoGk`$_)iRn-bYd1@*qoXEpZWgz5P zyxO~R8wthKPE~(p0$04iCT@B@^4l6r$2VbuBm8ux-vT9Jn1a1#7l^jJCC~*W<)$or z$}Wh!;+adf>=|1P#Vc=D>Ro7n?ck^CF!#>t${N2MVQ`bb=~RND^UM9XhO~OAYT~3-oys$taHUz+se;(D~tt2w{5B zaF_ksjD~kdS|!uR028BqbG1W8b(EbD;GER-?$xzsCh9SwU#S6(Gwppo3IlbLGTg~V zU)WqZdbW7qEF1iQY+8JTPO>an5`{xQNLPHQz6;X9kt1!bXSbZpdCkREcLBSrc+ARN zv0f2bZPl)HGIl>4O55ZIGMw#nc#yN`wS>!NytF5Vh0k;hi&x|P-No)6l{qjbM_ULH z+-_+iOWKE|Ml^?S4cC`Ww1(x%ljEfi_g~hY85ED}o94zHZf=+}vK?#noB&(I&tS*v zBX~2*(iiAaV*ky@B$lhZ^tqm-l)Q6}sijGTn$*=2vQi`xMa*0H6GUC1@qM=&T_#`s^S{ld=q((t7+?VOGyJH1Dmr&qqg#5oSFofPYNs2lw;S%8 z-7kp_{(0R%zm#is-9d#*4nH;R_okbmEvfgmnLb_QJ?w|;$VT)5qGbW6z3Cg^-Al31 zs}EK+lwanUM{H2+Qci5WUwnaqsrj9Pt>E7?I3V8dD-haZG$C8LR^g0y!^Thk=ah`U zeed+Up)F{EX%ul;WICgcsE{2=BffH}tJ2v1T66k(ldwe=?cs+=);CSEY~KA@J5 z%wm$(B9x$iGC=NIqeXkV`>-r3xwW@C5(#`F>|8TEG@Z;h%anX>SI(#O9u@oGEI>YL z_mx{Z9mGwQ`gh3A|<;#f3k2a#UKv1_G1Sa$%dP z_Dc2-oo@+9sgDrN5;q4Y6${fNa);EVN3^Wi!6A8-`Lt{@fUYASW2SdGYr0yfaD!!|$U2#^rlzt49_3x6%9R)RS=lgr4)fczj zpO>pw`L~>ena`jqN|nEKmqb;WMwDk! z0O9+yYi(|0@J*c^|9cy?x3m;w zFFkT*$-+G4GE^w7Hda5;^G~$hUZj4~`9x;F!f;c^ouAx^sk^;dS2reZed8UQF=W3{ zf}tY~_=jaLPoWy;L=gtD)GVnmkNWZv*$|SdXdid*1-{It2ga-~L<8TW_sO|~oMu2!OwV{js@@sA1UMVT7m($uq#1`GQ}0Li9?8K<2^6X}m7XjIwa~t1kXU0(Eaq$P!0v1-)PD(+ z!N-`Ips$gka9togzgWVjDccJL^@8!lmKYDQY(JC2pWeq{K0i3!RL1T5k3#fb$&~P< zc`6Ln_FMc>#hBwJUDBAml{tVk-vHB}bjrLj3Lk!}Plz9p7eGY(mZb_{GMZu;jy*(R zRO(drS+muEq|T{E&ZcYZtbYsy43sI%oqn&a-gj4p=Ks9DCXQ+bR+j(&Xw;c3k^u5& zakKSOk}CX7Z_xl@r+m}zd`0;@luFfS1>m1w>=(2x)0goZg4Y^ekVurGNO*rk5T~rL z($Rb4WhOH@9ILlDnBI=AzSsEh4?zK3D|nnahC-?Tm{e*K0&)ia;V*aUVI&Nu)RY_K zsb5dpgFujos3g=9Zawg`E?Ex+q`*{j#SbfX@$SL3k{cG~>+@D))5;gZ&e+w-mBj|P z$;MnDiaN~F1tPG6O1Nz&GQs>avrfTg1N6?}s&f}`9gFx9z60fVgQU$cwO5e9gfPM4 z=1VKzqmvsZ@}tFNYXhLJ*jdrDYD3bx>Wam;wL9olNx>?7`s(e>Yvp}vEr5BQBLC)K z@-Q5wi_P-Dd4gu=dJ*X=RaRFT(6R>23%dkeXD8$`gBtX3U2#wL4EwvstbLF)197)g zBsZ0_;p(%B;A5!JQP)~Qb&Tqw<%1<5n=Db^XjW$3aItBiJGsf2bi z0CZ`U&!ODd%@dJql(@0%I6hrRW{h3kXU4#%d)1ZsdnB|b#@%~;5rGZ=7+y>)d{m?W z;i-%qVrDfbPT_VEHQ-Q_I_qaf(`(ar>t9`Q!y)a$#!t`K2%zgkvIIhkL*9|oqx9jm z)fF}1(_qLx1TEgd(;l?--r@Y)bFds%LZb?Sb~fcv;)lpxc(L_c_JE2$s{XBU6;A^( zf;d;cUh3ZjsQvU%1UgZ6^yT$P*foH{pE$oOk9v}?Y`xMeKFGA9P@qib&S7aK5 z$$T`0(#|o|=}d+jd0f4RxG>SWgv1d%#t&wZHFA@kX-ep&&)5%U#rS@M5kt(T6OW1Y z(xVpBQg0iR-~PiEZ-W&9lKnei9tP!qOcne0NB@6)M^>qSH&?zrvM2W^*V9H|(Dn0) z!r&rfrGNi!6bLB7#7{?*hZgiJUmw>Vjx{39N(=1Qq@vkC zu(WJ%do9qZXiRFVsNh>&tu{`I_jy~-00WJGnL%;5ljW-pie>S^3U7fF7ZVh{q& zB?P{gL5d3wz-)?mXf|3V>9awC3)i&7MeO5Y^wL`Ark=r#+nIq!-DNdudZFw%z|#j zIkBRRvr&^jLymMITgtZ+1#oZZT9+WEIWa0^9am49T$~nHc4peng#|(S9X2_2B*_v* zWn9p|D43ci+;HA>*&%$OOJvy( zydtI1Ni>sT5NC}fdwM3!w`EFCo~VL5sO68PyQ#WdO(L6QkE?l;W{oC!y6m3h8&Rfd z720VGJULt}pf*!? z8A)PJII@jAcEC_bMuSPq4Z)kCMm{8~)yH*1&zBb0T9cWdpRYg74#c)lyi23F|{!MIZpOeEM`{8X>)v=2>PqthkxYANV5;CP_7AO45puYoxq5B;= zo$^OI&keec2D^U@Rkx=CRkx2IsGbxkKL~F-HVDr!EeOw`C&1v^0&n!8$W zY#P0j5M^GCk!LCe)cLQwP-SMHHby9_7aT*K$dS~ir(bO>3V$I@tJbDhdW^^Nf;H2jt>}{*gmj#fWq4yJPB&M`F}L^L ze!D-W(u*jbIQ-ch`WL;3ng1*@0qh5{68}zpqIc;|=6n7FnvbMhbRPC@B+nEZn&Trr zr2cg)KI?CPbrrnG<#XO=fU!4tfBCDyBLR8@4*wrKg0EmT_{)HB9O0eSpX%P%JSACr zz4oB~*eSCbJVM&x5-re5Grv!sfy)0xLNMn?qcX5zqXHmuNmhbquPwxi&z3wihxra3@3k(POb1|_7c>7@Fbxw_ZDCkA;Y($jsC#R8s$EyOC zc7<4aO?3!Bvth}Jmt=UtT@J#RvLE$<9YCzsS8lO1Fa)M%KC>ga%-`8SaeNv(E?1~g zMAf6iqZ7UH!8ul9U}X@60$5G5fkG@s?N}C-htfsU2j^c=9MPbeKmL^dHu2^_hTWsN z61I#ANEIbeJd43>pw&QPd9^>aIZrYzC52}p{7EzuGY3ncX&GKpO5tM>FoVyt5Zpjn zsIpV4S2*XIM~t~>Kq>+=lUR9z<7F{CchB;AfCYXJdx>1z&?N7bw5YkNmiNs0n~|rs zV*~&$7BJJxn|Mnw_D0|6YS)-MGwr+wYi9xH&3)Bc}jd#9j6vvi(qf7TsVOt zmTNeNx1UH&VJ1lSA9M!2KS7J^2fO5j95MXNzXrT$*x(q|01cfsLb|=UEuQR1=gCn& zY@2vZeHT8}7k*4`S33PVCh^E~+hrSFCVN5TXC`6wo{r{)`_#buO};G-*-E8L2qR3*!pulT``r&HjdOQW;hD zGm}UM5E`@cL5}9w6cDGbtO^i@{wg^2QV@ZzVR*-^^w|LMQ=jMi?Pxhssxcjt#?m8x zEl`Ol8ug3k?)#nUg1nRBv6pc$BC`;f-veHsM%x+$n4zC5rNLf{+}SbVmKi;q zY=nSX^30rtB75z@S&Qu11YA8AIT*(f@fJJyG&_LVHFaQ892`gSL^_I5i*VXxy)!Pd z3O&GHVh{wC+{3&wuUX^eKjYfpQ=1s_VI6=N9*E>08?zo-S``SH9kE%$b*nbtay_Va z$U?dW40|DYu2@Z7Gu^?PZ(DZ^<@7z{_zXP0R6*`MS#W;lPWIp}Sb62r{zY(R_$*An zHg#tC%x8SAXv6STYTjXShWo5`*}*GE`%&rZctN|-H^^PyU-yS$6QLJEovv~ML zVN)a~gqnEN9PCrXmyoKhE!V^z&KNyJ-`B5}h`CRLjhT-y8FIYup*xeaJsYFog#6CM zVITRav-<)*2Z}MtXMu3d@GiEal(VfVS@LV-lFf}BYqF}q5zRA2s5R#XH&w*B`D_sQ@YLl=D796_~_FUdV?t$t$i8n1jSXDSj8OS#iMVKlfQ=B zmjDC&3b6_flO4WTI`e{mDsatD(G+C(E(c{#$)d|${VT%v}mihxN zjc>~@Hu*bGSl|UyeR4NiKuT?LH`@;-(HstOx{uyba$bNf&<)>z4iK%HkNfs1&P^of z7863an{rs`xP}_PSSJv%B3)-r#;(eMGxB7PZ&UMm#Um75Ec3iap%xDvN!#axxG}-d zR>*JRpr`;H%W5doQNeakr;iAIbaIc3Ia^4V`k+JaXn>a9+7glY0&_yQzeF#>C^R#@ zSs;F7eyhOEGso|w=#0UGrVw3GEzBCr)a~y*)XHPTi%0cHKxuLwGBAKnyW^m}OCnMM zmvrhmtcVdc&pLRVxLS54>|JW;z7W$C)$xcRaxq5`Skw(J)gqXKzga-7N^DOf=!nB6 zUJ}-T0SSaK7}|CG^be$PwXFV5`z=zIZ;}27Wb_Y_GX6Ini%PJR`vwZZTPw-5G!e?z z;opgaMJi1}&k#a}2rv>9q^UkRHf&D%TmToz0=}_dHDRLNuLY5&O&R{hjTgo3^-M?H zM?6=P@2?*ZT)(ZYN*MeGpcU06iJ}gmRsUEJnF1yTIfcsS5INPFYJ0Y^#ZN*!e=e;q zL0hWGHR{l2KB-JXIieHu$Pthx( z%+_QzWBEL%vjL^2RZ+%(Ipad!;mVOli3dN}U$-(!q+dePaE6qh;fd3fCHak7P+Hw> zt2-jiCy?Y{C(X?4t19oQNZm_P!%`#AiCqVMfzTTf>B@{qt)u~*aXmhv45U-v+UF*e zHV^iNk=-S)Q`Sgl)NCCL-u02tz$(CaWQ-1ae;C0$Fk zwIWT>!_gnZ3sG(;jLRQ0r|1KvL!}pzxgAWwDZny?m?+gjXdoAn(ex%{w}+c+8zi%g z9%s{J>bMxf9<4_&>Cw_*f07tn-syWjyczhsaHO0(lNM_DPUOi>uJqGQYG%yP zP<8l=<==m(KL0x7>C{NgYaa=GK+wS4Iu+UBH1RVtGK;L{SP#{Z%a{KB5%KH*((?)) zoWX1g-)wJ+yt^jfzX8s$rFO%8IZUDbTL)j^J#wFf2C!I(ms;neOTg)!j}#%ft(#c? z`z_AYoI6)rKI>PMXLs1M`5wV-**)IBw|0}rt4V>sWoP>B^Yb6N>i?A8zgoP?I<|B4 z$UL&`ZWD^Cth_^NOU_z+`UZRUW{4S(>GQQAd6L|166!pRU;`t+_@D@ae<9L!+!Vks znPUhVN+JzBy`DZluX|p+zdwAdj%>O7?;sBt_7ev#J9*xvJ_bxQN;K&ZWk7q4a_YH= z;F&zr@`?EAAs{%Z3opk*5JZ9+n9l9WoTelDaiIM=4RHpH=7F^*N0MX?C%ADD`T6m8 zUI!W&L7$gi`L(eNCv<|EA-aN59^M-vW~gxb3$Z$@1G;L&NQM^i5J!S$al68Kx3Sxe zo`jg@IV8;oc7skNeY$BdU{I7HQ!>6xI^<^l@y=HBzc|s=5h2UDmol}Xc_zwkaq>f(JJ-bbO2MiM z!4rNI_L=n8P`0ghY{8206qs7Y*;N#%BKQqyPDCxicDjEMP5G_gR;(u{bo;lPenh5;R(G>suAg zL_rxG%jB31X0et#s<^1wOfA;EI7rFV>y37DxqQm)EGSTs%1;MeCrySI?J>^dts&Yf zaby{zz21I)B@opEjH*B`B;d*|mt*9Lalf@5Fu|&!PYr~YHeNm1!V5i}^l4&04GIfd z0Y?&9caIHvrkL5dT*;m^&<6%8Vx->H#jd~@&4Q%k&M{b3a@myV!>>&MGs`?^eoVqCFD3nRKGLyCtMvGX^<#^?%{MHSyF3Qh?M)VIh zZnInQd8~VvMx>i_^NQyq;r!_-;;kr%!mq&Ybsf!@A_taHs>fxftJg7~GIeI7W&q5w zd*9pF39pqw4Coa%{b~BixShn&HS|7rEF@BC!%-j-n)~f-R|h@N_RGV`u3L7M^RmTC z0RjrwJi|68BX!d+2|tXkAOYTdURKVamt&?Ab4VbxP(^gpOm>E17118nD5-NgByZth zK6w{T_(`_HrV>u^<~Vy^BBmD*Z`s-?A6oS_9HX`24?p*iH&9-Zd!|UWSYt2QHnc?L z0g(=)d>G_EBWz!gV{TCzmv+&J4qpqxE*Oq2$-|U;oC=fzY-W@)+Tzbg45L1Q$JCPO z?#z>niKzr{Q2#DLVH>*ah;IoJeZNDQ{%<7cWZ?AQNgPU+wus*%R6=!GvC(U20y!(t zMA2Nkm_u9kM`?ucx37h`36M1yuudNMGkt9O6f+@rIRuJi0+|O^tOg+NG!F06g zc}ahFx3q-!V=)$1$gd25K}BhzTzL|zuM-FZv&U&|13o|lqXcAYnTqNrCZxQr1H<6= zq)dzfG|FlEE5KyXWo#SUc#leSIU6m>m+Xq2VhqeSiI9VY!|>;NF?{5p;hsdnHFAJHUAG~9BD7?n?mln#IR4#E zV_?OSeaxq|Qmtk-7?-)X@}g=zWrO^ZEk#vMt>xDD2WRTy4%nt`y&_$;e#dRWDE~?{ zPP=n_Lub=Y_(K+HV2?%X{A1zwp(IE4+`3UJcfpseVM<+wElxU@6^BX;n-)wta%cn$ zjfxA`NLuxJ;%wa;Z#%tN6&TJu<1RhqJmyJe)ff)6If9$bR>36Br;(P$ljLU5&A8{=a6~N_pHmN(3$wx zVd#Cv3R;()gddgj5FebN`{lR_hu!#YKqALr9`|Y#m?f0sJL&5s0Y&7LmH7O8{8@Ub z9HPh9cqf#*y_|@OOmHwz$Z}C$g#!I*AD~6Z3cy3t(eTN_YQz|c{os;}#3Od%@dy&4 zDiVVYSN%ZNZT%!gQ34gnR)As3pjGr*Nee8%BEs@cj?&Bsl64g3mywN<|f(s*-kjKIydbKoRAmrS-yU zkmj1ER*FSMz6#XgTh802G^s(|^s9Gw{@teg(}v?^t0~{pLF=~zEIERViU3~JAtN1a zgqITw-Qx|0Hf@X)H1C|4jV?8u6i9ijR8h}ZN8;d^H*><&?G2>vNddL)K|xQ4Chih= zP$Os#4Ur0HO~RXp0EgH$+wg(5`#SlwyE*o@j6+%S5M}_2P{x5GRbcZod%qS4=hil- zMgwnDd27%1pK$Wef_3EN9cTJy;KMcp!NnnPYkr+DhSKYZJ=l)G0L zwP%@jm)ZAp;#^O#q*^ae$W4&#?Y-VF+#nU~67HN1ryl4CW>v9@1zLfF#S0VtktKsN<|?e*_~3~yIjxA8U2?WO9s$+7PB7fza8 zhW4k{;Nx(%P0G;K=pIhpY!+zquur$?wJsjWGi|^XD&Z5lS51unySKZ0PS4Yu85AGB z?IVOA7>v*G7@T88%xQ~^=wn1S?C=2?XfxKk5S(8eIp6M%m^bpy5H#;`!Nq$E{Y~Jw zr(!7&$#l&AZ9`1Xj_HBJ@b;0{JKz%!PiK&i;kkr&bz}{^edU7idqxL47xfJ#87~=z9WwST|*u%R5U<=wB~~m z9l)4B!!JVL6l6X>durz`k()<~2)mFtZ$;OW5udcUW;a1iDo3o|j=w(tgPPV}1JU`+ocnTHJjI2At`XLO7P zW^J5OEu_%E{S{oN!KT1JX*b??zj((d@`5qxRW{|3)+ZBvvDxD601_<8bQ%bi1F`{e zNl`tg8ZWW9fT~@j@4Q)HNd5HbZjnF2;FA6z$~k%nW)00L3RLT&Sg1inC_5(5iI2nr zX)ILT%_)CEJ*MGPDN3HwCI`j;fHvW?VfcsEw}<yB7@qjtkmBXkxFT9fjiesWs)XXG(LN7OPJ zldk;10n58zZQL1tarWpP*&w|)->QE*Kq)h3Fh#XMR0aqAn%q`HK(Q*L-9pr)!GgFi zKSy$mQpwig0lb{ z%25WR6hsMzy8!TE1PTIbWU5yn1V$E1f9D=`LOvMT-M2`7rwEi0QarxZkhA=1VFf6u z`hZWtFl5uLKT!Q!Nl#`>bqUTr;^@W-k|&}75~yC78TDL&6l1~!OiQ2Bc%VBGBNhp9 z8!2@Urg(;Z@9@#uh+%>s)U|te8`ohkEi~>IdkbHTL=+%7z2Z)*job^0qxteWS^JxI z1&8=WEzDOphUWF6N_@7Q6Czst=$>woz{+ zLEId4dW4W@4bjh8jqL1s)|3W#FyLGq83xG24ZpY9J-kTodFWgC;A56AIubMWaGk&G zlB>!bN5RR~k`5muQ#~q!>Q5GU8vH^+G=MaCEYvO5L}4kOkkoXrIEw#~@g+yR1_v0g zWA5yrg|~>^dFh!jILWDbdBUj6SM64(yP8{bE=4ksa@?u^(f((sZ`7@Eci}ZQ(4gmr zaZQ0{#)6+6u^cAPMjXGSA#2pGkXL?bMX^m#H5=DtM3PIWG>=t7+gz|Up@_dx*`qaq zRK`$qI%cwF=#kByIKN5mw2({Vc=8Hvqbr@Y(VKBtb62QxNEXz!$gU1ONkVQqfpmj^ zi~dB_V`+Oy`V*RdPMWtDk5Kmh;EB|i_%8T~`d7ji0W%+}3Ez&K%x8&q^ynVLC-g?` z2u`^4q`Vd7Ku-Sdi6aqVfo%qN{3c715XTJI4y*uqiUSeZ(=PlNWhiYeHLON)tk z?hzWKoy*gE61T2)N0pfdbcY@`)Kbfp2`D44)+$INj5AHjS1e?^59Q)sN-`{}HT7q? z?rq>u*V3Y38mE6+R!`3C0fVcObaOC9OJQgG&nG#9En*^+wuswG_* z9UA6C>TGqXNs1?zFO@GsSOYVtO5DYp`$U%#pmVlgr5c@BrynZS4rPeg z4+edj5E=Kqv7gpvXbt>=06Z zuUnb+{M5&4ax9(8mfXv;;EWq=;J}(G;q8b>1}c(J+~t5&%0x~xvPaZuO+b@40^J*Y z@ibq(!^-MtR8mC>&=$DJ*eMnOKLZ4_qRR0`WJml+;Bz~0j5H^ns!3?uXK`j+0FZ?%9ihMF%!UZbtj1Y`}gtd71;jR!k3>9S+w1WDlX z;dL+vOO_3ZQlxPd*aQqKdB`$pCaQi^a_mo|FUjlWOebk|J1xfKfo5RHuLOXhCZsry zI@{YbX{}6zm_+4A-vM>&EGo~AZ_j)P3&TJIQYUuEPPrv-Q7S2usW{^>^zhz(*C$Eu zG~*9ZEa7HS*)KZBZRgVKj#^Stt@T22=%}SJ!n?0NzFJyDx+#Gs=w?*jGV_iTzMZ6! zLts||X%|4;Yy0*xYmvD%*K2F4lBfQ};VGEYLk+~*;qSY>_2i5Qf2Z0o`HFt?geR4@ zk@wD>30J#OQ-Jt?7<;E6(V{5JHf`IsZQHhO-?VMpwr$(Cjhi-Z;$_FHj`ym%DxyEn z|2`|`UNQF=tzR6l$XCnAUF^H*=i>1CXyvwZ5n>o2YhSzD`|jxziKFqOr>K#G@-_l+~Z6Y6A`$v(JH?pS+dm z9XTN=Ih!9?$?0$PE&IaE@DnZU-fzWXS88u`+>HTg9z%o}dUIS+;fJ#YtoUL7djl`zb>>b84Mt=^a7wqLf2HN& zbj-U-&r!ZZ@X(s*3X?;kC`<7Mr>tpwBV-y7^rSZ37OBnla;37naOXV3>tQ!Ef=hUkW|D3KAThRufMQ>BJ&)WF@A5~hlZY5+Em!5i=7A21Hpd#7S5 zNK$l`4Wyr!c2E}CEBjZUDQSG}J2OME&kLZ-X@S3+*y6Y*3(vkGC=vhkp#&E9GBQM0?cTR`}wHmr3 zQwsaBhQ=o{6jjZL{Z!{eFpzGl_NsvO!T~ZB7b@~lpUuEAN|b59kmn09(-^u5sHx?g zh{c3)2Y+;R2fzcl5)~Y#hNYaqB^RK@OW=0H9I)Lnkkr6hD85e}w+P}HO%@W`vUC#p;OG}ssjVC%zyZ+g(hQ*Klx;>dajoG%q z(LNds%!2rw`O1c+q_8gbUNReK)YlXPrDdTV`;RSi!&J_YyF}HH1h@5SQ(S-o2*@ai zbROidC1*z2uGmu7{^>Jxn=)Y(LT9)y@GXC|!~>Pci`Vcx|KMM}BFZQ7Ou;&3%r8(Q zKj29ZeXW&)$Ni|JrAyeAcAP<2f z@y&t7108u{CeG%E#c{{z(t5$UI4KOX^CB*c9d@- z$8fqz(-)md`~>at;`0eg*78b4n45F0!oFME!t#Y!s-bzr?L0<6BMi0dIFba4D3@aP zq1z5UjqH~A(rxiU#m1auPifTcn%W@}HDFF~01Lr4B5nvtoFHl50)m<|UKiyk-sUKo z?&w7`wxAh2d~uft1n;Qu1tgvv{U5lm%&|plp4i>fq;q_p09~F0a3?(Y10uYc5uP0K zd!*b+RGyf$dzsopC0hxv_*Nqg{pisU@;X@FR17apxP~aO_4(!Dtu{+!UhpKQVW~qf z@Np&%^tu(ZQi_KA4aL~1P^=uEzSeVa72lo2j7q3g0; z8SNSst{u&6(6k)Kc(c?_l8Okc{9`4?F5qCSrsX?qSC(9=c(^gm5aY!3+%PRJJ9h!|s4ZuNX#i#Di6PTuKtU5n&T!fS9=@c~KcqFG z6te;4K;4Od-CIsxEOT&T*EB>F1;T)rft&K?*z--m-=J5DEsbX9Fi+ zjJB360lyM`ORUqPkQ?@mY7kcEmASmV$|HPpBwCe}G}HS4OP_D*amgpgeUh1AK5W4o zAp^gtweaVR{aK&5gM9+;(F7&IdOjdMxQp#1aw!^gCe|!%A))WER6(GY5A!C|@>GM-?N?dS?uhNY1c`&2F?SxqGM2&5nQ#@{(>`rHSMd!nTIg0jczX-wWIO)G7> z8hv5=_zA5o6uC$;iBGB~L|ubjO*?J|A0<8M7Fa&@8gi5To*JGn`Mx`T#GJd1#%?bw zFF1S?^DrTWVVmzeKO<`#Y%UjXX&O^D29xgoKKZcd!vv0@0|#<8*W)wGxw=e|vnQ2l zXshrb_pfm;eY%bB2>D6KAf%;9YAA7qZk@}t^V(F2(5z*h$ZFh>*t+O#Ir)J4;tvi0 z8BX0wYgjdehOl-P_Y-ZSVOzRs-dRH?^=H*GV7iW8?tJ~-H zpuIhT^+sQN-02RwJ<#>0*B{#hAN6tn!+(1O{%+_Sjz9KHzC9V%5%V+t@12*gKktFq zI~txU2wz?JO)_O@uJYbnLUtcrg|V-k?4G{m&$ZZmH(W_)@(~}$j?6WS9$$2WEANZD z5ltG{LLRB#osLSiAE3z{*wq7UvKpSL0@`F%4@99udV3U*=LS@)|FC9CXl~;sm%w4Q z+(RV~$UgSLE~NR&E!@%0PNxq;oRIfWlQ@pBnD{xj6gI4<_E!>`uZ&glnswK${=FA? zNRFzts=prBD1Wmvzma7@j^nouM%@oJLJ!&A^1WF?>&+myK^AUbN;ui|I?jX+v33QF zXt_%62ok+*Rw!Zk1b(q-O|yF^VF$yMMG>~ z4y9X`lV!!+ZPSBcCjZQ-U7&y~9}DznX)#}4TMU)I4HT1>Wsb68Op4lAyNsO@@^#sX z1<0(`1;(ajV3q}j%$*xcpneI_H}4@Gm9cNm>0=(E*IsecJMHGMy)tiK(AAsU2a=zF z`U7HT>W^UC-PrPMULn>SIq#hK1?Wxw(EI^@O3<#NohQ5%e<9CiG8Q8BmLhvprtI=A zxPtZ`1nb<`@~|L={K`ZaofU8q6^e7OHvV@ z;FhWtV@eBFedhc%f-sJeyYtg1H^k{dWAIg+US(O@T)9^&ngIyvL;L8&7V(n>IIM}I zRf;T%F{Kk$Ff%H~mWaEwsvTNSS&aPP8b2a6*7NS4ZZIpgVPr$(+|BZt68TO#L@9#5 zn@}~2k^0bYGY|6o*OpC?kNyWat?=}biQS65k)9xtkO!QqIo$Sxhdp> zkVF2%i1B&N8{YG~CLON9x#V)%i?K<|OA<#6-&Vyrb5Yxqy%nu2( zaD{ofD)D`{t8n_Ozm^A@YKsY~$TTEsbTWDvbzcO11u3(lm@Vk^tg17@&^s#0C>Ana zTLvo8Vy;K`S>Tq$<0R=tGqftO-?P-RuVwhf0+yltMJa44a1Jta(~~H>r|9OUWE>Ch z_4t(|G~imN9P>#SyXBhGPw*(;u4aRL_!o)mcqK^Z9$XzOmMrQya#1Tfl?sm*J(==Z z%Ro>SAt=hGPo^#5b_&wxt}bM}(ea<*zxKGlG@e>D`Dx2iB1x*@WK|cmEupa$E!m~3 z_YN%qIKLfwKZ_a0Q!S*pZqRnQ!zMBWjR52jS3 zU8>0XasOm1Gj0{O-t4yf>RcVLPk9RIgtWRvx@P``M>AqYg(~PAPcbM~9Q#NZCtWod zp94Q(?1>a1fWIsX?21J-Q=1kl=H(ZqPh=_fc&uN5O3Asmo*!QV}-v}T^U%4N=C%nj7+yd z^7J=|y9ro{wQ)91z*R~GNav*E8W5l!qO1grS{g*MKg{h9fWarwNd`J+Jc(3G6M$1aI!6l`>a*`Zi~DEWvkEHz6{ewAGyb^Ud_h-_KN)K<+QDu?Wg@x~qWvjeA@L^Xf+LT_a>^diNVc!Aj z=KZT@drxhEx+e6g7MCTPc4-VMTBa25J0WZcd}m<$PflaQ%Jv_f$qNx)>7QI2+Q{oD z2YdO+!9)}qtfA}gN)ayYkVHYPwKpS?ChY=%>X3ilObxYuyK?J@#B|? zQ*aGECn1&KT{-PzXXa%o?JjgDa~I0vYN*=gf0p*XiZn<Z;+G~)XAR{Eh!8M4?Bk$&c!)@D_<0SuvzmV zQZQyRJdETG-)#t<%P~}qsdWul4TP`eKug5B|2jyyzpiHtC2Z7nF;WxekXZ&S-sOp=ycm|uy zXRlD`3HdEOWY&B`Rr!UfRlSx=^~eK01BR?1b}IQu?5W@{ye^M9<7WnguP9oH$2dv& zi1i7jd(8|yk=^*YP<-?s%x`urB)S!{a2esZ0}6faR6V_;>KDJ*3qdO*= zw=K)iiT1c~4u^U-nVyoM>Wn=}qEePqpo1sCTu4=Wfhpzh zDRC{3HOa1u$pktUNYjA$g!z2ccTsRP3x-xk%DhxdP0DGzT4%X|JGT!l-F2bQlfLbf zi(+73jw?BQ6jtrW>oNoARgy8;vVs&aZkb}MF5^8fu2eOIbhq?(AuImHRup@lNx=|h0Cq|97`n3`s}0NXTh2GrG2DQH=gvFe|a)! z#k=j*@4vj{B_Z*KCHt+DDE>ZN`yVPLl6JrDJ2O)!Q#<2dhUWjN!b?%x`-80dD}id9 zSainDN3fBUsxZPxxqagk`>?-0L;L!59kk-#m za86#hpTW%gg8!s;7Wll8#iE9l$&j&|<9*Hj(|h~besTNr`2_7B^hOX&7k$Bj7YI+j zd50r6d6KNshg+EZ+r}I}X^wT~7UCdY$v_x&RHH+FxXO;TfzW0kV^1RNj;cVImF{|M zC%BcrY%f1b6eu&^;V?&4jy3O4r(JV;NEIOQnfaWTne}p|^q6*;32D}S4h7w8bX{QV z@knzE)!N}qoJ~7RELC=xawXJk*W|}*;r*D?+P#CwaZZ&EaX|#fXRlV9IgZZg%hmC^ zO}17uyC8BOcD1n=A;9zl>ssEW1hlQzG3cJL+-hKY{KK5eZ8@7Zd56EE?NvCWL7{xzaf{va#)cJgj!t| zEYyPql=V<*jyiP{C?LK{jE}|25OTHBzoLqcZfUS%f^)*Q+6WN?Rc{G`bh&t%N#5BN`7EAz7 zmvKHO2h6j6N&v?T7Um#6;FmsPU?gU6mh}6-#svm^Ng$;HN^k0c>}S)@ZTUv>J-IYr^w( zbl3A!kSbM{iJjAFdT2EG)@;&hGkXr|t}HG3@?(Y3mP?UeOxI+5Y!wg5yC&DIb))FH z+PRA&toNBU>Z|4*mul`hswkUDKgQUzP)CYC?j4v&jN#Xu)nNZCDOnH~=Yj6W<$a#4 z3m#CuInr(ptOTdD7PX`EuYGD@4!)ikQ9D3lJIvk_^xJD5Dd-j9O>cv5t_2xuO&DSy z_B$3w4CHr4W$w6GUkyb0Cz_xX6#K%=YmMjHi~I}ME6%eZ!n)KHWI&9n6}W|@Dda_5 za&jUT{!ksqg#p6}iB)vo=OD}`C{U)dDZDAgWRsflhr%AohoUY?qj+zS_dsDn&n^N> zyU7d#_UcU#}a_(MSIN_&4847|8wfsnIfg}gBJ`Z<KU~B zlynSm(RM%rZY9uiERu8#63YN6Bw2NmM_{P=O(1tfE0sxvC%8|z8SEYo%oPiDL?7OF zA+w)e`Fh^>pW9C6JD5?IzeQ4F7ytm8|Gvp5WBEIF4Q=EdR2|Hn3{8H)#s4AQt5Mrg z##Tl7q19|`v>{!Tni2=3u89W-SXB$rvPHD9k)SG8srYKQNi{KS%DS-wqP4QVeml;B zhm+^>xd@WSwTSgaqwZh~zxVJedI!qcl_Vx438x*=+JEhc z%IT-4lzg7QijcQUQ^-7tHvZ9NVa@&)l%9PbY z%B+mo0i7MDInRAXKtc8@ZeC%aSX=f#IA}4KwPwu38GXrf>oheR+lS3|e{V1WEA;%x z==;m;#r!$MjDa!_J1a<`Iyh(K8aRVkW*ntWM`4;=zV#F%v-f($i^fM6LViPxi}`C^r%R-OM%iKV5M9(pVbAnP?yj23hK0+~#Q_VLB{GrqcE+7CG7VwG@rD8Co z96u@r%F424AmM=0K|w)jC^o>>{! z$z0ezeo4H#x!$Uxz;4$qq3g2hpGu)b_Vn!G_-8%fmRdHg!c?@&F0ykw=yzqR>N!O7 z3?|-J<1rAa*coxe`PbPhRcfOc)6!oB=)=?a8^WHDdwSyKnm~IeT3IpGd6Ng!O{mSI zk=q)B>`|n~a(DjGgBCYSe=bmh#W)Kl_7B+JkNv?zUW0~e`H|Qd&5~org=bDvL*p*T z(bV;$&l3bkyy!_c7>i>{En05T8v_H-8~n!zoHc zNA)oV8SY^Y+;Gb5Jrk<^zaaR;!-A8L zezX{)<^o}V{)=l4m4zKn{ug1LiUt5c^?x}u|Dz?U?%|Gdg6nJE)RmM2gHXF47ytn1 z1b`i@)K##IFaU-olmr1=QZjUd0LI3BISm$A^W0y_YZIl!xeSCiqULGf0z3*_DH_%C zYJ1!D!uS19VY_E<1|jL%v{4r4$KsKjar^Jot+(%T3;M_R&=NrUP9D^^Tl}{NjJG!B zp69+tfX7Z1zF&%<&Q84^rft%#9}uXGx*fV@>MbyU;jJ(bc4r9Mx7S1H~6m6nKyxc+{>x3Viq`*x(^CN{*V{ zKg7gG8tkVvfWt#{R2+!qEf)S(ZSbjs$rq=5cwfHmD>!P5w4ACU)s~r*X?xiUveDY& z;%OEZe9_RpfxDmtImLpMAYvb^Pjr2w&b%P8*larLk|o1z4Yjmtm%MM!hTIwK$VgmL zcYCp0s*StZN+M4-Jl&qUU9K6r?iEJ(kEjVmpNP)Tjt`cRxJX;8k<~}Gb7~Q(Q?x2@ zDkeEWQ!pe07t9tK+qEg9k(st)+H8kOyQYQmkGz$SJQHOB+nC*yjQAl7%VMb;CR<5c z*|WRxwHYMo{V^Nl;{(%rhD1}&eYK{giOuFg+eF6L%_r8mY3O0qqoVms>9YhlKDEn? zlQ+&%?!sZ$s--13EoL0^fknYe(qWTWKJGG7R}4o$HNK)>SV_rMaVq1qN|Lb5K$>ZF zkF6(H#Yl|G8X0lZP=K7YDarH%_R(|cN)0LIMQU=6lfy$9ZH{1)7KTUz3O+{YL_^M| z9qnQgV`2i?)Z)wNIS(sU>xS`&iy*1t>N%B&4kW04=n&Ivb2J@s3F+2!Gc^ghJvh$` z2*`}{_Qc3!g0XQaXhF#qujGdwBa3Lop7avwd$$&!5F^K5b(TiQdL2^})29gz+JbE- zgf(^&R^pQn2U|n~^b`%aNm^pE8g$(KaDDceI=6YBo~RMyU+Qnkirut2Hc$pjO1e0grR7pi$bs>)2l&9p-l4odDD|+{@sLGr3uYWGK1^#-NZh&((db&Uf8Xe+gS(L&W9SyS=WRnXTf*PVI`jkGuF3dSr7 z78+^0vqjw-a5MFmA9=k8M&%!#V)89M9D9ohuKaxOQEG~Ln=HoMD>*E4*BqG(R(uZ+ zGf9Zft9k?Vomj+~*b2}qK2(2e@xNp52*8utp)spAuo$)xG@#9x^M)()^JiRMyfu{Ot?cw8dsB=$1&<2B~P;+r>oZ7INlLj2>V_OC_N zYMU<0n#DuzZJH16t!J?zHl|;)3;QCj!n~T7No*{nbC=88axK+RM$}QBzc98pUZJko5vJdX8X>sX#>vTh_)lO)v z9At@5AcbzJS*-^rsNB+Mf-$hYN+$+Q=?G1h$f$Hue8yUB)V&7Z=XAzdkI@Kkog6Fe zV9mTJG==3Pf@BcA1@a>fatIxv3lr!_DEgnG%PhCs$F1pSppq$rjl)vYQuQdB&Kk1Y zZ7e-IP)nR4@jTz6W7JI;2;1CTp%Ve%RBE4TcO z)eT6BP==H4*AWFS9kbLF)355sjl4*6S<8#VlRV;eW~ zR-8fFlS21K&T$ER-Hjn2am2A+kHmQVweJXCjtIBI!rq?| z!3$}f`6jw`*nvmh#jpm$^C zLJP9DvoOv1cLk+VRBE?rlc^7RaeIH}!}FuvCf(DbYnXOvg^hs#>bMRL?D6S&xF?F@ z&GR7SSrjPy^YCBt#9UY~UijlIztWd5;X;8mr(JrV4fRy`0xG`BF`e*UUJKZ$UX5MN zHP8mmg>{>kVhRpo%6seG%nU} zj&JxL+PE@$;JFPH{1Dc-{lUvQV{$-vBz&fLJ+LXg(vVwgnkgpcL%;&}bBo=H0vYgn z*XH*Ff9O>l6!oBzh;}NYJa8los%K<0*Mve zuzEj@RMPy7*0IL31>?rLL&^ZlMpowPPymzVPEzWZORyM39AO>Rx_C)YukPbj<}V2@ zjCF#WFEQBbJ^p2vNA{WDv-6R)Xn0o1Sw1{sAA%*6^gS&wpk zI5kb|!H|Kz+Z_OcA|>6hX;rgIr2%M3+uXh|NHAY$6oS^Z>C@D;Gkd{#?dR0|^xBgV zjDRFDCwb%jx@)h0%l*2CTn4Zm?q{`r6*h>bdGlaQcC%XF0<-l=F(Cf69vhePczV=$ zHGc=m5428{m4kJ2f0Wd|7KdKVNcd4r0}nYegvEC@hQWi> ze-`4+jfWaO7WdAG*Y&v`GY0$?xE(Ww?E70#=Uu1X^6}+~_-gzrq|r~jRtECX%m;47 zNxoJW*;WVTB5BNhIl??(2b+U>%HHOq@5EibV+~n^Te59Sf?8uCzl!xF&T+P(*37%A zoHL33a38g}zcEK{Vl^dSHAf+uxr~kx^I2_CdWOasJGX0PqC=cKQq$gaXo{_1uqMdn z3<|ekVp1!VY@f>&=kpz#Hc_^t=~-1v=R%Ne%3)Bdf*E7dQZC(3klHfgzC0?eQrHl8 zO*(myshy!)V?^rK)A2EtE`wDyx)R34g9+tf+CwqVUcb)trP8ll7aP{Qt5)k}FV z?9Oc^rpq%fp>@k09Im?Pj{MtxjaJ0`pmea4!wUs+RGXl&XXNbZMb;NumqcZ$?JVW; z96v*6)qL{F%Np#y`jJF;`s@NoBj0yWnKGjHu4N-wYq9bgYnV#90ztE%P!K)His$8aS zE~i@9f%Dj-x0KeSnQW)$B9bOd{s^j%Qk?>7i4*Fc%vf=BH1;D5?t+~OnhWW)+*;#O zTcX>fvqX)Z`5Tg$r)Zb4eJAOq#zpI?US@(d?$Wl+=uB{q+)H_f|1N|n9cQ8HA;Rbg zTJF(D)$IkEbQkYm$i{N@1!G_MhQVmxRT#BCJ@3<*Rfpg&*&)SNW>`+xv2y9{SuV&w z4WyVFtPX{92$V3}@zlcNFt?}8@(h` zQ%5AD{mY-f663tMde-ormBh~b$8v?zSVo|Pqi`Zx189$BY3XwaQ=(8 zruD+UN+;-hS=EZtlNVj=y{>8Ca(*v)vhC@ z0j|SueBHS!~*66kdZ+2|5O;=4jebbS^lGqiql9*+uF6O-~G95l%&lB`a zw;!AKh zUg|i z_wg%C>?ScPrTW(>59V0n>AOb(>DI0kI$of!&xHy094k$lhG)=ktplok5*#KyL1IiB z>|{}3UdkSr+|F_TxSEdD1dF`H&H3I(_3hmI4!AQ#raoeJgmOT+WXfi)D()^;8VJks zgZsx?10p`5GA876j8rDWiB%|-W6Sp#x)%xDH2Cy(kKu1p-qno5WQvdB~Pw9>{(Ls05Err4NJ4@7eyw(Jf zFEo)gyl{RS*Txb%B7DBQ>>U>0u_DO9>2W!2QLZ(yv&v$5hK=yaEBb;8_XzOdZw_VfkVp|+W-Yis_KC} zdM$i^VBuI?%;ABvhH{U|+}psSl{plQLxwj-5~4dF37@~dmM_|@3o*5G%*<3GoCqU*rj=j2*PFuel7xqq)y4u_Ag= zf9X`t7sP$($<8Um?QhyxWeMY1))G@-!GJYcV8?FeN#1NHX3T-b7nHETFu}9gLs6Hs z!{R8RlGfx2|L+4A&}DznX(2ZF)(S=hm~(qR|IZ&|;rTU$$Y7!m-)$6F5sKp-*aHa; zq;2q;8vv=o?@_1&bVzY(C-*tJbEHRz5tb{6gv*Vn3@;$&_SOc8O-yEJ#A;#GRb!~d z=$4qvg_-Q#X{YVM^SzPry_v0=b$?rjhNOAkcKFvrz*_htU*Avu@F4ea{kOP%2)vV} z2S&c<+sRv|uBj#O^u3q9#&=ek;YM1FoYH-q9n zx%$7*m5v?FPZ;xYL4taD3F@taO(y>33XX(^k)`wsSlqW5w>XCAj+ww}d`wB+^=^$K zc#>9huS&j((0PVKbEq>s;@%fu68qK_7)ha+Ejk7&gn$n$FhmAiFp4HJKjRTg3Y>KF z*s1*I_n(tltQOrY=&#qp^4IzHKP}Au|HX$K|bBn|#=mJYFAd$>FlZ zYcx?Gpd}o3-CUQ{M&%b;CgT7c)Y6*DlF$;38>XW@QOqsq)<2N-Zw~>GtS}{5N@fyf z9wP4r#D`*Ln7#w=XBYyR?C7dWv6-rvN$YaE{r(lded?)yT>JTXAou%dKoJBoGtGV^ z!1ag70BB+ujk6N`KGS>vd{acA9}!D-(3_?kPlwKjG#{SoW^gC!-}v|Gt~9F5w0k?Y z1Zab5VdyOYgO4JHk2DlEawh|TKOjC57WaPd$j?VO&qo;=^}8R-Mmt7%YsgyKf z^(@KJh&BR?lBkJYSWW7@0~w=66zF1A$Va!q1kqvxzn5_Rp(DAz&!o|X+bP^*6AmkB z+nLOzGkH9XN(IdkQJ+TdSd=Vp0e?|gys4IQ-$PV|dNl+y)t-5PT;lvuUSK}aKVc0y zqc-pg1OIAbNzkfmMS^yVeu3E-zIdjq>2lVxpE~DM$QAWC8!%_ih+8OpuA7AbmL`u zp0-A!;gfg7B*F+3sxqy?UMPa0`6r{N%p8=G*b*73CvDlCaQtZ1SuESAwKeS1JSp__ z$z|cJC)e$`r;ww<)lwRaT3nyg$4&hCekrKHLN*&%xREaZg84Yn3iQ3Yza7$+pYZ78 zPCfRe^Umwm`JN3yFBrKkv;^B;8hAtMt{0npfD8ZUiB<@1&)<*gljxX~g@y>><{u~) zX*b9Z5sI&Mrk2nn5!(Wh!szKGSy7uK3~|3>-}~tpU?Zj&H(vjadpr-kAp)@tmpH@h zJpip24Vw-=(DViaT%t8MCVxLK-3=g$xoI$UkRKm8Gk_5By{>&F`o zj2m5n&tT8ok{@);!E7(n?s3PazStO`eOTL^@~G|??k*D-{lH}}m08wM&Y>W+U0XT) zytY87za|U8*bng;1$CU-H}KzK52-9;u$iRoq-LK;uUxhgoMs9RATV6OpjH6M; zu;i&{AtQYPgFzD6HvQjctq?6txBs|+F5=6Qj5IbRkXWQQy!Hu|940T_6v!#wvC|*5 zYrX-u?Q8cNTGJujLfv=*atC$s&>OxccRil1BhwQ*8v*hfb*yRY=00e2P2bK*EDl~m ztFCEXAF__V%dbcBGiUk@$bF_Pe~*fI#sK}?gu5|jrc83#Cbbpb^uVSyKj+r^HD&4? zzGl#p+lupAFt)SlUF(oV#yM%Hn(pwoKgc_Mq#>*H?G)>r!YVrY&YLk=b-ese_uiSz zo7JEH0`TLNWJM4Dg%9=ow#DfF`!$d3uU}cg(8Ax6bken|nv z_l8Yf9ZJTaJRFJ(fh(V&H$NYe4oT90arSP&KJ5l9()xCB3)U}|zaKsw0E_<(_)~H8 zPnQvd%n}>#Suf8SC;jWw_s7=}xxZ;QMZW((t>l(;reC?DzaS3-V~{2?8x`3pgT29k z|B%A@otb7!@V`hy E&p&&7ep3tSY^l-ZVBM`mkghTo!g>L5U)a-DYyrkh4>mujlYC{5B8jiNWeA*YikNd3iDVksgPB?rfk)A7Hcl9P@^$rJ(Z+@-5nT}eukB%87rnIkEYsoun}3ou%|$j(*i z&MPKSqCPJG7vCbv!soajp$ssgh*&*>V4RD@t|uVVx!i)Ix%`5w-=W*;T66g#O!5}{ z07WF?mN9qjvDgAUi`~(?Ss2n9>W7>R2KYg^N0V;H@`m0W{bys|YUmkvjN60mgAW1o zo9Y!#kyXRVgwLFKrg2o_j#MSLH>hD?p1N%Q#aQ>U~{2y>YHS6EXBZjZspAEAvf%amg z{#5AzJ&FSVaN2x@a@b;8g&TLnESl?766{9Fj)-!9H&IbUadYR-LGUjEW+ef0j6RO( zbM<%7Z|JZBKJ%pHR>@71#3u4vkG->=KJy>Xhb>?LY=@<=kag-bAE%8vqHteSa0i7E zLL4;*5mEYBsYyoEvHQs1m(H2RJ#;_03I)ajq5z7ZjHtdCiB64RK^Tcq6$To3c}j@l zLV`*GB?P4TAxVTlJu3ap(7;$+@e@UzEgBgMW__%2OaNCNwsgj0@H`6gH(o z3e~0|uGzt4xs8iS&BOflBS)j#6BvySigSwZKF90%3d0&PneqOvUKjWh3yayCjW=Vj zLRM!&*=~83k6|&sNC9)z4EsxN6%V5^Tbi{(ieOVCSInOyowDL0Ik+V%8^{G~^lS|K zC-CLN4@+jCHxzn)#^y{4ndYjput}HaTjZasU(^nArUHNw@377UKUaXtMl3LZJcw2e9EOHzLiyDY-lyk!z zL?;l0Qd?u2qVTfn&!Zut-K|eAy&#n+)k5J0;L>EYt910#CnN{wN?~3gnMtjHrsIW0 z2;5XJA$&u!A`ynE96W^yTpwF;q*191Z&EU8mp-~=(S(0TZppyCU}O+dm+nW0HgS|0Ql?sJ1e&uh7w8Q+ zWfwugo;eB*U_W>$=G$c=yq4I&+8-u{w%xJGF5SV=E%CvsJE#tIxyujzYcJmihQ&W5 zhQ&WZei1RHU6?1M{ZJWV^%k>d_5M|-_4d02h@KFa9Y}kZ?1zTdIi{d0Wzd-|OUmiU z!-al;g~nKf;;QON4-snKqfLon?$PE{{D5FlQK|=+GPB7r$~(3=*~rti8-0-$4d}_3 zTUJ*o!U62%CtOI2<}9f1t*i7NRHI0{-m{Fs5oM{b6e$j!mg|oh_LU7T=nhc8oJH^0 zuWxYp*k;eJPb>)*tq0H7W{Wu;jz3_PHF;()5zJ#`Xz}98j^%o8lJQt;uiG_JzTTMO>!?bC+ezo?zhO8v}b327U$Ta6J_KbRz*(JBO+@um{avW zP<6*pA0}o3JHO@Ijw|IIUwdEJE_AzYoqDV`M+q?nfu=@q951H2H~!YtUW0!9?<0wibBZ8Up(hi?nlseNl?=jHOPbC_tT*F}Hc75849y-voO?;F*bPoKX#7D)9O zAmAliPo}{exk>$Zy{5sB^0Lrz4yX6JSSge=VnoL+A1ueYEvjy3N5&(aaVO|G+<@5= z<5ll!Q1I&X@{14W)HB%rN&LOiH~N9xfG|=z{5})+w8b57%@L6Q4(vN*8N56A=lI)R zXOzF&%k<6O2o6zqcn=^1BV?!Ieh2uQjVX%tEdsO=a!&YUBCh!q^ucD-&EjlUcFHb4 z2nlb~Erzr;z_QigSg|&tGlgfR*^F4vwB5m@tZA zDq#K9ed25|>uR`nB=Gz02xrTA`S|{C`3`BKY0eqQuU|($4V3>&^W^_^KK!54;Rm3J z>B|;CYn_@3E*fdm!D2&12(t?oou+PW4U9&O_Qz%ecfvJsXZmJwATNI}+u=$6P0)-b zBVpmf%rE)K$u%uXb}`ssc7ylKBk!yy`_=mU{dKMns2kV`Q?k3nL0zSR{LF>3yXJuN zn6*2|O{Kf+&5u z4xbtNdG#jileN}Zs@7!HRdz1*_WrQm&#;=X#g^MOokH9m_Q&LH7nb*PMrr_Dg!d43%oqLlzro>;O#O+*&7P|?{tEYzq( z{M2ZP1NJJ@VeF}jo0!o2>mQQ$7Dt3(3106mnUbPDoqS^g2vTqWYEC4FqJ5E(ExS&g z?W)|>X_QRt3#cx44cA>dO2}C;21t_2FAi&Fr?VD0=Q6Kc%gsM#JUpNMuG5>X zTjA(sXPa`D7Tyj+B^GM-c>D}_ryrgeAR3jJB3VS6SD7us1&3C$dEAUVfj zVETxSWN*obVJ5(79ZVB#DmOIQ&qk!Lj&!ii3~xAlDDDYGqgdnjD9!#f$Y=%*tj1E~ zxe*?0Z{!WwoQfSG{Q21p+WFvj$l&!NHYCQ_ar5beEQoxPx9)c1=+T^h`E>;*H*S=& z<$ea`&d~=w=*^AVTw_0f#f#nJZ+koLmp zWyWkp>5Hknaz4M<<{!Xq7gMwx#up~FF^TJv*L$eXfM!u(WVO8m6~5Ch21+Q#Sr}9M zKBknQ-V(6+8K?7vpS6v>GX0@S-4miMqUX!VG$&E9)WsZ~A!*#-oAnh6Gmg=b&9E!# zS(MHavkvQG!ns4#$k;t}jrfT1gPNK#lOsM`NMx0-2hzz0SSIgfdFD8W%2*2f@Vp~F zD-Qm<2*2i*)+fr(6dd;loJjsZmq&7Tjy49?N=^onwobPHd#fl>`{RYG_P>CMO&c;o zLK0hukW`?M9d!An&?UeDoBiYi!G;4cuwBAT_1sN2)2rN=$cwZ=rokH zfaYasEgLI>zPFAz-@E&uI6r@c$Xib43~N_*g8_;SX0zFMoxR80JuH>op zNn+Oik6CEJw=8tbZfSwvu_2;SW_aRpFO0I|Nr!Jr8t$EPU=p(XIn3)m; zY>i&eLsYS}v0G5QE%I}jhdVg1r=zms1Cx%eVOQ3g@(V#2=I8bHOmTPH0_Su!W@6V7 z)`OUgqcRj`#uuitlA%H_V)}re`FgbsadxT?SQRw@fY_oWxrUYFJR5Zwy=y)yF}#72 znd-2;R*g4v5n&gJT4R7I&HCNh=y`RMb&z5u=dLWfr%d0o38PiC%v_qBx@-$_zE} zjs_EAXa-6X!ZN^2$9v+16y#`U?S$(zErp{hCnz3b0mbnI+yjtOrxw=M)9ST+ z(m=wY;;iK^GF@EvI1W!Bq&L{oDn41$BBquKhi*v$scxz+IeF)tn(oNP=JQV8Gz{^s z#zo^l=$hK?lGVUCo9|L9uX?Kp#c0qIMv${Q7itSNxKg-hhWmYRhW%sh5~{bKMm=l6 z5!W3FgH8XFJf}Hi99K9CLqhZ|-dS}Q9zeHRx}!mK6tRARr?Gya_bJsov*jf~(U_IO zVE9(F!EGV4on^Nc+tkdolss!2YNvnqgbLcfZ`HO{utpo!g(4V<4E3y2V3#g*3SbXm zi4R%1>kQ!tF$3ug5iNWH`7Pg-n(rdBX`-v!pxIfyB>_6+^?AdIOj-VYP@89u6zVC{ zzQS77f!ctz>A49%n0N6lUDQ!V5^=M0B}}YuWGB$7XPLmL(6`ygV9ts}KJDsg^wi#g z1G3F85+1HlD#*opoL)aIai`Mu!k>aY!TtdV*IOZO0MWvbL*WKUnJ8fH6a zh8`uCjWa|^WLk~YY!X7IvEq_&TZ{|fS?{}za^2BS>IvY=e_3h{>LGY?A{*W6D&Hfh zFK?uTE&2cj%+@}Zb4?ZeT5YOHTEZ(YE#Si5>~CXJ1H*ZT0^dL>MceTDy(>Ng{&WC8 zH?jozfS|tT0k7f#3ena12nqM>+~<#$V_3}`XD^R`>9G-Wtgs^)Q663(HCm5q(8?(C zrYc?+^VAiYYxqQbc;S5gd0##Dc@N|n$8aONKJ9*4kL=c{7DAU@7w|wZth_zq7y2P+ z?INtw$WpARKMCU!Zm{wM_FH&s54GEWQ?{V8*Iuce>J4`@Q}`-aOHS}QSIk9Ti6gF) z2b~vHwY08h3wN@pw=6_BYj7spLSG1uVu2w^&nX=w>hD!Z`{lq*X?Mb2k-j#Pwb9+y zLNuO?2gTCHz=GHMRtSgdqri3$2~TpIQC+ZMF!t2ET+KCdGZjHH)svGbU>_4qjRhC}f*q4Q{Zj+$ z{1ZE-R&5gga$8E1P7%ip$XC6ERS8#wi_maFZb@5c_q$JoG4DJaT2+bOq;rPy&d$Ii zm4r9oyv5;_K#y--8!J*frIKhAD@2U<5X;vdaU6gV-Dd7?XM3QEk8;-Sr>i?$W&VDF zoN`d|oY%&h3nI1+B>S+{9r=*c@Y!vYdU|Z9i#s*^ThaK@UFq?mmEM(Zl`S|M74(Ld zggedVp=wbNX?&57G(Q@McX>(+AHfF{G! z)20v63$K;r2idhmYS7A}*6%en zEXf#eE+{DJ7%a%+Z72X+D;`j75DYQp=QXhUt$_CY-VwupY%ufOpto~i`D~w}g&A6( zlrvG`L69ur0iApOn79O4Z-G39Eno%Y4oL(IK&h#+o2FdnGl{+?#@n06U9%$m)MG7adyB$ zlT&h1ox~YM&ry!S-t3YbT>krS{NzSnHk8Jnt~1k5r|$m(E|j--wy?4A{OLCT$CKTU z$B~k=iT!_q3zcl-HvyQuDMB!+3eMEgJsb`oE=*-NaM{k)S`yTVk)*~15+SiG0*u}1 zCVu*UW`;~@bXs5C1T9w`YKAP#rp*&ho;N{OW(#VBp6nb zf-H*{-M{*BsVu=%>aI@r(3jV+V~U+LiX_BU(m>2==4OUul{dci7CpK{ zwcMs{Yo&6vlv(jfE2H`De}rmIpE4(iWco-k_=;An)N0t-nz(&)+b27z+b86V)CG~X zkR|9|_GZwgjkE@QcmNC`SYS=G(+!BmM8Q~#T~|8(U7O~d#>QOOUG=rwyS*yci5qt= z55R1{ZAtmJBC5VGO%_BfV`}C6Zwe^Tj8%aKH-Kj07&!V7hawQSFe?!cM(DOf{key4 zkQ&FtdSS5jUqm zFG$o_>)(aOchnw%>vimec8|VLzWe=O5gdJ%a1dWFm|q|DWf#YCdvQser&qO>DFuS z)g$k-_qONp&zkR((l7QSZ&*q1awsi(neH0^Bi2yPywO*BBvD-8ITj=Cm@_OhgHifO zgsD1ZB$O5;w=854si#{+E{*32CXe#)nKrCj5%Q4azei=**S8*ou{$KjdxiUtboY~c zhx-o^*u3E~WpB-q9_Z$UL^G~d+Y_Fm;W?r$w(aJUv?(zSL8}SY$xv=HFxr3akg93PnWKJF4KZO`^G&NslOg&`cLxhojR?~1)O9d5bf6U&9ZiFfdKhi z1F!=YFtlb9*)7Zp)G}B%p}aaNnaTKLc&tfW)+HBH*IXWs+Ch3+wXi(;S6 zyHQJqC42>T2XYm#-lj4)*?F9tN+>WVUNvpbo8(Y9yHP4wSUlcN@V{!Kj*>-z;aWc! zn&+y-*c4~A-}sC$h7n967}JikMJwHb?G|f_%jTO=+uQ&0+!(m4<}UuC%{6~8yOyLg zcdvYCn*xw^#qr>vm2JQ4kBe>9kH0kX;6Jn)c=S3SAAWJGXu>w~PR+pTvhKIi$>s*^ zuq+EDK2n4}Cn{GQHb>4eyf~gV*Lb0&iJk7j`mTX{xnw1%%LE#nHkgmaSR~;bI|jwp z%vP-7LB_N?xXs3eKy?Q+achE0c6=A!gc(aUW#|iY1by>&54B12mi~+2*qiQjbf8;>x88`e?C><^ zZz*MBO~51$7$_X?`AR*U-9kN{oyvTdB`P&v)dAmj-F+cT`5_Qo-cS&BC}ZK_BR2jZ zhB^=He-MxE>qEuw$|HYUy+PxzFa*C^yiwyX-EqvCzhURj-?=P&g69J6i$lxqnnUdl zqa*DqII0e?7JO8PoC^Q8M&6dc)rQ_e1{n>!rPZqRb+D zXRM5zM&37;%zmNH2@$az09F(~rM>ssgd((TJ8a3&*SdOSzEG+MeAGI2uUDo_b)ii) z=-TZ+FGsphow*EAN2bi2dU2wKMejB!;JU-BwZ|6vnAzX;?+65_e%Y&m+MJKDp+GHVRr%TIPOq!1T*q6#iI%XO{`sRmc)Vt zv77X=EH=p<)v;{`mDq?V(@iS5d;B>}CF$BE_DSt{Z3Ckdc>($ye5Lw=-2ChfO*7LC zsQFa9%<<^5#-y-O_~^11lgpr)%wnxJG3hX=rCQy180HRVOIqd(Y)KQlIk=Nlvnus; zs}@J zw~eTX&AC>vNDhRzo1}kzU$6Q&7hYJCU>*8ls6S&ulz$3!V{lg%y@;-dVy&|0V_TKb zY?D}o-biqBO)AG9<+wYN6KzMOCy51*tch)a2h(03$)qBrRvVuk9Cot7KZ7vgw1l2~ z{%etldk_ob!lfD4aEc+?fo}Ubi!wO7A#TzqHtq;m=J7o`S0ToB{?@@I8-lY?O?7u& z2{xJ=Xgg2H*vJQIh{VBQ59T7G9 zwaC3LW1`J-MmtAPUOs$EVQ_ZfvgU&t2liS_+orsjH$`)6@ITyeEN&a4v$hb1Wo25E;q)Vyny`<(!DBTQT)!*v@CR_dd`u0u)HQ#6%`l;al{;BV&9%7R zs}qP}=HZBTp}dPkN&MtwCOphUviy>)n&UILI{NRt(EKrQAJ;yBVH=={zoR|2m>tD& zG_6h|FXBoR-RSW9!dbI&eOXSwX!S@2luj)Cu{5Rdl($&S6U zhQU0=qua{BYWgAt8l8`T#Ye42%^>SAj!8hkkT0=27?_rha$pF3<$xi^EX)}VrYZMG zb-owJlRp=)VR$Zs+#KeC<{j_c7m7ecHGRrBwVIT1OI0+5^ek0$(`$Pb!XswTE7*UH zUo*?saOF?jzJBiipZKX-I9dE3ww8-*7xdtdEn?g1=qmIqeIUoVA-K4>ASEQU(Ca$5 zYy}l*%bN|nuRj4YeH?t&xyD^$mFfcghsk4t14`av%}ubm!4ydj>UZz+Vka3%VILj8!RVOmqp#m};NOT^9q}K19kJ?>Au;f9M@W$3M>CzTmqx#BcP$J<%Dz;JY7HzO?LD z9k74!Mi8@;Ltq+zDT1R4PmBz{Fw%rTcS#K;9WTi9gnUDQp~0Xg1$P#mLL~tx8`Y++ zCW)yf8efKc>89jO7QP19Mi4AkJW1U7a43|5kXW zj@QAHzCIjT(=l1t1wE*;;_{Q2Hbz9H1!Y@{6q~d(8?AmK^2RmRMPBZouBpZ9qwN{U zIff&&)f!rp5>__VSW(N<-;8u8)PRKov*&GBAvYxr>+6!Ii?&4Wq}1Ha3`Rxqtt!L&AqqtcvE=NFs5#l3r59>>4D;ksirQh@tE^!_rJKUk#*BlueJ2@8bbCG z&cxN7-Mh3cR0_Es1InZ0jfYcNnP;mW8*l1d8A~5I>#&$z%_N6*JL8Q#G-mDFyftc5 zF_;#gq<)&*gB!+(*i#dr6Ch!EDL>k)2EKmu8C;uLxJ^U(0I&is*2HOeD>-6>ZJtp! zT`eX?$FEvhNLNcqC1$hY5DWzF-H2?q%VW{mRL-GPMdFPaECX_FjZkN~Rs%XWeNCi~ ztjrGBGm0gP7bU?G^kT@emGp`dH!clDBg>*uhnNbArSN%eQ-g4il_WHNecXC7By@Rs zcec5EHgZU~-GvBiP40#Xxf({;GW#=F+ZtPu91y459Wto9OJ$%Sh! zHpe?~FFBv?c;C&G$+o?EXKa)VOi0{$$*~X{OE#7>JBdO=v9qMnC(++2dxR6r#Fztu zTI@Opxk4o{#$^sG_qMVpUjvsxtLVAuaMYL#L!j#qG8>!tx+2@DJOq*87scPcvQ#R! zTwBSG^d8smSprGTzn+>~KF8syhA}jW70GO=N)klX8F2m9GLBxQ*DhRqF#c#L%>F0Q zJx4{7FHeQ!Yk{yvidufN%S}TvfFoqwMJJL7YcUMM)4RER+6mlcx#Q{Lrvl{PKC6fa zkyv)Fu}#;7njuR8!FTBR!l=+Qo50##n^86E?9L=z32j4N^5Fy}D3r<*b8=F*3nfIA z^tE+pVrW78m+I=oN^fW(Do;lKE(#X-wu<*6xBv+i3qCqPMPwzXjM5lCl~qh!43?>! z^cEQTnO7u3u;W7Agy{7RIv&n~sBerElIHl1V2P-EgH%g<*4D*|SAtYjg0gvpl-j&v zN~%JR)bn!wqN8TPA!2T|VzO#wGxQwbTq*@y!^1OMok5~XMN?RonpH`r1U<59ITD1r z1}%||Cu3fj{w=)Og}SB;j@qWUUMNesGm@?9$=x$hO3S=T>UwzqT=tzZVZwZ9LZ*z9 zhp*Da3GBw=O3Jhe{Bvv^e{DM3owBlNLY2i#L?h%JX$V)v0>?(}+%m;Ayo+n(CTF?i zu!m#hI^Wrms#&^Zr&+wj%KW$4h3eMlSO1;7?AOw?B!frM^s_G{@bj1zCrc7tRxxj%7xXvzTUp{fTp=%Drc-l5sHS_+-H&)6J4m6*#j-4{Yl7;TU>x@X) zE4ZPu;-J%t!Hy{6t-o%16eW*qcnH*-{iR)towAyYQk3>*;|jqwmm6o+$#g&WIDWLU zEt#{E9Qnm~*vV00wqr*sv`Na0<#ZytzPW<%tP^&0D%pLi^bui7TZtw@vGNa`#}Yk7 zY02IoBkax14nM=WOh92M8L(kVkFMvHY6cl27gw$mABCE(Yw?ki`!CX`6z;7w98RbZ zoRm=wh#-r-Y(<7o&Y;GQ#16f$8C4VG9KnLAZ@`g1UXB%H7BAh|S9#vfN=g#=!*q`^ z_6zE_W)bS3glLRo|HeD3A@iJKrpI;#+tj;U!&**i34)opO<4I@35>gqxu~QPMPI9E z&q@>4A%{($!G#k^Sr+J9FjZItAxSl2*)(Jo}DzzF|=va)42%3p8zR?%L6Sz0rksb(24;5 z0b$OgTX)inXZYcn%U6myEbn&8knSD|aE0p~gmRZBNVu9Peg{i^)B2ugDGhtq0)nO< zhHY&mx#hrnD}o2r4ipCD^~^%5(OVrFZ)nTOc%92}mAj5u#SM2tD>QPpn!?eHLru^b zEL$yZH&6h#TL9;M4)i$>eha`a-4s2M*_*oR1(?yDDk6^?Ulpk0`E7C;;z7$5 zbg7hvAH9IJylVp?HLDvV)r&8NXGLJrQ)fI@bLs`tRh9F+H;e7u0AHvT&ASk2c`k#Z zA4_RFtgr?113kYI0xzm|NL_o}?+T9xJ_4>itYO4;lI@7y2&o}QpE6?nvxUqbMdqQc zaP@5TW!%Ufdtad%ux8c$X!+J-@>vbe8NH>;ADguuwE0GV8+g?e$sL9J{RA8a!5fx$ z$HYA3?6~ge@W!bO*E;;DKFL2t4oDOKOEi}fyFB9Rt{V>Kj)Z>y7rHxH>A(c+$MZ{qwW=Fit&^-LPtR#-9tetAQ=fmA!+Iu7sLILTLt1o@+1d zYhm0QGsl?EJKD9R+1TYyQUSEDxB|_ACQgXV-|J$05OXduSBGYKh!MG0b0^j_yy^Pw??Ksv1J1V3{&Vt20y2X0^jGee=W73YjkiY3qpD_OT z^paBe6?SCvo8?8SAvC?WoFOG{>BwalwFz>@q$J7XMax!!{~@<03tQ-`>Ai8SPF8!4 zo%;xG+NJs$)$(z^Tr6r#8auL1&@HjkH}S6%9$D&M1m&U*t-Q|%u8pbvj_6-zVSt#ywrS!G3?N#_ViX{{&yrqDXJUv4e_zO zH1$0O>3e<1*SaXsRRJ_9_$NesZhgFALOFa zFEi{-3w&CG!n6f}w@?@|6h0*57oKIZs`RMoAsfq1|&6S`L@HX&M7s^d$QC-k&lY(5M4QEos3;ZtmG$IQ@ z+=W~)B6QB85ut)_magH+ZihOx%XsvoVVZ`ohB*jIGm77su$|!0*L1($;?MFCZO6K7 za(08bwJrW!ZR@idCXam(mzU-Ow@_ajn@$jCopPq6jv3dy1zO|b%#pmMJ$db+ z-NOmMX|M7BiuZG>XH&;%$LmRoKC2H(YEUBVOdV^+T5s z?Qw;6sucwLP{zrMqIB*HGFO@}47o%|{De9hR#q5LD^9ZGkBK+xi9Kj4Wkh3l zw})jVst88Tt`yXLtCp&9blmFC2$x-`sQdYzJmwjb= zd$W_32%1`tDCKS^G)O(7%zj`%Dd7&9Ssbu@*61ZkZ|$1qBOtY+2?Vnl*3x2AUXzS& zn9^%7R0Q0Tx?0)CIm>Yr9s7OUH{Y;-=5T2DBZ- zZzXXFkeG;HUGVqen`OdoMUbEn@2fFEzv6aR&9!4V!7a<7BcOEL7y%0rCqOQ;z4 zaW9OUcu*foLj0EmFYcf`))6=9V2sN*P?(8_ew)JBU2!>Y@m`6i=D>{0vR;0CZv09E z%eVG`^LK9A1q@Ss6DEk^Ec|)aNjj4i8E544+IM9IhCf-z500mRR>Z0}3>opT|&Vmk~x!#mMP0@u>PsV!yNQO76iT=Pehei|QaMJmO6)w)H+8;dzh{&+K_$++5+ zJOzHNJ&R#OCNASbB8w4QG1bU0DyQi|ffEH9OsWyW4h61FF?w{$e6{33QZwDd%CvpO z&^0xVaffFETy4o*L!2IatBW6&SS`_gsqLEggdGTf2NQBC*$HNZX}1_9q4+!`(oa1;5|>1J<`L)rzO zJ!CcQ@8?8?g_Ybsa|p;l+KB?EKkxzR8!-Xds@EAp15vvV5L&U3+wQ-;D+t&-BEhO% zc$FP+RV`UDtG)e+P<9G2^=X45%Kh=8wyYkD4$1lCs`^BxbDauFeMERn92svO<{Jnf z>z(+Q1xG^bgiY5=I^*F{trmo@GiZPgM11F^yJYFI>g6eX!z5O-oXnMV^hC{@hjYDAZmp6^^o1glSE>l1gng z)k!+bC)mJn0}8GYZ46nvV8|~teEZBdIwZL?$gvh@w^c4mQ?FrbeG%j31I6*9;$W1r zoycQ%P79N!#|w8BGxRNCvrE&~Vzv2ciKFs7L+D6{Rk`@R2}L$&)F_I3md*exWv4`K z=7v$oL`ohvSpL>6#h!lvsctpX!@&I2Eo)--uh(}#L7dN4cs6BaPG1;BOtl%O0- zrd*a}VGj{YF0byCOcM_0kO6WF+ut`FHKFgJNgi7*D*W=Q{(f4`fu4CMh^QO*Y=8M!)pP5ng1r?@kC`i;l$prW|~Xd)3|0N?CMmv{ZV|N(LKi==krh+QS8e z0)K&FjvY{Jh&yf^AhWt3+0kosLbq3WtyGPpdn|>j)D?Eu#8#q#oYO8+licKg0+-UT zq;_KS0?Fq;k>0>{g5<)aD-3?pAua@B_lR~2-m)r#wIBfa^s}D8dcdYp*YG>PjqgU0 zB>lJK1Tgya{9W!0c}opIQ0kGK79z>khw19h#M%nLwmL2k_vE~z{CeKtUx*^Z8eql{ zk1(Wge-8}*DeeJ_QoF+pbsy|4qPr&dg_ zpQ1DCea;6sSCC}|!rM?3;gXF-5*n-$~?@+*@>-O z2W1Rt?}xN6B>ReZD(hFWj_!%qr!hl=Wo;!2So zN8gf$frKk~i45L{W5R5UJeLvF873$$FcI9dPzHC&;4W}TB8{}{`8L%y(kta+#BBc}d0D1NcW`43~SXw5<4{l2%d z--H!GO&L;61&>dehLQ@hBl05J4BKI6kUBj`RP?HB10$pq#eK^F4d#y;ur>d!FmEl>;UUO#)ppoJyl>yi*miX~95tPZ7jJb;H6XwvI!Zp=v(QkH*-Z&L0GRB0h=IT^vp1?IJH%>|h?B}Y?sE3(-pBUBv zTw-OB9!(_)QQnyqI@FmQjh%Dpv>F{J%DWf>=-i-|a64o!gP|d_{2o@RM>ILj8o(R= zZR{$05be{bhix=n*KAZ~cnxZDrkvoxSa*`-wQM`4B>;QAW2E)RZ)tY&2la@%z*$(e zUM20{&MK#|xHuD4 zAJMxf`24%l4~R-^bpNRE^!KQoX`>z!On?xTn0bM~_5l6IG#h6sJve+<4;= zIZIXM)2m|3&0q7>WJXvQERgt+_nkN=(FK*XNuO(iS13_-!tCUgyFL;pg?xV$7{?*e zJ)F)*Tg2fGbRQE$p-1V7ZNgCt_ayn1(+*uOgud0#&He$>ye60AW0)M~%BU;8^aVk= zbwE;%Wg-PvajQ@namF{BmtqKIba>n*?RKs10iQ+anpaOR5G^yd1?>{%{AbV743wr1+?hzSglhjBA8hEI)v_wpEZz zNXP;kW#s&x#$kUfB6s3#lAXpT>c}@~u@SpcKv3|ktx#7~YO}g@@gBV@Qr$!}eGB<1 zW`I#r-@i8)IxnM5)S`mlAvfqI$tDW?D&c^)G!EDW5#I-vd>V?QG>pC_{L5TX;Z#8- zHjGz6Q>F+)yFlmzS0U&wH!oO0LhKD2x6Czo7wmLU#Q)!5lAM+LUz(V|epNC2`i1vD z|5r-F!hruh+iKB-@=ji9;Xj*wn33rXMr0C@SZ|9Dkw_*KL<;v`pp_UTFNB{U#e!ls zFbxy{Q!rOS{W*p)L>O-h=^~_bHb0(Js%q+PHMCmjb-Z_STYYMz0=oZo?6D_F%EZ6= z_Kn5eW;xxu-FEz-CTIU;dmXeK&GiU~lsz2rK`-d_B+L3eF8D3&g?xl{^Rb`9y#HOy zC*gZgH~OZkD+0$$Y8Wf&8WSf+>C8AOIX;O`ThdQM=(F{};;Yn;gMBtc{tT7^L10_r z$YEY|hcuhCDj(253=exRk8kq1Iy(@Gxx1IpsEBtGxTiG8psC|I;MP<(#pDt59G$ev z4x@httP9)VS&at#li%0!nP&jtRnoLSEwCRgZ$NjB?<`BuvBI%V% zylSg`Q|q%R>fRUI1a#3JxU_U(OvZ^b8aQI+4x|cZ(QMBqswVd>8-!xw=ub6+(%j#@ zb*Zh^JQj3ri(0y6R<-Ht(7@}A9hcYW4GyJBpCTnV&=G=W?T)e$k!>;}~>ra_H#_u|ksZu++V;#=jHGdIbf`l3LQ7#5S{@=i~9d878p7DYr7B zc$)LeIkNdg?bJp>)VxwYo>A0hPzrJwh3W1j#W3LdWx-q zX)%y4++@FGZxd7j38G`ulVp-)%M2T^if>Y4sfenJgON9fS<>J+_`9I{DjQYGWe~b@ z`7A8nj5o#gz`6@*7%nc?yttY$nZ&yZ%s6}Xg35=vM1}jl& z#or7KN?Wm*+`zO3M$yAnRY!ys2~sGP1kn%xPhO@FpIJ}>lL=ni$cOEPWU!mE;0zY2 z#$Aya)BZQQ|9qg`5nkS<efUIxlIv`%qBfb zZQ>ey2CHGb2pO^8Qt>MxJH$XhR{O>=I(&vVmHR!HEvtLaghA}D16kW6IC60;F&tKR z<#b#O@at|QMw17VK{pgTaPN%nkUpX)ZQDg1=QhcpZ?rEH#G|M-7IHU#H^{F0Ae-c1bDnkF=*(^< z=S}h=@n_--MP-+Q=Yfzc>_D4)0BCGtFD>piC`Bv;&X^$j)f~I*H@cq91FLt%`)8!juWtTtxZ&hH%xKS z+Qk_89<}2xIgT&4p4p-xt=wM1TG-)uC`wcZ_6ZI{a$}wp+ku3EpZ*DB7 zzu47gwgRh>xTwWk3PVN+ys$aMvQozbeMZy$rC{Vhv;F;sHbd~&E z2QyZjeG8mTs3GLf)?t>5MjKxv5{kIt_{IP^=RabIXQ+h+5Q)WCV~Q^&AhXH-NZ%ii zn~kK?du{Z{HuY~s*8HmHJikT8gP7;gH%YI1$LoKTTaAOu*Rb@~5Az(uj$6f1OYW1Uh)5+%l%2_|NJ>@P4GW&l zLsZw0n>JL}aP9yPD{RrWZ_%9^KLzzadddr!|KMcxV$H1j*r?59?c^`|kmpqXZgPJ# zhwaBuWApA2AKo96cA#|^QKmj(Yr=?sXxlFcQ+xmjGO0junZe^BpWfvqjA1k(T9|ss}p~E%lGc>(}1v##E=j z3wD&{*ZhY#?zRLxoawA(DaT-~X?U{nDpEk)@@_38Gm_4CC8uRCj1qI5 zr)>5%KdC;y#$S;n*R<&DTB9GD2yr7Z0mO>|P-IKdGvN`s#r&44ldx0g>71)-3X+zM z5qghEjiMf~GzY6V=UU=S4XIMLL_6jb@s(unn^-a}5KaOyhn|pQ=-doNRAZHjFRtF( zlceM=N9T{Db@%C7kvg(#-3a?E*Kl5iN+vGjPe zLhg2Qy23@^#AE7q6ZHSk^$yOR2Hm%BY)ouSY}>Xqv29xu+qP{x`NnoKv27bSzjN-r zb>36;R`oy7{p{*`dau3K=g)w+lXPUKxi%zxqxebB9v4>HqBR$f{|+-94I>!uK>mot zC>M+pT0f~-->F>apKS1%G{oFrw6HXc3D~M6tQC1))}_^XUKRw)zcx1xaK{En(;U{C z0$<^8;*tqM8l$cYpv}%!GGcsO_=0P~S!0;UQ#Bk4w&TY zKjZ*iOtmr(UZtt8gGitFm)Tcx8JEwT&x(pM=c-`LsLx)~6FSpOX5`V$nVfVs*)pll zrf)uX`n~_uNj}n?IPVK2T@&!)LC6Vg>|3PQ;|Kf_J2F#D3#!sNPU>I9{2= z6UDSgMykRQg9h?npO6-uyx?vxbUHGjzo2#cHf-DGnfrRp3_gzamyZo9F!WEvcdxfY z^L>GA>8+ev0SYE*KKwH0z$4h6KuH+h81ujid~Mq5g~7ieWNjw~?0X;&_0;>SmF*@Z zf>`BTXNfV^-=N;I;$FC_+7S^Lpc8mP_*%D`i0=A+w?m$JunhA|L-77RmK>HND8-u0 zO8f+GkBy^-?Ls62HsaUZBQ#kVvCvUb&@qNwTPzUCTSE2Ag?UyG6TFpHS&Sr*@{BZ{?JYQ5*OrDS|qDJs>6h~`?*^6xcT8KZ_NFM(vE<}ehgUPesSVAyK#hKfQd85?bV#UFcu3iD^N>x34t^%zj zo?clNDaZUo891@2ZHvnNEB!DBSDuI~InD%6?M47;Sn`t6-KT*TN zGlkwnP4l{{Y2J}|AEuq)-*<_GCwmCd+Tr>I9Tok(;3#Lx zRL!7~c{OxA@fMLrW}FYSK0?~_JJ%=>W|(bu)BN>%;(XP^`<0YM%Da!3az?Q4_9o>N zPw#b3lIfcPmyzmn`X5K(s`ZHN*AKD1Q8v`c*liLf0@mNX36>)^81VvpXBl+#N1OnInb5f zn@{gDW{vD~J~mOs$o37_zQp+6$x%Z+SLmgeX$y)n%JaJMB9>@U1<=8Vl49h`e} z^@h(~-{OAx&m8dIYkx%@-#X;frcp2c;?pv@B?@j(mfbP2q^eaA?NUm<2e;uDyT0sFfIFY3 z0t?g3jC?7+k5?fen8UApedm@QcDmedeU(z@vcxa{kN^Z1KL?J7(|x*MIlNTzA7K!0Lr*0CX4Ekq58_@t?tK>jl%1~9 z(PfbjH2C~y34gU>hwFs6?B%Zt(XuJu#y}af^qJq)F7w+|DgtFTLe;-4I~A6MbVyZ# z6*7Y|Xcy7*rGh%N%f@`%W8%Kp@|AWZjW`Q8ZoG2y#{)Mq3H*WsayZ}yL@5H-DKgn- z)on{bwj@e#$TFt3^T541vj?=wQ(EVgdIFYjTrGF0DWlTbqiRd2Up3bN{}!^ni7yW` zPk^?g98cBWqU=g%UJ#yKj{q%QgzR)Lkpj$)q z_qM*l*E8x_}(?;C%FErJWfG{QluRTobrZPQC6~y{BNJ4l6C%jUFC{JiBy@m=qRIk#EFP2z0}<6sqqQv_ zNQ}`Am`FiTBtXZ7u=BU(UFssQ#o=F>?WcAS@?sYOt1IM!1Q@QLn$cFa7aoHxOC~%6 zEs=RM3rXw3rEvxTQ2pa=7aN)v|Fg@n_>njx1x~Ngb-N&N1rmshd^E>#oD*i)Mfb+8 zE$7-t@=a=UmK*csLS8eR2Lj$-Hg#zEkL%%5(~QV(o(8e8V8s=R(pix(aze{QGwXql zxF)vA(Rxm|S~^#g4n0ysh0LKKE@Eb;mxT@q=bdG0{_x3-!sPq)o@GBGXjG2Ekz=x? zB8TQqFsN&>Cs&SR@^-1=m%r32amEC}g5eiy^}%-DuQytq z(cV&sFHqK70?MF-q8$E1ScR0T-Cld*@8rzaYyTX-8?+Bjy#c)&*$>j~2%|o}!(Gtv ziP#FbE1}c7g7JfYOA@}~hc}^A>>g#w)D5}B#hou8B(i^r5CvGJ3G8_Ha>jmrQ7F;~ z7(#1Q+`IT27sR=@Qdk|tjiwl{STPL#m@$ck z0`*Se+ouLLw5nj&s1fkOo3-JblxI74EYvbFRji7PqExh}uhbekJfWIeauCL(qI~MO z4^|P#*F55K;*iIb740~(J8@p%xmd;OxTUkadS5eDObnR8Pfg*nZD*a{>sl$eaL`z8 zt7mn5SF8ec4Dtb=zfTmDUk$Ym=k}CqrpR2M{U&a;)%yxq5tt#Tr3$T6ESGOrq15p+aO<^b z;Vh7>h;cS)rpnn}bToT@Ci7O#73o`YH1}@F=Tm?_yS=!2A;M~1=ENba>KMZnJ5pwe zUz>7c?7}CnEZuz0`rAyU|IxSD3Bc4AxtQ#DoN=T6|>L-q|;zBg$s2<@A7b-|zS*KJPJu?@#{W z6>h7~alH)1I~(fFf+z-bZBA^ld6)W`bh)u&vf&je1!=c$Zr1vO5 zNH%XaHsk>7Bnfk}F()LHtSxvA!-6G^;5VoC1H8aC4 z_OA18k#Ke2SuNbE9gnRh@*dsJy}6R^_DT1zCuc;w(x+h#vda)(Z()@q1jH-Nq+*L;Sc8Sy0L zLeEZp;+XOk zv;-yi0{e|V`l*^@+ApGNM{E^sE;HqAhO7a6=%9se+0!1PWxSX7~$^gqSE4$Wn;Z(tyx(;vZ)_`iq}CeC92iv{KJzom&{C0VCG2o(+y95YH=T>1ufv>P`L`(R}fs$0+(#jtvu z@+Nru696~2o#|E=-pq{NwjYpth&UIEwPjoNZcGf%m1SFLVVcl0)>-v*&E{p37wF6x zyeGHL#QJGl_21*J7Rk{_g)0r6^)t=OlIFUmD=wc(8;`Ai z^Hb4Z;Af=5zE+(x3g+YS`ehx0Bx?&}3WL0SaM0!L^T!6cBZ6l$fB;Vnk|Mz4;o!j> zMG9aP*M}i7C^JWa?KwG$pO3r;njkVIYo$I4RkX}>VwF#eO;ymGO9NynDN#OJ;mydh z?t=0v*6sDZsx|}??wpeNFyf^;O!Oc!%4IBdLBeIom+ATxB9sVOGC|ZuUd~8wMX;jV zljvp)nEwE+DsSBWJXfBRV1|Vq#D#{N)MK=+o?;9>!2^B3a%~RIqsh)S1hSue^yQtw ze3qq}FNa7R2TT(W)P!bk``_5aF7j(K^Vc0^uYj8;es*P0nlaYu-agh!D~(C?v=YR! z;=rw?BFM5sx;54xdl%i0h_zD20rkoqX0@2OZDvyn@4vo5ds}eDwdsQ>!@~qo5H;}( zJ6t~4j;vY(@E}pJvu<*8|7I3a9qvIM?7qb1x#Oel_u2omet=hE@6i6oU-$#cX8SMo z<76OY;ACMWWNl|;MIvKhXkz`7J#GJ!LH++b){_67&vDcb{tI$2oqrIRVzNUl?9PDWq9=Wo{od5| zd0=ea4ahdnAkTjSfuOLXXa0_CSClJn4*m%;O7IELPG?lv%2A0~n<24_kSwNZ8+$>ADax8T+vPa0r= z>M3mXvKV1x0B=}NZaA}gFMM3)TOyJv=%y5Fe8uW`zy2C!8Y@`eiluh{Glwsnx<64v z5&YQ0jY^Avyo|N>>!ciGsQ5>v;)N$}H3{?R!&Y zvCbZsJ?6YxEz;nUK(}pmfX!zMgvx~}CFLdq<%Ma$Ag&<8;_{a25FiQEgxQj%zDG2b^>wBIlsKLGbT zA_7K5HH0*|)R0{s*3@vmLZ8njF9f{d$H|*DVyM|D^F*Yga_S8;j-i6NAnjH*6sZx} z8a@IYiIaH^Xf^K+;Ch|N8j{H{qBPMVG6HWXd(~*bal*XR|WBIwP z{!6s^Pio))QE2~Ri46V${`^=XMXwjuRx|}aKp;aq(g1U^f=FPH0NxToB`c6{^xi1| z;!WY;vY`DL&Q|9QLg>3Ee-4o839~bnXHeUst{z5kvROaZrj*xizwz{0l$qOA_l_4m zdcW0c@X^%Zfr7>J(@~M;sSr|#-?s&w6d>-`JlWEVLTY17-%qmuvv8x~*A}%r=Fho9 zIqh{C)f^-DZyr6BOv`@7n@=bF?jgDwr`l`JEM*b1mwv3U!x2E zWBdR6s;>S~kx`dEzduc5SFOno2>%9wMU5s$+Ka&lkU(L>1A_(toFr4~8peh<;Zye% z0h%+G)o9J=@;v6$Xl#VlkeV}|{~9&vtt)x0n=N@?{rv1q&Db+#!@i#a(><=Iyn5fg z&l9(|-1w1Xmm-+U;$m;+J$RJG8V?+bcuXe>eJ(-kJ`awUO+e8a8wj!y_)-OQt2 zEpiq)rH0Nt%&Q75rgVv7L2E9>aD!!_7S0JRkbRdw={5rB4|n)#cK>Il3)w_+;|Xrdy!y`Vj6> zTIrF(=fAsKB1#bYs*kFfdnIq!)ugvOI%j(E>;Xtmyp%S$7S7%=|85n;N7~iF+a?;Z zOE^_!>R6p9_S>5r_)nMj}60&1)rV$b(57x zk9;fq^2~TD4HEDFma?G!hrjiZ-Avpynu%)hdSoJWH~LjI=HYV{vv zp;+EW+CXr9%5LIKeC`gB9d!*WRMNK%VjzreXgZ4t(kz^SG9$!ITxtYTD%q9#McZ%S zo*8N~{zijpQr(2Hthn7QxDkMZ3qe3&u!w)0wQd6)Axsk_M5hhvK!v(l=P!qrNujiy zNM(-38uYzz3H^+}(qCj*gjl$L3tQ%+!l5D2h%D$?R=xMpk)q|go_qbr^(}V%966%Dh%e*sDx27@2z$<$PvTr?17rtM2>#8}!{r*j20e#-j#V6D zK4eBFT?k6p;@(ZFdxmIkj(sKzm1vV%*+zS4e#7yJFY^#U1Ye(=i$lx5(H;bqmf_+b zW#OyltHv{`LM@OuT(YQQ+%zrOsM9l4(qS<731sCWgNnmV8^}^{Gi&+>3AR$Tyj6*B z-4wFWo2j$XPJ}{;40P`)STAF%lsg0}#0t&4&lNJ|syiy1K^qaG`Y{zdfcVC>UOA9CnR!SuGZo}I8^o7SOGFF(l}aArBoBQt}Fea}vp* zQ$-_#F3vPYVTgnb-jpmZ{SIy}KI`2U&W~$zS1XB(lPAHN_bUURh#=p>%L#eu9s;Em zVjz_oRp%5j^977A$*^4;nGFNEB&}2YH3zv_+@lWLH1jIHiGM-6z6bHP7G4Cc$K!AF zri4A#69^TdNc!taCr44jcYt6>GXRp`OvIsBTxio^c0`4*tTCm&y&%7%rN#HoQ<-98 z7nUp_d3_Lg7p&SoSPmSfNkfLpgo(J0+|TPEDD1?2IH>1}$sL{704I*j)}*QCp|z&J z(?qa@Vf00<9h$1)@($%1tv{qg;hcS^%7TZ`f z6t22@$aDs&TCkGxCS#eIK2PdH_nkaK7yb=N$7FWqgfy@wY0lI`n>_aX(1G=HCC}=F zN`gYxmHhs2}v;r`-6d3|AzP>LSWl!w%9pcFm=IX)C|;ED6l4v0Q&)@15=ew z|He-782f{QKLpj85IPT^?Zp9QA3acapIiY4=Y!-@*01eP5ekX?F3I=wPU$OFVD8~D zoNtaEgE_(H*bc_)GlUP&&W~q*lBM7qTiU;iNI*Av&I+P;+K=JHg!2uexBQ*}-Zyfa z?FG-XxRxQo3kB>%L}&gN+}pYjpu^tF4U*|@qq+L4#+(o=lQOPNn~Jf#sSu~|&_K`Z zTng}6!|@~4IkM`__5mlMWK+tg7{agro9)EL6S75f z4J#sL?HQyvAMJ%Fdkd*67uLlq_)Z@FE#m3yBOQ<%>HR&RhxtM3SA72yTxH%1*uH6{ zxO+!o+B3~tKppUnc8-RZUBK-)Vqr-=3V~wXoaOPaGJ$##XRQTbMTw&$&Na&jGdIx) zj(5n9NVdFN}lmOY^t9Sh63wNHLm$0(Br#Sv=waj*${wA>5h> z#<0$xQ)9p#vjAeoHfTV@b=6yP<)(Te8g`kb$Ua+}98Qh>PP9*Vmpt<(hFr!G6m+TE zw6q@;X-MXy;|B}?3%W{tl=eDv?X6eZey8goEd-EN-+@~RE1`T{+9`p#cOB&%`sw7Y z)3Yq#oZZw5O4ta~#|dd359#)A=SFf!gCU=BX-|chjfKLS2I0}RO=>|Qb)Fqwr-muU z*pU=QS%)^T2Y~gyHHF(Tc(gMpYdP{WH15$3EGEn_EgjsKLt0 zAMh9ZjqgTD$yl<+f!1+5y|3)I?abLecB=H>Xv1?$605$m0wx(m^sH2mL?aIe;5yZ3 z6)dvXIk?BBY4CpCQXLYO*$i8#+^sdJV0M4ioe6FSxQSBEOXp-eJ~haCrz(iSM?$FB zt2vf)fvRRqeXvh;Z8L0ongBlBzy4UwUJEPWRRo{&Sr?~_u3}&Jggw!%2h?U%Oc%bpSu_(nAR>QmlNJHJ5o}$M&|w~cEcfJ%vP7$Fj*g?f0%36v@xUhdVT*jvQlVDv z8AsPrBNZXr+UbVD>)^wL3R|I%*_k_p{kqE#a4vRCi9ZdXcC4#qt$>Lk$tk_JmkfOdNOmPss+nrb_V4Nb8AB7sJ>^tgh$n1@klaUwUyoj~4sW zJ?C2a99zY%Y5UkCHg#Ww(Xy)@**mq|b6)lQxQx>s;<;V6h2j9A!;r&n@C3|x8(UV` z724!zL(Vyl$2~@gm@2b*sLCx#ProIZbH|%BH!r-Eour}LkcjD2SWG3R!H7LCyvj{k zIwM7=c4u#TA~!CNOTSVx+Kx4&i5+mv6~~auWKL;XI;&tAe6zeD!4)aCu&N@8V-Axo zEiRZRed2vL2aZ}4?F=iIk~z3g?TizTy@^nw5iMe!fgQes>))Gv#jtubGaAgPDDM#! z!m5fkV(wn;goxIHiot25qOvMXY^lRUQ{#fs?y6uK&n-sEh<#c%w^TQ*oQL6VTQYZc zj*q>hbU-(2X088LpnK@=09Fnk{J|DzkWQ%nPTYc38Ml7As}j9gwl%?C6%buP-3%DC z4d@rHMb?uWv*;`0~emMMQ?K;=4}*QytM;L`MFS3aF-Jm!7KsxGz=!%llGF>g`{ zLoEiASHz$F)j%8LEcSZ98-L#azH51^0DPkGTX){_H6XW!&<;DxEPDhXH^Mr zrKQ}$dtlM2#Mt$grqZ05!3wvihVL1%7_s94k_=U~McR3Y#vu39ipL&H!7m{uMY2>| zXksWrXb=)C>M0{js3i8d9EovljU{$A_iQMMFhP-`f}w^L8DmT5c>WF>>H?BmdLjhp zQKX0kOyYNgQ*>43_Veo{qs-!j8TtByX&cp2RI@I+yW!p?})N zMw_n_CW-|Lo2yd6+>~U1!x@Hr$OktH2QO5g-WH(i5%(WT;^a(fMI{>#`fYgG_1Bp% zl@k>l3vQZba&W- zb=stXR-%qgvHcgw2rn#h8l27eqKT=v@1+TO71U?r8sju)> zJtG&wYCBSG*QgW z2fALfbCLial-5Td*SF13?0vT6;H^A)MkX8HRBgQl>yrbkjQ+wNl0Wz@-XTnbDp9s* zA~+G!Epbkrbs!5F#CsGW0ExzBt)#-efZ-zLtwDmJ8a>Ek`Y+%qa*Bq>X@- zNeC5fQ>%L5Yyln^%mc?`zvwtMsPdijRM+319i&N#c+6h6e01S%Go$HR1`@YuVUlAz z@ESn-kxIslKr@GBgc3MH87ab?nsmwL9?o?s@~Ua_OE4B8Y9dZeNX`jr*7p{(?wK=* zHhl6eFN?D+KFNcn_c%;x_sp_xp~I+Z-TnujS?sw6BK zN{^OCW5vjFvinVvEQ*;jp;pR?*nygvN1AWLF$8k+8%oID((knQa3EBM z{5HZO>QRnf^(IA>CU0eANju~`VjAwW;dApilBlWFf{nu(J6&7W6nP;arR9(;Cp9pA z+=?w|9ICTb4n&r=q718|wDYsELK2$GAcN$W1&My5rFj8Y`O1n`$;%y{@d^hCF~ug3 zz|(TGW)sHfOusA|DU~b9g}GCtn#D4zXoJP%i&obtox5DAvdfxhscgWr%bOQGZAf+U zs|zxle)w3hlpd_YAS1-j36`E_>WnLrW=gco(sN$mFs_hNu0I&JRmaVc$>*|$R~w2$ zg5X8zQzciU+*R3w`1O~J;ghOJSVCPZapZ~G^%R>A2zT(kF5|IC^Ne|k5-K`Ov##(& zYA8~a)X~9YOLD8@j6c1Lx_^en@X{F-u0a^k8;o329@G_h>5*577wV7cYljDOHU9A5znXNC zja!GZ%IVgOjVU~7qKN$&VY?H;Z;`3}qcFgj!8fb!kdx2u#5!8?&=o8^w@l}=wZ=|Y zQUX53+~;OSD>uOqJ2=b#;My4x*crG9<{(nbKhH}{t04ibJ7&FbCoj^X%?ZCl{a4vJ zyyJRAR%F8y_MI1T?!DwQsa%QK6{8mv_o?jBIP8v!!E3PDe==V1lryw76!Wf24jn-q z%%e1S&22hI^_Hw$z||H-mzl!@$G9zdlST2Ht3SE00}#P$qUoH0sh9FGVEpZ1yGNVV zYj08A58QP`|BmqGC~71b;BU(mRvKH+{q@jQ6sy(+UgPyAhtGv1yru{7qqgJ~O{jMP z_-ICfFme^L5!)^_m}9vphFIH0Yqhir#s4|jl&!>7N%}2F#JtHUuW0%a^_N+6*cPV1 zJt7jdX7Mk@QvKsPcS~g)xn(bb3%SKQrPjJ&AdxL7A?-H_5-peU*GB^YuT=H~Y=~TN}ApLL6q@D^Wep?bYXmZH5_@rh7Dwq+SVAEr4) z@Of6d`A9I$GvmIlgqYSwf$r)rRxUu8aeRl;xyjL*en$8<3DImu#ECTtR$Xa_C1+*; zNHil*_ErFp>CS=C&)VR@iUH7JX@b4HnVHzZ-hW|Pg5Xe;$(kI(Y;Pmcov%zJrcLFG zVtQ7_YClAe6F>F-^_3VoXs3`ss44fJfvX+k{RVGxsy*Jw@R30Gf*e!IWzB~PaBk93 z0IL$wf*CmXhWoO6U894!ERxfp*^<@4E)M!VVn2@;tg=H<5{OGGX;8L^5LxUUCiNN) zON5_@ewkiwK9e-`U_JtJ$&p73x^@RBz?;~oX(CtOJPh-lD`82EDHq^?hq6k*u0rb0 zlon*Y|WGFR}RlQSR>DVkmS+L-~IZV zK4DWwuAwguQlzzBU>gU_MWk$|_d<3XIkwO7w*hbL4>ob)P1{&}cKI*WmGN8?%57Ty zzBc8nMcmRv*fGL<&DLs7_CFcyecC45OOm@3#in)I$Zypwn_aH`Bx20i6V#p*mZ~Cj z=WD12HC~My)%cqUt(w@aj+C*s#r21h#feqToa+ge?O0?aP{y)ETonYKxW7jU;lRZ# zf{a*`IoW1OM#L&yc;p^q$WJ&%5*PQ}BjkqGLp?J0H3m*GfhokT^4V&R#!_(U8f~#go_ZW;WjY*08}usa82BXIml(=TaQ%Ql?F7Q@ z<|(>HIJO#?J26r)YmY|OA}}YE-7C(H#qOF|{*{Xo+I09Nqd$j5xD#~Cd77yf*UoTH z;7*|7h;iZ=I(&GEYn>!nKuScggISn&L!LC_ORGoHpw4-|P0U&B@Gkvb~y}(m9*u z)DOJ+_J+1tQ#$dL-M;?Z`U$?@|JJ^K{>Tr-2WLllw2<|My06SX!nk8fpQ38F%uW^#tX4ol zio~Mk#^$Q&&l>b90@V`fdYC0GM1>th(6`Y$C?-IZK?vreI%*lvj}vJnq6H)${g!^ z=rwRO=8@nuvelBL!PTyx+KeQW1ixrL6WY*Pgw%+TA{Pc~*fcwH))4v&DAU4%GLk~X zq=GosAl>J;8|c~?)&FHjIWJCyj|6II5`~k5hdf7@(&~g7oi!2Tr8!u)H;yifvxh9x z!?>oS;1|DRXsK~HxUw|luaDPDGgvT4IKHScJ4p%EUzzhuL|im4Un#hnXrp(D z)<-XYO#QB;#xfY63J*zLQxwIv`%~lnFF5kjIngESTuun3`rlWHM8lGloEfK~2U3y= z_(6mV*-L+!+(A{c$kN`>atTfT&ckm^ZWa#hcyl5t%BvWCqSeXvJjb}i4(Sn@Proe7 z+;q`Of|B1l*pqN);G1)C(Ixu3j36H7W9H;)IRUJMUS5?U%^{wex65?YBGg$(>uMJJ z05*triZ@AQ=t=v|Xn7|VYnu}0{>v#I3>m5$(D6ceVJ8-kw4f?j_MyFVC(bsP{J?pQ z^nI#)e^VBdgz>55c5L4yV{*+SQu+-#Oc#>(;~_4LK_kT}9ygBVawrnGkN9E}-M45m z7V$zgZ#tihI@DxU@qK1Sr^zF;W^y7)UgZ``{hNfmNF5<)xGtL=JT_j?f0%8{eYtQS zt9_kK1*|`4Mh#dZO<*ZUtr6&P1%{)a7^y+)$=`k`egGkqWBuU2y%{e!U$%Qf-Wg@M z=>R2a>wVA^RFv;QU6dceB*GLi*OsWAKa+g&^ZpDQCCVu{a1T>~n zO%vJ!(U`SLQ35`jNm3M>aa2z%t4UTuY~pRG>st$JVmen^$F2>1qpwU*Ng z$1ll61L`#C85e>+npcAr09z-Yt6!oAo2}aj=Y=XQZSKMVcMfFu21?s}Ri2b}obGs$ zm}r&E%?a6zBWFegfg z@UXeSy=05(82vOx)*mEPUeDUDd;VonxCJErl(uap1QTA>u?MPRCkIMx#_ya75$Pob zi&F}%&H>rzH~8lFGL)24G``HVfp;(|xmea^2oKV=s+`ER*pDU!!?an6lIv`};2gERm){8u zVDQO|?dZ&X?!XK7TE8OK-Bk$=J87ToADNV0OwawGkdyXU(*TnfDH1&-{vkydU4V}5@M z8`*Z8FT}p^F{v%x0NFx>e$i|BgScxQsf-n0C|8UX=(v$p)t<(W1-i9v1N<7qpYY{ z?HF3;PO)LPSZV??%Zw;!cM?YclWJ)F={-lJlK#x}&%K{NnUX5*G0~8hC2o1RKLK9+ z??xzd6{ey)LTI`fTt<#y6#I1Ie^z=fV*}7cV*y_xpx2w>!|4E_mGY+nEY^+#r4|rE z;v_&fGfw}%*F=DJ9Pn!4zwRh9CuV~K;!(2iM~xMNReJjmqR%hVkVQ1k{KH0#K)64q zSX(2Bo+YM^Fru`|N))akW@@%0CzQ#QNjx!1tS#2m8&Q=86Z8}3tE=}d<4$XLV#)?P z*cmRM5%tNObFiL21clXO%g zv$}PkPzLljmWRIs3}Cj#VYpRg_5QWvbyAzVkCr$A7uqTU{%|%2&r5BQn z!2z3fxoo9Gc0m>d?vt$t44RgMu4nC?LzJa6Q;`zp=FVMbi_sfuFZEP0BY&KH1!J^W z-|T{qdX%hzcHgNR=bv?QwtBvQ5w{!nnCR7m^)E8tC=MCsD^5FuMAa zy`xQD={4@)zq_P_^+tx=q4fZnZ82uHgIa8+(iRVvT+Bj~cap3i=N!zKjm-5qX%>$3 zVvx*&n|_MRpL!D=-z72yRyPlB-|(DQwL#STU&3itgyWM5plS64SI#WXCOQtdq~-!G zk4{4x?KPMVBw1FD_BHSa*TX^8G=+b?L3+9n>uOisw>Bfqcv&H~ipj2#W}Yq1bwj>G zX<7*!u8j)nV;{Zw@85|HZ}6+R%=cU4GNup0;n{qfIerIf`ll4tX9PhE+I+}(9xzzi ztQK+F0a+d&=BecbuC2gX8a)A0hocA-(&0MzmBmVt8v6<|uyLB4wJ9}Ga{tE0N>bvw zF-w&i3%9XXXLXy%ciD%BGx@bNr%2Lgm(Nw)gv;!}nyX=XO^8_+P<0QV zY#qs*p;>~bNf^OdQ#Rel5_DUD;?^d#BsJ8klva)p!PCjb*21xKJm*=0I5_L?DzRo`^F8c12?5&k67#a>)^1U9kR(aXEL?QCfF zlA|z~_K`SKF0#CV^gt?7(*%{CTz~;9TGPOxB99Cg2+S>%!J!r_{K49anfK>ruKgoN zes$q7j_#ZpNR$O%vVG3(rjLPkzg$YJ7P!0*<<4UHhvmg~pcy!JJGEaDc;LFy59krm zutH#nH!M*#9G)wa%$%Y?aLbc_h}C+4b2Sy^b8CDFen{EbH=>s#SQ$qegmgwFrQi^3ZrkdXU@U{?9DKUzi98^mW)-qR2WAuN{h%PyD;f2Pk5guF_TbL7DZM@D_&H&gssZXZZGPUA1Sk~zT9T4+xu-m5l9t&852H+uDuvdl&9y$Cg0_`Jl zMS^v-TG+3|w|v_WPNUU4)e*b{vzLWL5FiaO1Gg-C zf@{~G(Ev+jhUXM71phfeTZYx&zV!2G`tvi__+R2De+K*h7o_7qCK_F$WvxIMe}!z9 zcg(riJYR@X&^BQ>oy-*~{Q3X^cy-{cjb;cKV)$txegc0g7E5Yhh#oW8^-tbU&RqXv z_s2MZ^9j-F&r_4bLoZ2TzGT_Gwa`uD#pq}fOYY)vJO#~Z z#?cwfZ~(i5qKW?MO}3pZr9G&uD8gWSx|LfD*p0FG1FX>SS_e+5gK+mYq%Y6QQSW9s zf9c-bNS(O#c&?A_31I4Ckb(8X3pK9=p|APRAS9&Ge0+A{cp-x3Qi3EBNqhSJ=g}O5 z&WVUZ0s-~?By$q}*LUUr32J_K!dXK5QcLN6GR+>0Fp}8{2UR3Nxn+s{m9Zj;&F(wo zC=8FPE{)@nxKz{7DK*&{tOR4D3{@a<$n^ zL!D5KHO%~6<2tj?ee8X_abDZ=`s@d^@i&&mdbkRv5|5m9(7pl`+qxcAl>=L)O{kz~ zuL(vzcsoWQFvgL4+MFYjv!3U73OOrJaOuzjv!TZiv+5;1BzNBfo_+@dTegQHMbFY5 zx))iVzS3QEs8;nuY{(9+Y=m|jMqBQoksnQfayY$MBnfSpJBBSv>PP$M$m)>7YV zDESmnp(Tv6aK&U4W|B-vWDGdKKKLRc28jwhyVNC%K|xLN1O zx$c6wnQ{OFVRV#Lwj#M76<-fu8i$1(VPqRen<`a742^p(}S&-z(`y>|HS9dWH}Jx3$WED9zC|ekUB)G;B;B z>c(G`H-y5UWS~UFK7pFfN+i_6^RZiu7h+Tk#0TWu03Xk3#JO!hfak~aH$SkH3pn`SekRySu3?NPOG3j zDDJ5$;1H8-8%~gLNdkCa2fkqY?Jw8 zJ^?lPB8&B-Dw!QIo5SF!tY`UdM7!2}MTkO0%jk7aJov#_aoWDbl=qp2+3aA@3cT~| zi0iB(dyXS{?8?+Qa*CDDDIo?cTFs#k%<}iwKuVgpr?E-w?0h|JZG9vLZB(+2SAR2Z zNe_%sDemI>)8+cnP3J6EZ6PAJ%SKRU`WBb|Kp(N0(7p>E=qUBdEC8~PC0 zgq%KFB}zpyo>PpD6x#0dvvuyxiF)76YQ;YMhu}!2yY$FRo08gTm$O|4H>#vro|92XtjxZB?14ZzNlE*w?_Ud=>9F zM>y%injbPU6q9^DO~cAube3u|CZbg5GgMC4E?ZD7uXam=*l1%=B0lE`-ur--vgQknJ`{>xcXzV*|*8P{>u-35A zx97C}-pF!juO#||b)hrR6x)s#it&mLl~O)=f#_FZ0=xq6j8|)_WeepGXia)4z))Z| z^J|~;TJjXZ+zzP^C6WYP+hL4YtK;G=9a#D!$Fp>?+QEF;Cq+w3xsqB`#2RQrt(toT zdzpbE&SiVWfymE0x|G{^qOIg2P9j4--o2@5La|ukK$DyNb84{O+8K+&e@7K?-!UD_ zK9oV?>=$60)rqa@o8X|&fcSU0WJhE5@gC7p=5-|f+>*X{m6SE`{tR056Tl$o*CA{z zYj(Nfb>R-m$d`Q(76;GhB3-bO46?;GkXcu{kBrJoHTO{)!h zKEaCc|38$yV~`|qxb8VKZQGb>+qP}nw(ag}+qP}Ht1)fcwyo*ybG3U;?A;q%kyR1( zAwOisADQp_{GMkp{_p66prRm|m7?J`du$Df1eDb?_xbBDlsm&905zwf;8H#e@I~R^ z2=7QK4HGg*JgVfKjv%`yq{jKd6#txdXIL54xXq>XEBH~$-omK^>O2Be=ncq}%#{PY z@?CCQ@yF>#!c&ip7m4B=o(XFAWAnr0LKuwIxN8H5TD(Z}??mx8d)P$hr7`seWBI7T zT^)e3%8e0j>U+>Z?#_U7@XKnLxKw*wTZro_)YxH$qK^cw9@4U3CHs=rqBgZWf*!9j z!Fqid1QZENEF5v)uoRs6Q*Xr?8KnV9%AED3Z?FS5_1?}uNH6h=*obVwSObLMgi2$(OoyaOl- zJ^l8fsDs@R7cZ?5xBt8akE38h*M8$YPv6nL#Q)nZSjNQJ+|HPo;lD!%(aJh<|6v3< zpF*pHVcw5W1_=g}g06ws`zjxlz?^ShwmVd6!qpOF(z>b>_BCS8Y#9|^aN95T`$J~f z-K+z>(561Kg~@H2=Xs*r?D>6~PVXo6p6oB|5|@X)z!+*rPSdz$g}$no$iG%;^ZJ(R z`e6_(yJp8&!>rbB(@j|s#}N@49+q!CCMiCZgFzWu8iWT8_QG{z^zrBL*{h~u)$M3g z^mPQdJ?*`%!0yl`*=)ifoEn?ORvNj#KA2GwNU)-_4sETft=_rwtnIr2B7`?E!oi|+C$lgRrvQh-)8k0u2a*uqVHSc##I zQ%doBE4T=l2KghhFug}T3ashd92N9Tf1 z&Ap4&?KkIo&7I%MFZB{{+jb=0}FTQZIJJw}jf%eG|Zm&ib>bsoh zHP2jHQ?=~#{p!2s1sohAn+-Ns^Mwp@2qR+-DSivtj80k8n8?H)RLuOe&#{BD=wX#j z6^c5>;%=-u@0kWZ#wWqEFbO|Xq$SyAyog2hKzvXyOBX2#oqu}v+#peZLB&5eMe6(e z?gM^$g%DTEu_=ffK+02%4xey_D-oz6DFjO%^7;FSHra=*5O_i#5=rX(T5%#?jpQ>| zqFF-~nIc~^h;lB8ZY}naXsYF$DREGpjcHl%6viq3YD&_`_zcN+Z77WJlXs2o7Dez1 z0`-bSdXilnWyaEUnalscuW*DnDl*I}U=H|=Ig9EkXpuAM!4ghg5~g)0X0A9X_v^k5 zRqo^0e;)AC*#24k-z+5L_jBj}alkYF_W_@*GHtgYis{qnx)gm*Vj-AU1mN#zdMDbM zL=apD$U}m*Y{DhY{OKRP)g1LV5^F&bnED{;R_0N)6j}sHl@$3Ep2M%q^SFKT(|tc0 z8I@$*wYs?%tM?nQd7g~Q?fLh~;Lose0)Sfoep*Y55|xfJoET)EN@EX(Ld#~k1?yqH zMI(ii#$q?q*Zh-7JsT;@ zt*MPTV>S>%Hlvalz}DK*a3aE%Et1Q_(>&wy0Y;Wk(Y;tsh4M?41+vS0*llmc=-yo_ z{ezt6aLI%^(X;JJC5Ro7y}h)#onF(yJ4QLLgeQIA+t{n5QhEQa!CDgbilY9JlVn*n zwYYCql|JAq$%Piyb;6A^dU*2Y-TBI^vWp8$08U|3%xuJm^bSn2lR=@)va>4A2dI_c zuqSd~nWJS?Bsz#Aec`>=_Ix&FsYw8$2a|Tct9jtrsHk$$=ZYu0?XvW3rsBBsW%l?OcAsE{oY_yvt}hYQ76yqgl3x1G8OVnrCYOuLh^xXpgt;Aksq1 z=Tuf?vkjGUVHN4d!)74zEGOzKV8R^*8g*GVW2>8Xtokj=MPDx3*1yd#ug!VKg3nu3gJThxxJlW-uf*t&QV&YvEJ|G|}PBb)30|36bW2m(#`-0kpjwpBU z$vKCSUE7KAuG zb@O(G$5_}1Ue81L_UWHugl)&+UCpx@SnmZX7;@V2EDXik{ZpyXtXPxN4Z~3Ofl}%c ztbM@|;kCJyJ2TAs;DEh-L+wypds52J<@RyTi%NWn>XF{!Ba;;hxOV#6B|7yd^CdQf zC26iag<+y}>UzcEf#FO7g4GYb*Xg)1+wQ-RZn>{c)6n0YM2>ILjqv}l<@^uIP2-z# zdwl%rN#C3>W#S;<7ytG17XTL^m88UhEKHyuh}$0|(*PJUX4~BS(23vN0ygcL zq-wzfMfg~=;;Cv=+45K+c4<((=J{vjt9yH5%9b?~=yyIcG4U_v`Mu}8`?uV0-y4G; zO3nSJGZsDE=$K72;#dcXyQCh> z;}z&0FL0XI`Kolov)~#nf+Zk#%?v?Pd8{5yhS1qGmD5PW)5*1VV+zL}7F0e`zBzQUFn|d{jRu*X9vUMI=+8*w3&SAV z+kzC@$2k+{_Rt=ppmDg4fk>27$ybNu&>Gg0PF?CkD!2|&*_WKun&NA(Q-}v4f_9yh zOGL_L53EgS5AExG9OD;Jj}2lcHm?)0yM1&Jwb2@_!x0-sr%vxrb`Y{z(bx8QDZcz% z&-&mi`V-mob&|B&gpq03w|0z6bUwGyWs5s?g4oXBaxccRxU1yiXOo%FCaonGsA?W? zo<9rEV;eztD`qovkVkv^Grx6bjv|FWkOVcAw8~y#|NYf#m~9%HJs9A zTlg^H>=b%2AhbR*p_p{|q2Cx>;!N7c` zPa3#zr-`7_%~p@_+R<&%o4cf1AC)|kj(`!6_>eL>Z1W=_oYxujuQz^rL^wd;z>j=) z8#-=kc+tS9&6B8?>SUp%C&Cg73Np{c=mIK5tOYDBkT2JOjU?#^_+i0zP7k zMv-zSC=(E483 zuqnSlX&ljm@J_I(yIR;=_IP7aPfOXE6TAIo2A1=i`aS&NIRE&PWhSKAz3MS+v&k|* zick({gciy>k++Thj%mnI1rUd=%vx;lD^o%*63NH_Wwr8tTBPu`hCuT5;n3~l(hOk%k4Or0_g)Ct=X0&CK^M6kAwN2&mI zJXc89WE%89O_WSe@ar9Z8weK;BM(9EqePq`C>8Z<^aU)JM!GXQxZu_s4gX0aaErGD82kO#Sn zab{+MnJ7&dtekd)4%6WIt`jUbSg-rwK}|d|d;i4L>Z{qJO1OYg_Hr529N+J7%^Q zwY$py`*8Kdnh*l-cmG2zJZ(dIBwA0kv#{d-MK(2u{o{V+w+RzBSY3xot( zCdMK9GlkkR8uJbguxA(M2Dv)u4(E{&4{hM7E+WurV| z@74JYdt}s*E_GZ8RGBkcP-(O2ZT6mYFz-B!M2H5mN9BkDX)|Jb=cF0KsAvg|%t!Ir zioBhKT>*O9U=Zy%hNMLQ$Z@2(d8H0a70f_UAeb(32i4Dq>Y0{82Uu`V0WAWt^*?K1 zg@4T=j{AA*bp@X2P z@BAex9NIpLeN!Rd{Z&kjRI?osouf+YhhE8i{Eg7SKHBbZt^x6E7BZM=6lqwiFNhTZ z4%M$@Sikud6!~#EKsfX5S#0{yF)nP$Zuo{t~@IMx>vze{}xj z_0r^pRw}KrTd6KP0pOaPyk;l1iswuWyv&F-=MLz0sb`MtC~ifh)`Yl`p;_O9Yq!Vu z(Gqowm)kb!PZ8X=iumSor9HE^=uc%l$BSCQc5}Ui)G?r2-`A`=|3sb9xKZ2Pg9WNq z`HU2~o$>^2v7ORA{KUW{{Y3i>mC!r7e@*%cLYL`|$$gto@5Ru9^&pqXTi}=eP|yDX zUz9vZqGe;*qR>B<#eLPqzX9B(M^{hBB=;jbDpqJt7-?KOHw6WJp7R>PXfDL_-pN#~1eC40y3_s0_#sFnyoec z=A78?o(%h5wXJ*Kyyr|3i|JHOx6&H%9qOka-6~Uzi(s=2k55_n@dDX!i9o*()%ZGJ z{#4sf;*5X|^MmzO=KeV4N2*ll3flVkBd$Z=J;?$6CsIFk=&eHozev5gys|#v`sI1F zEg7>gFhIXja?EH9{dvS+nd0XNf2eb(Qy5lFk{ynBJm;4wMRU*@OB*%G(#xZ}jlL6^ zl*a}CRRX4P%SPScY9w*i%%>!M;VOnL6sXUViAcsG?UO-Vl@#fbW|Q?$18Qnq__*og z?w0Ci9XD!yrcj~n>S^S;W$L2~-kMMB#`Yq$PLCnnZm5r@?sc^Za{t$^Owjx!-3gxN zSPNS-Bh9>Wb5)0!lkG~w9%( zchPWdbHCu{V0Hjj<3^dY)d%-vzJ8LFv_j{`L5PpQ6;e>OK#N$5LA#56!i2?FH{atX zE}W7B)65l&orCtk6!fa9wR4D)TBR$R|LBYZt-rMS9J~Jw&A;MZ?|=K~{62o`zIx`p zbPd}W>(^2XTyofik4HJ;(N1#3TO0Zu&b3E;wEWrI+xxv%i*J%e`|mG5r@yo8So+~o z<<}v6WIPOJ@!QTS#-96hTw2#!vvW0~@NS4es{ac7;CfMOZ-!ak_3RT6fv1gD!)g1; zcBd=D$@$)OeNVT_5j-tUMYjf5*yYZ~efVZul&a?3zaAX5Nq;##vH6#huJ^Y_XS`2r zkQp=g$Ht)Zl(8-=Qx6R$pppKUnbEH)1C88Fe+OvaLGrvFP?~Z&fy)2*G7V|jS4Q8m zZXF-FJ@Ot@QCtgN;UCZ}9y1mR%-@wm zXwmy+p%u#Xdizmh_y}2M!JQf${~gw(%YzBlmfZ_#&Vn->i#B6VbLDi*f4zG838u;doQ_t=ogOon>o!&BfBDJ>tw`rkOHv24o5?wqR8X>cl#n9YX zcNsCd2(O zGurt`@qu#-W37v;CCyUVlY1se+@?z0xgJQ&^VaQC=;i37;mTDmqK6=9Sc#U!-pa$% z4OyqTQCCE$`$jPmx%OGFt-w}$3y1Sv^N+TO%puINgsxZ$M5%iT966R=u*wzR(;8ya z9!dRS8x-Ppsd~0)`9Xhct@Pp)H{wx16DZ>dgbY z7QWGDGqiI8h3eE<{ZRL92nu6Dx1qwy6lPunMA zyPOoqdzcvaKwQ?r4M~qi_5KSNr@<66j0TEnRgdN}`%REEphgS1ESFp$93BkaBv3yi zcD9MW-&qPTJb8~z(olD49*!~_nX418={wzPvQ)w{7f)_WH=ZjSl8r`!KldolFFYuC zDd@4lxUyQVzeDBpBW1+*81l=~SL&i_!Hf)|Zx`xk9gI^ekqwT6u16`oEjy4zY?fl? zgc)_7GbsUKzZ~oEz)e_jg8FkS#xR)`Ia+CuDu%;EkZ*AA08!PMU*b@OtSNVJomgF4 zKS)avDRK&p!Cs2$krsD+R%31-AGftAP%6O#*^ym)dOHAx(%rW~)7+u{{;wVt2MYc; zAI5^p?SY^~@v?z%a3ZmZn@Z1kv#bo`G*|2eI$AsGvJ(fqe;|1gqGTC}5qT7Jgg&;5 zA-c_gASa4T6BwK`y6XI@dA<`;iIY8kcIdrDWx|AZigrHUHcQr2Lc`pF;6%fSs#E+e zHU=AED~xr!%FW4dWtR^ztvMPD z(!a{@+8x-m<52VY6%mD$aLv|7M;4lb#lWs7S`XWyiu?%?6@6p@^yil?`tM8$}d zVn>>YE0pP6F?$Rx@K*)<~kGZaK}_6}6)dvo_W53E_AO4qJ%Bkl;Hg>PJ=LjSJ;Xcja2A)V| zGxaV@{jvhS5)WBNtJ-JG1K8~pc)JjM?JuV6Et_e10zXXrO}}Ll=+?f|{FK#%^Ej1b z@KHghj8n?(4{o*m?(ivXVD#(KBnRI(2VW40C(z-6yyVX7+Z-F)6J-39hIwus@`g+J znjM}u@XCV3AT-7!-tk_Y`dnioB!MEram=7p|&&08BAom+8(Fqg0 ze6A7Ud%rSmTj{KtbtnX$+k_ETm)UZ~J?`YBQj7T6dF@N)+&uS3cCT~H&CnD4?i|Qw zq95XG!_)7V8Ph8r-I1rj4A7&t#LA7JAZn)x{(+I12)I21ZFr05=VcP_s3vRXb+wp+N*Iq|>Wceo8GScaDH`J(jdlb26n! z_<|L#>VF(8coE?*7=99{bVf|k^%-!fWS{hmaNdN6FPOS-<-l8AF4O5U zLy}vrGD9LWg!z(OweJD6cG?;K`}mq5pqgwNWRhTQ(&O}C02#-Y)v*LC(r$^DenlnA z3u)t4?pcfp&c_SIwfTA1985lIDPKb)NiIN%`vZ;D-#g@~ol$p}15Yz%3`Xx}AypQ& zqM0fI*MVBbBbEDXpSyBQtkO&+YobCu+}cJ(Fg<=B*UR6^F7gPcg=PVot>w`SM$O42 zFAW=T-cj+1dF|dhyw$bM8ZmDuplM2l49b9n6;+fzxjj9n7pq;325gG9{%3<(+}sEQ zpw~F>qo#?%uAaZW)piYfPP!X$+KBM*st)Q}npLNPrwl-I^15rkd*Vu3(#g3H!kla{ z>XbW94z*vY8Btvwa?KfBE7iAW=hX?`1Z)^+OnOxHRsWr#6|c+Sh7i&ftl5#|0@kd@ z_>2E*h3||_N7DIi6r8+bkU)h$)Isu=MM!mnp^Pd~5~m`f^whUpCu4-+Rl8?fnxSwi z-I+z;6H1^HOt8jct+Wj!_LW=q-C0?r*Y(Ksp>mFbbA`m{&FD~xTqIihyLdZByN@Uh za;~m9gibWb9Ur;T66|fB`X^eEyXr)6UJ)M0)&~Pe;@-DSr}N@ArTYfutl|Q@s9}sk zppE`?z_VQViAc_tMYFSx!0c_Z!Q(g{<55RK6<99RiI=`6+p^8IYUvx3zNV8_x*4?J z>@}OW8JgH$s8@aIAPBSk>Yk{D&$dh&tX1Wc8zi0i=sBVfjS@jhE67UPxlwrG7|U=lvO1G1Zo`~Z9u-19UVe#l z*|QZPc@8D2jXf#vowv6uj(~G zYzxNJ6PmlCUt(IW7v4mgZnB`1GuwIb^hQq3w`1|F=$iXZGioPpEU@X95nTbNEB-3> zwXdopYrqo)*R+{6iJpF->kpLlFUw2FlE$c`Gi*y2ym1!{>__IRWw@qOeCyeHhy0uX zDrXe76Wxt+vt3^v9E9_Bcj;-RJ>BWKH}qvzWV5;Y;PENLD}QeFm_O0-47Kr{M$lqL@-b=kueFhlB14M)SPDwD?U2nMih zlHk#LeVc;&}nI(46h1af$S9nOjn^t&)M?dq#0%>AlQo-Q)**3Gp;R@5eR&B;1y zCXdB@j0) zuoU~zjVjMtibPfD1Y2~Y^54XhP73LDe@9EaVd7TD4*l}smYo~7ui*Vj^U`Pb#^Xx z`ZNTQ!tGN%@F+0ail(XJZ{n5Y;_Hzz$ly-nLr>F9q-0K$lZ?I^Hc2*I3y<0@6CIj{ znIh%+>qrxBb|dzy-MR^JT`Kr%7adrSJT@|Dy>drH)zbsiKJZ>U+SIeLL(uqE3syVxR`nWu_!y^= z4#mE|Y8K@NA3gD|=2DGvxBBqgeodcK-A434*PfH@U%zR7DDjD;^Fu(iX^_hoD`0ya z6L-43uq+>^lx_vDGRLD71&p}=V>xUrykS;p6lmK47Bfp+u0%n~s47F>;*gd39$-$2 zF$b5dEdnsZ3Iyhr`BU2qFZ{WFW2yG>L@BhmNVDh7(PaOHdj2zfcTZ0VmqEM5c@m~f z2##kn!_XxGtvpF9YFfuJDXs9U({&xLgfb-Yu6}C(E#kMX4^OA6)ig5uh)|=sYXpuY z&Fern^=(GX(Msm=Ts;Nr{0~+pv61p)Zf}%1l8$=VB|kDvx-kKo!;<28L{IH*7zW9$ zFNpu#%l_3O(sl4HD+T@bX8qrDd5R{s1~w*+|4Y50v~K(D?#rXq>AH`-m*SOAECW&m zzwie?@@>WuN%2RyNWA;TN~LRLqo{7@o?qM!7E~E1^6x$|0@LiW!(dD;{OPFJ>8$k4 z&&T(7xgQAitNuYM2(-2x<{ou*rqUxr9g#JW>#(v8UG=aPclIZKO*}8D9Mt}9MO~dug;fs*z#&5+BYG28VC+_}4dT<`JGv6{> z;9$Z2b1D|@$#kp+3$|)Jcm5qmd97}#aZ#l4k+Qqmn{;VUvk%>*5=(z~EQT^H%acW_ zRG}CN7`!ku!H+DRdsyIB>hKthblG$bHQm5kbd~E~OdrCm>QXlL zGOdX{f13KDiG8P?Hq5t(Z92a(pC_>Iuls=xYC7l4dUT=zkXv;+uu-yR)Lr?4M$gf| zath{3H4=jG?Q%nMkR->-L^qiM|Uh(jU< z-wO40ln)9ke<|f~m96B8lHkh4?d3W_JDg<)5UGRe84QTT@dE2idYHCgF4_J6f^RBH zI2%2DYka)E^IjSMw++|-IZXbWi|_yZ^FI_n$ttIc^YWgg3s+CScTy<;`e^{GPcNN>FZxR;0Waku46vc(pf?19RtQUA2XrnJ zq8!F*D(|wfu7-@Xg9%+}GJ!JVoYqlmgZ;b@>8^I7I$klAoxVJ)8Gno#AAdR79+q&- z`Yz998qau9F+`bQ1WYI!`bSmy#YuWh1aR4!E+2nNs3gb>=no5Vu0I z=i`JWfoRO;=E9OgfDj4pxf@J5Woe7FVI?@GG?HWN9EnLM3W@#T5RQrYDymZwq3#Kx zX(uZkJ35+z2pveF^N zqvK=ni|6CCdg3XxRR2(Hv_&gvn1rB4Y1Gi)VQ)~~WPoC0*~jg;&3@&7a0MABJ~8$l z0CZ1y;{}OZvDoC0>OS4vXb)@3C$_>U617My5?x7veILF4z3se<*EG{N1SIf?&~st7 zRQa}mOn*5EJLiSjKrItJJw*PvobnzJP}043{ddR~{DL!-K(7QI;W8KZ`YKFzf6uV9 z>97a5q$Cyy$nle(e4bp&5j~NVhj7@*t>%hb`8pm5IGr@w!2d08&=~KH4U6{aUsA}zvqzEw@!}l|KA+?Z*$4Q)=b90-u{2W(b>vc{~@9KCkvy~sbdai zXC5Dk<|WXAs!(?pL@b;z0D`9LjopHxZsC@>S^ZMz-3J=~vQrt(H|B1-Y8VZ!)i^rE z!SpRv=Soe#=IikWs{@o`Uy;NM%ZA3hOJJtW3%KVI#Rg7UDoBvP-DBe;Blibf9;35R zBSxjlEOTz8#F$IOF2aq(Z)qyM^gKY_vy9uM4_LU@Y|`Ug%WPwqZeqmy)GW7;^-Wuk z!0RGTeEf+C))|<|SdRlZPr4qcmNt`hFB{g5av8BKBTwq=u1dzThAM*tW)b^cpV&k? zt54J*AT!@L(@$fs$MvP~ZN`1p5!#?_N1z~Yy$yoCXl6;RKjTx6TVx{3Gj(b`wKNw6 z{Yi;(ut3u)=Zt{k`+GRmAuU>`BW&S)af4>au_Kj zK0QB8SaUx|%2ZXJoj#j_Ic|Q~R1P~6DJuiA`)PrhzGnPf4M9Ql+629`$AbnLxlq}^ z;l_-WYc(S7rQ-Wl{>9d}1Y-L6>r(p&R=r@|##Rl{*E}siRTD|n+DE$t`7B(yY$%7d z1&2eLq^r54Q0Dw`4a{eP^=tE&C?i_C__nX*-x$t@+=~kz@|aBNF-VJ%Di!CZqiAC? zUxl_RZF9t(Q%frxOF0vtfmb9Jx;S^}= z8WMF?j68rF{?|BSGV?s+bGYwi|Id#f--*OOjO=Xa3~Y@Z?JSJxjNR#+oDAr`!IS^F z(*Hk~{r|4I$ySGQSN^6grZW#GySl3427eY%|7_^5LkR@P#EByl3J|uzCqiIJnC?x0 zBAu%`SX7oRY8JYj7Sy{s8HE*?SE`)bR!g1F4K2~OST@^|&p2&mN|TOCGycW6;(Fe4 zn);T+e|5X%aK7~M{%AZ^M&olcLh~h<)S26;&WC^gj-RbG;J#9-*9wAp{;MrLgb$~o zTB$w5D6Qhx&( z#U7$VjSVkO*f}FGb6w<{+y6mgBwmd-{H4Oy9kQDH&;|a!>5#XB+|C@hOJVj~xFP${ z82(2%xlZ_`mj03{-c`7Fjr}jcuj7`ktI~k>A5F`rn6!@^?046>Hv9l$?nABPH}qqC z#FvG71jOJ=EQ@!boXHClT&_`Xlu!Pi6dHswF7bEUQ0QN^Rdil05YnlY7L$2keBCEL z42j?%4JBYF1zgXpbb^Z&ip#*Tn{Q$F5ljo1&tKW<(#eK=>yb&+W6~quXIG*9ckW+} z{R*V0NSX^`Ne;6*HSXENn^1L#TXj7NVmS8hkt}e!Km#w|M$}lxyxG7RS#&XXcm3$z zRRrX6OQlC#s}acr-_1#1>RUbojRQy*;)szoGSs0*)>fxF0!!OtS;Ee~ z^Yr&*5sCh-MgWZ-u8ENmbs}JdhD_1f4ddv#FQ-KjM{9Nv@~NsU?Ze9 zr(#-8(nlJGJJylStV0{;Oicgv(HoQZy8i33dQw4;eGJRm^~FjwS3V7Ot9ZBW`oeQc zh~ZB|;nbeJH9UZbS^@`31jNnV)oh#AtW=T75Zbg+;a@ebl2T-ZP?QK|ZM2yR?sUkz zrWVSOl7ecg#$#BgwYDdKB0VKDk<2|TJWLn>)hc4|zFLWHW1CG+QLUJmPiyH+tsIUi z)dEHsV6LRq7cs0rkx0jDgSEMeE{?Lt%j%k5-W;&ougJwwyf!S~23+1cwp6IOwRb9` zy1>w`{QH-|CmoS_s$oeo+!G|#a5}vw%DLHT>;!7fxx$$Sr^#a(Kq!cw|RF%^T9ApQIC~uA5oMQR~RR0l-mCQ9 z5QWqTxb=cWsWl#3I1NYAcwLDSz6Ix@(oX~FH(Zn$1 zuvV7OV1W%v$th<|Q7M(qQL>0eDf$Ei`+<0}UPQdWx#_^GOZ)g%nseND55JwXEs4$6$o2W$y@#Psn-`+W+L~ z$A(DQI+P>rlB8k?YN2~x8ZSoxoGIfXaoc3nxZ=e6v;NV~BqbZa*1Y3IjkvU|5HfOS zO(^0bd}`4V6s z@X{OqCc?us*eQO^jUf7cq%W_!V;)Olszsp=8&pY7!6kPS+hGr{EYL>W6@9ynaP$IO z7dxtIPNTpD1=_=1OMDB72UDAg()e*%n5Ufm zG?=(421^K|bOcIsGFlcJsC$I~lz{s(he->UXsTuV%OVvH`H*HkzNqgod1*A0qq7Mf z8~iflk>p)@2pmCnmhODu=Z~ZhqOqG^!xhd>OsNVcsfnc0irVI8KD|m3J+f$6Bnb*$ zC1J-;o2o@|&p&HeTT5h4Doh(N4W!*`q6qB#``4@~@j{6b_;n8pB;C~$hv>2D3KmB= zQRZ4@EO4mAN7aSEhu)7mtX@JA-)wOoDeMoyoVey<*; zzORQvPUmT=_P?HA`;$*{|N8iH{`By;OW0?K{>lwhO5bNLsR_kn{Z~^_wgKlggwIY{ z;VM*Kb`ji23GT9FyF&Ri&}@LP(V5SXK2+3$vnqXLtsn3mmUO;fa@0AgB6sXcsQqIy zIP-`g^vH->#R!_FPr9O?P!nKOj?Q~TW$3H>J97s@TJov1&ZnB5n(EY~Md7eLlx*MU1GYYaJ-D1=DU zQ=X71#}<__mGmJEX9sA`V7p%^Yk)PsP5JP*kd{6Qb(TVDtgD`WrBB{0my%v0aLb)NTwlCWO{yg8jBDHMr z+a*($2g_Eu06VijSWVj>x{2YCALtS%Y;NhjUJ28=D^U?k)Oti5sf{< z?Gcw$Dp}pX!QM3r2@y8j!>0AQNCwp$@nxzGO%t#L*HH;O}o)Fmc&)=Wg*0_XktI1R<6;X)gB9+{Vz5I8d}BiAz3IwMmPU9mhi|%7(^6b zVnL-(!mc`KOXPX&%C~FIgIilj~5yqO*_YZJ6IN<)UoMito1zl5E{&`qA zO5WYS?!#0roejm5)drf{06$>z5>hPH?l0z~PMNBb%#s#hT(N-;vV1Y<@g(VLuM3+z z8U#Oo`lNwuUy9|rSjhV`bz~JJRIJ)Tf*1y`yR5>&Ya_O>Z{ITuX8q71lR@c{r*8eo z0{08E#6!C~O*e57#*S?m&2lrXFKSA6;zYDwC638X|A6w=__DtW9~5BHJ@N_~BR7G6 zK5E!l#Lzr>HI#+zLw96*Q@7^vtk3K5z*Ckoc0ClBVI7bzDd!5yLIc(PT0#e=`O;Ze z%opnFU@dT6ue2R1`a3U;*O>VgQssfcbe^oNL{4Gcw?+-MiJTTQBBV|cKzj&zAs^w; z!wBA)RNtnH6`GkW(I!M8BAp%ukt}(kRB= zz`vWQq9F`#!f;3~HQ9Hy7uW4?ktMXfSKyo4_~955VGU)ZSC_svK`&t4I{cB~gw4VJ zMSL7_i&YbtWQVpjylC2^y07A$c|S9H`bbz~AZfDWfx66ixYuKj z<>^p?Eq+ysVQ~I2;$^~Uf<7LXA|H56}5leB335d+Xp!tf7%_T;eYi4)GC69G%Ls~_>8d>ZZ zMpxMy(|HJ|qMbJKSAlb}!A%5~s+!5AD=Vlg)u>YPq7+7HI)C~7*|8|E75UIdJHXon zW8Dv}gi6gQ#*qY_YB}v`dY7ftNpWMMG&&oll-d`)9`BZ?o#UZ(2g2Hfx9f$#cTja) z)-fMfxISWCc|-P{fn_=ve*emousv+SlY2sSs--{{T@@7eSvX$fmx9q(>seq$TniF`UfIn6aBAI4hHZ zX$#=3Omoo9htJ$6kfvEAc#WGHxpHZ##qa#qj^~VHsh0jal+B7Bm00?@9gb;JAV` zGCS=i56B$%oKQ-+D#jD)-xBnCnyzGp=)L|EKv~-C`YubM&Zadp60N1H>U8Qm&)6LV z%_@R!TGJyZP!^0mDivyhrE|I~06blUP|7NQsy>;=QyN~C7%Bp=8P8qA-Rqly$Z}N- z!Yawlp2+$b4>p;ZJCw6G26 zC*gqI4wvZYXz0CrlX2&SB@Dk8kiuw>2c1A(JKCd}eUET2Y_qWI6oGfcy`fM}`VJ}t z-&+4x8gN}>M%f_NN#<`}DTs%0rJ=1OApPQU6yXZv_3jiccSR@?x$`7?#;7zK;INQX z(9BHd(P|7wbrN`k?Yhf@ExQ+ljh|cs)yZ;#xiAwM%7QyWgpEHagney6yAjHR4Zn+d zo)}W;E&%Li{3Pls+a>AB)AtD2tKIdzP?1-Y4pY&dzcKm{2Ff|;0O1rIAVW0*F`Nr+ zQ?0!;fYbCf2EP)qeQ8yDDt1YI^LNop+(oD}K(T!(p!I;Y%paQkzCp_@ALw@G?kKg5 zl9Rk)+*z;XS4}1+H8Cdx!&|TF>Yei5>9kd~ukYE9*$~xHPV;V_GDW^QS{w%%a+prH zLpIkRVMymDKpmfvy=pLgd^c;9CWBAdRyWZ-m@8{m=TiBlsrRWoDw~w!tmn^gEeWHh zG)thM{CnDE(`h(?Ufm+*ZAeT;%z5(~kaBA;vtrs=W}390>sZKYNr!1Sa@mCKy)W4j z|jJxt6>fsff<57THMz!#WXI6^*s-QG(Jf z>vr0ZW3~Rip;mo(>^`L5qxwMWo9xD`?ycEEF%j8FF>Im!QdA^Bj-<=HTswc24zv4VZ<;|J%K~af!Q5QNn?{! z_LNP*Ma;26Hib>TfI}m7f=pWj6SJEg&QsmtJG}Fy?kJVSveR}%<(e(u)cM0C-R{C; z@JG@ZB&KB4E!<;cAFO>8>4qzHuzXyvS= zT@bG%PR!Ug$^{hD-li(IzpE$i@dYKQt7~_(gMk!|Dv(|^u$tvL)+Bqz6}LY z%A#wEN7%gA23I8gPLU;VUi*)Sqjl2 zB5Z3&(Nfa-{M|QdwJl+aEy5cv-kpjl#EwzSHbvRtbttU3?=IITxmZJ`E8L}aKX+SH z@mwJajvlb&eC$!%oQcv`E{!klfNx4(A=9W5-RD637Kj2+1e)l!Y3NKlNov~}&RO&J znM$RWY2t8l#B@}>HLEecB|BL2_&z@IeZX;z)L**ujw}h8yptu|naw?59DVB5|MU|A z`8S1fZ%dm>j8h6{RbcShR0!C`y#ZpH^5*othhsgT!heKns(ABj?*R$Kd_r<1cS{c# z7iLrdfy<69NpAx0$FPi)PMlO`as59mLxbNEgY&7515|$v35FiVCkFH81lNSKa*Oe9 z@5DOW^)koCL|}1Ry5lDH#9-s^8mo#?1gi7{#~Mi7qe3|giHB?1^$1=5XYM5Q8(7J}9Orq39PPPme0 zGZj#1AvBxw?QajkP?tbYCY&rOx@qV$jNp2~mwV1EDpzf`CV4UDYlK>o{l?^&o8Kfarpaxg!B z(EWd$Cu-s7B8cJTw^SMk6vB zoMfFQbnx$mWbga1vW}m_svEn9&9zYd3DNGY3JaJ%m-V)SP4-B}F;9Q7ogwv4KQcVut3w zb^FX=&-JM>0S0{2)Rd5mu&`GX4^ISKY_n{uNz;&F2f#G#e{U8W~@`j6QueO!ikYjyT$tH=6{ z=%x0E;yR1RlQpr4dkBjmXGjv;6OV^QV}Y|c;p*QLSpRk11?IP5fEnybm`}03II4>( z1MFEe)w5%NE{A11@LyM%c_Z%X6(bLwVBjsj4I-x@xgFqjjAYp14R{dnZ{ea*LA4Y8EEKA_Ylo+ntV?nwuNxlX4B?lAreo2+bl3X;+X} zI}^QgE>RzWV~GBm(+|H$K`CQAhTE7mkcx`y*BzmVs1*>dstzT5~PT!vwmNZMshZD7JZpkC7)b zN;|Vbn>U999ZaUf_>taTYM8C}aU4K)%v8LPZ2qvgW_)a!E>3LkbBkkX#m$7a^7M6i zeOE=dG|l8v`{4QSHCuq1A-0Fyq;%WDrF3C`<7Ke`|uO6T}ZjS%`Miu(5LH1XNo?e1=Z}=v}#w3%{o`c(zA8+vz9IeSPd+wV~JDy8xL}n zbp)tlNmZZQ<{GH6cC&K_s*H(upf3_@nqzA+mT8O7JG#qOaDq%uZ+Uq)T!rfZ+l1ha$oGF%n`BX$E57coO4dr;|oGW z8xlm{Hdta};f^4N+d)$p+-L+%OQatKP3#eqr7#6N$BjT>4p49cYUF#_++MIwZfHhM zuQT&~?ZUpszI(U`zWc0NgP9b90r}V|gObwFaNhZGC^EWEP)n0}KhJRfl>CN+q*RDx z#XC2oYDC2EU~&c+XK{Toi5$X2{RFic>yT%k400_Ag@k0sr^p5&vg0pVM9SIk8pvgW zgR>$Uer&&<3OtgliNLmm`gDD+4VGvtkg_mt+T7zIu@5+q(oI%qA9BO|U-459 z9u&SN@XhrnD!crh&z>w;w|n0#ShvXCBfs?@iC^plH&`cIWI*6+k*y7v$$|rYHgNB{ zJpcROE|rZl6XnlTzxxMp{=b>*|7Q{UpT$J_rSJ$_Y3PzU%K(;#@AW?h2;F^w@oL)@2n4;&YXzjc$*?Qdv zhCdaA3)M+f&Aq&#M2Z%WlVj`64ZalJZenfIPk@^YTy>p%U0rA2^PFt1eSR!^a{R*W zuNW#F+(Is&rI|a$hw?s6v17POumhe$&K&$CHbjn?ouB~mVx=UW_7_IR@2w3(ismER z6O44Yw}3Kx(Il8o-o?e=uRs8}1^Mz*?=vCA0OUbIx9qo|nxHw6m8z8gFrhRTQ4oih zg&k1FF^TXIoUQyFxm?*w{fP;yNy1)`*^++31fSBGxFU_GXKvd9ZvV$IHP1**IBP}5 z3e+;>q=YkBIL!K<$ZQ&0G`Yc6zRI1$fC;kc4CJuL%GR+Wk1JMSabn5`iI*$hEd4L~ z3SK=ybJ0l}$XNpfyYV8?Fp?7*;x+pmzthEtmFpsliM9G&>|)wuu)khRHw%U^ckuwH zanhtkYQDM1GCJWrDCr8r0S*?(a|QS>4W0rO6_Q+IX+_cL@44l8rY(E0#1ZmD39@*5 zXOelNjd4~E*Xo1YdSK)uNx5{YDbi@~^K7n4vT)f3vH5h#4r*15J|~Yl#AuWId>Vmu zo9qXqlz&FQB|N=|m64$Saojl$j<1$4*W4=!;VjC*xCTVD%qYW6k6D2t$%XITz7JzDaU8w>-?}u9$T@zC!^RU02L>^GW0(w0PJd^TUg7h?b++~{!Xy{Oex5{HC zbE{3c*^QRRk=Ao9ik`+jjE3vso3ibn?vxOwT!)8bPwAS^Z@zE|og%+=qzB@B5bS;Ly{(hcv3zn;|#g;}gKJlm=@>z7Hxswlz6iGr>lR*<*$5Oa0>sLN#T zq+V+vy2}k1zD+NTE9M5(CIjUrgTiEYzv>g)_$o)K!A^d(cPRQ3U;7%usgVHjuunhM z6ASq&1LIoFXzdQ8$N|lTYv=G+FYG&tZCwxV+PZjbmAM!Vd@Ls$>9*k8BjPSGorHT* zp*0B<%q=+l0eyU9R%JZ}^@uCt7o)*}hkJmG4Rj>6np8o*^XKDRbD1Xi89E(Svu5W^mM`E#203oQI&X(@ z*mPfhbw@pm^6|u`mxe>Nk4LmVAJ@f>euM{T5S<((H-?36Z9F028ibNOEJuLJ)ZfLjZ}Wd=idtlqHsPGTB%DCVuj`qvLMkI|4J1rg;}42kC%Ti=nar6{q+=6)K zMH*Q$Enq6(GhNkGKehqEdJ~DK5V1u^FXb6+7rbSiYMb&%>w@sKV!k5}opXa>kBY8y zV0druk1(Uig2FCXg^KBPmn!#H1M zf0+8gE$Q|{A2Azc^-9bq6y2hBSyU=43jL$0w+`N15WV7_p5>*f)o(5utL|;H#bI@E zY&D;K`EMv9Tv@%#|Fg3DAH=Y#gqi;^Sr7Nf2xVfHSimGABai3&vLM-O#6^Urme~@G zNF>h7#pkT6Q#%W25Pbp{*_Utwrq^!$wciVJ!@h~cxcx^2n6xl}?0R}~`s-ur>gB(5 zH{2ejRJz(4Rvv{-uc6*xmqz3(M_tx}rHcKZx)c5n-Hj+lt#>^Nhh$=a1>|j}Nb;se zh7$V>h7yS+zsJoC2;)yI=0G^UiIc+)$x@10(k7bPc}Rw@!nnsnYOY_u&#fL&hml~l z_ASaFU%|J1PhO65&gqoFtpJ9F_1aAb}Ug;!^@t8`VMr;eE;Q`W3{7V zLCU;&D(}s5mTm7KV?u`?*Ij`rfs2lbNM@sr$zz)xXMJ7e(v+uBbD%OSW2J6XW8Vdo6JIYcmNd2g>3WE%DcukiQLjo1xJ}C z{ip6C{zG>J|Dih=&M2?}N+bLK)ZLu6h3XDbgU-9(1r05$RU1Xwf9P%imiXKp)|{~E(oDau%(3L<)ES(}m{q%yEs zYP0>r&j%8l5;PX6m#t@HgszYGoRMxgTit-;>#7$R2Vj69eEsrGR9^^zR6tb4c`GQ_ z<P~VO*SLWIiI5xT*RT-)dPf?KWu+~=P}$1i5oMysA@>Lq3Pj^^iX?LFpc|9GA)F- zCWwdKIe=^v+McHmx*4nfTizy&2R6``9NIo*Zz_l1<4VAN)7H%R(#y;O(Z%aIXIf(N z#@a^WJ*HMXaJw38T?(=nasC|29pfw-|H5U>tTqN8X>N_!4|l?e{0on0SY)OyU}@n4 zM5yJp&*m8goj-Ge-s|Z}ZcxL;kFE0E%@0od4mQR67|nWq>sAtFT}$^7PMb4~58{br z^8xq2Ur8i4o@Zb`x;Xja6N>$xsD%GR87fwC3-Xvg)5~*JsD1vsh+t0t*b|xQf#Ln@ z0J0df%BJW7&RRo;D`YxiFB<*GOvrFKp9;gzjW9x_>AmZRohN)JTr-|LDL?-G&tHt8 zYRJIq&Z&-A&}w-J>NpYq!9~{!Fl;;h({15 zGlrv8R_HD7~M%%rQ<7BgUlsuMSiM^P)H+VeHoIt&&Q*SqJfEhR-Nd=&3Oww&%l zl&qE6SQbjvU?*x_=8GlT7itSi7OB9$RoN$IJG#ocr%j+=g`!!RG$k=w9I1t$ywxHf zE-Xv|9oaEM9Rrlc*lbyOJ?83frWLw#mo1t@g-CO3O^^P2I+d*zmlhFa8axsIRtJ+J zT!-9N!ID@vcG-DCz@#e9y{;GvP`{z;xGG==FkY0yQp}s~=W;)Sl{Z8t3fVPXRAz8GY3IHxvyS;k-TXqCZEgd3$Pc)5!*cBw)SkqK zfAZfHx|kJMsf<85I)vD0Nao4Pxv&Z{|E<4DGSljL#4v)En-1j9!wv15xs0lssMXvp zw75xFh6Fc240g#XVdx;87)h8=oGRkyXXvWO++hDACBfqwKkB92;SM?#glw^gfITSO zA{!GpL+oa_$@%>vjXe+qICQ)Z%5kzks6KWSE3zZJMdPD@wClXa{lagm4;4av-f~~> zSab*>{dfQ|G_<^c-0u@e287wKAh|L@0j2hnK!g3^*s?bVj0P!jyD;hW2Rfa)$r1JN zqOcss&0J2+^PH7n*k#|~w_R0(%#T1O4-kDL6|#H85Ty)w_ajv|&G|<9JG^-8LhiAH zdv=q^KM~}s(ZPhCs!jL{!(U4P~R2_Mc~#6YYY;xEV|WV7g?%&-Mi1 zXnbAFx8N6cx-qZD#ppcW;QZfTpKaKhDvy79&e5NqQ}qAGNt1E5cCv6Zar&==R-`N? zhoXS`WqLd-M1>HS(#)Iax)dD_E}To5j407dt}h-*o7&7_Qk%t;<&U`XfjBS>r$B^^ z@&|>0hQm@``?NpGw;%I%b7Q_Le0rbvn(yR&x-HGM=UErHHRzrQbXF;l`ayDzLc|v_ zP!QIFF@m^6u!p58kNTjRyBqxO;$0|kIIlPLa`lUI1iT~^U7c);wglVMT5MCBu2AGQ zIceIl&|-K>{S~ajT&f3`)OYQPRe7fR*n0y-o16ENGe31wE1QDT(VP4LU3y{+U5CfY zbVX*SVX`r)%}RDnWG1KHTZR1$eLiwvOy=L#20z%(7qj9juCPN1-KTl$0yk4D|}#ad>%qE;qLZs&e=9QJXtmmyPm#j#3zD;Q!yW%N28t#rvDpDn`PFN-VlX7LjAXgAHuQPS zi~li_6U;a@E)qM4gD5qd2%{gipla&MvqFgJo=D_HlNd{Eq(tkWTT;YI%9DR&;hDu3 zdcd7(jFI*5r+<1sMU(c3Lh=YC?NXuac#V$6Z)9Q*cdZX_jYpE|ELnx`djZn{d>MCR z%aSM#`}VfD1GkpPoIx3FViu!Q-(sG|Vro%#hcBaJC(N!%BnBSf3&M za-;VB5}h4O&NF8l;M}iJ5p=TnxIL5v?VtgbX=2QktY0s`;3Eut5N<+9fmcq?R=A^; zEpNO1h6MT87V`aX^O(^~^Z@Fg1;je(U%!5!p8wl9&i~63+J7COE-xrA<)z2(w&$)i zj)@7OQGIeK#3$o;L_|nLMr2@dL||leLFEu*aq##wP8I{lG8oII<@QFE-xWp8Wl88o zY>S#HdVedL=&PClP0dTqnpLWo<)~BNo>!jt%xkgqIXymi$KCH&e9xPXJ!al=IUhG# z2q<%~Z5xOwnEOV$@%xJ1+QTUmuMWWoDP8>SBH9*V6<+(6xAp|?Lu?-xn!;ZFVjBD0 z-LIs2)h9qX`^#`%ZE>O7gH;)Dw-y9Z$T>`dX5Pw#`~$|edlOY&Ya=P2UR=E?8!rw# zdi*D7u3LB0^q!ve$w*zlUSGHI`*-j1P1<_gJl+;|bx(kAcn#F)vi~ zn76_2@N3L{rta5jqVAIdk^T1&w@oprL6pu7f}2W;*E`{E-l3F|*E?7N?_{daQK|Q# znAba8J)eHLoRbMT@77PO79X21y_;(oeoY3Su@nq%r|uWD1-EdEk94gbra{}bcN5{x ze%Q}xF*U%>efWnzMbCIfdk90#>mb3Mt7F|&oo{_{Cz%~YFALLSTH@rjOP>O+EVl$fo z%%Y{HNWe=VmEP+qMKRzAW866xD#6(v+jOc{dl;nSx`&e*KWL zIld=VO(X_+S9xkFCz24CNZ3Gx4j}!vF)(IKYB9xfEe{!aHjP z+-6r!gM{QH_+4_J!ZE^A-d~sehj(3ZslI|5>AKP~y5&!KGRs8oh64^ChL*PGOh><4Bo0L^4-74M#%Ar z+%%6n*N%8BR}$|0I&(3n7-2Z?tJhPhC1_0rZd3%sg$VI-x@~6L(h{xysg3tK zcTwWaHFjI0HEuxYgr!Ubm@mmxHd^-bAOndNYfP) z&JXakdR;1;s z686O^+`35=0|CU%GnZ$3tuoR6;f8jEr|*O&WD-M}vyfA*czspTJst1$g{Qyct?)>e zk|pqmPhtdHOX`BK_WBDUGmUICf1YT{Rd_&D72meLqKymr$8S; zxL3PAM&~h;j|C<&^w%=f(>hN9opqN(!5AB3NX7oRIM+)rtX#ZUIX;T|_|1zHUj)H&f!yr2-462OH^>{cBGoE(R1>SHOVRT1+dGXGt9($=%O?TtNa39u8-Tx2 zX3D=?9a0Ym=D7tOX+qyK!83inTwok~osm*#wm|Z6*w-m+53$S^z-n8AK%u0nJuse^ zkL&sTW$JUasR1NkVbTu!9xbCvJYSEPu{E8^%`spHjE^3YFlWjJp6QlqwG6Ra!!;Fc z@<-b0^&ukrp=!#6JGQP>dgrJmI04|wCdREa=Vo2DZnD1!YUuxKhEs)kI5;Sq0$WQyuh(2M$jR&vAwNd9-KIWEge%v04s5lC)ZgTUZAbBah%#hFk{5i+{1ATlsD3NSL7#X3k|T*}z(u zb2_tNM~ihihZmQmQ${oiz>e76kzA1W)K5U0I~@}zH68U!Iy4wfZ~ZhrBZM+R#y-rG z1C?kINk5==wz;rVr0o=pGw^_-{3BE(6oLyjOZeOFffUb77N1xeQ?WuDiH7I5Byy-K z>0c!p^NUzaaV^87YC>vfR4=5KxTCB3#tqRT2ixXib|SncWP_%S;P1K(ISjFj#`Gn% zPLomEP0=5%{4svmkNGc9-r3apRK!AN^RYZsG0>QSNCOB*7`%dbgy3bNri zGB18&iDCqdD)WDnN zT)UL`7nw@ZfFMHERgi$2SoVt0T#^&)WFd`OVn_<{IQfqePpnUKBB?cHvXi<$14<^O z{+J7YDX|hQqI0o1I$h@@ywb3GCdr$sBtfS-&2pMyk-Et^C#tf`IE-|iM5fieXXjK< z&|exp4FtGn+i_F^gS3l)0TUBCV;|xHzuKHow8q^YXGgDEk>bt1iYsG2YMf}pbmvfT zhpcbz7E!-Bvy}O`(A<2K#T0N5dJ<0T$~}+)Y{7|dS2W8cq^vMZU{p|fL>=!=fNMpP z!{Deh=42)Ib})jjfT@2+^Bz2`5M}-~)23#f!=8|nIibFtnvt2xZ z8&OgE^RPtBloKv`YL)382CzT>R*$k+$`_mJVG>NWEOC<iC6t z$7#m+vso6l(G`g0r$Kqza{lJ#>G{Xx@Pl2y)Mpw=S-YaC{sZ{))y23E@tmd^Z5RHQ zxhEP3ipE$iVnX40_Nc2HIsqd=ZCz!%E^vqAq2gY1tZ)2JBO5kMOTh^ArIak=l&%Pq zb&uSi0RBnPr-4pBuCz|M%- zu*nIuSu`yVTL$OD zdzODu3vM&es1XTn_DCCR{0@TZw3eW+Bj;Sd7>dkg^NUoZ?>Hu7R{t(ORak-=hXjdL~rDKKgXM1Om8m=~6a7C(D^3#)9u zMfzzSWFSw_Xi;m!m^9B46oy1gWzA^A4qs^R`7rva5Gi(Hb66xSsZKmWX9*gvS`@Yc ze6jDOGfq7jSUYLp2_rOP!!09Z6U?fUK0T5;kniXZahf@T(jRq&q=t0fMJ5E3 z9*2BwfM#3MjC@oJoh2pBRB{Xbay@syvyD#%jzqC_kHA+!u-Jk4Jl&te5~21VXs}?; zKvp3SWsIZtCV}#^UN0ZA-pQ9#>ovaJ_fh0~hkZ;T#wD+;!4iXm+M{R9mT%4{-~zoz ziShaT0Z#jxLdfzTF91jvTp71G}>N^V+kLtog%dB2NEj z*gKV66r6Y9o%UbL2k}NR%gs6AR}cd5StiQ?1@0pshXM^h(;FX$N4CfAVwaqCO@wN; z#HjP7!(uDS-#NL4?a}0OkEr=G^JPvnOAGv(67Lo)c)6E|7x31%%wbR5kWZARA(c~e z9A`jZwe{Wdsgx_7&M3s5%QCmJ4VPl%F|# zEH*QlsN9mlFEssnOkbi0wy|fs0c@)g(ImQh1XFP5;S;v-)XQt#avoD=ce5^=-R)Sm!U=j)vPI_OzV#u%yYF5d# z^LjJ{MMy;k+setV+ED6cwd3R)xgikcu^AW-bIU0F#Y=Z0o3d~fw(9XsJWJ8pCE*1R za}N(2*K5b5HVj8V8|Ts^;?!!c|E{#449>%NF@Ab56VGexW2CST`ui6X`~?^8#XW0^ zk0i{g*`koZNZ(gL`zcs^n2!WO0md2i8=BKG+39#qmavU~Vz<-|NV;4Rrtu>uJS!+C zub^DHaQ8&=GQ!_ijhXEJhLSlY@i%+!p(?3GcW@7kV%19#GU#5o8J$?3hFSYpEK6P8`+8-0)=27&*%d$upM>#LaoL zLQ&rHaW0B;R1caiv<~=KZKRNBeg{tOyYV$z#jDWX6fiW zf4S0sOb-h#qCd`_(NN=4r0{~4F_>2dl`B8VXT8f({}%f!XbfZ86b29!k?}bV6OBn$ zQLROdbgx2tfcb8ml;Fn6yc&Z32ao}U#3C89$e0;rBFO-vr+9}lfq8?8sv*ep@# zjjjuJ_|89F?bKD>|2b7g@$&Y0#3J4wC0-k}@zx2Y^o{X2+2F=WgCKh~dD(KQUH8(^ zT&1JQl0+YL6T(7Oq_@`K2+9LfNEep94XR1I{U>F8+wYv78F<@rMHeK@gPE0kms=99 zDKBD9%wmmyTy#K4wW(VT1;|_P`s->N0RCG#vf$Q`mor10hzSckKhiV|F^hcMqO3GG zDL&_n;)fxjAF0P|}DYt{nykIE_PV-JUgu_jQ=16~U~ zgqW2Dn~dP70=4wvD3O=8|io>NovEc zWoukQxjn^E?5>N2Y|B`~w~`LqXt4rMva%<8rFL2kzu>)ilX{Vi8UGdr9%)*92x~d9(lHQFV;B}28wS}70Qx%)G z6%3D-J0vTyE3fos9k}`%O}qWjVH|1Q1^niJr;k`f2>SBLk_0#Z?v(R4BISdb-y7Sx zdH(6cs+v{;X=&uJjJa$dFwA);s(9fRKIGkR6*TK&KFXQ&1PUL|EQsFO>hQSNWd-Me zECzR%_c;N7LJAlhT{Mbw$&_ijCYU`_wbp}BX0p&H$^%GhN%QU5TBhzw;IFkrs} zBM~SeV#HC=tDYyR2WCCiFH#FN=_;K|&||F+*3@(G7ni!QiW3wnbdH+`qo?>lQm<^i zdkou%)!CyEoXkuZ{46vmm}3CsxOtLdNA91(qwL)5=`*iVZ&|6_$ zC-ujWG@J5A!Hg!^FEWfTNOq98twcDm#LOQfB0M2*?=U1VZoKy={1&&ADX;RF_U%Gu zrEtL|cga(M@cQF~8aOUY0=3K`@$j^_o7XhJ@!i|8sHx$B^kl>=ru=qgy=aWE7Bq$% zpTmWdR4sSFWpFaE~lXPw!7$Y9|&$wWgULPeUh+Z zm|#NO{q)}WX%`VFwLW6W!%B8zvWuv1Nw`%$g8mKON33X8X2GGnb}}dJ_V0Pb4LlO# zz?oAqS&RxD6KfjQd^WBVQ-SN6?+|LhG9s)04W&a0xL=>F9j>x^dbXtHAi}14}{qfO- zoZ)lDZ)TOe<`cuaj|m*%3p7A5Yd-25kcb+OEtACE>=t<}F#ttR-aGI$`SjPvq|-@0 ztvUdPzy0+onJ=usJ9<5>lPU+%y@c}dI3@Bay50Kn0QFa~bvcR>=seTV8yZoem)Sw< z8|RD>3t2;{xT#Y3B+y7(^goO^sZ?SqdzQK55civgZg=HgZAkR`1=`a!eG5=fdmeQ= zlUl;+Ya^h#$&g{m=wN47j;C2JHhNh~_A}R7g3mZ-{1b2;O@yqH{LK3`sOMSJ=)5)W z={YTB-_-~obi$hnI<*Ab<9E8$RqX>f4|h0%@5zd%`#NyKq@tx_%eU4vG)52&3mCUC zeq-CwSvO@VXBWy-IAe&9i`fQX%v2`Y(va6mgQPPB(_Z5i1P_3)^;0W{V%8KFJ#kGH z8&@ChMZ2>%W2lCu4gvJ>jWQh3s!!pvzqNM*Us1=i%C?v{LKC0gYDDI5;*OY}On!U^ z5H9~so>JD>t{ieuzSuf+Xb-ozzkH2+hhe0#160GIx80c6Qg*SVFm_LZnchS)$s)>R zBeS?%=;C;CB@b?Zn-m zVQEP9B$q6lI{XbU92xp+)1Z$#8+K_kG>4kWRN>k;kBY(1NQlFC z4%&b|?11!B07&~i*dbL6aRS~wf6c1o3myV~O%DG!Kl{Egkm#Gj&-PJ+?(o}%B9XyT z&x@=?q9G0GzfU;uO)Nj0aJ&hjkw|YLV0@88%uR?WwJ0Oz#?iG9$60*2Al0Z*ecO~t z=_Sr%Tlq*dgMHR;dwxZuQ5dpv8hmTiH zVQ^Ou0dJpu$5)~%^bl|*7Ly=^O3(9JCm0ljvWKDPl@lRG-`nXCzsxIS+^_4n8G9^& zGtb*ZbHB(GzEUg4e_AUt||6()!edELV)A~!uuL*d)D3~Hn8K@Fm+wE>^U(r9{7Sa zd(0DK&PX9<+EDvUX!Aa?VdSv?{}DJGvhdvl(vNq?kH2q97<6ijVLqVNOj#++PXOf2ddmkX|^Lb z-fg2Fk=mp=2N*xGi?IgZkC?Amf2n~4)2Uw_;c%Q&R_)!OCv4DOMe*>ZEk_MBox z37K}6b%aND@5Du|HFqm@^wkJjAJb9p4`{{8j)bE7mjW#ClPAo5W4SqkqUXW*5;0@< zM|5t+s>Fte2a`0Ja8K^aVNN3D@+I@Rp)XnOzhsN&IKiHMy2qIs>R0Xk_@1X z?3msw@SY;GaBVrBPC|gY z{V*&9QoIAcAWn(L*s`%%%pEK!V7l@8elH8AW3hs)x%`Dd0;x%*p#f>*b7B(XOq?sqU26;MVSc=VR#6C6T3R(G&E7_EsaL0ShLUm>5v{L3t}Tr6LtD#_BsoL&%2 zxCsr}5|73Hf;m0Z0bTcXtj<`k+b=V}Ewjcrbh z&i^Kw^_JGEhCe|xcBiR-pvIMe-x35fOn2~8Bd*S=&U^~CODqxUk!jC74#zs35R$b6 zq?S>mCpiVC7L`Y{oMCrxvW8ZpE{%iL6sR(3P5S>80He`hlYrk}kbkLms0Z#s0JK3v z`*{3b40ETZd1+6r$&HnJj#xwh*WOHprle-zZ1 zG*Qwb{kLvB6sSkh!p}Mbn%;h+|3y^a({DKxk!GN42z40eMF&B;tcM)t^GJ{{)j5&g z1lDmY9dQ!80dbB*TEzNaH_V_zZx>WZ!%vJy`?)Os@zyy=OPn9kb)isbK85o1JCsm3 z{QxLJ2~cM+2x~X*E=*EMOJCpL*+4jJRgiX1UlhhS+EX?C28oSd3H5Pa>*V8e(?z_0 zSK4WqIgpF`p)jI*Dye?1YxeT=Bzz1hyt?smr$wq1oF*Kq%w0p zkiP^(8X8M1vY%*|ECs;*e1U%nNYFIqEMQ+^{JMc@RPl^6T$f5*^pU}^>dB*NN;%WK zRB0D{C&8QD&b7IeNxf@1t$kw0o7?u6@J;D1`cwgOK=5M+>l?9xcEE4f&Mf-9TM`q# z1P!|86lbmo-jU&e2HSS=5o;7rQ13rn1-jc1HD*l_8yvNR><6?gF$2dvc)Hx7D=eirU5FL+@4 zMmhV1!fGuvqFV2DjI#zdJZ+5E%6Zm@S50}WUkDecLs}zKoktv6tN1t0NH87 z`AWr?Blx#W&%Ut(Za))xDgHlSY?Y!@so#2x|Ic7E${8E$-@FR{Xt zs`TAFGh1Zg5jVZ$WS-a?G^^}nPQ!!0Y5~NlTlY7{so;7M#@vwylTJxYvD}%_DY-W- z-lEiLEPr(LDaz>vH*7S2xKCM*WY3D(yww}6hj5PYb-TfDY&Co5`g4!^;ppJ(}z2$w*e_Uus~n5qtXP1Bc1tDr{#_B=-9PhqV*< znMs{)Cfs0j0mdMBN;jx{2hB#D$daS+Ly$gn1_hChRC3&0L2DF;wMTyp_K%O|6zV_j*YL z@_7XccdH%$&Diz&8UlUhaVW7WM-ZsXANs+BbC|`Vc{>$}e#ZF^r&?y{6iisFc4iH& z@2|CYQzY;%;IKn?3hfX#fkNP+Z*(T`_C;Dv>#rRZFf~$^PXShS1p|u63F>(QY&&?a zMGCM4W&tYs9OT*vJMCHsdb1P;*cKYWg35$*$Dwa76C{>i&u zn1f&*k_G!0%IkFFAHeTcnS}VEFhF#5&3AP=^Gz51uC(MLv&v6Yo^p7{vjr7?& zX%+Rb>YQapyx8xo9-UJWzb7jA+2SSDQZI;S4$k7CuiBzvw^*A^M7#5hn0XmSW|#HG z7*X(7atIDOJ|{Sa-!cfnz+@XEz3V#U7vqV+2xv{96IMW zKONzEip^l`OMG{f_M6My*<~#S6L!&vMPqjEmQh(Y)!$;`O3nUn~!=AmdoM7L+Tfn2l{2szxPuUZ-K5Vf?R~hjV$GY zsDH})yMZa0MC+#}s{lZm(4QooH5mPAMVBLM%^JU{Bwr z%P7{(N(F{hwr;#kMAmq<*A`h5S>;q=2JC&{{TfnIq1+->Je%2HvMd*hxVC+SJF^4I zrGtghb8bEdN|E{ud!2}t1Nci))k2@~2D+gCTuqh1rQ?(d($~Nsc7Wr~k*GqolRk+O zD-i8xduvL|nNM5)U@Y_<;u)Uwj#;Z+eTI!8l#X=_UJ;RZ$lBax6H%N~aJ=>tQCLwh zVTswtwd=x4jhaq~a2QTk^{)GT;Hw`N$ku;Rp}5W=Z0cea)ova?eF^;E?TnkXHO^!| z)E-#GU%y!YA52&h#y{&Z7C$?T|4DrPuSLfHi6u@_({fW*L;G?)b~ttbhQzbS{s~%^ zA*Tu~D#j!nhDsSGmmv)UzdV|p^v`5W!!jkO)3>UMYA&KHGH>!r!K7}K)RIqKEJm+k zSfbeRy1CoW;D62c34W>Jqp;`(75X@y;J4cO>RRsk>Y5&VU)ga-=q3N458?z5T=fei zS|lP_mWR|h92^HYkNy_S9zq1B3}?d?Lcx!_DyToRgPgDzPbXpaR5tCQoiZZgjjjp0 z0qwTjl>pI8U<)Jy79d*=BlOZ~---2>le&*&ox$cL@12pj?cvl#&~rPATM~ zn&L2d(lWGPn3#WUCiEKVr2&_v0)=VwYSFs&8eCS&k91;o!=V_y@{ z5@-Ys=*X<}{=Si)r@yF+$BL%C951Sz)UDVR-@$uG2FJy3uxEFxGapJ&{iol_^4ClX zp2ISR+d)`jAN|xs#X!7o6vKh4Lp;bCE((UkxOPHv9SdxU3NNZ$zUP-qs|K7y%mMHV zo~vVRqT{DxX%-x-wgdC+wDs7LD%Xb;^~)U?k4#I{{@ixN5ykIy{z^nj{47HO`SHIk zEG`la9Oit6D!a(CWi#lF|GJU6{x#pF%TQ;O=P^=YfF(p9Rt0RO(V0Ry?+Ag`nh;rG zKQn;>LQALx<+wW9^BlK#MQ{b7JR_P5b?UY0E8-7HjZN-Alt}W<)}W=JTr7fNT= zdbjNfjc=cY1zFk9&cVeqpyc#gpy1rvqnO?3ptu?&_+O{JbUR%QlcNaqmiEW5jj`Pd zM~+`Hp_tv4hZ9IV(@v*x#;go_Yz@Yk>{GPr@56Ok?9!oN*pKzf9ZAe4adaU(`DgP6 zR;E$tkn@Ljk^7LtYbPJWoMN0ugx3eLMlVRe(%EK)x6s)C+DC5CRXi z(RO^P^0bF*q(3w}bsf(mp|@?NKhSGvtY5yNM^KlrXgmqG6L1@q$iU_1lb``^LeF**SC(S*zClYhr?^dzue72DX-)7Q0T1lvOCFr1b`U%;74ksU zIsUyB?X)CYd|Xs4PmSH@Hh!EH%40t5ChhNAT3S;ern-qLj%n$^Mh+vgCGxaCJFN+} z_z{)6(P;NmYRF3oa%U@(aM3wb{dA5Z{Eq1#nikzsd?E&I1~xz)2A@Wn{X_l%34E;- zEem_12^;?xW$zeV>9@A~#zu!7r(@gf*mgR$ZQHhO+fF*1v2EMN$vN*jd)N9`y=%XF zex9@HsWI;{Zam|~JkpY#qogPZwv9dJ7`2J3BKF^R z+-j8INs9^;C9iHR-mkf8n17Zx2eh%2-+`U#>`K+<(3A%CQ{ZZeKe4CqRA-kdL;H{ESDmITMg?&#;eX%vj zejL{<_t^!u^H?>p7(7Qr&L<;TKd_2&7$wVl!F=AeQeL(ZMf~xS*TIa?c+W;B(ieI+ zz=(P!6v34I0|N2`I`JlMQMZA+LU!-Qv^KJ6eVZpjP@j%!ubGih@)8s67?P~E(+3CN z0$v#IYJg@(Ozp>77zVnKB2l`(8g7-dpNO3YGe(s+_Kcz$GW_WM_wDw@$iRh{(TX~; zUszbf;Ya~pAtKzCON*{^R!t^yTT*;If7#Kp%OI67n~1VU?-Kg`dLomOhRdPnp=CcM zyj5ZhCWNz0#m5*b^*Yk+emogq@VFv( zxgvGg#naU@d3tmOdu#Udc1Fs^E*id|#~8eFGxpD4@nbvrpdG7;_-10WpNXRS7}R7@YYuRB4G_)RgJZ~POiwTb z9h9dbJ;`Nv;cNw+o`rs^UX}547ke+y)U0!5%Phof9iLdJ<1d@P`k!nt61Zn9bYrv; zZLdLH=OuVg$hW>OrOjPz;xVZVtWdtjN_*(NEZ#N2xmov;Q=hp9{F{mSythV=1i_^r zn6~MU9@!L)tg_K<{%UXqdrctKh|QD~9ivc~a|nH0deP?xuZQ@SkYGTIfEcI|g@<7w zg?oijBMy=)=zQB1MS+zK{*G~7$?jmLDeO3gzlJm58q#>h@$$-MIRIZw+^fVS!#I#E zye9tO?nA{3h)Qvia&un;pk5jf6GT@onIYKwkaddzL=#!VDfvlvE2ZMa0z#uWoI|d^=F{vXLuepu^Pc+)1f*EPi-Jt06!Op(m|9jbi(K}zH z{;i;J{w_WKlNXP;wWE=}v5~!zwSkeSy`HVPKLz(c`dlsMH&h@sOmn8Zn5Dr`Lxe(W z)!NELnyiK^jY8!(lU`~d4H=5KeiTiH>3h8JY9CxS#a0f!p*;(O=HAayQL3!MycXMh zgbLxKZp?u#qNTg<+TyMy`Ll61`Fxpo5?7{9QOXyIID%JV4*R8=lmMTY0m@s z=a>e3N9hz+{9qo+dE}^IX=|Vb$VZ80#d>=sVR))PopR+)UO19x(Y6KJ*0u&3+rc9d zH#&wl4{zE)t(_@I+|snj-@-_FaMXidDx^J1$4V;lie=wCUBy9kO3HG2@c1tc5RfB; zbXru_2f~-goOqeihCefPmbXhf3(Ydxt0du1=MflE`_XIwV*FcwgieQaL8;I3=8Mtj z{>K!f7k>3mq4o-{AxHD3bnE!knZM9CM)4-c49<<`Hy61EO`7xOyN0@lP(CkN?FFjP zqh3EYpZaTOBjB7;b1fFeyOX2a!4uOPDGwQvA7%LlU0Q8~Z#^H^deOY$LSAFfK91*_GGnU>{aPwtJvHzY zuICL-LGWE#?+!s#y92eT3xVKB3LALHfyB6cUpZ%)d4LqCJ34;k=hUYWop<7PLZspk zhDLk_+wcr$;H{H4T-{b{f;WrgLXOvrYV!r3Z9U9;PEagk7g6X#MKK5WT-ihBwT zQH_`X$U#U$s4?xnu}y;9CPk=<7>8k#fH6Fb7iOp69grJu-5qM@)63npcN2*vtV)bRB0y0;09en@vW?+{}0WPl$o=UwUL7ZzqOvFoBRKUW@RZ#+I;J|KUu~1h+CQA z&7gObOU)8)Yk`!LfbxRL`5&yUV_)|wKa;a>MU*15AQ_w{5-i=3 z`O&0TbLwzz3lP8F=UiCU7HSK2kQSWwt+@ucXt>Ij^oa{-b9?qv z=g(bXJl5^~4p{u#kerw0jUJ`+meUyH1q`W^0>STg zVV9;l%SeI;m5y*3Ce@y|!1oFCJO`UXPIrY08%>jgFNt}kO%PFf6-<>6Azj{8Tc&KB zUcprkDCXYVt&Zq)Vv;;%l+#`-zm@fFww_@tG`2=-rU^~V>eRan@s!d?4u|NILZvFeeK(^LH4QBT9|lF=@{hj`NP-NURNKsXucKl&%-2 z{$a;i{N>Ai0ye5oeWHp5WBR3>=t&_%t{-Lz11MA#gFywv3iApIC+k_J{L{#;;Z^26 z^*g)_zkP(b{%^ud#>mxC#L3#g(agsBzY=1WqQ$p<@CQ$db%&L@b`y<%DBV1I;sJ#i zw!ol&QqxCmk@y~D{YG_bYnOC04gX$De0=DP>GOFEnmt4;VgleE9#KJ_!ve4!_Oi5!yt7iePXFT@VGh*A*tu0U%UNukPMXXD40}m@-(Vr zmj|~VX}j6lNRB$HSJCv~FGvqiU{=$(avCDDnJ0&S2n%@?TUoO$VeYCPkB~?@cDyVWa|Aki zHsed{$hPjH{QdjmAhq; zEWroa&!|#_Mca7AsFAR_; zwRZ7{Yds*)!iZUo&)^}AE5pHw~`epS#7@&at;l8ppE6f zQS+V_ETCKD@LDuAH+R2PhZcUNrAf2?0DC(CWW8}8{XTj>TJMm>X|+N0O+X{@t=UFK zOM%$#GotLq@Trg|NlyCiUpX>s4-T_jOnjyMssDg3JApGP#31$QPfrq z6j56Q1Z(Hz+l4JO?NZn#pMDkIm?5&`vCIjxH9RqEsc07wz6n&kqk`5F7P}@qf@{AG z2`n|31)R7`+jlLf-lZ}4=y?wHE7ZeqPo{5{41js^0J!uhYLQHTGi=p(+@R~i7jFf8AzJu-Y)iMyH)mJHe5+|Fd4*-3FwmVK`9NlkJt zEY*k@1qNmbyIAk!MmTG9*{#@rcclIJ)l_+vk+T9FQzgQhX1iF%pldU;xjw^_!s|i; zTtdyyJbgxF<5Z5G23gWsSs3L;X*N`K(4)LnVPUtDbT2U<6IxQXYDUqWu$Zb8!_3En z*;!ke-DK;e%+v)E@oi1mCBYvvM81LC9E$<_mrD$5RcVpS2{ct^=o!y^7KZV|`@m`R z^lYGY`a_uM(U7!zIrWlOA~!{{RH_OkZUX{;nXdZvfS257oYW(Y%+N^*0}@dlTT#dA zgOWvKmtqPAiNVZd(o77S+8Pr_rk3ErhTiTaxkCQr7Gq zj-$);GzAfb#-?5%N-@}|$+btS7W4c@QL!|SermFRKF%xv?q@_GeH_jzRVw}Z1$IY6 zb&kXI%_`!YMhoAdtTOkG(hr4&iK^GibZ%hTkmP-_D%qlZY%N2w7-k=^B$%P_bldz* z^HF06mM}?@BS?aMYV=e=FWK-8W4ubjr1R?VxP0Y(9D?JrWNRLgvut7$gHir^>Xs8E z4v;fm!jnX&ekct_@vBm~Rps}{1vUO$k~EpY`=Vf>l6~FJ38XK(ir^fB8vomZ#Y#Q2 zY=s}(fARsJ4$Ob2t9KlpJKcYsRe}w z>^%hrYKmUqy(@NH?7h3h&f`c)CYW54&u6c3vdIRSJAHq$yyMZWIGx$PW4O&skiz@) z0$?O!lpI-@^Th|KKaETrNf%YB#K@=%ByEnvPBvtu zY0)-QNaIyb(hWJ0j%w#?jnj%o;lpN~MF%P0g$Hzm2hUsu2QpkG2i9CA2Do-3*lwzW zdq%IXX5R%LKNQ`+`g>U3A-@)`@gB`w@vq_wu^s_=h_-wKK%;vQy%0<5-7+z8Pk9C1 zB!`r#Pd-`{)Ib9fkaKpXgi;V9RfZD$D>KCSlA9qUY5wvSP7#pkbA8EL+HL`F{(7UO zAhbqTPX_)6Ar!oOBB{ktbIX6F?r6-c&E;xqD~$s5202|npiUWo%BXjiMB0x1B{LGe z4l_yOrim|W?Q<%ougf|>Ju4bjTGY=cxEGXk>1H@?f*ybybyqa^5uHa(YDSqPy$|HU z$l1sd1Z{&Wl;fPVyQfOU#<|HJ?>a*SW@SazUa4(=sa#xmsH*rWoc@!JXt{C?b9X!R zDj;Bs)t>NN6RDh_CgYIhUhZ0M9eG{vjz(ontg`9s$Q4_nRXnz_aj}J!nU%Sz-ZmUt z%|p!(M_(>5E3|c zlw+f6SS+SclY1`&-0oWbG!Dq*0-!Zk?-pcT%vHwXTB;-3-JXgce3DsjaPCqcRQv;9 z8b0_!DvsE`qChjdPmnO`#PcR+D2M8WJehD(yKdg@4WMu1qyBP1C&|@=N0IZ`vZDPY z*3?3Rstf){E&C70YB;w9M7aPac~i%ZS;jh|O+kzG>3&seEp~VF^!%9jzR~v9xw1Rt zCY16fY}2hZ-pwv`^IUGdRY7V41J+S4Sk4ffcfd28aRDw>8&-ZeAx?xWa;R!zo7`RN zEyZM={tTbrMIQ0BYSAmb;!bLTZAe-8*;U}B2uj8_H63~^=jvDhI^ZU2R3U4!3) z@}d=!;OE)8s^^>L`cKO|eV0XrO^u45m603`>Se4&PDXFPZ-|H%Q#vY<8jpbIHPajI5I8I@U4f*7X2qOVF6PU$THSCKfT+Lai z5WwcGcuaPnCtgG+b|~i0cRbM}Iy1ht6SAM8QGa+_YX zPFIDr1kcFr#*urc<#00V{%!-LhZ0kI{o>Yqgao7}y+2cO&wEE5k7Dt&;%}g6JW+>t z>_{gPh%dC~cPXfc=9&>n<*vln^%zNlk|i}g8k#vQ%$AzD$*=B8Me%BA?<+Kq?}AV? zEL~~;D&mCR5hB~-)-^vc*x!|jOiCMr zt$0L+$8L6!Mt{%kEvPu)2#unTUIa~q#OxjNu2h~yf-OLT%qW} z;>z30oq_xFSzYj%YGC3GY~qKiCTcz4(!bB}_wS7JBI)sgKjK$f?8^L3*)6L&yL6*# z;YOS0O+rbVATp(FeOnRX;bGm#U$paXg)-Bot3#Mh&u~>6mAAWYh7CCvlbe2kkWi%o z576)wa?jN2XC#H&(QS}<3SegPg6B6~W)&)f=|LN|qa}wAkRptqlzWyjnfx^qM@{Z| z8yOQ33fAPmukw{Ev(8FM{#M+=W&#Y9qwAAdS9m)|x_S!9l5{W&iyZ1B$OcoIMz&%+ z50`;z(3A%UJ7?Gx>e9?gV~OA7b5R*yZXrthxLSdA8E>y7AFUpY=GSg+b@NK8$A$^V zbUJNk|JmP#R}Dcce)o5F--Ax3|4{DAI9XaM7@3$ke9t=nmow~t)x1ecYck)yFj^gR z&bk;vf9Tf3b3w8cFlL^?2;`BQ#3ds!kiEDZqc3Jo;L_6a@wY{v&m-t~P4$1x{6)Mr z@q7Z_Fd;YBCzvffs;9H4>UtXY!n$*rT1OoPi-~d!K%(kZHOK0)JB&|lx7cn zPlr*emnls-o2cCj?~M>RXxpS>iw^2QiwKrl&1+em>L5y|TmKU~a-0@vIGy-JRJW$> z)C|26HJuO`*ABC9+|oc)FswgpBAJKB8q`BWSaii>z-m^Jx}7anzw+=QT3@7p*uM7$ z7Z*4~*%uiDhFmP0B3rwlBLE#?LLO?nQv?yi6M$~-ZvBv9V2Pz;Z1 zU*T{}=C}V|Xz=nzQag~sdks>sz?Q+0$TB=~wglM&$}7S_b*S6V_+1&8tbINywKnfVR_)o7tvywBx~{xa`GfIkH3S0XU=lj zTruFnVsu~j&6Rq6*0QZQM@Z5&d$HUfovm53q7JR$T?LNs3of=gdx@ZX;o17yS_QoV zGB?I^y!UWn7dMqZTQOu#5i8gMLtIa4g9l=!1SA}10ui3}QMaPgLTAYJ3!5S554r;L z+sK+Ak!Jsa_93>ndP65ylI+O&fZCh?dBP~@KGu-C*)0vsf&#_Tx^Qgj?=Xs+GU8Nlnuc)(7_t#|?)UFA+v|4d^kd!PQgyY+YawwQ zLUB@3bBHp;n&K=|?;!s^h*u;PgADi{!Yh7Ld;ZfP{=bROELAgCY*jQKgHbFEEF(KY zE(xh~YWVs+A-+D}tl(8^bib4zDT%13ZtUQZ;b{sE}A=MVhb-GNrEAyM;dc{=oMgWZqZ zNUqLO!F&k(pL=A1&sqA;DYYIg^lmY(>r{KZ4BoR5Z#QLsaQaKSp5b`U24T2=CGwJu zvincHU4wH|^G~M+b51?OSk8h zuu2}oPsH3|RW_f;Z(lMP5I5ASvNe7>>Wej0tA^~pD=b-vEIiXL%no{77I3kYuieRS zl|>zYqZ@YZ%1fjo=2N08M8-Dr{+Rb)G7UE_J9`Cw+6VoyPOMd%kT7RTXZBGpEkf;$ z6v|1LGLPOtqFE4JK$=_aS!g^44UaV>pGD5|lI#@AbTe43z0S7ALdF8L(&;ZlSiM3j zu0s-J;sRWi`tAEQQ(EX#=kvjJX}~(x^NmOchbZ%^0*j#z-OxbTF@AT0~XP)#30Q!NrX?(hz+ zPY;EW=$583cIY#p%Rdr*pf3$K`Z<;hak8tZQw5~cp8%jm#MJxC?fdmPQZDMPimOUR z(yP!o^nyFQbZtfIysb|zWG5517K&KA&ANZs7_Ul?Jg3i9<0afUVQ%F*)XQl&={0tj z8neNm2Jv_(@MGA>U5j*z53!+n!fqK0le^-OrB1+P_liSLsE#Rum)QOh5s6IH;fPU% zh;R0%kV~eCRsCH z=vplof-I1SsVxQOr7kt9ClnFvAv9N9hm60|0+AVK+TjK(A;3AZ?_!(#LUv_8}M*7k@mV*}+OaH|Ab<|wADRq#oF_upDGL4d`0>2{&Tm|AU z%{^CxJO^`of>sOvj9QAeUYou5tT{bIrIG-T&@1bD|8x{Th; zoZo3KSHR%qvV0}7&Q!kj6Ke82&BQOhAa?{zW+?HxEx6>Fjy^N$tLx0c@C|-hh^RT& z4HPxZ`$p*kGnfhN;<|D{gmyFaN!_L&>T}wH$QE4Y0Zk^hXo_Rl_t|}%(4v{wZ6GYW z9}mckP|}+2L9H~n-MMrDi_U`!mx#}xV|L7k#9qKY5UA>cJ6!Lxe~VHY##jCEkepif zEMTKNH^pPN!0|7Kkk=!OS`jPkLeZR3Dc*nacqO*E!m-(U{*Go6#q;wMjXQh?BDMVy zvxE1khtm&@%rm;6NX#DP@Q%+u<>U90!y{~us?+Z)VhA!?J9-^( zN`PefVlsDpy!bOB94K579QS=0_kbMJ0O*{_<_kk7>g1TXDJS$}q)NwAcGuH-gUi8h z{Etsa--u`GAYiGA9R;iaSCS|LSC%Nu@p3(xVGFb4RM{P;&OFbQIr`dM1NpA4d3mKF zDswf30cBhgT$>YDjbB}6EDjIFCR+$#^#>Y@#YWbFGIO2hZ;Q?=(EaLuhOTqa_DA3% zW6ev9G%Y(GG6R;DY5clrPJnJJ6;O)_jfYhjo}*S7b~^fmEBN2^d#2KS8uwTVzZ9J{ z+v;b^C4DB!*~~D>J(?FP)w>H8xkRKHQ0XPAsXhja(ZJ#Xnp5v>uniKRWVZd_B>ug# zeuZH=wIIXMd<|Vl<^F0N-l6($bs+saipXM(UMo;aVP9qS+kwhu2>kSa>aAX8;lmu) zdr9m~dob26wD@W9h|kvv3?<-Lxu$Tu7Gh7SH7>}*qm3SaJe0X(chl6cQ`&A-J0?&9 zBbFYoO4He{KNw+d-eYm9z$w{I^g?Gc#}3B&={0#mR=}C&hO>ZP`GaI}W=8ovU3W(# z!g+?qz-bN-L-6*MfPBbO8f-&|?P=1b!Ott}YrwQ=S)n!zhwVfFkc}uP)@@`Qn zRu`|1-htnDt!x9A*wLSOp^EjU(AX%VYh2iRjKcC{yK&dFpN+J`Np6s`$Kmtr@0$DF zwM9DDcI>YAab?q8QH!e<>*GV-7-9RUz({}QxM;bPk=~vyfW`6_l}ZB&DFnOoCa@9 zH0|YgUKASvc(@!6B#UOSCT}dbpo)bmdvux@df7bEb@nlG^fL3G%qG#>qVKXOB6)nt zBY*Q%USse67VVwGNdN=U*@hd=Gj)KNq6f}TgBe|mGGUm7ClAJuDVf4LjNnZ zZ?O{SOyvK0Kcy3%k1n72S3X*Y(62`9#A5ah0^Bn~@)<#RT^MugPGM`1^76X-10%^k zi8$hTz+t5BFU6269v!^^@SH1>n}{*AN6;S(5*eWe5EBN%8UwiUWxGG{ukFdue@KbU z^ke9Y2IlRw-*MCEgwkbh=;V=npy~FgO+XvrbKkfozgp}WAL#!57}z(sX7>1Qy|2Do z@Bh&;@Gl4UC`Bz<6n<15MM_uz`dABosjqM|O}%GnDL67gJabt((CzM=BNs&g0PfN{ z>N&%eLH^y9p7*UF(j{3yuAC*q>MFC%W3tWV^8NYc0ozx&(y;)$#d3LMCABvZ9=63w zYT$w&4;)rF1KF5*y^h|Z&)_)H#V9euAhq(@eQU2A-CX_7+@_0sS3Bvgrn4&4=1kg4 zF8|!9%&>Ee{-9ZQ>WaQ_$w`|2Ubzr?3hPZ7$@$>e>rY$dr!h)&C#2**d@qcG5>rfY&CARhuyAun zZP}_%f%qx3gu!JVl8b0D*h76|TfF9f8Lt;n3b+?{>|uA5(x3?Gxm#m$R>pBnke64Mz~6 zmjIpa2EeWSKGVlASH>7{<>CyUX%A%+))J|MDrg#rlIygFI>4X()%ub$KZ~$59y{Ts zBg9&o~jKF`2`q z+8}%0)kCBtO}qsiIXBVJHw~IRkzSCGy~b}t_X;(k&=`)&9M;xbTa6iq@+V&W_R@)JT`2FIQ!6EXVf!2$kOb~@KJHTAjM50;G zBwR#*%zTfG+r*rfb}!sca7H;?VP&|`qpGZ9etrTqd`oX)+9R^MAlZl=TD(|1b4V@T z370MYD}&f_8d^%9yiQn^n!#7+-ve0GDbUjPJC9j@=P`!=Ngk6kHB&KjFmtrA|JUT` zUkU9D(W;WtDt&i4Fgf@~xB(Z^G_sgJNR(OcHt`^WpQ`$7p}E#5(P&!p)H|}at1-kl z9HNvS1P09931|<5F}Vraa29$>JK}0bNBdK@!<2T_<>%c8A`tC16E4K&$PNbWacd~s zLT%+9O=ndwT9f8NU2yncE>3&36j#~Z_`kuvi{_Az4`RP`dW><^jM*Mn4~ys8OIa1c*$h`Cv%LE5_`upW^5#2gl=;IVz{x<^FLKhQm0Uyd>Xxggh3@aD^*-dAsuAeZxECs~ML-O=I zb3;wB057!*3Oa1({|Uh>G|?;ioEisly3AM`g$t^B9VR45lMd1#i_+Um%bS!tUu0s6 zuDrrCBOSj@XYEBlVk&b_clKX$g&}(> z?NV%cg~$VbwG*_-#92+_5g`%#olydD!qWoLAh^Tx%?aM(lqpefhHZi<`?eihIwjp-;>F|sT`wVKd8qpd8^TcNR zo1%ap%i*3=w2ZkMcR*58a!h~MXq@S%I6`>kE?TAuw0h;9GOAi~G}>V{NdWXGc0}Yz zuFw=_As&4gseH0pqFOvXxbjN`wW2Fc+`g04oQ%CQ+|@3#LsSC4GT;OD-?y*Nj^iLB zA`lQB0T2-B|6u$6YtO1dyK1UBeNLGcl11foj>MyV^ES1KEb8`g0nx~SWUIk=Hn#-a z-hwof6O!3T#t8it0yD`~zVH8=q7^%ql*P&~o*5JKFY+qtABm^r>5iR%-fPnaC&?V1}l&iAU>udM2iuE|gS5TC|t+1GaylIKc`X-PSw5LDizZV06*C^9I-m9uW@m^D{8(92A&+ByW>A=g7Cqn^TGV_PtU&`UqmTShtWTKFqS}Daz^%-GEFAIe)PzR8Ub-t5ZPX z;M&TzL9<~-z@AT<&WBy$!jT}$2*|b86nyLh`(>gfUPcL{jLI>)Q8K66!(izCu_i&z zvnJ#Cr8a{W4bKviALlwA#Vkt8dMD{1duTyjFIj6i64fqvNpjRWcSRa6llgANHZ}@Q zb}2LvolAfp(=GSxcQ`5T2)UcL1I$PbJDg7>!|g`s%*~pKM6|5x;=wa%o%+dxhi#28 zOeo`!4D0sIhZn9b1w?U%C<=PXybG1u#8Me))!CX}f4jt-cC@H9W)zdGfmIwOdWUx= zfYMs&@Kn?lva!m?#Q*)P{kqzqT3c=Ht&$iB0a;cZc7EQS6*`;^t$#_41p|-Bwcbp+ z)f|Sq5iABi=zx@3M^s~8#3MdN3c4pC>7QJQOdZW7Scg<%V9L(n{wq0hMjG7dv>~7O z^btshs{Il%DllD9+@;n{mKzW2BA;}>#nN0;B!o=AfoUsvqam=2C((A`g3??ygOIua z0maaV5=*9C3g|FU-YEH5`ao~gTyhc096m*kn|Yu7QuZ%G`v+*kET8756C+wk(qSX^ zOyC$S$$)3@Tg0Bs*QOd}x?z{m!&s4s%uk839(Z&6!0g{eG4f8d?W2#8O+~~kibNs6 zVO(MJx{NXD4R_8N;N zHcSNq6vxMs&i6Itm;f>#$eR+BlI?FgZ@*DQ|W9(2>t(K6XvT>vXvR@w9bWL_nPp5^qHbCrVsc$f zMzNnwR;-^(o+}@@#W{>&a@im#+0$RfTr@~fR+99X#>wi-QzFE~fr?`9Go?0#ak4ECL58a;P1j_q!rB{gZ7$iUD8lqeu?D+ zj4=`XW31gD{RlQ$;4#z%_>bG04vJWp8ZaKB@BrvO9!qMD_7BplY02BLfZ>=-Qu6sP zZIMT*uF8ERu8Vess=iETgVCZVfAPu_jKu@P5tit@32F@CKWh2ZGSV;H%m$-e%}t|I zB@6sCY~AyRn6wWV3IT@HOgY&E>f!y-mjz_*Vay_34yNQu|@QT&4I_CF#@?<+YGt-YD?FajQu^0Ckvn*z1 zK+lLb1$woA(#BV)Z_38LOkH#iPR6tC+ZYxvWW0M7iv}up&TK*U#vHivOy1G_Wy61! zD`q2`1l%_pW_Oa`m=%D5+KRjV-g>kxiJ6+U6SMJpzs(60U9QZ2gb$NZ>1JI zu3Jbm0DHZ6KCE+iDgHg6vKW(B+kGgEy1>>6rQehNwJRi^T=x&$^WlNL0kvW$z0{LC-q$^wZfF+Et3TF`>!AOL${h+TZk@DDte;sq0>2Pvu&l=yXm zeLFfA9-#r5S=^s(9Y85!bwKu@T-2J)BO@hCa#N?kuX2L*+y$4nv|i|u1??@}dT=ae z^Smj_&UrUSbOjhTMY&s9sM818go8pO1?%(RaV%z)RuTpq3mQ7<0)KeJn4=z4ZM^O{Kn;~$c=&4H5B8f>#Y(@HA+G# zd}5O~T}z_l^+Y?>^xKdsH@-=$cl1aO1$kzVE_)qa+RZ;0A7T&5T@hFcYV4MAbl(XIZQt=Xgi{Khj41m$o7F;f+6F-7!{XWi_X_DRq^eb*uKaDiPI?mEJVv0kxtZT z?f2#GKH&6BN*tnU3Hd84mrrPi-PP9A5l6dn7*kkxN786cdSU*cilp5EyA>2p`E_UN zvFNb4aaySvorX;9k}FqUtCUycURr^l$MNLousnB|Ckg+8 zO1-6wS|NO~28&GvGq>yk&SiSf`^BVI5gb)e-~#ssKq$0}U0bWkOK4!eRQAXj&a>9Z zK>tg7d4e~*qg_;{x)rq}MwI8Kgp^isW~C-nb$XHl0ah5)y%NY$4<1#Y)V&gnu;Q0c zkJ2?OL4Gmh)&_}WMppQ^TaPo+ABt||^%Pnrewrk&(p1s-ySMyH8#KEpvE2980ABAN z5`sIW?GyD(JMLyv;n^mCs2?8*@oJr{Mn3{#2oHrmerE9e?blG`{J^EoWa_3o3 zG2A>`#7QxzC$B%pPYjF4ER(+J=u8MOTC90nDOYuXLGwF0$Q~rg9vS=DGMNe0jWr^i zq%f15IpO98IN=x8%kM)~`~q*Xs^?!;X?()Lr##w>iTy4plBV+x_P9;1n~sn^{V{a4 ze@$vXai{9TZreLv3)mO5rd0r|?X7jqk61EK+$ww;-QQ2dtA@60GYU+57&k?l)PH;=lO~zqPfE zqn@LYp{$dmt<%4dT~@Ij*8TLT!C#=vJAcS&aNFwxi|{bG>V6R@>+|I+u%T%5kvGZj zDtWO6^YY=t*kLIUD8oIHeWW;0f8ii*0Ts6*GCYab~72=x5%>6 ztcITWokAb3?Q*LauCyvt>1k|v%czcmS1{;QP*RnibvCqO&si}b^cL}IoVb;|=s&I9 zMi}w1Uf6k=2V>Sm{oZ{&)x!m~x9kOFrhFKQd@6~$S-7i{NZ-nB+O~3%T2x{&=)n8y zhq>qJI~RYzbT51_9A&Vnie-{zfnt3G9vf7P=hF1=f2{62o|UlH_wu5A&(ul&o0SqU zbNrUq`cXN^dnFQsyhZ z-fRcy($G~eEjj3KF(5G79~tCt;AA|PT?djmY2;al|(mMWyz3AWjBKPx)ijZG4a7EtNr>A>I|{C*BjIPE@bF! zGB<8Y&z_ygtseHye6TO0yAp6W0i;teT0&gJS04vUD(-T!T) z>y8U&5U58eXqvDdX)%#ohjrscyI@YW4Jq+A-mu${FgPC~%(G3yOM7e2kFz9{l6w$E zXApW|Ij9zHW0%>fUGt@;@@t#MysKWY5?1&qc8&BRc*>0brawA%CtXb8G?C86Lwj%l zOp6B_j%Q>>5DR!vpOipLJz$ftTF%k8^5_21G1u-Sj$hmGNZTdBG6CEk_BfHFSDr3{ zs#%j0A=xo5Ts+G>?Ozs6$i^g=+>ER&QAls~H$FPQ?<+?}-u`Bui`0xGod}m^>?K*t zejWTaKka#@>R;v8&$qim$~xLFRri1A9zj;B4j+Fe_0eU~PvP82XM7&3HxPh;>Azwl zhMGu7XON@pu25T-y!?7G5DGHGf>8TS)6)23uaGA6FL5zB^q&KNJba&j#3#IvjR6=0 z5Rd{a5D?M-DL(&e;1;E_rmCcj^ZA&`l&QzA2`+yLb4VW$A8VX%DmPCafCT}ff|E*w zlLb40^Mks>O%gzT5cH>_={D#mzGaobc$4PCs>M~+r{AUq&0M$FA$u$cmD+j3lg-uE z)0=lo*UQ6Qd1@MQM? z4`uHdBudn53!b)Z+qR98)KMgZ4*xeL9jB6!Yt~B++}29uOIy zr!pWG6c%!Em=C^3CX%dF%QcPA5H2~#kRD8l5~fRN%pIRPJ``FFrE^hpW!8E~cS!Sx zVJ!gqgQ5^&qTI@0)QJNkr-nTmj$bm9M#@iQ|27nk(_lk%ylbo?v!l_Gs;e>+F=S=z z@*}a%pmziSho%Y)9lf(FQy<<<|(P zGC)-1WG&G7%hY_z9$<#U#9pz-gG10+vzHkScbgX-b6dy%l+KcOfRu?=s?LSRNxPdL zEXhe*AhhpYUVv0XAI(|4TOK`A=$c{pz>(Up&hjgYkL}h%BG)CM=j`rv!qMHQ3a%}a zp|u&^D~?v3Bav$?ba6dQQki|Hd`dl0qzFJg1yeC=9QJxJY?h!1HZzf)B3)5< zBmo5-G!US`XENDHRNvQ$JQh!>Mu^F9Y4>+wP3>6VMrxh)0I*Gz(r7Z0lx)?jkN;(X zwmC=@oWucl%8(9nNjifRW?k}VF2#z4Pc>K3sa(vf$AN0KMrV_rhIgV8JgE*`rX zB>SqRiN9RTYst#e-;>sr><+HJiT&7q+m{AA=YSF#&d2X_S3C6I5g|99;9E8zT(dp3 z?>>3CQqmC4uDO>eKomIOG<6_pKg1e2?Ipqam|{@hc!yj7AAgw=+MX9C`yVsv!m) zpeO^V``6s+0jSd57ErD+AGD$l97ZQ@%>V^%*%_Ycg^xg$3Q3EQ05T1BtFe15M;tnj z{u@-s5w9U9UG?K{9mdtaSRW~Ey2(w7&$?Vina%N*!_%=DE#)L!B+*$ShtmRzCwY`D z4afGGpDwgaib*VrO_Pym+2KHp30xQuBeCfE*Ik?GFkgT_*ylog19%XuMv>(M*3L{9 zoo>W#QaJ+zxC=yy$8@>5UGJL6l1ZQDEbYF6=j0uWj7wYHL6B&KJyJ)_)QM2#sXm`0 z+~Vdv?IHSp9LOLXR0wLl?QbJKv_lP0L)f||Is=sp0jr~smi%nm5%i`!rUM9~ zZ{(_7?0yEJ4;i9(#jiE<9M~fy(7U8AfVAP!Fs^X`_i{DaD0744jr)I$=;W70$8g7y z&#O<&YmnyGEX7RHmYmrNlV+R0186XxBSLONdurDn;5jg1Kc|49IwN7(3TR}Y{D#g4 z>mQw)RTNU?9`!6m`2edQpKo`kXmGkZ@->}iB|yW zuxLTDcB?ZC{WyKIkV?Xz$0hy3*WQXVtNdF!YbzECh@l4;!5>V}-vQqV17b8i)APSK zZg7no6V!i$2+VH~!Ts-ph{OMkA5JP;Hpt4zd@d%=&jD7y((Co>5ahV_ttw5qQo#-s z&Aw`CYK6jim4QYsOR(pH>1+M6IC#Z?xt`oxeb=(S@_&TP=I^<@Z=nPXgW#Cbk#MIK zfp9)A(~cTYvA?55Hh12#b~s)veOh0Z2oZRMY+TEN6?ELwo?XZOntiWLqJxS0JQLKB1#%=13n@66{yUTB=(nOjK3pi27WCc5# zX-(lNz+}}_Nw+cPrC@+8925zbXiQ>~@NA@IomZ+ndYa_uP`EJNqb?p`9tUUy#WAIu zJ}U59V>$KvZe0I zfHg%~0#KYjUv-@33CWV)XwZ6CCWRcb-3yE(E~lz@!g-Bk7J?dJ*qAQb}< z)}ZV`+3kw1mvoewlu(ma1tuKx<>G_#i!PoDE}U!g;- z{^<}lu}h-f%6+f6uJVitOTbBCso9#nPnq1G(iEz!~g^5NEI%@a;{ zS3)H0$-hlXC;39W60@-}&GW3^Yu5!UrlIl+M4xY`^e`W%3>q^gM7)?qD;O+%<%Z~Q zDSnIwBaL>Z@;#kNlq!vxpk{}qvs7}(M(G^xvvN<|o3Iw55ai*U92E2Lzo=^Id_C&k zsgST1ud}MeF=|26Tu7<3=54ik=uZU+7+NU2pKIzUnyASoWSwLxdnv9iooGJ(7;-V_ zq-QY#%e+P;F61mHR4!ifrnB^H&v&RtJK1B@%RXhQ^kF_LK*Kb15vlp`DWE5mu^6sa z5OwcV?cQ|aYJQKC{`RoK;Po+zBXVp6IOk}(lSeplE@D&Q=7KoKp{|d4IUA~su*_7v zWHyodzHj`W$|12um7}y1{DE0(LpSFhu->R+!3k#sQ#t{S{8=pgppfd zLKgMRASIbdtABGA^{4Rz4NAWaR#L$Gvq|iwRK<~w62=ru34uXj=07eJgRNj{W~cRV ztsfv=Rix$8HBxP(CRp*vfo5?D;<}F$0;Ql+%mCo&jzYe{a-G2cRh4!Q? zZLw;%KrLIInl)>#SViq7uDICuAmD~kJqiuk9kb8n(HjmEk4>;GufO^3Kg+q%)s%ge zhrW<*wE>PBcW1+qzR@`Y`K)c~hZstkg7aSBiRHmw2Eu*!IHfv6^= z9N@O08?+$!gUOml3{?jG{s0`0Vbb*0`fqPV*8H$!aQN@cZoPpd<=c ze3{BcxRlO$GM!E*KV;N8=t&KuCUla!%j0U>^Mm@iQsa}gX9Ap1vw&sBfy8$t`r1b? z0~@|5@pCZJJx!0oU!@zQ83O7dPU$@{VC(P~=IpY}6exR!m)v8F?>oeP0AADOf_YK^ zV!%h02eheFB zwrnU!5~}9qVyDM9kbhn80&*ni`CR-xwCBIQJ(qc+3H*UA-Ps@sz1ZELUJayXbs~?! zaV`&9q$yt9I&~<1U_(Ia*@|?5*A>3HJ3)gZlQ9{TY;D?%o&4*H!p^7fg>vLI^?c3m zo`TEIv`DXPR;)9*s^HQo1e>^~A(c~-mHhFGZhfd7TPVQl5~ylO41d|^lD@?Dur#yJ zQQbBEomRw}@8-`|Hy6Bk9R9-D6qXqVx;MIq4U5!``PkX(xSMD^&YxSfVuAU+N|ch3O&+w41ww`=^b$y9BoL`%|R`Oz;`x6 zvAH%_2{!9CK5Pl!duchfo2EoK6WzSN**=ua*e1C&`TeJm?BPQBw(K_;o&BCP|6NdW zb2JjLx7Twc{%hnY#ad#a)>ZVL1b!rLinSk z9T9OA>aKs_jDVqqzvw zZm6}*X)sp^Y6Zr`(#tNUMNlqL%DTB9HBCu=uT4Gc;(wg!X(=oGEut62>@OU+Q&7U- z%Y;l*>wlzMA%e$tBy9PDY_WoUw|RkY#K_%v{fF!EAJtr1x>~37FD8@zi#V|Se?GIc zo3Ngvp1AcdI-}@lZ=`4SUxW$;NlC!pvFg#$GBUjLxa$@Ojr2vurs}{($o|a?o4Q$= zTj(Z-oGK3u8p5;rc(XC#)2l$tdGWKL5k0e;x<%~;w!CQvhT-S(CzeYl|GO|t#`xE3`1 zQw)y)1a76=DA)+j6N&^a>%axaT=B6Mkv0->S3V*2rwB zHo+x?@CHnmUms7vfmkgX-*PTTY2mF6d`(;}`!a=kdL&W63ZyC!&xx0T`h)sZJKsrV zGIhj)Wt*?Y=~~ytR+&(b)IBqv57u1wjbbxJ;E$mLzShn5f#;!ug6d$jdlTcU%?O-b9QE}ho<;rjkFDaA zNiAcVY;+SCmB=6bWn5?a-65b3Y9cozoKw_pwF3FBwvwq%`h zjKr6Cb9eE#D!2?dPeG*1pR!p@6=<;CX*N|I3~odco~Z3wc<+*31eT3^Oiy1rd|%a` zAU$`u7QDU)Rfluj09y9da{ZasY_<$10SYE{s9Hj2El};&X`G?$x+;sh97#^X58Kj2lh55pzN=dBV=G1yFva_vc~wDhY;RK{Ke^2$Q#R_8cuMdI4h z$G-v;?G;vw?ggGMNrEd(ijLjKB}SQ3p6&y`5!WDiV6aX)L*UAb?kViUt<+bOXVzr& zQrD{WQwDW9Zfv zl4yZ6_UN>dpSO3bvhz_u!CUFc_Y3*jDlO;X%Inv-QdN#qqH5-eGtOv6)d77h9^KY* z!Kf{4a_`!Bzp&x*az%N8E&$1rWKLMMrCx|iETC=2pE#5mGDy>u#W6~Bl^Xbb7ZnPF zIgC#3%F6rcB7fL(e82x=e;p6g^HlvMmva3YKmWIA+5h@~|7$l@(YE~+dw#3LH^mcf z)MJ)7k#I>I=&PGka}*a1iklj;iS$KdZ30WZ-f66hNgO6oR%vkY#{>F(-)d_71Jxm? z@If-}hYmyMPJr#CAAsUcR893$-F74Le7QDmN@i-lz}WG)?mF>2;X287Q1yA+!Mg@b z?cWd(wiSRbf)A;Wr6lkKM^n~<%*FJ_tDubhV@?2Ehsn?5ixy-q1TBqX{D+31dr^pg z^B^ZY1xO7_559t+@}NGPE|@+r0>D#zQWtd~=}$GNt#oKj>1+6(S95T%TNacRA@rdY zWly2L-p}_+V{^BHZAP@I;OZ($@Dmszn@Oc6V?`Uv(=1&VoC;TEfm@EPOf#1BreOc< zBqzmEx9O8s({zmirQAc5*Yu=`cEF#xaCwFpD!GIchqupHj_k?BaPG653iS80<@4}u zR{_m3dooT{D$^wgjRL~u=i(V^)zBWFYB|j*Q_(v43S_3CCaH-^B_<9|zByCViv`He zc6s705k)Gk^p*4Z%r!;3(7{u!)@Ra@2Y=%x1^mZ8Vu-6yEHey|E_v-5^r9drv~f0147;mUTYwEc#acaMBgZCG+5VtoOwJYTbWU{bQGaCQPDYRLGCU4$K)OZ6onqTFGLaCNvui8OX+9E{qeJ z&Ivdj10D5PXe>TEh7zfPs1{YC0(|NSNgF4oGFpo|^Zlv(q>*H{0vY0lmyVG8AYVEUrEs>)KG72l{FK zWC#ZY{h3Od#>pV4Hq4KbGkxZG!?bl+q!2_EuqY@UPx|-+%5Ct2jMrrU5H8zFux8zA z<+6H|GY=6eQcUjI7~=j{)^4KUn|oL?($wd(KoxpT4Q0UlPY>6Gq8ES*wn!3B(Zhoe z$a%b6?b(P6X+;xV5EcOW(j_-K zik7q^56&N7nm6*-CUmLUx@4y|E-iXpuW(oN@XZz`KH~8>U`)Eb2uZ(owX%hvj$HJe;ZJ5`Td~+o0j;&5DwlTooMy;G-2Q9 z0$0S3){Nf2ckI!ziwxJ;BO|te4Wk4x7~HaF;u=NN_KV-4udj-T0u%~}dTxb}%p`Pk zzFoIl1wc9BM3luSl+Vvk6TUI)06F;iwUEX0+mBnU@4)gg#F+754#XUESvL*HI41%d z9CR^>G_8?ZKs;qTeJ%@r_Y+eMh@_SjtMuWKi;OzO*(ncVl&CfZK0t9K{jU1hiASy2 z;gxfd4V}5z6lv-Bd&Dni<`vC-iOO?+0k#MRgDdmpq7vIYx;mI zoN|5dkMdh z5u&UYI!cE})yuw})P) zkM?SfA3Pyw*zQtqzOgf$E4R>B!mI-?iin!o=icZ)2jlLmcks;(*9d%YR*mXdH2Z>B zy4lz0XC02tah7|J~ps>_M*SmGBu-ogA#jjd$E~{>>Zvmsjsr3y0 zSm@gODGztnz5r;xUjSjit57*xQzizk3nm8+&37kvARDjXO(L1!)x~z2nrXM1%L*E( zGGPUG2X#q-C(G4h$hhc!^%3B%I*A3*#3z5#`hYrf7>Z32AK0A~GZ(&hfBqvbm&+(y z+yB-)r@viRp8v19=RX?L#Q$~wf3t<$lKGW0eH%A#T~!AO3djkFh*+uqqwAyx9mJn& zMIfo`%_5a_DUC2nu`B_t_C&$!g%T$w)_MKIo9JrnynslJmQHFiJ(+oPk~#hT{&hg+ z8*+=in%X4auZ?nDX1gOe_3G*Fem+}lz2_Ii5v>0gw9N1yZver5Y##m)0FKg%bAYVh z3haLJN~{@j3o6EB5qb0>(uuoBvg_T%b6UsSSu( z;q#lGfOjY-^t1#v8Dp$GB2(fQJL;J^*Qq1$7LSevsfP}Hh#6v#j_aJtG6l)g;kn&LmV|C?%hVr#pQ*WYn zctNAZf|uX2-3#z!7AL4nNsM0W!w5OHnPbvEaCjnZes9XZ2Qu{I3G@S522mI5;F2BU zT&AK4$Ku4c>BQ!|q?*I=8gP?Y^A1I2hihOJ-D!FJZ$y%7i?FoHS~9&CVoT{sik@%_ zjyuq+B-5cU*aCBJ0r4jz>?1`#XTa}dPBS^O3=Mt4fJb7=b*_O#(KOgz%uK8%>tvNiCFAzu32i@ z3U6*w%Gg@AT9Ob960}g2t9ZUzR#`Dwvff%&*|I{=``Kx8u_h&0rTk=n;qJNl@R@N4 z{wvFE3*M_<-UkN;i}l*=>9ac$m?9<#G+W|qxxtE5=S`(ZhvhmHEZXg^`I7y5 zI#Pxe;($3~Ow3S}oIjJ|O_nvDhxBW9dkv{BjZ+4gg1ySWrj-g;@rB%LlM5%9+Qt4ZbAGIDo zM1(YA$RKhHT(1eU3Y(%iOekxUtY2Gwem11t$=|&Yb1pG>6HF$f#j%>{f3B9g*;M1q zo+3VQIM|pxD%yB}==!y&4XvR({D6Er6Qb8djr&X`AXp|jc*BKUO;~NFPRJL_4jOZ0 z>=EnJZm~P7oPaP@CzW9sZX{a>lZ5QbKwM*~lctzfYBFipFPkt}D~zlXSM4Sfr;NH0 z=M6usTwsiT`5M)n9lU6hEO|Xz%eq@cMz4b zwmv7fw!g^hUu<_-F^{;lx7m+HP5oqhj%RZcZ(%DvVy$wPHGVkO@`vZvIz?@{HP@#C zwoXIU7b46+IKQrz66nROL*{Xk4z6{oVIyd$-d4NTNUNXBTyQtBeT{FMh=|*zsb+*e zm%@`Bn%{EZx?eMF*EFzuK5ieHkx^GdS6yL!#|QvOpR!;Ya(Bwu=u;PU(m5b6xsxc^ zCYVs(mmo6ePm!>k*8Cb5*3hyMH@j`WSZ{OzWnE12a^HlP zopWd^sxUOZ=2V|HU##}j$HJgA#%)pg<7WbC89?N+(5?xx@Tq?y#nHvGP(*K_WVd2D zMbCunzTjNhF3ezABY1fCHOp*`A|0nS)ojlX^a`gbl_jAM0reev*?0WvJe}XEd?#qKNe0v zwSXjm%A~y`HMCw(4C_G&p*O(snsH=f7$j;vapMKul*yOc?bKi#zWJ3D)c7)2|1wIo zNo{$i5Mdz7-0`BaU42RB*@d zh*CTA&i+P%WGl1qzaUlXmg^P5U`L!n%;^wBP45}~h-tYNf~(*{{BzDO2a6zR@)vSdwQ3KJ{hglr^E%qgk-s|K z&ZInawaz6lDdw+T)xs5d<^EjBa3e`i(_2}0z)7M6= zBfZv3_HF5&e>=y|Br2;qD5GL-@@<>RCuQD8jUq|r?|#1(sIfqf<9wxwJ4!U(V z-;N?T$Owd5iT!D66vRA;69D!~^@rPoHk|XtJ|>89kej_1k)Ce$lujNmBx7~V&G^D! z6pwenJY|Sg(!g1X4WRhZs?zV(_Tlqi9)8)k-%tC)@V4nBUP7JStTa~{z&gc)D6z~GkNERi_r@d$KmiKNudu{r}xqM$w= z+q+ej^ZC>F1SZ$!4X>=c1cZ)-%U^1a%~kLB1rUih7&ss#$}rTO1iB_9->pRW%&mF$ zV2W)QZtW!zHmI%{=yQ@N={*4tTZN!{Lg?JtG7o1CCchB#ud4KNHjDn*V83fVCeTJh zQCHFhBR)Sn8p1OP{be5HrZE4yAJ{X?dM@VdRduqLjRDNXfOpO5{42ePW>4J_D{fYr zY@*==Kgr$PgyhWSg50h%074>+v}H9Pj}RrVVHJ7n%O#vvSJj05bjuDBc46qI2>V6e z|0B!*&kh=X1mEtGEE;Ig4u0wtcVRdWkvhWae;hQd$si?t^-II|nL$PYVMDHbYKFVV z_-fd$?5Vbtn*a5@XC+BQs&y~o|3Drg!Smm+9uWM_Z}+=R1MuGfgt-WoDlu99=ido zdT|cjX0_R5je+8~;%-PhN(NT2f+CBV^{jqV+aNGgJ0MWtnqCjBxJgoK{2}S@6(4<1 zRa{vDKU`B*yORqmYk-_F>#5rabqf#2t*s{m@yeU);L!~^uwQ?|!Ok~wk|D~jubM%z2 zZ$su(&QrnLiKllavhT9dI&6laV-oy}(#OX;u`U z@N=s(7#c}C%n*LZI^-I1fP{Q-=z(T{W?ehT-cLcWzE1DEuClN}=(Dhf*@y@IZ(a;+ z_D!H|SH=1@3Cti7?H~~@AqlTR3B!0{=A@LtR6&5ckX#7Vx{1VQ$l6mF>s4#Bl;nl! zC#@J)2)4KkBnmDXiP%ab6^@h2_1txF_Z|kYWDLcA>GzEjS#rm%YZJUwZ|uUkVTKxg z14uPjh$o5^?!_i1P+W=>G9_ijcBm;A<1{DjHz)4@+RWFb#B8duwH+-+<_q4EuM0)} zElLlipp2AMM!tBxJXcb*i%JjHVZkwDLE-|}Pf0I&a)^T%UY>zjjByib1;AT)kJ}z; z^5%B@>0Fleb*DU)D>dZ#0`|bIYG7=YiEUDdGLWi5v2l~ERJb^xk$t518Z45S@>6BW zK2~Vjp!~>bd~oVH+JWkCnFul;elKSNWq7EqKFF#X+QeaSa4}T7j?UEJT=HyPR4=}x5kPBnLhB8?Idka@V_bS}vIbhM zy#zWt;J^}GiUWDsX+-L}l05=dODd$g4(tT##G6n3S(47_xTw~t(n~2?dxmX;6T6i* zTS+MW-@W!0?>`NNK7XDrL^@ys{!ylPS&MmaUX&q2FG<2(8hmr8z-pxzuL%7>p1$900yo5)|`qECA(O|&kf;PD^4^gXr3^9fhiFkF*lwSMRY zYPIW|rwLuha&2;Wz&`{_TD4!HN^~VD+~h8<7*xK~V=mEB%d!2ddk44rVz89MYboeV zGU>@RNETdAW!=|pJSrkP#YUgd96@V3!cxDtUb^efT)CxNEviAZzOhrPP?lIfunix3 zUX7{ES_U#tu7Xg6f*NQ!58=nxTJ&|R;&lLD5th$;N4E1yZ{-ciZ4Ya;7R_oe8YFC> zJ_{)AvwGfI_YF{xMpd_N*#S$@sFwnFAFJ%&S}5Zyn-2O+4ml9QH7?GhV|2Tw&|~S- zR~En5ov%c`fzz!k?J?8F@{lU@?kga2|9&rT0JVGGv#quMr2w6X1%?EOaIyrtFUke*x>tQ0#UZ1!|KzgT?7b~9h!wHz4P0U6;Ddn%&Ga(92E?xF=vd+{p9XbO z)ghmC`4?v8INc(tLAuBEI;7<1urJQ(TEMtHM6Nh`_9a@s(;b~@kw|JW2Jtlp{F9-v zVx&%#r*Hj*Nwk;la*!v0F1O}B>Tp+N{?Seu5el$D;y$zW5gSOCD|nXS%cDQ56O|LV z+JJ3~ADOOigV3p%8_{J54X3yN38pEod|80n+vp&`(aCTZuFq=kao+9)P;$ZZUBpgs~DFBt7ywA&1&NT4Usq-f+-qgx54& zS@VDbB@((#IQolBca}KBvK}a*G^WIj%p-XEl{(_Yp^|r|;k~mL@SX7L9&uWcu0Xm= z(4#ZFV#z|Rln=k`d-P-UVzh$IHp?BUV@dP1^d0J2&PSw&Gq_`EqctS>HJZ~eAabw- zo0j|Jc2_#Y&j6NBhI718`-KsTSRJ591>|+!`F_g->dO#kN9s%KX~DYU4OC~0XXOk} z)Nsf8nAIVt)fWZ$@(Zgw?Yr!%T;YbrbQSgrEGUaEa7SOI7RtU6wle2<07OE)N5KZ~< z9qN9^h}w=2w~~ikm!j_^W9K{7^!K%oT`YNe9E4Zwrc!6Ae&i9u%)L~7Fm;w6+}$AQ z`V%Rxp2@?8uEW2vOs$_hS?+LqK%8Clh3xI<-#`BW!6@0apNjq(yc+)Y`N;ko2u9S* z)yPoM%-u-p*Msee{@XTbiwVad@k|>hB#tZ3!=<(7CW^P7(xRx81#k^ zan^&{-yX)Z*&>fPPGXi0+X0c?)@tF#jr=`gBug0)bmb1L!BBd2YV#DLec;Rn-z)6& zndb*GcH|~Glf7^y4Ya{*gR#7{t!KAYC$Ot_-c|w+azkCz<4fbZ@ z(wQ3tbb=iFnz5Q%{u)?uZ+#?KMr`NG0M#tHglO!b@XBcvxOgAMgUI6K-t1f|ajSg1 zc+<|qS$2DaX)a@|UL7rr0hnu>M(NruIc*rB7s%6>HdeS z_`ipeeu|7ZJ(pU zHONmS8L2~mrLlnze4xHaw?%t;i|hZX|8!xDJY8C<1G{e<2|2Qf8$kiqVOh~5!R_%* z$JSGOAy!y=q!AGgTCKMgh#ymF9+!zhd7!r#&f5a;&<-=N*n;d9#p^u=jdLA(z= zB$kN+KY_~?2Pk0W+F6k{1w8`WG~Wvm$VgD}4rGwtv-I+l@o9R_L-Iz<0GO`?ZIs?P zU$YU!&R5$WEChO1%jL+9oP=56Y=O49*LI!Wh@Z!O45(-v%ZVS%( zG(Q0;!4Plz@r|8mqnnIrU0Z_jC2-~~L~(M;#aLSwz8jg8wI1qYbJZpov-J<6i9Jx5 z1l(Texeo(0SDY%69b$l!B#tT17s{qBB73DM*r2+Gp9f{?h`doyCas;t`cd~^%4+dH zjUx6}Rk3WK)^Xa}BCtfLDL&j1nxoYnAU6ZS5BqVwJ7-iv6R5YlRKk%H=iA8XgNv9A{o?U(8 zd}m=5n83%4L}jJqPJIk^>QZaHnKa%x0Z%v3UtmED3izn@?w~{hk8KjC5%o=5R|#|g zH_#xO&ITU?>GO)U^^mTEuMaQGQfT;eFTM=`lidPmagNn<2Q9g#XZ=9uZ`uqu0N*$O zUq1j}K^^+U{qqX*^+?;x(MOaqpwsDtHzRU|fxD;S4rinHV^eN@Q7G_xLdQ@4OawQG zEuBkkG!}s>Pe+Z<>+8n_`GD8W_h?Hv>xfd8RCrdg-)>*@U&)KPPhQbA^aWM>+#ToG-cR zD5Gpf<>7e1aB)J@4fZ8s|HIK# zsv^B==JI2S0`qG2@6i&&q;s zD~OmZpo5uN8yjC}0ZCD0VPFX)6FK!MxJIeGG}!2!UR<5gOq`W(s#sWErO*VTw62uC zY^I@VwnHlIkuWclKq{TyC~K8`=~I1E-Sw|fMdY3%=7!_M&HLws`$X#@gUey;8$-fkI&3)iUt=%7AL&Q4~?z}nPRZJ_WHFJ&q*n2gy|I$gFsZ=V9?goSw1 zv`-PUSebb1mViXN(1?ksXWBe9!Aq1?w!AfWKi}8>S2&Rf3$;q5jRY9&%A160iaT*Q zUo!EqaMoWCc1E4!I&wcI>`W*>I(l;~^w*455&1TTtM=6uBEHWgbYwGJ;TAF_Ps|0IS2F(;i>;2I@#zUT$JAtHp zm{K@pguyYi2WLt=`2wIOTPq&z%w!=HH9ZJd1(T>l+2cIM7aEk-XeP8%d`pc@2bf5r;c9(vbo#$FOLx{d9*tC*nG%Ph zbhRjzbxt_vYgAu;kFQO!nh4y>6#aLj2Hz44x7k1HgioYNZ$54uOkM<8hpW5I&MMI4vUNF)R~|6jChs9d_cNmP;pk%N4|Rzw>ziA#HlivbP{y{`x*+d3VX&NQ zof^OZZSe!M8o86iTj5?BT=dXz>2W$oIbfeVoW5{QC_eUJwR?i2al6`xP`q_)yj50K z{$asY%wVfGM_jnrR1NU1H9(HQRM%nE0m`jz%ieT=zx)v(dZZ>2j#|yiEUAymjX)*J z%OHv;4aa?qZ=Atz`~oWvPkjx%*SeQW4csBi(L!5ja>+D!79!B@2$oY)6)N-noyFb5 z(P&Au`xlX31I(5W2p0ZUQfdrf9~$1S6x22YfP4X!=wAxJs@0!x7+*cWXH8$aR9~-l zeL%_;_(*f7H{R{Y8}@^!*c&SFePA=u)cFwe*M3ypoS~H_2wkwZXARFCrZ@LR$ZX29 z#CAuYjY#WEUeZ}#huZ^&HwEIgM3EBo44u3ShBItWd$=rxJg7M99FZ4z)v^6WAV0Kf zL8!_;w}2=G5>v)g6AYthU^H_`4K{-(3OOU5D0qx40ADpX<<2l?p zP1nYOYP6c%vXSbS=#YuO)j|arI5oJgUrczf);e_c=UJWHn72TTU$NYL`dd1r8z?H< zl7+32LapXShzt@;MVhS+%|JKPnXOgXzAuY?7W`@|8miQQ}lX{pIhELj3m};NO5O zr)TeA^k25JQOequ$SWw{)7O*Jm#)h?*tCXr&=CYrve=o;jvMHLkg)8qta7$e_!N4b zT$NzU9TS(-bqkGAO8KOP=1C#t<%lGs%0^9IX1d9xxs6^C{+JXt@xVTRA z!6Vd{E%evDeb!h=?_T_HU^s<#VijHk!+KzU>CblUq}JHWTXJgcCWr07WcMkcb{cI3 zW7jd10!&lz*H-vQ=ta#*bY~fGmA-(c*39@aAB(9H9ivymb&STLfV#R#nDf(e309eP zDyLxGmK4;WB!r6E@{Ey{f^nZtVBPcv;9S5b+p{5-pQ3V}r`?25YBX>;5rYJpItzZr zcpjDX_;HS+t^Ayt)gwN);`oP8$0J&W%2dlvd`2Gypy`8-I7QLiVwh%?9T1Aus&w!g$0QuSq0x^RT{l1AF-w&wTZc5 zjjJ%seA0;GRJobZKD^{_2zcaO!L?INDMM$W<}7h^YSAScJ(nu&`4h0 zoySEmnA|bc*su1XQ)h#XRAAXE)pyp zN;~Jn7Rg2iQazP@8+JDiZSEfS70>U%c9a0iw ze{1T6)4pU9uwn8d9A8i7SwVf16!kWJSz;FwC{dRce=VF*&Mg{ZsA5K4q4J7uiDf4ph1rLyTtzoW#1HJS+{kWnU%I}+qP}H(zb0>+E%41ZQHhO+g9hj_ebBa z|F1hbVy}pE9?rvFXRbNNnivDhdL*DsJ4v@2#UtOOF;>BvPo!zo$di^(CQ788vlu$b z-T1bhAmW+8^_Fi=Z<6lBN(q+Xu{^Rlq$lx)lrtp|b9F{v6aG*q*kvKR`Bw#%^`Zrq zMcJhDn5vUELbL@PdxSh@u;E0>73E_KaD>ZTA?oyM5l#_uO!ho;hH*;ocFuq9n8n2in-f zpKgG8yY1hDfA0EjQ@ls$R_>U4LC0)pB0_btlaFDJ4|@R5#>^>hhi(gukIK#)(@l>0 zY_6g(lk{_>9TmO-9Uh2qQ_<}ew+CDe%U$cdfMlnjc9Nyo>wf-1+n0Ope8-?032nyr z?HjwbedqrS#2WxRz$rH-m9QG-lK)qL56g}_i2e=dp5r5Q= zt#xS+-Ad@u#chsq2MDLK$#DAzngTS-ESJ9=he(!zgOuFk6#ImGk(;u~4!_2rf9-@E>DkQs~bR;oXl-Z)f~*fW$*rV=ZjJ~ zlS@!T|H^u#vDJb!Fc&DO4L`1KP%Ua39+=pv2+#YW(4NxR4OPfeh|*}xpf&tx++;Pv zn5NKV9ZWlJLR5plzH^-Gj-tfvh~vktQyXo z%!~ccUNa5?88v(EUIEUA?6O^Nv=XPRmMsb-2pHxJ(EtY7IofpV>`hR2hz(H^dlnX+w9#u`;7AZ~YP3kg$4n$aSA-}Hmw`06 z)m3!iP~VI)cLM9~&a*Om3QN2`62cEOTjc6Lj=(B)sNwu7wyc;~Tqqs6yQTZkr@tWF z7Wb0LtrKnopPEYL^smw85S9e;?}nAB?TIW4l#n<>fbSQjbPyWkB47^9s*E+&}t9rwJ;rd(D`AX^ovnGpd zd-sJ!LeceH^{PInDWE||wpN44&^ql@1ME-Gwb6qbEQg??HI8jeC@u_aE(W?rjmM5dlqO3qnz z<{>&e^cILJ>R`HbSk#XUh?F0=21=gl5p-uPslZBsDh-&* z(68tLDA1Dg@pzfaNjI{zbnl(|TDfJVw}HI~Tm2|j)5IbtjRI)a4R9MA*!waa#41xo zB56DmQi$)Iy$b$qB8uu4&i5nIFZjsPK-~lFx^}Du%N^jkJ&&kzVSR2{ezPTJske>5 zz52l6W|qvi^t6l|tC?QzSUk~J$!x9rNqLpuSu^MkhxMYMwwEc^;Utyf3Yw+7Ag7M; zy6=$PfuKPL<~vi8$( zJxKr?N!!>SDd8DF=^6NHSL)REn)h-S6?a?cJu>DRe(o6tZ%^)$TxAE9>%75$Ct2;Z zCUVIfsZ`6W*em1*=jL=eD^H*fw@B8dJ@%sgHicNB3@fN>V_CR!DoP*qo{Bt}%D`%U zA&qO=*KgY|Zp=S42CJIGXrJcOsd1yMSk8emh5eJeY70dbF-!>yu67hH|MKuYM@kr z==c@x%7YT|jztlDl$uWYd*6q;InMCO5C3jCG6$JG1tSk! zR`<&P!0N_-d#rlMi?R9a7v^XFU#Al&eCdv(zFm6p_xd{yxNibDiEo##|6fuRGO{(W zKm^EVTsPB>H*ng{aXr5D`ZGNfFdVz~0^+euPu8$Let5<~J^i#Y8LSs?cV2+Y`aKLs zX5j5gPk|Un`n8*x5aVA##LPwX!q$(A7`=+G#0g=P!Oa&7LI|py>p{2H(2Xb;!Vs}mf&q}l@Ocb^Fo%KyLGWc9BiY1I z85_-QJC|9i6%UFHjlUojDd%KY5$JN2uuCqa*J|cI&zv~3bbXxu%wepZ)XQ=)5_)f5 zW%6hsm-0PwZ9RDBJh{_tHC=hX=eq)EN8|$<3Ca&kGEq$M5HRDjg?4xW1OxmDSjG{A z_cXGoVtxZ!#uIGGq!{wYhaG*=HNQ+a`~<)S-|c}vG?W8?1G%aG#X~%i68J0$9OcQgD>F zNR1;4*F}kR>2&V4wN+~%I^-Tjx(Pgu7_Mbi?`(F~p-ml)waMV>YdJ$*?5ef%p~GP( zO}*F0CW2*c?5GKOyCQMnxKj#;d2|8fn|N<>07q@vQs#W>iHCa?BTa zkbMz9IWIxN4wHEM9XaD$)#y264okwewOIq?Uc;92?8_P6F-ggLbPUTW8(az_vK3j$ zv#A)QZQ5XfrN(1FDo4UHDlUnmH&R6mbD2pHvD&l%2_-9^<8-|@@zt=r>Ev@|oBq||d$ z;N>p?^g(BJq(N2l?4AckFV;w7Gi9@9?wumLh4aQsr*y2jtd^P*2r4D=734from z1d!QK`4D0B=`(rq-X~_@dsuGS=MD2xR~fTjRFO7T%IeyA*A6%Qe8#6-iwhB}gQUTO zQ&{2!yoP(+)K*qQ5Bte^*b;#4@Pi2L=%RS9B4IeF4uZLP?6t07*NW(*y0AoHpY$Px z8UclnQnUv#x)5c`=_hLNGrETR zV3=TS#t3S6pJv+&CVIKmquFA;s=gRHuVVmvu7HPn9GWd%QTb~-2axn%(DQ!wnAzEf z=@@Pqrh3d>f8;9kv_x9AKRM=={4LpaM{wn>a}FZSQUe)vE2Jnin9H4*BNYNuwu19| z#9%sT@^VQ?VHWDgOG`pxtifWogjupuLo@6_Y-UPNtqIf%RU~X#Jo6~?l025XV3)Wg z)lM0<<$#NC63Yk*0JlVWcr-1RH-oX5jS2Omh<1#@9^-*EZb%GlLpKAyh$%g$@Y&^A zj+g~akv5y;lj%1FpON8S$jcD{aS=t-ZcgyeU#p|;0<~9Ue{;zP(&fUs&ZxPznTUW} z(yX%7lfWXMRLp_8RP&)_Lm}@#Y>TQs0@%c}36ZVT)NCH3Absrw~mtAAbOCqE&zzd6TuRz;+PS%RgCI;k^IgO&>UmnurO#t5)4bHiokG9PF!-Ug$;kJ3}2?pj9^-*@d{}j`D4ncPx@z<}jR?I=w8D}hV_|@m6$ZLpIb2jUDk6Sm1(dYF<{R3B6zTF^wA!*sJfLo?i zK6wy;9;meKLIRG7_7`3?S^ER$)mxJ=op_RrdL5X`KFn(o zHsT-G%GTi1p^#ds9<0T4vfP!D<9a*BegkhLNquAr3uvASs)3kB$L0IZEEqp`^Q7TH z?2-w$NRaq;PN(D}avZ0sn$OULA8?=E<3Wy>Y>H`&{U9B7Op+qJk^;3omdt#^UU-AcIRyKa3ZqPohFlJqQsYElZU533A$!gt&W=ntipXiW|v|OQZumVmTtio-|B%90G`9Fo7NkQNIoSg_cDSV%~<>s4-?3s$gD)IkJdUyucW> zui)xZ{P0{DSzmVjX7x3h`by^i716ZaWj+d4-t;8^i%O$yewN`CW?LClb=q}Y zP@(m5=74@3eo?BPp>Y`@>lq6T9!f=ra43onmPz2HfLrGVfh$ln+ zwNxq}7Ngo)t(Ht2h*latwzffaQk`xNswTdryw>S46FcAg|5FgK2M zmB3F3u4EIHK16ooMXk0#8;hAd0vHloy?Dy+;75J558E_Y9#7%Z;A(yeZNaBtuB;KRbXu9t>AqF{TR6w37Uo=6CJ zh!!&JTf0vFtir0K{^};G$ z?$chdxty3+0|JXhR4$TPsWF-PIi4m>QzPH0rOri+$j6o_`Ki`K`fyrw0-6sJ%dXf3 z)-)cAW()!P0cJ)(TxPV?p623^bcjc!tas+hC-7kjnL=51o?*^!!yMzouAm@~v=v|I zviY+61&Q_2&IsNI9xIi(J3&IQF!W8f_P=cXRRYC3XlZiQ2y9`TCsnzjSQubn~;OG>KaFj4#{$ z2dWGizBV&w3&&_s##0%?GsmRm#m^WSZ}|Q_<0Ez1PBHZjpXt8|oACc0Mt}1{|0~hs z9Nl5l%MTx9+QS!=1FZN*B5u&8IbfD2zEGSZR&z+{MFt zzJjzJIt3{?OH8Geqd4Xx4hjzeoX80YV;F{bssL1!< zH$x1@Y}W646B57I-`$a<^$m=zjE%nUN&mrA#r0sj#0v@vY6vRp0_x%d3M&d4eLs(w z(_b);EedJ^BO@mYTDko`o42prG@hv}3JO@QY!PlMVNt28YM?<#6zJvPQ|V)%E2-dP z67C}z>|-ur63rXW_?t9V@FTOo-O2l_pnQHGkyR8_6qFPcUe5?{wXYklf)teX zFQn*FFcE#y--RLf@2k=O;}!n6rZ#jQ7=f4dbVE9Um;yywvZFYS7#Sh{a$r6FGA4gMou^=O_KJ z8fXw5?k+yw92P3WZLq5VMRlXj6Ft&IZX!5d5R5|3l7|r;Jj6h<5-laHHV(l+HjpSI zol#7_e6Sm&gnI{>6wg!?i<^D_=Wal9X=w~C)J(V40v>#O7P3D zx{+Y6{U`)1>XDQ5s|jc7QaQU^v;}fhC(}iiL*9mmXn2UsfFgV3v6K;Hda^Lbx?J;) zN7hlBQogkHS#aD?{#`F2Q-zUBha!!#=zIL$nCuX{tAVjAMkk~{6HU}j)~OZ8cGyio zn0F$CzFN$i&B1;u+dgP3Iic1C7gC*#GJnN|$wOqnzU{6`Xr~rau(6{gvj_+VttsSU zG259Or%)xc#{tU3Npi??Gawr!@t2qmD{KCSD42(}TWZY>uosq!ogr!3*nGgW^i`s9_D(;Z-_zPVB@+XB zb(bq9SdQ#8hmlc5*Y)f?hI<28yQcWym{I_!G+_=h4rokH+i(VbslR1I}QOLyoF zN15^B^!MhO*)YO2o*ij(k!dIDhqaiA3ogN`;pZMry~U>&tdFnhI^MZ|gdv@Cf3X)X za?nhUv!lQ|r0tZQoLx1WP#7exD1M39Ke%{r2TMU(GA?mGN?|NXh^Ib$>Ee#ca+#sJ zy!qTXsf6FZ^V1$Scc!9diFw8Kxzyj`toMth#e|5*5JecCCb~eGhU#4pfT$WLM98m1 z{K7fF|0Ic=YR2qST{Y=9UyIu=LCszr)X;K+WFz=-tN>OUNm0X4%Op%Ftq$S<|U=BBI74&s8-Du+-in%jUq>qqIWy+8fus*-M=|K z%~;}3X2HzjNKDMq*_Nw*I`=9k(o?(sI5oo~m>*hhHWa^Ii8B~2t-)7_mEVu9s$346Yu9;oLt9nS3*j<8qAe1%!gEc?Z7TYb0zI#jZ=`Fa6})A!s8oi5_b=`?1n%U zt=m7EA7Q4^U;$Xx(q;l!5n=Y$7-8`RX^A3Qzuk4k8RM*zvxsk^LHvA5dJV+&i1_u8 zMwUyb^il=CT(&&a&~}4KcXP(V$aXz%W6`ar-)1q&hnaKxS3dTl~3`h*F#5QCL$|4N}iisidaXG1gRq%vI9aV>9jZMS5DSaMZy+3vB zVt9*}3RF1-8?Usf+EBJ|b&GDt_>NzVjR-egdXx8lOPs*=9rTow8_^&37&7`wr~rBfLYM zmjtJvf+J^=9?V5Gd~qhB=_ky2BRubL{~l3~4wdNCzBy5dzBy4y{{~+CBM$wa(i8vC za-P#sZ>6sP{T%ECF0v*<@oY^$7^FN`uq^}w!CkWy^>{-|J5({)9YpcSTZlH z^B;oFjUsP;u@mRx>l}`kEv6HL%*_%e`f8O+|&LljLBR?2)C|OYl8kdx6S0Fu> z#0v5ls*mS@(ONO3V(Diw8Bq$}R=AW6<}c~e{2n$Ux$n?hiwMeo3jBlGyPa6LKO?$5 zz)*D3%Ms>aSukedaf5nAUP|?I*%-Zya>}>v1SeB|EJ1{FxiaKp_=rw;dd{V{zV@o) zfm|`(2YyhHm9@np#2HEitW4c8R$#FQ_>vR7uUTkwtLYyq&ExFN;gxK-#tFB5^|_GmAAztS@jTsGn?3FOQW} zCJ{`g031EgcF=S$BkU&lS#OuAXYp#1T1si{l+^R8WiqJ0~LD*hebLb#8t`CAEGf^lf#D@cJSf5^UNeNRoB|-_os{4dI#O@Cyj9Wfr zA3Ig3Bj%(SLLbNpOWuwQ3>wINq;-a@+~&6yT)dyb%6G5E&qj4|43|j?%@$=FQkDbF z7v({hxAOS5pZq*}E6EwC;G}CI7z;|{X+SLA$=0yaD55e)kqqfalY^ZGi^FhO(IiU; zG6PxF!*S|KLWr@Z!->oSL@D{cj6@QGbD}=sJA^`OwT_38{135~MpgG%YGc!-hN$6l z%mGNEBQfp#R{NkOGC=R_%Om-i@qQ*dW;cM}s>JS*CN&X64(Cw6k~F4I<9<2WBLhlt|X>bFIY z>GhM>ayra1-eh(^K9p4&LYw34&31{r4lT*FL_?@!k~(V(=nfG$F)46DRy!jL_>(Rc zS+0=y&Z^*4?Nsw$%y~ga%cg6n>7A_(7LIG@g$K0*{2(AHy8kaW{(8>qu5I_?3=5 z;ueXSGvLRu=kdBTCU0ds)Bf70{)oC3G6TGl4eSYtL=rKcjq*oE#BRMug)gAqZ{org zfAxyU?h`hkDYxGDhcRGol{+$jz@8{MHWGG*e4wd9jESb-WvF9OT3svbYVDJAzKk(>tazZy7oCCxo2==CvzS-Iul4|@ma`eJb41# zeE+MgIJxCJ?u42Lrs>I0E@Onwg*cMKQR?#6g4k1JQW! zS>JP$aPSvTWhzOVCsR6-)l|smiiQ@_X+o^1;Zr+#UB|Js49n`pGxlg$Ag`{Q157}5#nwd)65T&O@611}Mlr>i$U=(;Y^)5l ze&vUnilt8Lsy?E>+GS2$0I$tUs3*QVLvMR$4u-xDePsI9{oJLt*~7lv0m9V-=5zQ2 zLA#-%-C+~uHBx(r0{t|ROC-VCtDC)nP&5LMy&iU=d6 zY}m~QK&Mur-{lq*BKC_rq;#j7s8nMcpTW!cGUPf4jrQz7^}zWpAXEJ@uP+I00#qk@ zOUVW`?(J8WXEx+wIAU1J_~3HB#X$v~&X|+h3?EAas5M(N|H46>Uw1E<%8}k}u>* z*=+k{gmvk7W5WY2jQom2X?8hGdk{v(I#d#am}7*DLGUxF({6o<=ZL?7@>b%C*-+qI zWM^$cEiI1&Mbfd{hy9!5H}Ja+ZD=gZ`zT6D6yks}yxJ_JPRz~Y*aIve6fg^z&w6dU zN0{CJOk!H*_Q5q%|Dj7ZM6wWX%{4&B)3W)hB|yJszq9wBFeZwl5p7kD6y`duJ;W3X`7tpkyKq8?kyW#j@`IatjT1R{5WgO%`7R>{Nc)|5MbYv3r?V^%#V%Ar<;Ix^MUuO-R`;I4lT(6xWcPj+KQn_( znz5%E@BgCKelgV6ZTy|OYW+61zvEZ`Z&MR-Gc>ky`Y(>XsJIE)UVh}@sp~n)JaWig zxja!MkVu{8{%V5sRAn}JZMZ^zhC;(p<(nGqxaMm>FY>*tS$Gj~s{|%j(jy;7o41#T zPrz-&HjDy=X~p?k>pUZa(4J<*PI>2$-n5V5oR$OoE>jj2{CC}obrW$Gqb1|vm0s7Y zK7k<^&Gx++iOpo#r&Vrv4?Mg-%0HnoMjMI1P@mfTk#)+rY6VHS&uEp~iMVrhtHh$; z3WDw}p%1%pVBP5mKP9^5U(?DK;PxXrDZ-Oo+}H~`d$qxYj3>pR^wa)8{}}2(@Q9qv z{H8l#g8K0%IWw8N?}QJm(DruhWN@)$N1)h8=yeo_0-HeOOPo)F-kazI@#0i`8VWt> z6#YD^6gXLeY32m?;amv@nT)m^A4>tc+#m`)Jt<>Ia=aGymvggULv&PXQjA7ZB9la! zMoD%|TxKv%!UJ&tj;xhZDhAkG(jaN^X5_b?>0dzC3z|G%J&_J2t?{<~CPhio4` za&XMrAM*^x7*G9UIc&RewA&-ovrn4 z{^fN4hYaRpyjRTZdOx=)C<2U3PI-T=@IOXj`L6R2kAG^1BsW0 zw)#sJGqt4knhG2M0ONb~{qOn^m0fLxY^|KFZT@$AiBk2nQ&z+H+Bn~{v9Z}CHW~p% zr6jO|+)*juFZKgby!#!5sAQp^&@n>0asH>xHDg{aqOoz|m7KQ*S+n#{MPsmJ?Q${u zX(Us0e)Jc|>2peUO5Oi6*9*XREfa$RH0e``&)P10L! z_mT^Ivg0%{FTRv5DBoOPj!ojgz>#z)s^sFqmdOq`L9BIQ8!MN9fdN5te%RpQu!>p> za|$mVtz8o-4?_3~a*HYYJa=x58+l{}srV@f=taY=C0C98R z*D$?^MzoW=xvlf6IVCV`#wGHFy^BC_6Wa{I~w1+QAXAWS%JdjZG z_oeS%$nC378ZHL(rCV`lNewDyoZD%)$S3-)2_p-Ua^B!*z?!RT&CiUv;mDCG_P6uP zfdpb)o zx#~5AE!~8KJsHG=an+cDEYXcjtPI#J0n4p1FripK7hUwpo6hqr% zT=qG;=n4&Kk#gIAP>`M$YtcEEm1b$NS#=1RSXU0q->2i(n1Bg= z2`g&y`{L0$ZiX+Swg>cQ;8!_ccBp9;FVvNuysgdkW_GBpEk1gxf6jX=JYe{-Qt^fs zFO*?*C82tDsJoObW#B7xY2}PO7fff22@ke^MGyecHIiRgAovbENAxwK*oZ5fd$fHK zRL8L>pT{s@B>X;s175HGDS>u7p6icr&R$E)aL&;VMiCsM0|jL?xsLh;xrw%&{AgS+ zzr-9DF7sS4&I;SY23}yhOh*002?%YRCyV#7Z+VJbC9tD}r24_fBTl>6bSFujU;7Fh zpG?Y=c_!7BtTC-x1Xn5=i*Sn-qxn0kQu-_8W4~Rq-5cm5rYw1U5q;lKr$5Etn9~V! z&4GyowxAcK^EnXjsR)tNM8@={(MAm~m=`&ye5Ix{#N05?s*sZQZamSwZi3OC?xKrY zJmAahLC+Y1R9Ta(@2_yqsa$ukz3<>bmxXZo!)e$jvh0m+=qK;6o;a2%F^4j-5~}0| zwgV&uWEA3qjKg2?DPr=7X>~1lC82pDdjODbd=z~St`@E*5#nP$7wk2)z3JptR0`MM z{q{@(?ry;5Z%sfbWa zP@7;`?a_Glj>A%St!6bl-d=T|1yQ{P5nq04v|eV`%UhH@zntKglUw z3oRMb>l{+%gQ%6IW|JaCea?-)@c>gve?RM^#x5>E=!%?t3zi&B{Go*w8l!e)r(L6K z(L z;F)jXMprI|FCB0&=W^m>F(GVA#o$n5obnFGCGrB7*&-^zj%jSfKC`LH`9z8WP6@=^ zHPY(({5oH9`WM-dufqM-Il&i&a?l)yOA8NiMQvXP_g%S}qG3@YrSJ1!O22W>?DKEm zV9D$onEoATQqy;^`JQ|D7ijX1nUL)NMy7HW)(xs+U{1M_+mm?oP${EU!fFG-M0=cb zAs&S?#4@4oG-?4*c-^6hwr74&J-{}TJRDC@FaJcQ{`vtZ&<0jR%Luc4OjkLFX38kDD8+XEn1%j8VgbshZfa2e zW0wr6L2Yza5+5^~21^CM)M~E0qV(BL87pmd=HM-b!>ALT<=TTxpb7%}*#mX{MR=vP zSF*?!q21+H3n~Ww{I-GEjxorxYcuZCZR+Il2zoP0$v@6=vVm{}TQg{JMHcMbDNw~4 z`&d5VV{-NvxG8-8RU!KiIRAYG``exS=cvekNH2OTjC^0a&_Dlxgb$Pcviv2MOUgV* zG#CLd7>c%+Jf4mUN_=$tbVv#9f@_C?T;_m6|1zH^%g*~gz zDnBOB7w)g}!xB2p8{yZnpMWj%8+1wE^aHwNBY6AXiP`pu67O}1VvSJfn>VdUCfR_p z69p->^BRO0Dx5Y3`zCjAc)e9cWS4u zYT=3X;$OM%2|e=1BI_-jyL^RIxb~J=`gb{4u`PtJ z+|AXpph8n&;%84NugfCgo9wulGPl4&syw{;5Cs!p)t(Ewzga%Pf6Erog!{i^2Z@C9 z{{jjR<40>fT^Lt0a~)2nn>LY~o|KT!Q4mrK5LpFG@NyN;dyuIQK^(28qo9t6Kyi*f z{R?N*w*~)~jylR;u)nplm6N%VvD^P4q|QbX{ipw15US;y;o+}>Q2+HK0S7}fa~ETI zeJ3*!D`V^L5g=j)VupX6g(Q`qN?0n$Upk1jMk|8An3_r9lEK8iK#j#9HU58SSRfiG z=JR-|Gq^^q6E?<8`sBO(@%-hc(eO^Ca~CGnb5=3%yzckZr@q;${QJ|G)7JTpvhUuq zJU`dpAFi%^0iL0^#2CUOI0vhd2Y`8(Za_Nc?IFf)^+aHQ!Wf|Z9NVc4sfWd}2rp`!nC1>Ms^QQq0V87G`-UBOkTMb85n1eqI{zM**wW8 zRF5wieZa;&t9f485O0z2MQm{xU2KfK37{W(^#*PFDHlqxnh+QDIiW)>v0u6O4})H%hosbT|CLbSHhTBVUjZrB?iS}GL7#FI?n(%iT#TdfCt zg4hLJ7R76&4|H?D6SEO!y(iNDN{_L>Z7JNpP0?5rmP?#bx^rf% zEjZ+3wP?I^!m^eb#dv9)0Fs>FbZK7DkLbBY;CQ)T z@NvXkL62pEZ>fU>1976rmO<^&6a&TdcDOkJ79=g`-X*m^{^Ur6&a{g@uS!u*Bfr4> zfCgjFv9ig7_7x;!EpZ6y2~_(czYVSWOpZsJ?uA2u{SYK4IFQobIK`kHBjF zm3cd2Rtv&Qa$H0Z3H54xg6b@~z4(C-a1<{_4@*B=z?-DfUm`X|@AL!_l9ThhT|^HA zT4^jsKf=gWQy=|L0y3}4{?Y2Nke)r_qya6yF7z(LH8ew>+mSm}F9OL|%?0WYncwQ^ z*la&Ml?GC7C8A@vIrTGbm@eVk!NEuvVnA5vX7OqhWw(LcAtPh0fF`EQ9AE#E!nGeJtDf$s18$p7RL{v(a6q+>frkIbW6Ycj#83hCs<)Y!WUOC#MrqhOvM!d&7d zE|TQtgjDvB$Qi#U{Z8%1FOGln<5}U?Spl5!4~j5@pE>J}Ufx#^Ra;xWKyLoBIAzUO z`5|DqxUY8C!+njRL%1&J0ZfHKyb^B7VUf8eCXAMRrpK`PPPh&zXUc;++;WkT14Y;B zVodG?n~qFeGX2`*b7Zq|%Cpeu+0K-8t%jga#8Du9hw_v+tT}Q)pWS2-1QYt0H%8+P z^=BZ*tJCO@Wi~Us1=EWK2yB{BQT_6e4&1y6EC`G``@ z=^;ejBn4kW}3J$U=i3J!no8U}R zhH!0wt8R$DVfnf_vlS&NO$)ruC_I%nN0CDY50n)BD{&L_tMW*b7~|43N{4?6CSnyC zuI>GHU{fe*Gqh65S?b>QXTfCUng67^uOPyA3M>b#pxJ$T>0~ z7*st82Ce)NY`lQpA+!G57i(a^0aEk>EHj4qz^9YgSz8>Wa8B^lWXBQeve!btEY)@o zc7pbD7k6>k0NAjue6LZ5^xMOXUBqvd4`gl%ST^3KBkRD6%pKtW=yp$6e$e_a^M>p%3r^PeG)1zPNyb!&v!JhN`*S;0( z0`%~YGBZ6L9Y)sP#;E)ZtwhXnu?(1mV+hz)G+UTL7C(Cud+^ev8J(004^(s}3p)1d z0y1?ifa(6MmmarKCkbr^3{|eYBA8$$P}$RWEdpG5PgE zDAWZZohU)Nw6)&BcW8ix`{7!LZjBkij-Le2Ci`}caUK>F8cVO9&UFkwm;<9uurR-r z+#Id4`^y5C^%oc3zjsm`OJ6FceV@ks?;!oxO!xmKNdISm*0DtrL+06A*7dA|2!ntK zQe21ccEMis@+A(6-%j*P;Fp;rwas{7#%SGaa2X=MmU{(zg;umDCQKTV{E$&u;A*S1 zub~0a@N_jj%w{^;Y;k>G;=}s{u*2ap&+MncL29npgT1t9F47ke18P!ISH60qpe}j( zfn)Dgwnvc6Qhtmc1|O41VX3~r5PikWy;%Kc2cmDDXva~@;q*85(t;xEZO!dLM;S-$v(Vshb=cATWJQ9ep)nJhOcVWHeibK((HiBawkHf;jST~JB&{swtX*428Vib$wb5`FXA zW^w&~a_DLDN47(jebKlg{Y-4gd-|87y!h61m8Zj{(JqkaQa_oT*yk_(eZzS;r}|} z)-f}ZKmy-|Q~L!OsXFOgFz|KS^a$E0epDg?`SokoLFekY6^xZEl$?qP+~1+$lbGu2 zY)oG-hwoo$cQ-GOu-m9Qc-DAm&=Y3t7}8)P<7%Jn%BfjvNZe2c&tqIKBAFFR2WDWS4}uqXyriAB*;f3+=(ZZ@+yKT zx@kQ_2yvKkyM?m*=wx68{-h;yS!E)pRz;Ite#Rw1!Kt} z#MP0@8PnV)aAi$)Gth{U8zL4g&@9;^umYs28&&1WL^Ycl8yhmD*xHr{78e&UGYY{! zpE}Zr6UKqx4>Ow9Js{aL1p;DE z4*Ym-Z|5%FhQf8b76E}X-jl-RjwHHuP}apA8OV1V4`c^L;jYvZ??J*v-qT}^9(hZt zyFqdHRn*PC)q~7_l%Hb4<&LO2+_ije4LIVy-o?W8LfVS=oT7Se1Ved_4!H7=54#!} zxRMG%bGRYYjZaB&y!r7y9f-FxvYPD$5wzpdsbq3e?s zwIyEmGl9^T>YMh`%Uh@Cibvf)a5jxk+}~E*@{>I0Gckg#@R;q!6z(&ii}E>xUtsQ4 z<>DfR?Pq&SOGSsVPzL|ZtB(H$pf5Z8$!$|c2=0jm{IF%XsDTN-felR18#AD(ZTC59 zY7H;?#SIuC0a0n_JCC=%5}di`J64MXsT@7_uYpw{9?i&btD67C*gFMx68-z4aVEBH z^B3E;ZCev36Wg|J+qP{^Y-@7zuiEFH+UMR~b*sA9LszeU>WB6H(5D3dxz(Dy)p_Ho zMxyT$KxuDxe*M!Pz>;9>1b%E8QofkR>Pb6?v?2sz)amCHj6Xju=AW*LlBUv~oWd?D zoWUXNp#E~U zA7?hFW-c!f`%9*JgJ}n2GRALSbUbm<2H<4fq$dmmA#6mR7#l|Lg>;6B7B?>ksFFToxuR8?a^zq{(Ku?Y41c$n+8NJYXl z=W8pu9^%Gf%^^{WX&Aj|OOdXgAdO4-HMg0AxxVSD%H(umLX8?&Mk^P&K?S4V$bv<9 z*OMedpC(H2r!QlqW+I}ps?j9_SSc0^dq+_}wfp~|eyaCtgS_?I(YX(ckywez{#D3x z$~sx_Z9gF>X%O6|(O*o<3CSrRlUTM3A@!u?M*ECiuanU#91aNCu@-~#Kd5*-&K|@~ ztAyi{7B8xsmr+hrp^@BlY4pmL!-VM649wBcuQk)a0ojRak4Vq79ej8UE5~BaTM+X9 z;k2-x1L$D^>)Y~NWUMtSB*2CG#3`d`0f%5S5e6Lds*M#z@;T2IxkyWw1KH{IZ_}y3 zijGLv#E;^PJ@kkdW>9X&Z1wo1K7R`tPRo9Hlvjmof6eU$jJM4md?sK41@7jz;gPtiJ8GDR@1&_ zDUl(7-&Pwx_mTxJP4^ylgWzNS%ySa64|dgr<|L1GBPYp-R+95e$viCJTA+&6%3|8E zI+R3w>YNYv&WU6LA5cGro{_{z9e5S?p-7Y28GWki6xSd(4svD#GLKU@&&Z_0Ix|>5ml_0j zX2_iqWsc6uLIJrNQE?6^=VeU~m|j`im$hGDd>vP0oA2R8jN$txle)qyw^|AU*n_AR zil^WgES8*(^UFqt_VINDUDg z*V-sG>4%xs2HN_Q#7ggcXoZ}Qc{T=W!+3GH!oi)!u=v;T7}e6By%N954H|SQdJH#? zIk20&=Ch!jvlR+r{@vD_Hj$Q2YlwA4Wh#gVWLN|#3u{G9)3JDOJtR(DMjEoIuz)%g zpjtcfg^v98b|yp+b?Q5Ej?ZFi-?6H0MUzW)2FrDBb46mi+n8yk8#|y^xWoy%#S1)4 z5H#V1D6Rd=)E1*rl}TqPr}x#hk`DyK2o5t2Ez_J{kG2VPAxTY9aqJ>JuQY5lmX7Z5 zh9BxBQZ#B*T{;FKon(b#$nARTTTXV(``OvKeTeW0La9U4bh zNARQcM{>u`Y3bl_y2vJ*Dd^(3e=#n(QM{$A9KsU!*P;0}tjG~032%eL@njQ`l#Nx) zq8K3^L0RDj*QbBO7ebYaE6gO!)@-4LyLi0wSb(fYYKmLzI7R7*P;g15A8w6!3|e~4 zBg9X9I?5+ga>5L6>kYCpS7>$wNL@^yPM4I3dv-%-x|*R<_gw@O$T@L| zOS6dDfrqZ%zFXURDM0A`3X-=vpzG@vS!R`490A$vewW z7I?u_agf*>aW(#hvEq)Xrk%EKiRgqB8cl~`2x>~%L3rFzh8$mxSie6sm?K7$f=RMJ z`o2DZ_zgJa)Vx)>%0~4!--um(HWDA5<+K%TZS>)#@RYi(2d?y0^+f|_ExXu(s+DGM z?6ET|^qDM`ZN*V{N{aNZ531hKvNi2Taj_)-#jT=ulo)D3*6`~c*rh7Rj#zv^rlkec z>MLFbD>h-S3J+z0}!n*@K(meQnIJY#P*(cL%ivGGpIid8cG-w0Y8yaZ`;- zpCPZ+bu{Dk`7EWt8jx+h*&B0m=LBrhY3vdWQK_X3o<}nouzC^4MRQwb!sU>u*@Kd! zl{;3o!$lOn%hmt8I(+^l-6m!muf;j1&& zSdGA5JlYx!B0C&}pljN495A7)=h)m@qLb%Zv#!>KaHb0mS%ngy^-{_4J>q~mXv5A1 zYN)#AoU#RmsfBYbJAr|v|B^7bpasE_ya|O~8BuzN>zNH;0Q;Mcjl7FltdH34o_MJ; z7r~H>O5S*c4#9N8{_Q~8A*M)2v)zDa4rP*l1DZzdIf`XhQSDIm70wiRL@Ar)j;R7q4L0l>4* z%QHqbhBfC3bZY_*+$lF~TWdU=U_%Ii|K?h`6&OzCTB#>GHf`f;er9!Qtu| zAi>i=%oOIq>$+y49TyyJ-E&%BGAt+&9y5j6ghlzbMaP7Q_1@j|#$A5Xp%^!1uWExU zU9oe-o(!#pcm6}jbNw*)G|8PcF*z}cJDOLX?7hFfl_WZrIvK22$nvi?ITd_*EI#2~ zpobuso`<4pujUv9Yjrnr#34{C#*5{VHDr8M-p4IsT$6qm^gLc`8-1U-7NvagEhlLq z-z&|Jv=+(FhQg2ItT7m_OZ4VabM8V=UxA1!v2saTkK$yv>Ql-`z(1v_}y_qGPhDfywwR(qJ}^~lYvjXfW_i7 zN(JSdZ{cI?b19}k)Qy5MNE#2x>FO6}S77APpMYoRFNXP4@%-Rk5rV{Bq)QdjHeAj{ zW7A12US$)+K$h`z*d$)RmY!IYLd!Qr-gTspnzbIQpxM&49qk|v1ANopYd`Pw&W|X0P#X8w%y&Cn7N;!G_p}VuSCN+|DKLCllaFiqm;m8 z6wU0F>`Lpyuryp;nF#K@QawpS$=+iHlO;BrZ*TQfY}+#nDo6{mO>%7-W62;S?Zn!Z z^o#_CS&aV}i4A}J+55aX;-8s<-Oi16b^ZhT-*G8e^txzlI3S>3KWNGSh&{_1TH1-2 zy8p+`_upX>4H$2fC%o@}n%mfkrA`b9lV>Q>K4O4(FN1~ph9k3G^?=m?~5Z-qc*;v@`}!}0f05FRZOT>hOf>k>=F`Iz?@+a zDQKwb3!g66PdHbutf~zkX%jXzajAL8$u7T7baZ$UC(OQwRA~52TbXCs)&zZD&#w3?qz>KmI2 z{<knvf-@X`I>P3)o$z^9u(SarLXprhc9YvRi#)0j z+op$0NNX>!p^U6Z(6!UCwydOKec)mwF{5s327^f^wL7J$6?ODjS#Mc1%hHg6FE7es z`R{uip(=Q2W)p*IxuHm^mMEoEZ;A!5tSWZyG}u{RrMO8Q5A zm)f?gaRM&(zcfpPP+CYaWmp|wU7he!m$G9!KYNFR>mr#d!_TkZwu!C+Xs0sOks^hY zFp~4Dk2?TI!l0y)`Mu4ksNcGgR|Wiu6Q9vPVrm+%^K#cV(6I3Ab*H=WViQPu*J^K4 zH-9A8YGXWF+v0SRObvNgNCB#tLR+QSxh6Z#z{Um>59jA|K_-y^GF;f83)!|IlW>z_ zI2~G%@D?80${UTAs0Jk_ORn$fXGuWzz4yDFBo#s58XVi`(Iw1+1`eZUEQCjUX z7cr_ijWVA{9)abA=}PQwd1D4q7qV=?l5#9-$&3~}lsTl6i5hiLPPmM~hTY$kPZ8ir zUIqz;x3qX?=G@3cgGqep5?=HR3oaiC6uZ=>;9l>#H}^UEaD2hEG$~7 zMS%z`3gwx#P01u}X_Hj}DuKlsVK{8+GcM5tDpP_KTm_d^SiTxc;VHZ$b&Mr3p%{%( z6!}QRd*$QZOr_Jv6i}oyWT#!7v>7dnGol`$=2XFcZKNc_ z-pfXb)H!O`4a*XZMu?H8g_lmNWh(s0E*iHsrb9qci|PX+I| z6}G?4r^6Kf^nvq2%OS*6smPJYmb{A_{XOzE&hU$P3gh^J@et=*nSRkr}>s}gzV*B@JC zR^%Jh$&lq5o0(OlrsecabQc0WTgVWue1up={YZ_P@6JkZRXIQ7yI(o)S-E&Sn!c%m zWw^jp-}#+;s4i^uQWfx;H$^}q??=YPF)?&P%|_G8^S#?VAkqt>+PCpWD&A}oeAB0Z z-VjaRqJ`E>*NMtLNw+*>1QX@N)`3aqlKNrE?OcvqusA)MLO582?Q|cgb@=SQ=>DQ0yTPh1}Ql0vaxsf>hCaSO>O; z^p@|_e*|mN6>4(h#o=Qi-)|>zb4N6~(f|n^Mb%|K0SZ}CbuqALqU`HbmT0blTsI^g z+g!la4ezxl2#)F(!X~2}5Jh!{n|Q4%A)fST0Ktw1M4ZPIE6(I;7O;#FAJ7&rum;tX zZZJ`2^ik9yVI-<$Ev=9QO5b{%wn0U|COE?!pgA8?EP0|LZwRNc9wp=hTn5H_Sue?b z2bhjz8FATB_r+r5WqB(^@lg3Y;fe}HWt?Jp)(1o{)Mu$f$v0abR$;rd)VyM!)=7zsVm~rRf26D6h6-(X`|iqfCX^%bILVL zF5ok$!(TzCl2G7;7qqx_@5DS5?BF8hk}}sqBI);~k{nDT-9dhG5@Uyhb%nk#rA#sc zCt5s~-ooY_e(3%@d80p+O#ReGD)nKI;sDN}Lci~l{^cQeGI861b?nVHPo>Hc3{O`K zGkIDCWkI%#E+YsXi6z3MGZ8nAIPkY7ny3y7!5HS*n1-t^x{IFTJ3Gk$GG-6DtFJcE ztv<3rN7}Mx1hOqghk@i~Qk2P6sQ_;vmPQ1s2GzMvIxF0oYJ1rTiQhcsz>|VU8!JN@ z(NU;A4R=&IN6X9^@W3ld6)`SIf(poB*-F+ANkO@FP-9jIZk#}D?bBS>K`T(1D#p(& z_ef8Zm2F`TGkxvx+t*d;*63%;H|Tu$PK2fhb;B_y7-a!ZrCD=CeTW_KqMsdNO1jO9 zWK;eizSHS1#a${y6jyYJ3CPy167TUn64bwTA@o9Ax(|FJ*%V!Vmxkp6QHdLb{PU^f z;v7ewy!*#bJmix^&Po4BMbE>%(AaAld`xShx~Nmb@eS&HMNuYsB}p|+)RvzZFRfcX zV=Mp2`Px-^HnaUNg;h$u_hf+*zAJORnHbxY`1GmV;Kmn6wC1(-ji*;GNhhiL1p6;G z?AAKw?TNg$X(T7o@#qp>zN?Ou{7#f8+0?yKMKyG1ko^sD`sIm6~Du9BC<->rL0X7PHrM z#)Hse^egxI$sa679c2vEI3kDTkT3b*YXdSxUnzNJ?k9=2L^JTsr06-{z$TS}8!1!i z_4hOMZ`UPu7x0>+7DTgJXRk#}fsGG;iA{N9M{+yJL8ffM2lG~z-TG&#Zj*9E<Gr}7*0dLKnp3h3TmTQe(cd4Y&eFv++A8xqrai{NG z@}-^Rm7cxuQt&Zq=V>)D_Ck&Cq2kW`X~8{`qu}j%{=XFHiN*YjcH{9hl?Ih)|f&yT5l_2o#A&uDKyaEFWVB30XqXhU%AmbF>tZY>o z>)N%ZW?QQpt3@{1%!N*?g94)DqEuVY-4~zMvp4n3Qo671#>s}h`y{@P%NL&qpPR3L zJ1?0Y@BFd)kPbBet_QKZWQHew#s+DQ_W97vRk{`+V|h9qdu@88hAUOOMnZ+Mo(`Is zd*z<>Z-zndZy^Z0IZ6+r^}5C***_E_ocS(?G|}wu46$a=^N{RS?^?X~h!Sf0Hce0P zn6py%g@B8@7egWM=m~bBU&`Dij+7-xc4!6%^}6Jfy7WWDyBk*3hYN$(qDDow&ZYSM;h>?prvH`MQP2waw_uHKZh9IA3i4vN7@2W! zq=l`Stzp7n$DH21`flS}$U)gz6yfTxodOC=Y)1;9rIZ4QJ)8K~EVa#=a#3sWdBt$l zN@k`s>dumEFB@pTmU@DCljjP4lWOwC29fvgc+GTf!Z8iO zCy;U;ah_$oP;JV`DJ_{u#DuSS@bcq3jSa;L%BG{R@xuG@2e}A0hKe<6@j1)1OL$7z zb$v=?U`nl(>+%*?ylyO4Ll<0n{_g7;k1^>FCqnaVlBq;PPgt3WS3DEyk|=A6SzYwN z@&|i~mTSmJymc zC99c@Maco!q?01#7xlPP?q&K9GB$L^C{2(v0ff5D(PhhQv{1z3u17qty#f`XgIIB3 zR)5E-pcJDeTYf)`B)B1GLSs80dt~I@I@Gl?V6xE_uEJkCl83TKQ@SA}3JTT`QQU!d zCz?MR|8rWSQt=MK6B#zQ+UQxi>7m$?mc7)w-b)>Tg0S8<{7nL>x4hkE{7CoVLF6$ zXDlI)O*qn}P1<6As23jN1)T}xhitSoco~ux#t(#%l;17rL$dat=Q~_U@K-39@ZEwbZGAw6pK=(id+GfOFPo;^Zh6vY4>($FcgG0+0^F z)L}Ume<#*OW;-zXW!{0Z+jJ>{>)Qi&bJXgW`Nvh0a&1}_|2a>Di*l80K{-3!7L8Jm z94~fO@824iWM{0rykfw>Iy`B9Rw!FYS4|(~J;VL_Z~S6o2e;^c60dX0t_EEP{AJ@? z$Id!yRITv)|Jbi4VY|FP{fw&F;Xd_#Mu1xtMX%w8t3@X!PQjSQ|Yoj3K5h z#h=hA&g})2Mk0Xov{ z{QI%4ccD0F{QZ8~2T62LP!H7{QzJT6yA%vDDKH)7SK!SZ=5j@s`6;D|&xw1zo9_Ne z2_Iv>h{*fo@r8GcL_qFi^#^pke@2j=i<9RV2CT*kz_gnvUSrov8x4xy2b@*8BwV`v zP5NG@+*^|&&?+-!Ku0W!gqkk~JAoc(OnBfr&wgAF4E{Ap$WA9f@Qx>cffq+JBV~|t z@~R`k{S7Ybfe!8+jd^RvSu|D&FYZV=rm3;*Kf2d@nl$SRDIEb?M>W?Di0_7scVTHr zPn|X4%L?RF%?H@c`XG{%S5odC1VKm4b- z@|a!LryG+(Mg@h1LcWfu=2t?;&CIQ}d>KoYV2C$kMc`Kk`g!N8`o~Lf&s+2> zu@Yf3EF>G#zzaY{B6Lpa76X_^S9j#`3qq+7D>28ZSQEM4qwZ@!#BHZCuSH==6(L6% zb3RI-o*?;#%91g*M%eleDKXL*E{8f`Q5I{+KhQ&CNKnE~Bkb7*%w%DIQ0PR{nWo~b8Zewa}Z(_<|!ff^PGaK4i{x?6=e>Q@DlMp}t?C4SaKjw%3&y9k1 zE;dfe|M`Zhi>1x~c0*O`KzXYyKk=QIkuv~z2x$%BDiwu znK1W{g9+N|LThbOUl$l%#B9illC-H*i)mZi+EzNaI+H9ys^WPiI|dp-Om1CXW@ z^%8j8^mJxDY~SqsB-^>+->lc-zf&Q}D(^nb|MqUzsfn9R_U*{2Wq!5d_jscoZy(vS z{z@8FfAe6_KPe1-d*|~8y?J!9bf-qZJIOwI+(O%5KULNbSDfi_T0P(#g zZ~6&C<*VlMy)a77PjTQ&<}v%>4#ZE9sy}&X@698EA9@RO|Ef(8n=~5#8KC2Pa)|Nv z;_Dl(pR%A1>$@yJ`HFCVD^7ID8mNy!_UHZ~_l?2ntul9aj~(t`X09B_st#cS^y`h% z1wn$R9QOC(sB)13^tUwq?D(-S!E9U?)=xnGz1i)q50Cb}ne>iL<&`!ceQKA}IL%4x zaRJQE-JOyo-SHpkbKh~V)zReybvlpb&zwGYedvFOhs&S(?cRi`Cr9@=vFuViV&j{X z9ys8t)kRjKrgS6Vw%@a(a0#n~9zVj6Q6dl6abpREVA31dac<%JnYb>%tFYxqd~EB( zsILxw{OI@FEABrH`rNT&|C$i~^y^O?)1;G!!ik0$l~gI@ zv0+v~+Zdngdw3dn<+ZVHU{Z^X(30!R8VhqE+D3z=|8=9yw&e{0*$+9$uqa~MVytYa zX)kZfZ*M0;t+K8`KwnMG((C%6WtC8;GGH77TOfrzp8D}31DdPhtZ}rl3#XAv3QVqA zw2SG8`*iV?VB;5*TC>X;H78R_1j_2$#A;yTG3-y0U1dX*WORm2)Pe^4#|9Mgipka% zimUD&SWxFdR`VV_RDaSRI+?aGvnO2)eWgy7fwDky!mZPJ7Su-Sm~gA?Y%Acz)F7>d z$FMZkbufNa!--%Yug^S+w6c^eot2-u{MoK1i#HH9mS(}UWKw}x^m~06`0K#ZMlzw2 zn1m{ACvYU!*wM+1XbB~Dk4!q1ahjn+VX~`x`4<4X5p*Um;4G*K9JJ7y4{Jgox2g%$ zOO&gz+6Lz^Uf&$lKVI_C3Wcc09PFPb+WzLaAi7uM3048;jPDVsT z!~3y-7D6+*`Ydb7^Z1TKR#=lsgvw zQI$&QhLn)=xm}zBz=mYqq>DYlFjBmDCN~6MooFm)JK=&F);ws`X{rqb>S$)%WEYwL zPAKDW!m+nnH0Dtdb)-wlZ&lA&HsXLfY1u*}QZdvJh)njj)8QAxv;@(XA%o|zZ}}Kv zhkFqhL&I*f;+g>9K1LhEh}I$A1iOQHA$en%H=?vL0k+t>-TXN~T6 z(d-{LsU(hb*t3N13z_>dUecmB7!pYc6MM4uG13_&bHT_SB7 zD19>-tZH;cLU!G-%r^`o&Y?p+{a}qlHW6Xs?o28&Flh9qR#0paa=kfM9?gUW_(+8@ zosO`yWcFxD&(!HWCMd0-hI0#q8B#(ff6;Oj^?GG|-bh}ui|3d!FVFzf5HMxv(u%@I zyx-+wo0kuf9~gptIpmvJx`IV5Zp2@-5c73lo9M2B#8y9L76AN4_vcjkoUFtu3Rg`ks!a+YF$xgxnU=}!W6H>DpJe>)DF3i1l(a!5yG#KZC z64Lrig%+m}oJPsgIJ)%;t%~09?iVP>=;<$#FUB&Qq;fILa6)Myr>f`Lvq0K2)i^Tx zxaYXkrX_5vELct@O9YQD+gjLm>8vap?Gp(9j%t4ha|Z4ls#4<|P+#2&ieHjNq&Fi2 zdWco|qegQA+bMbZG4o7iMT@b5y47BX9QlO;C%0lJ5JE)4$K(65mrPfKnQ|bW$G0Vo zGHWC)3D5o)OP@o+okd;}tD62k2k2WX7TMZ(G!%Bv${Q4Rc$+U1;o21Ow>+%V)$tvB z31XaUm`iu+q2mPzc$&C1Fs!Y9Ar%HL($3xaF@R+-RfC0>Gx9{c5^b4|Leo01!NHVrnM)|~&OJb~H zZ@F2Sk}_Vb_-~MpdU$m)^K`3{fcYu5Wn9)_73X7S`STg|;}Wer^bD(bEt?85tMa0h z^a>%R$>NFdiV1~f@@_v!PemuSvg8sjNz^K25!SK8ZSVYYwMy0!t;!Y52^J(O!AGv& z%!`h^++R$~p1&i?*~+3VXgzz#6Xb>w@s}OL%H@a9AA&x~m4nYfZQx{=X??azW(=_7y>E{cWJd5d zv{Y2m7|f|p75`8Na)X&vZrGIpWSfPrSe7-f~f2^}DG?%72(D(dOp4MjC6XUW^^XlduzzpL|~C-(HsD=wDdN;XO((#W4*TX{;T zcnc&DeqWkz;78UhJc>Yq+DBlVv=9{liC|Pf7BW<>c(_n@+$LTC%xhvz4%!a^Zg;yZ-KjSp9v}cvJ(c zN#oKT7*`?KHhZCDea6Qjtyo%VY9*|gaJ|nSuIanPU7A$gF&IM4s-9CakfgiDno!CfPDsX+SNr@6)ix&~}&FlQwd!?y^ZBoN}Oge;?Uw zuY+5&+RJLJT#q+z7$a7`OG<^XS_=iKeGYOzF!o6r=hdbf-JQaGDPfArOb<+s>q8e-_Y18b?iyF2$=aZEYK=Yb){d-U8CaqSXsL=b9wh zwg-h}N@A`~RxfLpMr5TxXxBZoT(}Qp^`P~{;Qn6=0aru{2sbHxyhP26jA2|!L_*qY zG{O3GRg(G=UiOvWfJRSd&V<`ewrAooYMO@TW=()|FZR<+*dOO#fTe)LdK(e zF3e<3ocVNQMPCaK%VZ?`q;MmTv{R1Ak(hIl9=wrJX%Y-sR%-`mHMdH*F(pT04S}^W zZNx{@Q0nhlBPC8g-W!_C;h%QaLyY2;sx`ZrasMbpySwz3El-b5);1%+V&3PmqzG)- zi9s?fTbLy5nZ=kZAGQ4T8CY~R-!oJ_kLJ;oq;-Vm0oP1zg6aWoN8(Do>>0JJExWBt zVU=oRs@hVOUKG0Um0XZe|NHq~`i7Gi+Y(L;<5IdTmmJ8V=TvoB`QU{9mhw;b+05j@ zN@1{_-OFhVt-@f`8o!Sx@q6oR&kRC9N`S{UwvyX5G0D>DE0MKAsoErV9df>J9bXGX z)a*?^a$GwZVofT*b`zh38w0}S!eMpaEHzlSa@zqcbZ-CK)&<(h2%hXrdt_7Vn1fF8 z2_L#{r%B(&mPLtY`J#;~kIDs4S6&4Fb6eme>`bf()rWyw+ZUX0;LEH-bl1N4ixMZc zm-~!RlQC6~^V>sm?uj#utNM%Sy>j&q2*SzGEHXgk)a1oG6NmD!G` zAWB$kMEJ3c&KRR3&EHEAxQJgC1;2#$aY8*ei>y(>Zw> zqeG@1$81k!ZhSXl4h-cNaof+dlteKQX7T^TiOH~sn42A8=E&Nz+!G#4P2vtlmMTJ8 zHvOU$o@A0wEWJx2?c?Ws9 zzeQP7!YW0K%@hO$MkQ(TI!s%ciJA&YRj6UsuBP|@1`(v>hY~g{BCh?!-SU8R3E%kz z-Vw`V=i+1gx4-v@`16k+scZ$gWO5hf-i6#8u<~L{rFc(F$+NCpo@`v6bY149Hw8yN z2nP@@UJ;bA;x+`nixKjiVQqt25EL&+GU+S-jmmw+Dt<$CTa*tfn4Y$O@(1$GfAg`P z0%#d?=ff4AIDJfGR}I6^Ijk8~l#QFFfLqC!>>ABHnM=H!yO@MV0~PEQV^&M59tmZ= zvL-ex-p_UQ=AJ6%lDW4Q#Q-`s(HNM zksT4qW6s+oHm>QW{eZD0kGW~$X*|oQ@`cRI^|?$PpYUnRrK=oZ3j$^m=E#pWYniW_ zVe11e<414_$J-0T6M$^%MbDfLw5g{64O_y-LE-+%8ek@6rLePfMrndAp68h=Hmxc& zrEP*;(Q;B4Txh^oq25fjpnJ$0c6EL*wyTMrKv{|^VB*;*E(u)S+t-@@wX|TxTq9s^ zF!vc=rU8Ve+7c6dJ?u6wGwaiYSz|qZ)Y(kw&c4vEr2k3R@GaNBoBq68{Aw+Z)+U@2 z+q+%UtKGzp%esZ4O}lAv=F7J@;ggn9?ItD0FM-x^i(1J@qPHM6`SLK(_7mcmc$*ogmwsTb9#ZTEjA8YwUeE7+veH?C#=6a z)@8?EQG7zQe@@B{7ot9FF4+v`q|_;giQEq6+_}8O3;+GjBST?ms`Zp+P1X?-GrWc? z%r{erf6KA$Z|%-$KRdvbKJIJ=L0b|fof@{K1K z#)F7pHqxDwVgGkmRG@_IKDFJkRZp1u{jxXm%^`MA=IU*%J1@b3@+;QP*zA4zCvxsc z?E|@QsP!9f%}K0BW6pTzUbA;ne_{QShX+`J1x@qPxc14>mD7Dq2`=|<38~@SJLv>- z54L}#W>^woe!8h*XqqryCgwy#|g#4Pc zW~PY(kcM(n-vsS0;rdIuG7#Vlh}f{mo@9VUh3Z0crU%1V3Swos9O90BuwE(oCK~{5zY#rqC^}W+)h68H_Dlzzy&@SnL+GL0lHhl99lH0A~(LX5%^K1 z^umYjau5%tiwAK;o@^j8h;dtLnvrZQVHptu8&!v_iT#GE>w(hf1hQsNz7M9?FomyT z?#n1OJm#!};H>-mAcV7m(3eH~fyNf`K2sN9r;$+4nZmS<0=kjs|CbPC{UD&iSoa@% zo-c+1L%yXq72Po}_BD%iIcO`01BPYWD7OQ}nnP)S2nNY9@GY5+VQ2{`q2NGS9*{*+ zGAz;3ScQijq2;DPhD8UYUnXegmG+777?`hX{xXxuqe*=0O)F(ru6~< z^?{0bR}EFDRU_~WuDXF8FgrI>X3q>8&w*}n`9|5<7B(&t|C~(0+3LI#wmE0+({|9u zt(cl^D9`J2U|xzR2;NHMv-16BHs0kpBAiU#Q>i1%4XfEJiIer+gQQP$cbub3%iJ98yE@!^hI04-IDC+&f}oE<)396l!Xj-H!Lw(O*4uE--dfmS!KJpo`+N&K8E>x~DSL5;@VQvW#bs>fGR zo?(BOh2FglfQ&1U97JE<4#4KGn6`OfH!yX~*{7J!Njp=vC%=oH`bU0hS(v^n6`gAm zy71YV)|pxmb;`n3i;_7L4}Z-gNNM591N%1K?lM})DkEQQC*#y_#wqX+vuHz{17sNC zO4;Wu%#dwISPa(z2gOUQGy7qXd$tY^-~pVqxSq2B#!-JpNW=ncA)1>y+i~m8J2=D- z+ZV%rw~E7220WiPu&c?~y)lXv3-Nyi&L+3pU?*P;V7vD70=}7Icibvt-yytRpkD5= zD-Rzr5BQOak(@Vhau{rRFx*e^g3Y!#p!H4KGhV10M>awFD`h&+NkUuqYh^mf7nwXd*j~4O=}(?&*N*QoU6U(6Q#8IaEUT@HsL83(fXgjnt6qZwi|&s5rE1 zA1DF+d6}&fN>~5%6Tfsw#?D8NaXYXeygxN#keG$Hh`J<=M3q(x0G6fSN|vZ{Tq3Jx za~+b|a#YEw@8vSszvNkjOy?aZZnBhwN(wpke})_>o&mo0r2Z-5e*rOoQ?fZ{q(9uv zpo`tv2r{aFm{r)G)IlxEuqBL__O20RklZ`qWdMkQ6S4fMby+Iz?g;u~ZhqAumjU*| zGM?O34_w@_#sYmTfMDn z@jmR{y7ai8H}7@3U2}x*vASLL1n$qeT=m56+kaNUd&8eq_@1fD^&j@Q`t3%0%+aLV zRafwlwcFJi_yorF2B*-yPp2zi;t|00YHf9_^kU-;WUDv$WB5qC9 zB~QLzT30iCG`!?{zkj#{16UZM$2}cHx>GnMnhAG3Ap&9kNuWu>N$`|N+EfktM%elx zjhZ^x#wZEQWJdZq0#$-EG9N(omB?>%?v8y9oRoZSa1t%d^@xrTHO4IqSMfYMIx@tx z1-eBx=|zwp|9&*!UZHXjS?Lm6lZnlXkj%vux^qiSCzolhd7Z?!JU~?n%NO6Ys^Lb! z|KjW&n?(zQEX{jt+qP}nwr$(@*tTukwr$%s@0{wciK*_1nCO}>`w!&K%y=_%J&Rx5 zWunG*DjnM{dXr>QrIlq;n>KxAE~TY%eh)&cHLJkFt|)q;L@AD*V80^Ds*U!LU3RR^ zUjjp^jbg69c8Gd$nd?W9SIx>e(Vnu!{6l3FUjB*r9%WISP@ zs1IL->_ml3bU7TwBfoyoDkcVejAD~jdw3y2q>vo`ekDm~m+=WP`8%u-!uf}!(UX#a zH#tOSn(~pD2Pn`=>fb~$&zK}@;mL#LjV&b;-Q07p_qYR8Nwr4uV9BCgxes4&T~^LG zB(o}4a&cS5f&=AvP(zy9fo06eB(drvMZ^e`WPnlf)bbLwz*^wf-H-upF(&J(JtIr* zQPzhfUUelVR^g|*jl-S3)AE)$n-5L(({q?OmmY#G!QVu4B0Dm75WMEUdUymce4#J$ zuQ7f-aCe`LwflNi`alNVp@;^7p#Xy8gZKu0gYX7Lq@D5Yq&lWG<8Vx1JiH^=4{hP? z^M~M#R}M^0Z3A`)qH!(TA)Xu7bRT1%3;_-g5FIa#M-W^7k~xDsXGb7cdE&YQLfnLY zQDp9tKhU%H0be9L`mtX;J$qE|Y+rqHj(D;P7+7s-1$a11HHD|lJdm8KB+i82Xye!l z=5I{N1fBLNTd_A2e1z}?5L#mh5dYPC=|48CJu2O#82{l8@(Z*2?<9!Ke>RL928gg zeF&BrFjtJ@aWY@|VttOA1V#0d1>>hL58f&FsfXLkt)K5M$Q^0QM*d+FHtDgws1VqU zr8}CEql>H%!YPaMK|qtNl{?&RC3*Q9zla9DZKulM3y81;zZGWAd>RWTDcncOMCFJ} zp+1&uw>$**WVswTIZPo1yhec=wLQ=v>YNW#9K-2~RC6ZaC}Z(I&|h$Nfk>+>b$z4c>JD>Vl-W)8_~^`Lp3p@b$AFgZueIf~8TD@na~`vohc%WCzeX)*;= z^ZataF1>Xn{V{NhTKwdszX{w_oc)xeC8>o7j$)E}DDtufMAQWulW1e`_Idg&uL9Q5`8t32AUBYTSmZzV((Wumsn+CuPii8Ad8SO{8Bb*{p^kkzox zW5r1mN#%`~b~l1XYK-mE8G8UNPWRa&LnH^vBPZ_=2@VQ%SzDD6f)MA!oA{`LGec`k z?0q=@YvM#1e&H39+ig9x(`2P-^28IL3Y4UR4ntSDeyu@L_pO3^JZd3knzf|ZUdlFB zmwX7_twssC&gOTs2_G?qm*xbnt4s`Ea{CcgbLm=-hT|Cj_?YU;(lmaTC~3TwjJR<_ zXpe@_Y#Eg79nZ~CCEoGi2>;JovAt<5JLGz3iWuN%n_o;NCi0I*!WV+i_*N}^r(51Q z2Z#21Feu1uC`IvNY0z7g1@x1Xn;{)M9X`$gv3=GbLhWvGD`2ugcZZ}!Dfjl^vqgNM zMMN6KOlbu6;o=2ARYfALi4|T)JMlJ96w>%wg79RZvvZ#(W>7)r&kmf5M}z!nEI^ zEifV&kz@sYdtu5H2(eQ(Bf*R%q{<)L{qBC$`7sj-BO5Q+=CWl@;Vn0jd;*8gKdc?F znyf1KkAc0oEFPR)bO4juhhhhux3e%29*M(MN?mjs6Kdr0JxXhR?6&)WJ^kE0!z$jP zD%Ok#sMWin1==PCk4XnAqRj?~W(o+Zn(hXycb;pE?U=`s5NdXJLZ~Ex zoI8Y#=u9f~qE_6<&VTB`it;Pif9WU$K@o0gm%N0?p6XjdqdX(RXMizC;tnfeC5MD` z@h|@cr}ZCI#v*Tw&iwa|<3#xXkuClowBi3*W12Pp2i@uSioZqO=USB=1A&5GN zMREWY++Q4AJWi$wb{rmbfOtk4zDcusWu;@KW{q;GLVY;G1{!~P!E%1%SI*lpzhc?! zs$iv45mxlC-OiMeDLoE4|Gme<&Eqx4>xSc>#*L51!<$en{5-QuPiD>Oux*EbrH(Tc z-S`ov?!}3TcMI0^@k5KMB^Bd4wk}1i3TUmX0%>jhO*3e&)g33=vry*j;bZZm6R6%^ z0l*as=jFEc=<~ugk|9>n3Vw66;-i#JBJ?_S6Bd&P6xh+cv3+A#=bT94@B2L%8WyS_ z)x+AQ(5t;4ZG6dQ;ZEY!HQlkkKef$*&`-C6E;(oNR~OHwH}k^lV!0GrgAy^V1PY`JUPE z(F*<35?SFM+TYq{&fuqpyUX;ZO167ag1JL+tuwIkdhF22yefVTX1nA)uz>@*OEI-` zT(I1w6}CeYi`Ox)O&jZFJoqXJbNC95w|eLE@W+d9qR6vncid}xDHYHDG4`E|v0Vih zZlZ8{`qRC433lv|fDP{`SMu6`jc4PRJ5Xew?=<+Wz3Rtt!ZUPx+X|B?c_pbj*&R4Z;i;Ds za?6jUl@W)&CgO1a^m7Zs9QAeUx;Par6cd(~k@apZqVzo7QahXK9V_ej3|(8|oDAK3 zIh!@DR*&#j4Jp_c!#gQX(k|;cAJAUF$NDLYaJsJg@*E2f-3CUkOL7|h@a(7R=CRS2 z^phS$Q>Zl|2%dahC|U>qbrVoLe}ScsU!Ie_6nt1Gg$8xE_8v0$a|1Ju4k1+OUx3jR zaMO_D3`-g?6O%U}!>|34x>kqwT7ZT}5E5r=1In}VO}s{7?4;(Mh3Cw)5H&UstSTE+ zyKGf#Ylxt4E$?Bf4AxIT^oys^KVNmdu$NWAfdNiUZ{Z%J;oCNB2Hbz{#f-T@|BdhQ zjS9y7rp+Q3&yzObxkHta1Hac}m1+0WLrNQcdaCB%$pkUMv~_uX_BBPc7d8;XN3gy^ zmm3sca$E%Sb@GTTdt{9+C9ETZ|wf!3bl{L^_RUv_fnGiqW04)*i~ zru3=DkOTCJYn!HXVs!`0TEb^hN1Ho6XkVC!?LD}qTJeU-_U-_uW#A&A8vHvYl)uvP znM5?9-Za1FXnznd=~-N3nEuI0ja5Wf;{aV|J+Wp;|IuvtG)aUnVuLqF^h2usypn%_ zcIIUBthOzgGFO=->TKao2Mutz{S|c=$U=Cgk2xa-{<%ag`SipfP@4PhB_w3>jJji4 zk;*BeVi?cWzg}wh9yN9_$bXBGuSHq{ekd5k@}jsR4k*RPXk)%MQo{x-)%W=Xm5LWq znqG>O(98on2Oj8I-dsy?Ug(F?%RZZJQNcTFuxwUJ@h7`vPJj?Lj5aMhtta(muez2E z)LR96FoXV~nkyOfvL*qJWpm>pwR;L}Wr~&*u{W{)OU@P*NW9qh;eNoN zQxvsQj&TvT;^cLi8qXKR`D|#V@jQ;GPbsTpEFE~LDlPn2p@gE3xJQILf%NKFZ`Yai zW>i_jp;AeTxDtN`6X<7qmkIhW`n*Edb6olUk@#+dZyi3ZM#>_eEJR~A%Xnh~5f&^& zbHz>4AkERzO6g@*?$xuH3E>)#Q)?IB4vk;OUh;)95;Sn#L~$_w-Kd2-`&_8XuQ-b=4BIH+W4xG6cUlFqYZJ&IrcFQST!k^iS#dzk^m8 z-_Tu__ADytAGThzyGhc2p}TDFKtFL7BNBT1=}(9}HV~2)x&dO8debA3mkuc?wjnH&384CW^Nn#)Ow-7-aCK9AJls;>x9$ zN0oh4_!4*W-O@>)*qgz8mHm`V!jX4M;iNtNb(!C0OD0r-WQEDzljxj5GbqJi7?<@G zbYeBqsFgy~CWKnkEz2-XEA}1TKG2k+<%!}EULK5XD-D){L{!LE|$zH7yz^CEwwZ7tE`hEzhM`Akhr8-a&lx>JG_CB^-C%B#L>ze zN+^{@N;1ksGb+?&Bv-A5@dEU(t<$bhClZ&DJ)~KdnOU}#NiLv?KT0^2l5#M~vJvf- zrsazhu0XZq>6DmYSSFPlm$8+mRgOzCN>4H?1Zn7%i=FA1mkCu&DjJszg;bqZdA$rc;EQq|JAC0n|+movCE0f(_lH1lT|mL=7@HAz-F_L7Ri#&l!_ za19=ea|)QI9(2hB8|IfSpy)X^>6bB^S#=^McwY!=%AI7IWsQAv)}G#QJ;#FRt+LS; z?Q50NX1LekO3Q&%(exzt%@AXO%6ZJyR-wg_xk}XfsoY&o=W6(b_mG#4LlN$|EVMOT zdgp_v9&cWf-B)=iwxKLb2z0g^oO@jtw#770DM}E?xOYl-CLv~3q)ocTqtc^5_1uGN zV5TzTF1%jGXvd+xj(-YB>hOR2@QaFo=ivkAqPWBgMudF;H1RF)Kfd|GqaB0=2xffT zZK1DGZ>=%Edbxjop;@GLde|_J6^gou?LzfI8aHdgL((uFDipA_*`A7DZ2S{G*?WHI zQE|zJlWKYRusrEB0J*3%XZgiuqGCry2~FD2p$BpoG4jAGqU4rsvNEOu{1rcGc<4#^ z?PY%OIjo*SESUK4dz$a$sem*L0G90MX`JGEml}~NU>CFDS3%|MB*L;!5G~xpQO*|X z1CbMXn3UI^&aIYGT`{pf8`TM10}2#!T?i9aAOVGP%mo#e)#mft_s<|l&l@YJ8{y^A z#h16?!`nN{L$Rw?m#G`06Hm6QQXfg?AqTJ!(rRvXr=`;C3 zsy;H-MO%mU-HRN0JAew42#hbnAz(jtahAQhv~>0;xEu1bQ|}yzKDXiiBr2MuVGaer zX#nml&4v*aMcFvTa#Xp!hCD<%;+pC*M$eFF&Yj&m4<#>mW||T8umaFy0>PDtoZnw+ zWGaY?a2|VI+97ds*|8ZL6>(kKP(QwzoUO|Ee0dffg`K8`At(JR*|fMsnW5>tke;9| zGEiS?WG=$ZQ>jH82!Moc;$6YnTw0QP_g;}ZV%o)bSKKg$lqfOi=Zw$CwREl??Gv0Z zGbUXrwq* zj?g=xOc9?Di`_i2XKcw_D6@)HK{}%a)6O>Jiw>dNhD2wRB45F+5I(e}*&^H-ta&}$ zH%@gYIS_WYWGBNQXpe45=XvPd26>eO+zw~orft>l^hNgLyunLuPXTtY-ws!lM>VHMmEG%1g41V>U31 zXQeoURS50@DOx=Q`fz}AKw;Y$GPiqh<@NGY3YLC6y>(XficBKQh#SN8JKLWLAmug+hz3 z3MW)qr8wWlt_MebfJnv*;5C@cGdQ9@ohg)kGuX)X2K~h?8B7_!GoX(T|H-CLUksiF zVg>~WjkzwMwlKenu3VS-hBTbMH&pa6RD6lT_VPP5;To^ICe;!RFQgyUT@rmS4jE;a z4!8r11?WRP?gNC9%6jLR`Bo+tedJ+u%p$1?WOk5Ih@l!yKU@VN!iedLz&mE(}DG)hbyc8n?y-48thIBh+AO}BAN}x{8pCHGKUDM2xC)h z;>%q>Myxtqhev0v5;-hDO3mOS*M>`u1lieM1ELijckSn}%z(=|<(3FW^ zf?arG5&0|=R^AphOWGi~XOhAJvlzjA6V&SGr3`+s2B}tF5oO|e8B|VEIGA!MFj^sM zRjNtin4vgm{p%CUGkWgOJbzW0b!RKa4Qm5%mogIu6P2978o_nyMzB-kcp=)7dAmTiaC7}93;68|syhTHDxYrg@=1*xKer~2O}`da z-8gKgs8?WEfvS0@JJ>DYFVon0P=*fZcXxJ)6a>pZpbn8xfq%?rdK+ln(alb=3E$`( z%{*v-m)*{`!)DL|2*|>0)Eb2g4}ye|Hu9QDyA&hM0R`wPAVNnS(oQ_EZIl%ZkI=ut zt_%8cM+qvdi-QrI^q8&KvSZW&-QvyCx+*P;8w+k}`=my1UT$G`krwqSh=nL)lQQ^2 zCQ9oo{*smpX4FKOmt=@PsxVZ`Cz>Z`NS{_xIOk_b8mI`Ol`}Pkpb9855j6V=(SZ`m z2Cqa0jtn>o(;fJ+^bIE>Fv;8}B&@`X( z0{srPR3#N zvQb>gn;@5(F0y9H1g+p;R-X>unXpL75OY!np;3l9qi&8%DHCZ@RG9~{WB^fS(J8Pz zlWaytbz|Kwu{@`34uHkS<0?{}Pqbv=iFK$gdo?lqy?MXtSXx@+r3WP$lk8Y?>@asLBD4`$qm{4eFSyw@_NP&I}70A0huK zjTJG+jvJncR4#{#S>nDV7CTQKxDlIxWj@9$8WF1i!5O0f3illp(hpe8A0e{+pa(kc zAz)VJoQzf#a{^+;c?xm?c-9Zav!oDTQED+EW>y9h?g3z??g6mrnSfRoeN8q7wFZzP z@+XB)17rd4TV@PuW#ky-`rf0zJ=~+8a~x`B(F5Re>D`+OZq5OlCjlEApO5S>x3mVj zgFhHVKm2%THx9v$BYx&sKI`J2W${9lKZ52Zh%N-v@&bPtgi$D^BbQbG-Vt)D*%W#< zXMbHF(&WL=8wNSMHb5cQgV9hfG?)El9S(S@8e<1roHOQ&r&PV*PtIk z6GXhU>5SVOq*=u&_#g=e1265r*k;DxO<7aPLve_`3NcGO0vjqlWLvYm+-+*}JOW!n z>QqV+yYs^9HM{o$>}6v~k%${C7GaXQMXa5YT;1T zYRbhlil(X8)aPRv#+?2qs9hv%3>+4xC)7?h?N~IKFVL zQF5!3+a8v=u#FzH;Fm|mxZ2O>-+;$wM0ztMhM4Cq!(F=ytq0M@@SrMtkpE{eT80Pz zMA6*w(V!dfV_7{YUgOGZT{Nhg4f>Ns-LY$Bt8{|dbqG}C%S!*HOB@T8J-7}L)ta_-S3H2E*K35sF)}1 zwp{9Y;_ag0o8H=XPx0WaiXeN@OPtKMn5zrlvx*l5oY@cJvr*csoO!xsvC~o@{VnT5 zxlfbEb!p@>KnKb(+>+e6?KAjxC9H))ZD1qhubn;F{PdkGk@FIJYRa9sPX={9e(ZsE zl@5Rq9t@kl7;aC7T;Mai{Yf`=1bX52FfK0EeW{l_c5J9*L8+`vDw*)PBfy#FAz!5X zipNo%)iBS7Y$b`2-`JjD6ErQOdqEp0?MnEl5T{-43al@qVPP0CQ2o|DvAHLsT)2D0 zB(>WVM(`bcDv?8_KP%^w?wi#PkZ>W887x{Y%& zF->T>Ou}uY@Gb($Y+?*uGA8F~>{CR_HLh3;lf=rPp~Z4vylx}5{GgmsIyYY!;DxuM8p01ve4f2?dKHS;UNeiy^^ zzup{V|6iJ2K?AG*A>RE@7>bJ3??M>acW1k=!2v3XtDC%R4L)zOxJj{&hN8M)D+rau z{E}2-KrkVCJf!>w$ZP(&c1HKrtr5_(*qW~0f@<`SlWhMzE_hk}zKs8v zQ38s&mLuegBuQ?A)NGYhjGE_ec|D-VEuuO`;qC-_W@c0 zN*mhWlPbZLBBjze8~FM{U3vW{o&|v+oCp^5_<&B*a-v};keU!A(KgGG{ELg^)4x!p zCduW9Ny_gDm|f=mf+TuR>#in)jSHWXs`GRt7dV&=OAuw%@_6_oc5TUu8>UQW*Z&q; z*TI1T-`4tEw&?8>Ljkt(8Z7D6sk^Q4LmYHD00VEE((z`@*O=;Ju_Iw0DQAID$`r5| zeJ>soA%O4>h=4@Cto32xjzK332jP(&9=B&JZEZMBMxA`>8vx)?{9l|nt4m(4n#krn zM%I@bbp?kiU0r*y$IYM*|*^9U#8!X zCSS|d<2Oo}2JUY$FP+<>Bhc_Zg2y?P?iAhY^A59sc-pV8tto{>u8UU7!gT%QyaBr? z0g|<<5(&@U#CZ-*4WFW7X|V!G>#G75G!Ytv*8+}D5}b;kRtbCWv*6)%44NTw?uPa6 z%ERuea**V6k{k`hPhC0&YU2|xp6KEfc~$*_!FUFZH+rI8+;WK6sg9pFdYTt~hsk*1 zBD_HO&?vsBw0;g&G8fB8NV;E!RR)+{irGhqkJRK*`QRSb&QA-p6!(ytl4qedcQ4qd zK!(w?e7m3t%+0M>R%-F&&xsJ%!G=0YqKZB&`1f%6@4uJ~{YNpwYZD&?`Mq!n{YB?e z{+|>xAsgfWtY@lPZdmgiLa(L5()<(WZQ}>j|JqLk5pz`Mu0OvF5y zFQ4yMl6Zm-1!f%g>+Y!``elCSoq>lIT+V_(;yk)KGgdV*rO2N-IxE9&XVl4~XA=-D zRA zuIv}pv>}M?2rnbMCQ945)S}ne@an`iVa!@NSq$+Rh^Bt8>7E#DHRCX)NwrvBwwwga zS@+ngUTey5nPR6obK|j_K0Ma-`$}XfSttC-YTFZzs zsc&A3b1=mHa`_T$-fi`#+jCk--GLjc(uU_j?Ho~5g%p-ww3XzG4$e3_Zy4g^*Oh8Q z^Is0lz?)3VG7ID`&?3FJ3nZ`V98;VWVzAd34nAzX0~Q7UH3^y~1rQA~n7&#g`j=W? zsOEEppEluiFxpX@9(bf8Tz5;=4MM33#v1BKLqn#ljw#!uW^C%DNz|UN`wnMB2(8v8 zB`iwB{J1u)l~iQwGnc8_?EX^jrW*9~l*kXC(TN1s`ddkfW=ae@yWB@=NZ1S}#|}1^ z#?Ox%YFH*7xw7OyTuddosjRi!QVBSiBX1dfmBKkuBCskqkZFUpYB;HV8mMMiu@|+L z?pj<(#XYo{#m>Us$HmtvpV)1QeF`Ku;>Y#Xsi8`Bs~rSUsL2BGANx`PeYCx(`}^P7 zYeYtAs3dEIo>iXWYK{00I zuCsHpveLL`79`%p(^m%as)$CO!9ab(&`_p8L+%Y&K2wz_Y6BTLFP*4{beZpnzSIq7 zvp?8X+<3$w>7;58pDg#t+$C`NibdDfor$|;=o)!px}tJ1(1!~_eQ8&I$xb6`kVAd7 zcUHmOt!M<#E$lf(M3KATfxDDfaz6D>MbRjc781Yoj*4<}px(h-800y+ST$&Dq{}pQ zl6pz^;Au;iZ&Hc0VWgrTFl{S@FI7)Pa_c7}ff>7W*_9nl&E0=BA007n74VQl?n2E6OHYVjK&{ zgqo3B`%rIcZ_vs$NWWD@A?aeSyTeAPFYzxqZ(7&|64!@;ZGOTA6r9rU*2olL+U#fB zFbo{$A%Ab=qR5xlAN8v?9~H~ccy!t(!P%&9w(?YB`}B5t{k~XK+uMe3tc&_kNUXu; z;jfNs3yE4k%+L4I9f7TS)wWQO z*BR0qc86lsHiZ7}%5W}$Euw1sThy&_(i>z4YYMkRStwg&{NFPv1l&`fq$hRWU9qD< zZ#jo4IPFkOb3YiHRd%bvv?>Q+KMAI@5e!Yyh#`$Ar>i009BX%uojb!V;m`NWG3YA& z#b0aUg~c8hUubE=2qRFrc$v&M1v~ngFF9o`u%ED)RVKQAca-&;ElAGVVk){)Di4kJ z@S4Yl4PI}Yk+ppk>z)Xpt?qD|qq=6VO~@9f=1woLXp}2!_w{E`P|%}o(3rSwwz|-? zn{JA@8`Zj7mMcW(Pnsj#V+eq6jP7nnUAg;)(%Mo9dBT9s`UxQG zQwc8zIU=4dB=<3}M;^%!KqmG%skizNwg@j~*&}-Q2)?2NzPUv1;Ci0vl9a(jmry6< z7K}^E&5OLy{|$XIOfPL49^f89*l+`^g=@dQusJYCJ`NMv8ET=Tb#%}t607b5JvlHS z41i@0G_^BfA0uiFc5I&ftyd_$FQ&dJWk^zQ- zLWa-TU#r1%-NY5G^jqY6E4_sw+oIRCq_?n_DA9>-QtANH1v|xw_V-$pW0nK$>vmc1 z-yikSMTn`rLh_x#(Sv&lWUMx%ep7T316z@MiWaha4BptiNbnm-C$fNT@Rx$N&`$(! z3;~X)+JUzWf+Oz5t6`Q9!D0*7q!x=7mmOv;ZHsMQ<*S$qs|lUwc4pTz_tw>O$4cRF zt&Dt*O=zojC==RMbie_#Fg4~tzB3ohEzc@eXU_EUG#QoJ@)T0v zrD@mLuc%YykZ0gg@yTa#t@Q5I<&SZnV$nqdb#@^N4wY;~Q0bSb6sm`&Cp-r)={NJ` zD-9W6Ii#i9oGdkkFn;crs1n-^;sIW_ob+mXN(SwbWOUPdJRwXrL-)TxA;Jo1ed$%* zlC{&+*J6f6hXRLjY}x3H?&u?I4BUb&QKJmrP=-G5*UI;znrNLhDTFr=)AY?|o+h%7oyA26}mD6~y=&{Vkhic*UW!4I8X^H!@LU_0}r`HQ|M zLqi3YjpH^QKUPm5^6h&(FA+B!88z5X*cmgoCLzu#8bT2`MNOSiI( z6OPJv2Q5=S@qggqIBR*QF5$v_*^FSd0RO8H<4j0F8sb-oq5E4n{<}rvKgAfy37fV^ z4Dca-r%e)T3r)z1k`y#L;(``xz-KVv5RT?Vj&0)0x=)0TuGPki)0~b854>CUFyi0@ zOJIBX@P{yp5&ZZ?&r!Y4?!I0lyFGsGf9`-?F)Q2B1tF~{GPW1mZ1-A1U~F#88!hxF z`&fl$EPL-sWqbR@QiwuTTf^_IB;BpIS+Jlf2dcB2fvMKxTpF2Xq(8kIEbp_&Xu9hTe2v{lzF;ye1>O7 zgl@bztvoofA)49tPP2e1{SPPW(Vj337gB2gCi{4hUgMb@KuW^7AxUxdLk(o?>V0sZ zu1c)svVE74ei!PJlt^$cYc;H1A9w|3BCRg-NT*x5mig7*`%OQsYi7#Zik0iU7gnD?6Y(Lx@rBlfMY(wS+A| zmH7g7yk-1^j{<)Ra^WMJcL-iMhky;dV?YfIVxlx7^AVobI{vDMruP`tAZ3(DFBP&NW4--GaQS?h!X#I1;chg zh+53AO)uE*pC$O;Y)A42Mph=qN^Ta;M&?S+HqQU^%~z~ADLE()&(m66JyO0Odk}t1Z*5*LKcHZ3mOd3zD;x{RRp#28mo5ar6p@%=j|gwDnobzqe$7T~Xf(GbBUC<6Vc#=>@YWeU%nY#$g> zhlOSHsm{H^Y!I8~ASF6^37xzf7C)NY1ov)}fQ{h2b$=sVhV@!ZcL)^H=qQ)H+>2AK z&1lS={i`(baoD)WM$okvLr^ROp;b%ePU`ppWbyUh?M~~j`se|V zMUEvDhziv8ru9oLOpf-PgV1pxd|q3a&1q)sJtYM-$Uq+m2*>`Af$keKh&TAhw`jpf zV@q|zcFj~uqaCnd^4+THH8)I{Et3LEDMQyD=sSiVH*2-4JP#26ZV*AFOi>hK;3SE^2|q91v{T7E76N;^^)svuZB>x)buFO4O4Qb)W9t0+;z zQ$#^Wnn5DS4^A|!p*ZlrjU}OVA*{oHqYeE3BicĪc9|L~`=`18huwWt<8mS<(g7=1wnw_hqbZZ! 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 v12 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 ++xUSv=m#Ls99T!Ggb?3 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%0AA@J^q+1nzY>jRp;O6dDe&BhVK}I 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

O>!8_$<6ys0pu@Z53UI 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

GVv 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

yH>l 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 Zo~Wm{E=)c?YGZ`DMuB+$Bkr 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

Y;I)`ICx8b1X7<7{CZ2v^@Z5pGp*lss8I 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

<) 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�Cfw3&F#ve-eJ9FoQ3Bx`$bN88oSvR2j(p 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 zu341⁢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

5|GUi%{+H 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

WjIuB^U+$qae)iI)~O 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%0DtUALSQS*HQ;=_3y~kU>*v8t($W#wZ2t*CMIiK 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

JFX47xPBa!;vz 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 z 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�lnDUg_@k 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 (Qk~a`k5zL!-e6*X6*~ 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

Jn%bWa=q;8 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%0DcxdP_B93rTO)>Jm$n&swQ%Q&8{l6V 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⋙84Dh^r~<@kgnhpTXUm*&QJapaPU4p3Ig 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

x56zh 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%0A*(F^ozz_{1ni6bv04 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

`Zla4EYi&cl& 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�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"N%!iO{J~Bx5Xh|?jIUZ`NV~*sM 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

NB@Ay*J^JPkFs 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%0AQdC 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�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

0b^Jh(V*ch6@L|u- z3|K9gH*rG;Wb`ziy}<*Pdx#_)fXS}LZ_t6Z9wKoE>tyqLe(dAVo+60{B)}8Tp0I;x zGRlFQa59d4C>0Rv*pF*G)-8x>TuD$Y{=g8J>0vy6!wvi^WIA_)3dB0;2tS||G@W#( z9j_L2+3(0cSRtdFbVnPnC2M!@i8*K`qa1Y?9+&g%0UlTiie(%e2#Vz$;0lT*AEXM3 zWgln>n$F);lI4%xfXVU)ZxDg=hfr4F{4taaIDZ5c0nVR5;eZ^6P#Pe|F%$>LaRlWC za-2X>f%S(_7GV7`lmuA+vHk}Ncm#=#3%CW*jtjWIFalkV{cy+I-GTt)?e0Os4{P<$6!PZm0HBS-e0aM17h!ZrTB3&jPBA3=G5;wMlvVE-W$ z0PH`8=99h09k>d1kpB4hMlPkLB1n9ibM03&H2o3+q|pGOVZ zq`$J?@(rr`ALF{JHVr&GGqI2ZKtrhw7XyT`t>)zxGibl1rtD@Ir>NML((|m)muV*O zU1?&S>czjLnLiss@j}TR@oV_@(zX2T*ktGqkx(oEcCv!O5jE2SE;*~la8iCksP`+O zlo%ljJ!ngt&*rD(f4n+NAjb|Xp2a0cXi5ReZ>gL)+Qhx&bW9Ml=%uxk@n{0+Z*&S@ z-b4T)L5W!{P=_S8A`lV~2fh-;Gp=oL%yvjTRmjO~(Q zv~E?4W^p>TVdc^kXDzQ?sRDq_Fk23AXK&4DXdnR)UYe3JT#wfEDNUDYY1;GwIb-X} ze0!)Zk+b&AWR-1-Rr>d}X^lRRdVPsLkam5V{+Vihlm3}z-BuWEoBGt*133lW#Dgg%a(TqulyaCZg-DaPq~Nct-Sfz9(O`RX2q(hNi1)5E zDp$!>Ozt2w;u|LBO6>v5LmTchR2&Kep%%YWQGU@UMGHLN*dsz>Tt)PI?v4a{g^yz( z#1N!GSDKfCVEKsWxPEsiF2t8MnrD^tp=&fL;w+KrB91x2-U( zRMvs6CNMuAJ1T75WgMckfP0rI0 zob9i5%~}Qvk`^NP&V-c^_TMAg85wx-7L}|`T0#|(BmOLfCMBR^LAo+fcZoS=h9coA zz*utuq32xN@r(SBs<+SYufwCFa+W#dbe+*9ifu_h6yf0sof*=nnw}M`e`ooR2FE3^ zS)CJb&&|2mAQ8`_6w1+@nLx>3=iRpC%E+7d&_DU8DZ5Eg2p{~^n=S{$`V z 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

3p`T2OniFD|+5xfDHh?u+Q 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

*^=El`hs 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 og#ceR=+{zVb8HCrpQC( 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

Oa1*eRk3LoMnzDE@Hn$pReTO~(yH+44^`tDEp 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�>&`ZgLAxaN8LFoy_N)D7Ny`fSW05cUgR4IL- zUKt3Bl|eQIR-pQw9&Sd3Ictg}dA;xW@t z1R59`g(jQvC^)(e1Geke$x^7{9_Bg>E-YZ3EOj?CHba@Sd0M2o+3+As7aYBZW$a^_ zB`NL{(L*QeQR2d8ZWq?sq_Q19AKn4}Y?ig3Wglcc7i#-hP6;AYZJnSUWW5%mHKXKU zVeb-tko8&U=KGktll9Hfs0yk!w0W#*R7CZ3QBODPp)JJv?SQnBlx#M@ow6TR;^IwI z^Lwee-o0!f9Sw{^n#DezV$ZVv7L7cC)CI~Iq}j1ZvlAdwnFc+TGU%(6L#|Q*`AQ{> zRi;C^G81Z)D%hyh!llY=xJH=+_bYRe!|P#}G7p|p7QoBOB6vet4DTsR;6KVzTn!IP zQ<_*$#mo9CE$l>P1yayTHdpbng-Qimt_0XhWep1|A+}x#vkR5A>{?|VyG2>gwkoHy zhm|wfLFH`rlyW|MRymhFubjtTQ7&L_Di^YMl}p$Min*7$9Wq%Z%BF2-mZY$`D5<8S zd~v}wa9GF^4!htU`kVr)n6Yexe5a5!C$P!%odxvPp2rrG~odL-NC9H?TKR`-fEQR4R_=2C6yEq0RMVB#QL?ID7IPq3bb z+Jx*@1j~>oQcz^E3;Co}YZ%$v%Cg7V@Di>}&~x-0?G88@NlNczBPOH}aiw&!yb_n& zwTF$A$L?YIPqBiMR5#DjvA-ei)J|4dzez{kdI;Mq6H;D#IUWJTB*8;#n6nsBN%MgY2Y*``F1PhCCrHC(WH|nH{s- zsX1w;;lWBu(v=ArIT@nMLhLeQY)Pg&-JOYDcCtyGZ1NV!a2xLQoDAB$U{f|_;0SMS zO2hQw$XtwlY-&jw&LvIEC5`5i7PaTzMZX-BD?n4OgdWOO$fQ@pVC7mUP_BbUT=7}Jg0u6)eyRX$_8mCxDJ$`|Z4V**XD}^g(r6en#ODW0^Qg7uS z(m>^3(op3;#K^2K`U2O$2>B6Yo)owR2FQDmRb6mDve915rNVhIMefA6I(&|0`{eyt z_9o=Z6yf87=kYBWZ7FOP`YVqj!@JlOkR~6*dImcihKRSR>?8DK9>cOsWY969zYO*o zjF%rrTRENWg$7YCjaW3o=9nX4!9bG+%TJ;$jZU-FOMaT1X6P%W2|=U4U`Z3=MTNC& zm;8+I2+wBs$j_q1&EXm5m7hmpp|dpBS3ZQf6m|yOFCRvu(#7tDv*cf4E|u*@W9kKI z7Z_4+YaVG4%h{}tHoH|Hb5?z{;SCh(FUzl3X2Ihg*GNnEbl%s}%aqn&mIOi*F2U`OHCfDgrdC#x(Ay z3h!^gcDM&!KbzOoLXsNQo5>8g*sYdmIG>scTow|IZ-o5$ik>_HWiq8Id@^3MxiNk=m@hwNY|9*Lr<@-Kkuj(^` zRLNC)RQ{d(4z6kjJR-kKtLoUYct#Ltq}F@3L-%_m%=hI#Sb-kr;dmLi?(2mXL{BH8 z1xpkwkNQujK`mt>w>9B-r(UQRwq%SZ)SQ}-EFdKC1{AJnSk0pa-oxg1vc@ftZeeFrf%9Rv+6a%S3*cjQ34ErW2H&g8;9u%;_*rdY!_;P$ zuX

+
+
[Become a sponsor!](https://github.com/sponsors/soot-oss) + diff --git a/docs/installation.md b/docs/installation.md index 824f968e7e1..239f709f565 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,4 +1,5 @@ # Installation + ## Use the latest [develop branch](https://github.com/soot-oss/SootUp/tree/develop) For configuration options of your build tool please visit [SootUp on Jitpack.io](https://jitpack.io/#soot-oss/SootUp/develop-SNAPSHOT) @@ -48,12 +49,17 @@ Add the following dependencies to your ```pom.xml``` / ```build.gradle```. sootup.analysis {{ git_latest_release }} + + org.soot-oss + sootup.qilin + {{ git_latest_release }} + ``` === "Gradle" - ```gradle + ```groovy repositories { mavenCentral() google() @@ -66,6 +72,7 @@ Add the following dependencies to your ```pom.xml``` / ```build.gradle```. compile "org.soot-oss:sootup.jimple.parser:{{ git_latest_release }}" compile "org.soot-oss:sootup.callgraph:{{ git_latest_release }}" compile "org.soot-oss:sootup.analysis:{{ git_latest_release }}" + compile "org.soot-oss:sootup.qilin:{{ git_latest_release }}" ``` ## Build from Source diff --git a/docs/migrating.md b/docs/migrating.md new file mode 100644 index 00000000000..c7302e738a0 --- /dev/null +++ b/docs/migrating.md @@ -0,0 +1,116 @@ +# Migration Help + +### Version 1.3.0 +- The Typehierarchy API is now returning `Stream` instead of `Collection`. The simplest fix to have the same behaviour as before would be to collect the Stream on your own ( e.g. via `.collect(Collectors.toList())` ). +- Default Bodyinterceptors are added to improve Jimple. To mitigate that adapt the List of BodyInterceptors to your needs. +- + +### Version 1.2.0 +- The (Java)Project structure was removed. You can configure the (Java)View directly. +- Bodyinterceptors are now passed as arguments into AnalysisInputLocations. + +### From [Soot](https://github.com/soot-oss/Soot) +- The Scene singleton is dead. Long live the Scene. We have a central View object(!) now. +- Library first! No command line tool as primary goal. So you can configure parts of SootUp (near) where it is actually used. +- t.b.c. + +Below we show a comparison of the code so far with the same functionality in sootup. + +=== "SootUp" + + ``` java + AnalysisInputLocation inputLocation = + new JavaClassPathAnalysisInputLocation("path2Binary"); + + JavaView view = new JavaView(inputLocation); + + JavaClassType classType = + view.getIdentifierFactory().getClassType("HelloWorld"); + + MethodSignature methodSignature = + view + .getIdentifierFactory() + .getMethodSignature( + "main", classType, "void", + Collections.singletonList("java.lang.String[]")); + + JavaSootClass sootClass = view.getClass(classType).get(); + + JavaSootMethod sootMethod = sootClass.getMethod(methodSignature.getSubSignature()).get(); + + sootMethod.getBody().getStmts(); + ``` + +=== "Soot" + + ``` java + G.reset(); + String userdir = System.getProperty("user.dir"); + String sootCp = + userdir + + File.separator + + "target" + + File.separator + + "test-classes" + + File.pathSeparator + "lib"+File.separator+"rt.jar"; + + Options.v().set_soot_classpath(sootCp); + Options.v().set_whole_program(true); + Options.v().setPhaseOption("cg.cha", "on"); + Options.v().setPhaseOption("cg", "all-reachable:true"); + Options.v().set_no_bodies_for_excluded(true); + Options.v().set_allow_phantom_refs(true); + Options.v().setPhaseOption("jb", "use-original-names:true"); + Options.v().set_prepend_classpath(false); + + Scene.v().addBasicClass("java.lang.StringBuilder"); + SootClass c = + Scene.v().forceResolve(targetTestClassName, SootClass.BODIES); + if (c != null) { + c.setApplicationClass(); + } + Scene.v().loadNecessaryClasses(); + + SootMethod method; + for (SootClass c : Scene.v().getApplicationClasses()) { + if(c.getName().equals("example.HelloWorld")){ + for (SootMethod m : c.getMethods()) { + if (!m.hasActiveBody()) { + continue; + } + if (m.getName().equals("entryPoint")) { + method = m; + break; + } + } + } + } + + method.getActiveBody().getUnits(); + ``` + + + + + + + + + diff --git a/docs/migration.md b/docs/migration.md deleted file mode 100644 index c2dbf366e20..00000000000 --- a/docs/migration.md +++ /dev/null @@ -1,3 +0,0 @@ -# From [Soot](https://github.com/soot-oss/Soot) - -// TODO \ No newline at end of file diff --git a/docs/overrides/partials/footer.html b/docs/overrides/partials/footer.html new file mode 100644 index 00000000000..12330e0318a --- /dev/null +++ b/docs/overrides/partials/footer.html @@ -0,0 +1,108 @@ + + + + \ No newline at end of file diff --git a/docs/overrides/partials/header.html b/docs/overrides/partials/header.html new file mode 100644 index 00000000000..cf74cabac7e --- /dev/null +++ b/docs/overrides/partials/header.html @@ -0,0 +1,106 @@ + + + +{% set class = "md-header" %} +{% if "navigation.tabs.sticky" in features %} +{% set class = class ~ " md-header--shadow md-header--lifted" %} +{% elif "navigation.tabs" not in features %} +{% set class = class ~ " md-header--shadow" %} +{% endif %} + + +
+ + + + {% if "navigation.tabs.sticky" in features %} + {% if "navigation.tabs" in features %} + {% include "partials/tabs.html" %} + {% endif %} + {% endif %} +
diff --git a/docs/qilin.md b/docs/qilin.md index efa54851cdc..9c9971adbae 100644 --- a/docs/qilin.md +++ b/docs/qilin.md @@ -2,9 +2,20 @@ see [QilinPTA](https://github.com/QilinPTA/Qilin). ### Dependencies -```maven - // TODO: add submodule -``` +=== "Maven" + ```maven + + org.soot-oss + sootup.java.sourcecode + + + ``` + +=== "Gradle" + + ```groovy + compile "org.soot-oss:sootup.qilin:{{ git_latest_release }}" + ``` ### How to diff --git a/docs/tool_ux.md b/docs/tool_ux.md index 76edebca727..8528055cd3d 100644 --- a/docs/tool_ux.md +++ b/docs/tool_ux.md @@ -1,4 +1,4 @@ -# Prototype to user friendly tool +# From Prototype to user friendly tool `How was the parameter order again?` For a lot of cli tools we see an arbitrary order of cli parameters, different options for giving a working directory etc.. @@ -9,18 +9,21 @@ In SootUp we thought we could help on improving this madness while saving your t The command line parser mimics the options the java executable accepts - at least for what is supported by SootUp. Dependencies: -```maven - - commons-cli - commons-cli - 1.8.0 - - -``` - -```gradle - implementation("commons-cli:commons-cli:1.8.0") -``` +=== "Maven" + ```maven + + commons-cli + commons-cli + 1.8.0 + + ``` + +=== "Gradle" + ```groovy + implementation("commons-cli:commons-cli:1.8.0") + ``` + +### Java Code ```java diff --git a/docs/write_analyses.md b/docs/write_analyses.md index 7ee09b1b10e..914b008d803 100644 --- a/docs/write_analyses.md +++ b/docs/write_analyses.md @@ -1,7 +1,30 @@ -# Writing Analyses +# Write your own Interprocedural Dataflow Analysis + +### Dependencies +=== "Maven" + ```maven + + org.soot-oss + sootup.analysis + + + ``` +=== "Gradle" + ```groovy + compile "org.soot-oss:sootup.analysis:{{ git_latest_release }}" + ``` + +### Useful Knowledge +Background Knowledge as online lectures are available on YouTube. + +- [IFDS Framework](https://www.youtube.com/watch?v=QkK79fT0TFU&ab_channel=SecureSoftwareEngineering) +- [IDE Framework](https://www.youtube.com/watch?v=0uMHX3UY9bg&ab_channel=SecureSoftwareEngineering) + +### Examples +Taint Analysis, TypeState Analysis, Linear Constant Propagation, ... ``` -// TODO improve tutorial! +// TODO incorporate & guide through examples ``` -If you wish to implement an interprocedural data-flow analysis via the IFDS or IDE Framework please have a look at the test cases in the sootup.analysis submodule. \ No newline at end of file +If you wish to implement an interprocedural data-flow analysis via the IFDS or IDE Framework please have a look at the test cases in the sootup.analysis submodule. diff --git a/mkdocs.yml b/mkdocs.yml index f73450910c7..b2a88399d17 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,6 +9,7 @@ nav: - Getting Started: - Installation: installation.md - First Steps: getting-started.md + - Examples: examples.md - Configure your Inputs: analysisinputlocations.md - Basics: @@ -29,7 +30,7 @@ nav: - Misc: - Announcements: announce.md - Design Decisions: whatsnew.md - - Migrating from Soot: migrating.md + - Migration Help: migrating.md - More information: - Latest Javadoc: /SootUp/apidocs @@ -38,14 +39,16 @@ nav: theme: - palette: - primary: white - name: material logo: ./img/SootUpLogo.svg favicon: ./img/icon.svg + palette: + primary: custom + custom_dir: ./docs/overrides + name: material features: - navigation.sections + plugins: - tooltips - search @@ -53,6 +56,7 @@ plugins: src_path: 'sootup.examples/src/test/java/sootup/examples' extra_css: + - css/customizetheme.css - css/hint.min.css markdown_extensions: From b009e5be1fc9542367c9adef222677fda6938d45 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Mon, 17 Jun 2024 13:50:50 +0200 Subject: [PATCH 115/145] fix pr title sanitation --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 60c5d17cc68..9aefa61be04 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -65,7 +65,7 @@ jobs: git config --local user.name "github-actions[bot]" # sanitive head_ref name - - run: echo "DOC_VERSION_NAME=$(echo ${{ github.head_ref }} | sed "s/[^[:alnum:]_-.#@]/_/g" )" >> $GITHUB_ENV + - run: echo "DOC_VERSION_NAME=$(echo ${{ github.head_ref }} | sed "s/[^([[:alnum:]_.-]/_/g"" )" >> $GITHUB_ENV # on push to develop branch - keep a doc around for develop to show the current state - name: deploy doc in subdirectory From 60086d8858e4ce319bf2c7c906585815e9d8ff8e Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Mon, 17 Jun 2024 14:44:11 +0200 Subject: [PATCH 116/145] split up Jimple sammelsurium into multiple documents --- docs/css/customizetheme.css | 23 +- docs/jimple-body.md | 140 +++ docs/jimple-stmts.md | 1166 ++++++++++++++++++ docs/jimple-types.md | 539 +++++++++ docs/jimple-values.md | 178 +++ docs/jimple.md | 2279 ++++------------------------------- mkdocs.yml | 5 + 7 files changed, 2251 insertions(+), 2079 deletions(-) create mode 100644 docs/jimple-body.md create mode 100644 docs/jimple-stmts.md create mode 100644 docs/jimple-types.md create mode 100644 docs/jimple-values.md diff --git a/docs/css/customizetheme.css b/docs/css/customizetheme.css index fc2c8b184fa..e3652403932 100644 --- a/docs/css/customizetheme.css +++ b/docs/css/customizetheme.css @@ -11,7 +11,6 @@ --md-accent-fg-color: rgba(255,140,0, 1); } - .md-typeset a { color: rgba(255,140,0, 0.8); } @@ -87,8 +86,14 @@ } .tabbed-set.tabbed-alternate{ - background: #EEE; + background: rgba(255,140,0, 0.1); + color: rgba(255,140,0, 1); +} + +.md-typeset .tabbed-labels>label>[href]:first-child{ + color: rgba(255,140,0, 1); } + .md-footer{ margin-top: 2em; padding:1em; @@ -109,6 +114,20 @@ html .md-footer-meta.md-typeset a{ border:none; } +.highlighttable{ + border-bottom:1px solid rgba(255,140,0, 0.1); + border-right:1px solid rgba(255,140,0, 0.1); +} + +.highlighttable .linenos{ + background-color:#EEE; + border-color: rgba(255,140,0, 0.1); +} + +.md-typeset code { + background-color: #FFF; +} + #developedBy{ font-size: 11pt; } \ No newline at end of file diff --git a/docs/jimple-body.md b/docs/jimple-body.md new file mode 100644 index 00000000000..10ae286516d --- /dev/null +++ b/docs/jimple-body.md @@ -0,0 +1,140 @@ +# Jimple MethodBody +A Methodbody consists of the Modifiers and its StmtGraph - SootUps Control Flow Graph Structure. +The StmtGraph organizes the flow of [Stmts](jimple-stmts.md). + +### Control Flow Graph +- unexceptional flow -> like FallsThroughStmts and BranchingStmts for if,goto etc. +- exceptional flow -> for exceptions, handled by traps. + +### Stmts +Learn more about the types of [Stmts](jimple-stmts.md). + +### Traps +A Trap is a mechanism to model exceptional flow. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void divideExample(int, int) + { + int x, y, $stack4; + java.io.PrintStream $stack5, $stack7; + java.lang.Exception $stack6; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + y := @parameter1: int; + + label1: + $stack5 = ; + $stack4 = x / y; + virtualinvoke $stack5.($stack4); + + label2: + goto label4; + + label3: + $stack6 := @caughtexception; + $stack7 = ; + virtualinvoke $stack7.("Exception caught"); + + label4: + return; + + catch java.lang.Exception from label1 to label2 with label3; + } + } + /* + By calling getTraps() method, we can get the Trap. + For the above jimple code, we have the below trap: + Trap : + begin : $stack5 = + end : goto [?= return] + handler: $stack6 := @caughtexception + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public void divideExample(int x, int y){ + try { + System.out.println(x / y); + }catch (Exception e){ + System.out.println("Exception caught"); + } + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public divideExample(II)V + TRYCATCHBLOCK L0 L1 L2 java/lang/Exception + L0 + LINENUMBER 6 L0 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 1 + ILOAD 2 + IDIV + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L1 + LINENUMBER 9 L1 + GOTO L3 + L2 + LINENUMBER 7 L2 + FRAME SAME1 java/lang/Exception + ASTORE 3 + L4 + LINENUMBER 8 L4 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Exception caught" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L3 + LINENUMBER 10 L3 + FRAME SAME + RETURN + L5 + LOCALVARIABLE e Ljava/lang/Exception; L4 L3 3 + LOCALVARIABLE this Land Ttarget/exercise1/DemoClass; L0 L5 0 + LOCALVARIABLE x I L0 L5 1 + LOCALVARIABLE y I L0 L5 2 + MAXSTACK = 3 + MAXLOCALS = 4 + } + ``` diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md new file mode 100644 index 00000000000..0fb058a1665 --- /dev/null +++ b/docs/jimple-stmts.md @@ -0,0 +1,1166 @@ +# Jimple Stmt ("Statements") +The main piece of Jimple is a Statement (Stmt). [**Stmts**]{formerly known as Units} represent that can be executed by the JVM. + + +## Branching Statements +A BranchingStmt's job is to model the jumps or conditional branching flow between Stmts. + +##### JGotoStmt +for unconditional flow. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + public static void sampleMethod() + { + int i; + i = 0; + + label1: + if i >= 5 goto label3; + if i != 3 goto label2; + goto label3; + + label2: + i = i + 1; + goto label1; + + label3: + return; + } + } + /* + Here for statements "goto label3;" and "goto label1;", + we have two instances of JGotoStmt : + "goto[?=return]" and "goto[?=(branch)]". + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public static void sampleMethod(){ + label1: + for (int i = 0; i < 5; i++){ + if(i == 3){ + break label1; + } + } + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x9 + public static sampleMethod()V + L0 + LINENUMBER 6 L0 + ICONST_0 + ISTORE 0 + L1 + FRAME APPEND [I] + ILOAD 0 + ICONST_5 + IF_ICMPGE L2 + L3 + LINENUMBER 7 L3 + ILOAD 0 + ICONST_3 + IF_ICMPNE L4 + L5 + LINENUMBER 8 L5 + GOTO L2 + L4 + LINENUMBER 6 L4 + FRAME SAME + IINC 0 1 + GOTO L1 + L2 + LINENUMBER 11 L2 + FRAME CHOP 1 + RETURN + LOCALVARIABLE i I L1 L2 0 + MAXSTACK = 2 + MAXLOCALS = 1 + } + ``` + +##### JIfStmt +for conditional flow depending on boolean Expression (AbstractConditionExpr) so they have two successor Stmt's. +note: The JIfStmt is also a FallsthroughStmt if the branching condition is not met. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public static void sampleMethod(int) + { + int x, $stack1; + java.io.PrintStream $stack2, $stack3; + + x := @parameter0: int; + + $stack1 = x % 2; + if $stack1 != 0 goto label1; + + $stack3 = ; + virtualinvoke $stack3.("Even"); + goto label2; + + label1: + $stack2 = ; + virtualinvoke $stack2.("Odd"); + + label2: + return; + } + } + /* + For statement "if $stack1 != 0 goto label1;", + we have an instance of JIfStmt : + "if $stack1 != 0 goto $stack2 + = ". + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public static void sampleMethod(int x){ + if(x % 2 == 0){ + System.out.println("Even"); + }else{ + System.out.println("Odd"); + } + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x9 + public static sampleMethod(I)V + L0 + LINENUMBER 5 L0 + ILOAD 0 + ICONST_2 + IREM + IFNE L1 + L2 + LINENUMBER 6 L2 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Even" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + GOTO L3 + L1 + LINENUMBER 8 L1 + FRAME SAME + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Odd" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L3 + LINENUMBER 10 L3 + FRAME SAME + RETURN + L4 + LOCALVARIABLE x I L0 L4 0 + MAXSTACK = 2 + MAXLOCALS = 1 + } + ``` + +##### JSwitchStmt +for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's. + +All other Stmts are not manipulating the flow, which means they have a single successor Stmt as long as they are not exiting the flow inside a method. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void switchExample(int) + { + int x; + java.io.PrintStream $stack2, $stack3, $stack4; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + + lookupswitch(x) + { + case 1: goto label1; + case 2: goto label2; + default: goto label3; + }; + + label1: + $stack3 = ; + virtualinvoke $stack3.("Input 1"); + goto label4; + + label2: + $stack2 = ; + virtualinvoke $stack2.("Input 2"); + goto label4; + + label3: + $stack4 = ; + virtualinvoke $stack4.("Input more than 2"); + + label4: + return; + } + } + /* + Here for below statement: + lookupswitch(x) + { + case 1: goto label1; + case 2: goto label2; + default: goto label3; + }; + + we have an instance of JLookupSwitchStmt : + lookupswitch(x) + { + case 1: goto $stack3 + = ; + case 2: goto $stack2 + = ; + default: goto $stack4 + = ; + } + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public void switchExample(int x){ + switch (x){ + case 1: + System.out.println("Input 1"); + break; + + case 2: + System.out.println("Input 2"); + break; + + default: + System.out.println("Input more than 2"); + break; + + } + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public switchExample(I)V + L0 + LINENUMBER 5 L0 + ILOAD 1 + LOOKUPSWITCH + 1: L1 + 2: L2 + default: L3 + L1 + LINENUMBER 7 L1 + FRAME SAME + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Input 1" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L4 + LINENUMBER 8 L4 + GOTO L5 + L2 + LINENUMBER 11 L2 + FRAME SAME + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Input 2" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L6 + LINENUMBER 12 L6 + GOTO L5 + L3 + LINENUMBER 15 L3 + FRAME SAME + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Input more than 2" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L5 + LINENUMBER 19 L5 + FRAME SAME + RETURN + L7 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L7 0 + LOCALVARIABLE x I L0 L7 1 + MAXSTACK = 2 + MAXLOCALS = 2 + } + ``` + +## FallsThrough Statements +The execution of a FallsthroughStmt goes on with the following Stmt (when no exception was thrown). + +##### JReturnStmt & JReturnVoidStmt +They end the execution/flow inside the current method and return (a value) to its caller. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public int increment(int) + { + int x, $stack2; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + + $stack2 = x + 1; + return $stack2; + } + + public void print() + { + java.io.PrintStream $stack1; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + $stack1 = ; + virtualinvoke $stack1.("Inside method print"); + return; + } + } + /* + "return $stack2" is JReturnStmt. + "return" is JReturnVoidStmt. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public int increment(int x){ + return x + 1; + } + public void print(){ + System.out.println("Inside method print"); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public increment(I)I + L0 + LINENUMBER 5 L0 + ILOAD 1 + ICONST_1 + IADD + IRETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + LOCALVARIABLE x I L0 L1 1 + MAXSTACK = 2 + MAXLOCALS = 2 + + // access flags 0x1 + public print()V + L0 + LINENUMBER 8 L0 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Inside method print" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L1 + LINENUMBER 9 L1 + RETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + MAXSTACK = 2 + MAXLOCALS = 1 + } + ``` + + +##### JThrowStmt +Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler. + + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void divideExample(int, int) + { + int y, x, $stack6; + java.lang.StringBuilder $stack3, $stack5, $stack7; + java.io.PrintStream $stack4; + java.lang.String $stack8; + java.lang.RuntimeException $stack9; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + y := @parameter1: int; + + if y != 0 goto label1; + + $stack9 = new java.lang.RuntimeException; + specialinvoke $stack9.(java.lang.String)>("Divide by zero error"); + throw $stack9; + + label1: + $stack4 = ; + $stack3 = new java.lang.StringBuilder; + specialinvoke $stack3.()>(); + + $stack5 = virtualinvoke $stack3.("Divide result : "); + $stack6 = x / y; + $stack7 = virtualinvoke $stack5.($stack6); + $stack8 = virtualinvoke $stack7.(); + + virtualinvoke $stack4.($stack8); + return; + } + } + /* + "throw $stack9" is JThrowStmt. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public void divideExample(int x, int y){ + if(y == 0){ + throw new RuntimeException("Divide by zero error"); + } + System.out.println("Divide result : " + x / y); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public divideExample(II)V + L0 + LINENUMBER 5 L0 + ILOAD 2 + IFNE L1 + L2 + LINENUMBER 6 L2 + NEW java/lang/RuntimeException + DUP + LDC "Divide by zero error" + INVOKESPECIAL java/lang/RuntimeException. + (Ljava/lang/String;)V + ATHROW + L1 + LINENUMBER 8 L1 + FRAME SAME + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + NEW java/lang/StringBuilder + DUP + INVOKESPECIAL java/lang/StringBuilder. ()V + LDC "Divide result : " + INVOKEVIRTUAL java/lang/StringBuilder.append + (Ljava/lang/String;)Ljava/lang/StringBuilder; + ILOAD 1 + ILOAD 2 + IDIV + INVOKEVIRTUAL java/lang/StringBuilder.append + (I)Ljava/lang/StringBuilder; + INVOKEVIRTUAL java/lang/StringBuilder.toString + ()Ljava/lang/String; + INVOKEVIRTUAL java/io/PrintStream.println + (Ljava/lang/String;)V + L3 + LINENUMBER 9 L3 + RETURN + L4 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0 + LOCALVARIABLE x I L0 L4 1 + LOCALVARIABLE y I L0 L4 2 + MAXSTACK = 4 + MAXLOCALS = 3 + } + ``` + + +##### JInvokeStmt +transfers the control flow to another method until the called method returns. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void print(int) + { + target.exercise1.DemoClass this; + int x, a; + java.io.PrintStream $stack4, $stack6; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + + a = virtualinvoke this.(x); + $stack4 = ; + virtualinvoke $stack4.(a); + + a = virtualinvoke this.(a); + $stack6 = ; + virtualinvoke $stack6.(a); + + return; + } + + public int increment(int) + { + int x, $stack2; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + + $stack2 = x + 1; + return $stack2; + } + } + /* + "specialinvoke this.()>()", + "virtualinvoke this.(x)", + "virtualinvoke this.(a)" + are JInvokeStmts. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public void print(int x){ + int a = increment(x); + System.out.println(a); + a = increment(a); + System.out.println(a); + } + public int increment(int x){ + return x + 1; + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public print(I)V + L0 + LINENUMBER 5 L0 + ALOAD 0 + ILOAD 1 + INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I + ISTORE 2 + L1 + LINENUMBER 6 L1 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 2 + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L2 + LINENUMBER 7 L2 + ALOAD 0 + ILOAD 2 + INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I + ISTORE 2 + L3 + LINENUMBER 8 L3 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 2 + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L4 + LINENUMBER 9 L4 + RETURN + L5 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0 + LOCALVARIABLE x I L0 L5 1 + LOCALVARIABLE a I L1 L5 2 + MAXSTACK = 2 + MAXLOCALS = 3 + + // access flags 0x1 + public increment(I)I + L0 + LINENUMBER 11 L0 + ILOAD 1 + ICONST_1 + IADD + IRETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + LOCALVARIABLE x I L0 L1 1 + MAXSTACK = 2 + MAXLOCALS = 2 + } + ``` + + +##### JAssignStmt +assigns a Value from the right hand-side to the left hand-side. +Left hand-side of an assignment can be a Local referencing a variable (i.e. a Local) or a FieldRef referencing a Field. +Right hand-side of an assignment can be an expression (Expr), a Local, a FieldRef or a Constant. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + this. = 0; + return; + } + + public int updateCounter() + { + target.exercise1.DemoClass this; + int $stack1, $stack2, $stack3; + + this := @this: target.exercise1.DemoClass; + + $stack1 = this.; + $stack2 = $stack1 + 1; + this. = $stack2; + $stack3 = this.; + + return $stack3; + } + } + /* + "this. = 0", + "$stack1 = this.", + "$stack2 = $stack1 + 1" + "this. = $stack2" + "$stack3 = this." + are JAssignStmts. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + private int counter = 0; + public int updateCounter(){ + counter = counter + 1; + return counter; + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x2 + private I counter + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + L1 + LINENUMBER 4 L1 + ALOAD 0 + ICONST_0 + PUTFIELD target/exercise1/DemoClass.counter : I + RETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + MAXSTACK = 2 + MAXLOCALS = 1 + + // access flags 0x1 + public updateCounter()I + L0 + LINENUMBER 6 L0 + ALOAD 0 + ALOAD 0 + GETFIELD target/exercise1/DemoClass.counter : I + ICONST_1 + IADD + PUTFIELD target/exercise1/DemoClass.counter : I + L1 + LINENUMBER 7 L1 + ALOAD 0 + GETFIELD target/exercise1/DemoClass.counter : I + IRETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + MAXSTACK = 3 + MAXLOCALS = 1 + } + ``` + + +##### JIdentityStmt +is semantically like the JAssignStmt and handles assignments of IdentityRef's to make implicit assignments explicit into the StmtGraph. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void DemoClass(int) + { + target.exercise1.DemoClass this; + int counter; + + this := @this: target.exercise1.DemoClass; + counter := @parameter0: int; + this. = counter; + return; + } + } + /* + "this := @this: target.exercise1.DemoClass" and + "counter := @parameter0: int" are JIdentityStmts + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + private int counter; + public void DemoClass(int counter){ + this.counter = counter; + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x2 + private I counter + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public DemoClass(I)V + L0 + LINENUMBER 6 L0 + ALOAD 0 + ILOAD 1 + PUTFIELD target/exercise1/DemoClass.counter : I + L1 + LINENUMBER 7 L1 + RETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + LOCALVARIABLE counter I L0 L2 1 + MAXSTACK = 2 + MAXLOCALS = 2 + } + ``` + + +#####JEnterMonitorStmt & JExitMonitorStmt +marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + this. = 0; + return; + } + + public int updateCounter() + { + target.exercise1.DemoClass this; + int $stack4, $stack5, $stack7; + java.lang.Throwable $stack8; + + this := @this: target.exercise1.DemoClass; + + entermonitor this; + + label1: + $stack4 = this.; + $stack5 = $stack4 + 1; + this. = $stack5; + + exitmonitor this; + + label2: + goto label5; + + label3: + $stack8 := @caughtexception; + + exitmonitor this; + + label4: + throw $stack8; + + label5: + $stack7 = this.; + return $stack7; + + catch java.lang.Throwable from label1 to label2 with label3; + catch java.lang.Throwable from label3 to label4 with label3; + } + } + /* + "entermonitor this" is JEnterMonitorStmt. + "exitmonitor this" is JExitMonitorStmt. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + private int counter = 0; + public int updateCounter(){ + synchronized (this) { + counter = counter + 1; + } + return counter; + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x2 + private I counter + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + L1 + LINENUMBER 4 L1 + ALOAD 0 + ICONST_0 + PUTFIELD target/exercise1/DemoClass.counter : I + RETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + MAXSTACK = 2 + MAXLOCALS = 1 + + // access flags 0x1 + public updateCounter()I + TRYCATCHBLOCK L0 L1 L2 null + TRYCATCHBLOCK L2 L3 L2 null + L4 + LINENUMBER 6 L4 + ALOAD 0 + DUP + ASTORE 1 + MONITORENTER + L0 + LINENUMBER 7 L0 + ALOAD 0 + ALOAD 0 + GETFIELD target/exercise1/DemoClass.counter : I + ICONST_1 + IADD + PUTFIELD target/exercise1/DemoClass.counter : I + L5 + LINENUMBER 8 L5 + ALOAD 1 + MONITOREXIT + L1 + GOTO L6 + L2 + FRAME FULL [target/exercise1/DemoClass java/lang/Object] + [java/lang/Throwable] + ASTORE 2 + ALOAD 1 + MONITOREXIT + L3 + ALOAD 2 + ATHROW + L6 + LINENUMBER 9 L6 + FRAME CHOP 1 + ALOAD 0 + GETFIELD target/exercise1/DemoClass.counter : I + IRETURN + L7 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L4 L7 0 + MAXSTACK = 3 + MAXLOCALS = 3 + } + ``` + + +##### JRetStmt +##### JBreakpointStmt +models a Breakpoint set by a Debugger (usually not relevant for static analyses) diff --git a/docs/jimple-types.md b/docs/jimple-types.md new file mode 100644 index 00000000000..fc073396599 --- /dev/null +++ b/docs/jimple-types.md @@ -0,0 +1,539 @@ +#Jimple Types + +#### PrimaryType +- BooleanType +- ByteType +- CharType +- ShortType +- IntType +- LongType +- DoubleType +- FloatType + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + + public void display() + { + java.io.PrintStream $stack11, $stack13, $stack15, + $stack17, $stack19, $stack21, $stack23, $stack25; + int $stack12, $stack14, $stack16, $stack18; + long $stack20; + double $stack22; + float $stack24; + target.exercise1.DemoClass this; + boolean $stack26; + + this := @this: target.exercise1.DemoClass; + + $stack11 = ; + + goto label1; + + label1: + $stack26 = 0; + virtualinvoke $stack11.($stack26); + + $stack13 = ; + $stack12 = 127 - 1; + virtualinvoke $stack13.($stack12); + + $stack15 = ; + $stack14 = 97 + 1; + virtualinvoke $stack15.($stack14); + + $stack17 = ; + $stack16 = 1123 + 1; + virtualinvoke $stack17.($stack16); + + $stack19 = ; + $stack18 = 123456 + 1; + virtualinvoke $stack19.($stack18); + + $stack21 = ; + $stack20 = 10L + 1L; + virtualinvoke $stack21.($stack20); + + $stack23 = ; + $stack22 = 10.1 + 1.0; + virtualinvoke $stack23.($stack22); + + $stack25 = ; + $stack24 = 10.1F + 1.0F; + virtualinvoke $stack25.($stack24); + + return; + } + } + /* + The JimpleLocal $stack12, $stack14, $stack16, $stack18 are of IntType. + Similarly, $stack20 is of LongType, $stack22 is of DoubleType and so on. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public void display(){ + boolean varBoolean = true; + byte varByte = 127; + char varChar = 'a'; + short varShort = 1123; + int varInt = 123456; + long varLong = 10L; + double varDouble = 10.10; + float varFloat = 10.10f; + + System.out.println(!varBoolean); + System.out.println(varByte-1); + System.out.println(varChar+1); + System.out.println(varShort+1); + System.out.println(varInt+1); + System.out.println(varLong+1); + System.out.println(varDouble+1); + System.out.println(varFloat+1); + + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public display()V + L0 + LINENUMBER 5 L0 + ICONST_1 + ISTORE 1 + L1 + LINENUMBER 6 L1 + BIPUSH 127 + ISTORE 2 + L2 + LINENUMBER 7 L2 + BIPUSH 97 + ISTORE 3 + L3 + LINENUMBER 8 L3 + SIPUSH 1123 + ISTORE 4 + L4 + LINENUMBER 9 L4 + LDC 123456 + ISTORE 5 + L5 + LINENUMBER 10 L5 + LDC 10 + LSTORE 6 + L6 + LINENUMBER 11 L6 + LDC 10.1 + DSTORE 8 + L7 + LINENUMBER 12 L7 + LDC 10.1 + FSTORE 10 + L8 + LINENUMBER 14 L8 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 1 + IFNE L9 + ICONST_1 + GOTO L10 + L9 + FRAME FULL [target/exercise1/DemoClass I I I I I J D F] + [java/io/PrintStream] + ICONST_0 + L10 + FRAME FULL [target/exercise1/DemoClass I I I I I J D F] + [java/io/PrintStream I] + INVOKEVIRTUAL java/io/PrintStream.println (Z)V + L11 + LINENUMBER 15 L11 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 2 + ICONST_1 + ISUB + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L12 + LINENUMBER 16 L12 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 3 + ICONST_1 + IADD + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L13 + LINENUMBER 17 L13 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 4 + ICONST_1 + IADD + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L14 + LINENUMBER 18 L14 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 5 + ICONST_1 + IADD + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L15 + LINENUMBER 19 L15 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LLOAD 6 + LCONST_1 + LADD + INVOKEVIRTUAL java/io/PrintStream.println (J)V + L16 + LINENUMBER 20 L16 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + DLOAD 8 + DCONST_1 + DADD + INVOKEVIRTUAL java/io/PrintStream.println (D)V + L17 + LINENUMBER 21 L17 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + FLOAD 10 + FCONST_1 + FADD + INVOKEVIRTUAL java/io/PrintStream.println (F)V + L18 + LINENUMBER 23 L18 + RETURN + L19 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L19 0 + LOCALVARIABLE varBoolean Z L1 L19 1 + LOCALVARIABLE varByte B L2 L19 2 + LOCALVARIABLE varChar C L3 L19 3 + LOCALVARIABLE varShort S L4 L19 4 + LOCALVARIABLE varInt I L5 L19 5 + LOCALVARIABLE varLong J L6 L19 6 + LOCALVARIABLE varDouble D L7 L19 8 + LOCALVARIABLE varFloat F L8 L19 10 + MAXSTACK = 5 + MAXLOCALS = 11 + } + ``` + + +#### ReferenceType +- ClassType +- ArrayType +- NullType + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public target.exercise1.DemoClass getObject(target.exercise1.DemoClass) + { + target.exercise1.DemoClass obj, this; + this := @this: target.exercise1.DemoClass; + obj := @parameter0: target.exercise1.DemoClass; + return obj; + } + + public void compute(boolean) + { + int[] b; + java.io.PrintStream $stack5, $stack6; + boolean check; + target.exercise1.DemoClass this; + int i; + null_type r0; + java.lang.NullPointerException soot0; + this := @this: target.exercise1.DemoClass; + check := @parameter0: boolean; + b = newarray (int)[5]; + i = 0; + + label1: + if i >= 5 goto label3; + if check == 0 goto label2; + r0 = (null_type) i; + soot0 = new java.lang.NullPointerException; + specialinvoke soot0.(java.lang.String)> + ("This statement would have triggered an Exception: a[i#1] = r0"); + throw soot0; + + label2: + b[i] = i; + i = i + 1; + goto label1; + + label3: + $stack5 = ; + virtualinvoke $stack5.(b); + $stack6 = ; + virtualinvoke $stack6.(null); + return; + } + } + /* + The JimpleLocal b is of ArrayType, + and JimpleLocal r0 is of NullType. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + + public DemoClass getObject(DemoClass obj){ + return obj; + } + + public void compute(boolean check){ + int a[] = null; + int b[] = new int[5]; + for (int i = 0; i < 5; i++) { + if(check){ + a[i] = i; + } + b[i] = i; + } + System.out.println(b); + System.out.println(a); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public getObject(Ltarget/exercise1/DemoClass;)Ltarget/exercise1/DemoClass; + L0 + LINENUMBER 6 L0 + ALOAD 1 + ARETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + LOCALVARIABLE obj Ltarget/exercise1/DemoClass; L0 L1 1 + MAXSTACK = 1 + MAXLOCALS = 2 + + // access flags 0x1 + public compute(Z)V + L0 + LINENUMBER 10 L0 + ACONST_NULL + ASTORE 2 + L1 + LINENUMBER 11 L1 + ICONST_5 + NEWARRAY T_INT + ASTORE 3 + L2 + LINENUMBER 12 L2 + ICONST_0 + ISTORE 4 + L3 + FRAME APPEND [[I [I I] + ILOAD 4 + ICONST_5 + IF_ICMPGE L4 + L5 + LINENUMBER 13 L5 + ILOAD 1 + IFEQ L6 + L7 + LINENUMBER 14 L7 + ALOAD 2 + ILOAD 4 + ILOAD 4 + IASTORE + L6 + LINENUMBER 16 L6 + FRAME SAME + ALOAD 3 + ILOAD 4 + ILOAD 4 + IASTORE + L8 + LINENUMBER 12 L8 + IINC 4 1 + GOTO L3 + L4 + LINENUMBER 18 L4 + FRAME CHOP 1 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ALOAD 3 + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V + L9 + LINENUMBER 19 L9 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ALOAD 2 + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V + L10 + LINENUMBER 20 L10 + RETURN + L11 + LOCALVARIABLE i I L3 L4 4 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L11 0 + LOCALVARIABLE check Z L0 L11 1 + LOCALVARIABLE a [I L1 L11 2 + LOCALVARIABLE b [I L2 L11 3 + MAXSTACK = 3 + MAXLOCALS = 5 + } + ``` + + +#### VoidType +Only used as a possible return type of a method. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void voidMethod() + { + java.io.PrintStream $stack1; + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + $stack1 = ; + virtualinvoke $stack1.("In voidMethod()."); + return; + } + } + /* + For the SootMethod - , + returnType is instance of VoidType. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public void voidMethod(){ + System.out.println("In voidMethod()."); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public voidMethod()V + L0 + LINENUMBER 5 L0 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "In voidMethod()." + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L1 + LINENUMBER 6 L1 + RETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + MAXSTACK = 2 + MAXLOCALS = 1 + } + ``` + diff --git a/docs/jimple-values.md b/docs/jimple-values.md new file mode 100644 index 00000000000..fa49fd97c8f --- /dev/null +++ b/docs/jimple-values.md @@ -0,0 +1,178 @@ +# Jimple Values + +### Immediate +An Immediate has a [**given**]{as in constant or immutable} Type and consists of a Local ("a Variable", "Something that contains a Value") or a Constant ("Something that is a Value"). + +#### Local +```jimple +i0 +``` +A Local is a variable and its scope is inside its method i.e. no referencing from outside a method. +Values can be assigned to Locals via JIdentityStmt or JAssignStmt. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void compute() + { + java.io.PrintStream $stack2, $stack3; + target.exercise1.DemoClass this; + int local#2; + + this := @this: target.exercise1.DemoClass; + $stack2 = ; + virtualinvoke $stack2.(1); + + local#2 = this.; + $stack3 = ; + virtualinvoke $stack3.(local#2); + return; + } + } + /* + $stack2, this, $stack3, local#2 are all JimpleLocal. + + "this := @this: target.exercise1.DemoClass" is JIdentityStmt + + "$stack2 = ", + "local#2 = this.", + "$stack3 = " + are JAssignStmt + + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + + private int global; + + public void compute(){ + int local; + local = 1; + System.out.println(local); + local = this.global; + System.out.println(local); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x2 + private I global + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public compute()V + L0 + LINENUMBER 9 L0 + ICONST_1 + ISTORE 1 + L1 + LINENUMBER 10 L1 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 1 + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L2 + LINENUMBER 11 L2 + ALOAD 0 + GETFIELD target/exercise1/DemoClass.global : I + ISTORE 1 + L3 + LINENUMBER 12 L3 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 1 + INVOKEVIRTUAL java/io/PrintStream.println (I)V + L4 + LINENUMBER 14 L4 + RETURN + L5 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0 + LOCALVARIABLE local I L1 L5 1 + MAXSTACK = 2 + MAXLOCALS = 2 + } + ``` + + + +#### Constant +represents a value itself. don't confuse it with a variable/Local which has a immutable (i.e. final) attribute. + +There exists a constant entity for every Type - that way all value types can have a representation. + + +### Expr +An expression is a language construct that returns a value. E.g. a binary operation such as addition. + + +### Ref +#### JArrayRef +```jimple +$arr[1] +``` +referencing a position inside an array. + +#### JFieldRef (JStaticFieldRef & JInstanceFieldRef) +```jimple + +// or +r1. +``` +referencing a Field via its FieldSignature and if necessary (i.e. with JInstanceFieldRef) the corresponding Local instance that points to the object instance. + +#### IdentityRef +The IdentityRef makes those implicit special value assignments explicit. + +##### JThisRef +```jimple +@this: package.fruit.Banana +``` +represents the this pointer of the current class. + +##### JCaughtExceptionRef +```jimple +@caughtexception +``` +represents the value of the thrown exception (caught by this exceptionhandler). + +##### JParameterRef +```jimple +i0 := @parameter0 +i1 := @parameter1 +``` +represents a parameter of a method, identified by its index. + diff --git a/docs/jimple.md b/docs/jimple.md index 007cd9baff8..a0ffe406f2e 100644 --- a/docs/jimple.md +++ b/docs/jimple.md @@ -55,7 +55,7 @@ It might help to visualize how the Jimple version of a Java code looks like. Hav } ``` -=== "Byte Code" +=== "Bytecode" ``` // class version 52.0 (52) @@ -103,9 +103,147 @@ Three-Address-Code which means there are no nested expressions. (nested expressions can be modeled via Locals that store intermediate calculation results.) +### Signatures and ClassTypes +Signatures are used to identify Classes,Methods or Fields uniquely/globally. +Sidenote: Locals, do not have a signature, since they are referenced within method boundaries. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + + specialinvoke this.()>(); + this. = 3.14; + return; + } + + public void demoMethod() + { + java.io.PrintStream $stack3, $stack5; + java.lang.StringBuilder $stack4, $stack6, $stack7; + java.lang.String $stack8; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + $stack3 = ; + + virtualinvoke $stack3.("pi : 3.14"); + $stack5 = ; + $stack4 = new java.lang.StringBuilder; + + specialinvoke $stack4.()>(); + $stack6 = virtualinvoke $stack4. + ("pi : "); + $stack7 = virtualinvoke $stack6.(3.1415); + $stack8 = virtualinvoke $stack7.(); + + virtualinvoke $stack5.($stack8); + return; + } + } + /* + For JInstanceFieldRef "this." + signature is + Similarly, we have other signatures like + ()>, + + and so on. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + private final double pi = 3.14; + + public void demoMethod(){ + double localPi = 3.1415; + System.out.println("pi : " + pi); + System.out.println("pi : " + localPi); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x12 + private final D pi = 3.14 + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + L1 + LINENUMBER 4 L1 + ALOAD 0 + LDC 3.14 + PUTFIELD target/exercise1/DemoClass.pi : D + RETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + MAXSTACK = 3 + MAXLOCALS = 1 + + // access flags 0x1 + public demoMethod()V + L0 + LINENUMBER 6 L0 + LDC 3.1415 + DSTORE 1 + L1 + LINENUMBER 7 L1 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "pi : 3.14" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L2 + LINENUMBER 8 L2 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + NEW java/lang/StringBuilder + DUP + INVOKESPECIAL java/lang/StringBuilder. ()V + LDC "pi : " + INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;) + Ljava/lang/StringBuilder; + DLOAD 1 + INVOKEVIRTUAL java/lang/StringBuilder.append (D)Ljava/lang/StringBuilder; + INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L3 + LINENUMBER 9 L3 + RETURN + L4 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0 + LOCALVARIABLE localPi D L1 L4 1 + MAXSTACK = 4 + MAXLOCALS = 3 + } + ``` + ### Class (or Interface) A class consists of Fields and Methods. -It is referenced by its ClassType. +It is referenced by its ClassType. === "Jimple" @@ -130,7 +268,7 @@ It is referenced by its ClassType. public class DemoClass {} ``` -=== "Byte Code" +=== "Bytecode" ``` // class version 52.0 (52) @@ -156,7 +294,7 @@ It is referenced by its ClassType. ### Field A Field is a piece of memory which can store a value that is accessible according to its visibility modifier. -It is referenced by its FieldSignature. +It is referenced by its FieldSignature. === "Jimple" @@ -187,7 +325,7 @@ It is referenced by its FieldSignature. } ``` -=== "Byte Code" +=== "Bytecode" ``` // class version 52.0 (52) @@ -219,9 +357,9 @@ It is referenced by its FieldSignature. ``` -### Method and the Body +### Method and its Body The interesting part is a method. A method is a "piece of code" that can be executed. -It is referenced by its MethodSignature and contains a [**StmtGraph**]{a control flow graph} that models the sequence of single instructions/statements (Stmts). +It is referenced by its MethodSignature and contains a [**StmtGraph**]{a control flow graph} that models the sequence of single instructions/statements (Stmts). === "Jimple" @@ -273,7 +411,7 @@ It is referenced by its MethodSignature and contains a [**StmtGraph**]{a control } ``` -=== "Byte Code" +=== "Bytecode" ``` // class version 52.0 (52) @@ -318,9 +456,8 @@ It is referenced by its MethodSignature and contains a [**StmtGraph**]{a control ``` -### Signatures -Signatures are required for identifying or referencing things across a method, such as Classes, Interfaces, Methods or Fields. -Locals, on the other hand, do not need signatures, since they are referenced within method boundaries. +### Traps +A Trap is a mechanism to model exceptional flow. === "Jimple" @@ -331,48 +468,48 @@ Locals, on the other hand, do not need signatures, since they are referenced wit { target.exercise1.DemoClass this; this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - this. = 3.14; return; } - public void demoMethod() + public void divideExample(int, int) { - java.io.PrintStream $stack3, $stack5; - java.lang.StringBuilder $stack4, $stack6, $stack7; - java.lang.String $stack8; + int x, y, $stack4; + java.io.PrintStream $stack5, $stack7; + java.lang.Exception $stack6; target.exercise1.DemoClass this; this := @this: target.exercise1.DemoClass; - $stack3 = ; + x := @parameter0: int; + y := @parameter1: int; - virtualinvoke $stack3.("pi : 3.14"); - $stack5 = ; - $stack4 = new java.lang.StringBuilder; + label1: + $stack5 = ; + $stack4 = x / y; + virtualinvoke $stack5.($stack4); - specialinvoke $stack4.()>(); - $stack6 = virtualinvoke $stack4. - ("pi : "); - $stack7 = virtualinvoke $stack6.(3.1415); - $stack8 = virtualinvoke $stack7.(); + label2: + goto label4; - virtualinvoke $stack5.($stack8); - return; + label3: + $stack6 := @caughtexception; + $stack7 = ; + virtualinvoke $stack7.("Exception caught"); + + label4: + return; + + catch java.lang.Exception from label1 to label2 with label3; } } /* - For JInstanceFieldRef "this." - signature is - Similarly, we have other signatures like - ()>, - - and so on. + By calling getTraps() method, we can get the Traip chain. + For the above jimple code, we have the below trap: + Trap : + begin : $stack5 = + end : goto [?= return] + handler: $stack6 := @caughtexception */ ``` @@ -382,17 +519,17 @@ Locals, on the other hand, do not need signatures, since they are referenced wit package target.exercise1; public class DemoClass { - private final double pi = 3.14; - - public void demoMethod(){ - double localPi = 3.1415; - System.out.println("pi : " + pi); - System.out.println("pi : " + localPi); + public void divideExample(int x, int y){ + try { + System.out.println(x / y); + }catch (Exception e){ + System.out.println("Exception caught"); + } } } ``` -=== "Byte Code" +=== "Bytecode" ``` // class version 52.0 (52) @@ -401,172 +538,35 @@ Locals, on the other hand, do not need signatures, since they are referenced wit // compiled from: DemoClass.java - // access flags 0x12 - private final D pi = 3.14 - - // access flags 0x1 + // access flags 0x1 public ()V L0 LINENUMBER 3 L0 ALOAD 0 INVOKESPECIAL java/lang/Object. ()V - L1 - LINENUMBER 4 L1 - ALOAD 0 - LDC 3.14 - PUTFIELD target/exercise1/DemoClass.pi : D RETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - MAXSTACK = 3 - MAXLOCALS = 1 + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 // access flags 0x1 - public demoMethod()V + public divideExample(II)V + TRYCATCHBLOCK L0 L1 L2 java/lang/Exception L0 - LINENUMBER 6 L0 - LDC 3.1415 - DSTORE 1 + LINENUMBER 6 L0 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + ILOAD 1 + ILOAD 2 + IDIV + INVOKEVIRTUAL java/io/PrintStream.println (I)V L1 - LINENUMBER 7 L1 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "pi : 3.14" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + LINENUMBER 9 L1 + GOTO L3 L2 - LINENUMBER 8 L2 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - NEW java/lang/StringBuilder - DUP - INVOKESPECIAL java/lang/StringBuilder. ()V - LDC "pi : " - INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;) - Ljava/lang/StringBuilder; - DLOAD 1 - INVOKEVIRTUAL java/lang/StringBuilder.append (D)Ljava/lang/StringBuilder; - INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L3 - LINENUMBER 9 L3 - RETURN - L4 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0 - LOCALVARIABLE localPi D L1 L4 1 - MAXSTACK = 4 - MAXLOCALS = 3 - } - ``` - -### Trap -A Trap is a mechanism to model exceptional flow. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void divideExample(int, int) - { - int x, y, $stack4; - java.io.PrintStream $stack5, $stack7; - java.lang.Exception $stack6; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - y := @parameter1: int; - - label1: - $stack5 = ; - $stack4 = x / y; - virtualinvoke $stack5.($stack4); - - label2: - goto label4; - - label3: - $stack6 := @caughtexception; - $stack7 = ; - virtualinvoke $stack7.("Exception caught"); - - label4: - return; - - catch java.lang.Exception from label1 to label2 with label3; - } - } - /* - By calling getTraps() method, we can get the Traip chain. - For the above jimple code, we have the below trap: - Trap : - begin : $stack5 = - end : goto [?= return] - handler: $stack6 := @caughtexception - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void divideExample(int x, int y){ - try { - System.out.println(x / y); - }catch (Exception e){ - System.out.println("Exception caught"); - } - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public divideExample(II)V - TRYCATCHBLOCK L0 L1 L2 java/lang/Exception - L0 - LINENUMBER 6 L0 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 1 - ILOAD 2 - IDIV - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L1 - LINENUMBER 9 L1 - GOTO L3 - L2 - LINENUMBER 7 L2 - FRAME SAME1 java/lang/Exception - ASTORE 3 + LINENUMBER 7 L2 + FRAME SAME1 java/lang/Exception + ASTORE 3 L4 LINENUMBER 8 L4 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; @@ -578,1885 +578,10 @@ A Trap is a mechanism to model exceptional flow. RETURN L5 LOCALVARIABLE e Ljava/lang/Exception; L4 L3 3 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0 + LOCALVARIABLE this Land Ttarget/exercise1/DemoClass; L0 L5 0 LOCALVARIABLE x I L0 L5 1 LOCALVARIABLE y I L0 L5 2 MAXSTACK = 3 MAXLOCALS = 4 } ``` - -### Stmt -The main piece of Jimple is a Statement (Stmt). [**Stmts**]{formerly known as Units} represent that can be executed by the JVM. - - -#### Branching Statements -A BranchingStmt's job is to model the flow between Stmts. - - -##### JGotoStmt -for unconditional flow. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - public static void sampleMethod() - { - int i; - i = 0; - - label1: - if i >= 5 goto label3; - if i != 3 goto label2; - goto label3; - - label2: - i = i + 1; - goto label1; - - label3: - return; - } - } - /* - Here for statements "goto label3;" and "goto label1;", - we have two instances of JGotoStmt : - "goto[?=return]" and "goto[?=(branch)]". - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public static void sampleMethod(){ - label1: - for (int i = 0; i < 5; i++){ - if(i == 3){ - break label1; - } - } - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x9 - public static sampleMethod()V - L0 - LINENUMBER 6 L0 - ICONST_0 - ISTORE 0 - L1 - FRAME APPEND [I] - ILOAD 0 - ICONST_5 - IF_ICMPGE L2 - L3 - LINENUMBER 7 L3 - ILOAD 0 - ICONST_3 - IF_ICMPNE L4 - L5 - LINENUMBER 8 L5 - GOTO L2 - L4 - LINENUMBER 6 L4 - FRAME SAME - IINC 0 1 - GOTO L1 - L2 - LINENUMBER 11 L2 - FRAME CHOP 1 - RETURN - LOCALVARIABLE i I L1 L2 0 - MAXSTACK = 2 - MAXLOCALS = 1 - } - ``` - -##### JIfStmt -for conditional flow depending on boolean Expression (AbstractConditionExpr) so they have two successor Stmt's. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public static void sampleMethod(int) - { - int x, $stack1; - java.io.PrintStream $stack2, $stack3; - - x := @parameter0: int; - - $stack1 = x % 2; - if $stack1 != 0 goto label1; - - $stack3 = ; - virtualinvoke $stack3.("Even"); - goto label2; - - label1: - $stack2 = ; - virtualinvoke $stack2.("Odd"); - - label2: - return; - } - } - /* - For statement "if $stack1 != 0 goto label1;", - we have an instance of JIfStmt : - "if $stack1 != 0 goto $stack2 - = ". - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public static void sampleMethod(int x){ - if(x % 2 == 0){ - System.out.println("Even"); - }else{ - System.out.println("Odd"); - } - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x9 - public static sampleMethod(I)V - L0 - LINENUMBER 5 L0 - ILOAD 0 - ICONST_2 - IREM - IFNE L1 - L2 - LINENUMBER 6 L2 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Even" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - GOTO L3 - L1 - LINENUMBER 8 L1 - FRAME SAME - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Odd" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L3 - LINENUMBER 10 L3 - FRAME SAME - RETURN - L4 - LOCALVARIABLE x I L0 L4 0 - MAXSTACK = 2 - MAXLOCALS = 1 - } - ``` - -##### JSwitchStmt -for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's. - -All other Stmts are not manipulating the flow, which means they have a single successor Stmt as long as they are not exiting the flow inside a method. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void switchExample(int) - { - int x; - java.io.PrintStream $stack2, $stack3, $stack4; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - - lookupswitch(x) - { - case 1: goto label1; - case 2: goto label2; - default: goto label3; - }; - - label1: - $stack3 = ; - virtualinvoke $stack3.("Input 1"); - goto label4; - - label2: - $stack2 = ; - virtualinvoke $stack2.("Input 2"); - goto label4; - - label3: - $stack4 = ; - virtualinvoke $stack4.("Input more than 2"); - - label4: - return; - } - } - /* - Here for below statement: - lookupswitch(x) - { - case 1: goto label1; - case 2: goto label2; - default: goto label3; - }; - - we have an instance of JLookupSwitchStmt : - lookupswitch(x) - { - case 1: goto $stack3 - = ; - case 2: goto $stack2 - = ; - default: goto $stack4 - = ; - } - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void switchExample(int x){ - switch (x){ - case 1: - System.out.println("Input 1"); - break; - - case 2: - System.out.println("Input 2"); - break; - - default: - System.out.println("Input more than 2"); - break; - - } - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public switchExample(I)V - L0 - LINENUMBER 5 L0 - ILOAD 1 - LOOKUPSWITCH - 1: L1 - 2: L2 - default: L3 - L1 - LINENUMBER 7 L1 - FRAME SAME - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Input 1" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L4 - LINENUMBER 8 L4 - GOTO L5 - L2 - LINENUMBER 11 L2 - FRAME SAME - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Input 2" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L6 - LINENUMBER 12 L6 - GOTO L5 - L3 - LINENUMBER 15 L3 - FRAME SAME - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Input more than 2" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L5 - LINENUMBER 19 L5 - FRAME SAME - RETURN - L7 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L7 0 - LOCALVARIABLE x I L0 L7 1 - MAXSTACK = 2 - MAXLOCALS = 2 - } - ``` - - -##### JReturnStmt & JReturnVoidStmt -They end the execution/flow inside the current method and return (a value) to its caller. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public int increment(int) - { - int x, $stack2; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - - $stack2 = x + 1; - return $stack2; - } - - public void print() - { - java.io.PrintStream $stack1; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - $stack1 = ; - virtualinvoke $stack1.("Inside method print"); - return; - } - } - /* - "return $stack2" is JReturnStmt. - "return" is JReturnVoidStmt. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public int increment(int x){ - return x + 1; - } - public void print(){ - System.out.println("Inside method print"); - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public increment(I)I - L0 - LINENUMBER 5 L0 - ILOAD 1 - ICONST_1 - IADD - IRETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - LOCALVARIABLE x I L0 L1 1 - MAXSTACK = 2 - MAXLOCALS = 2 - - // access flags 0x1 - public print()V - L0 - LINENUMBER 8 L0 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Inside method print" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L1 - LINENUMBER 9 L1 - RETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - MAXSTACK = 2 - MAXLOCALS = 1 - } - ``` - - -##### JThrowStmt -Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler. - - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void divideExample(int, int) - { - int y, x, $stack6; - java.lang.StringBuilder $stack3, $stack5, $stack7; - java.io.PrintStream $stack4; - java.lang.String $stack8; - java.lang.RuntimeException $stack9; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - y := @parameter1: int; - - if y != 0 goto label1; - - $stack9 = new java.lang.RuntimeException; - specialinvoke $stack9.(java.lang.String)>("Divide by zero error"); - throw $stack9; - - label1: - $stack4 = ; - $stack3 = new java.lang.StringBuilder; - specialinvoke $stack3.()>(); - - $stack5 = virtualinvoke $stack3.("Divide result : "); - $stack6 = x / y; - $stack7 = virtualinvoke $stack5.($stack6); - $stack8 = virtualinvoke $stack7.(); - - virtualinvoke $stack4.($stack8); - return; - } - } - /* - "throw $stack9" is JThrowStmt. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void divideExample(int x, int y){ - if(y == 0){ - throw new RuntimeException("Divide by zero error"); - } - System.out.println("Divide result : " + x / y); - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public divideExample(II)V - L0 - LINENUMBER 5 L0 - ILOAD 2 - IFNE L1 - L2 - LINENUMBER 6 L2 - NEW java/lang/RuntimeException - DUP - LDC "Divide by zero error" - INVOKESPECIAL java/lang/RuntimeException. - (Ljava/lang/String;)V - ATHROW - L1 - LINENUMBER 8 L1 - FRAME SAME - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - NEW java/lang/StringBuilder - DUP - INVOKESPECIAL java/lang/StringBuilder. ()V - LDC "Divide result : " - INVOKEVIRTUAL java/lang/StringBuilder.append - (Ljava/lang/String;)Ljava/lang/StringBuilder; - ILOAD 1 - ILOAD 2 - IDIV - INVOKEVIRTUAL java/lang/StringBuilder.append - (I)Ljava/lang/StringBuilder; - INVOKEVIRTUAL java/lang/StringBuilder.toString - ()Ljava/lang/String; - INVOKEVIRTUAL java/io/PrintStream.println - (Ljava/lang/String;)V - L3 - LINENUMBER 9 L3 - RETURN - L4 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0 - LOCALVARIABLE x I L0 L4 1 - LOCALVARIABLE y I L0 L4 2 - MAXSTACK = 4 - MAXLOCALS = 3 - } - ``` - - -##### JInvokeStmt -transfers the control flow to another method until the called method returns. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void print(int) - { - target.exercise1.DemoClass this; - int x, a; - java.io.PrintStream $stack4, $stack6; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - - a = virtualinvoke this.(x); - $stack4 = ; - virtualinvoke $stack4.(a); - - a = virtualinvoke this.(a); - $stack6 = ; - virtualinvoke $stack6.(a); - - return; - } - - public int increment(int) - { - int x, $stack2; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - - $stack2 = x + 1; - return $stack2; - } - } - /* - "specialinvoke this.()>()", - "virtualinvoke this.(x)", - "virtualinvoke this.(a)" - are JInvokeStmts. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void print(int x){ - int a = increment(x); - System.out.println(a); - a = increment(a); - System.out.println(a); - } - public int increment(int x){ - return x + 1; - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public print(I)V - L0 - LINENUMBER 5 L0 - ALOAD 0 - ILOAD 1 - INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I - ISTORE 2 - L1 - LINENUMBER 6 L1 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 2 - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L2 - LINENUMBER 7 L2 - ALOAD 0 - ILOAD 2 - INVOKEVIRTUAL target/exercise1/DemoClass.increment (I)I - ISTORE 2 - L3 - LINENUMBER 8 L3 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 2 - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L4 - LINENUMBER 9 L4 - RETURN - L5 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0 - LOCALVARIABLE x I L0 L5 1 - LOCALVARIABLE a I L1 L5 2 - MAXSTACK = 2 - MAXLOCALS = 3 - - // access flags 0x1 - public increment(I)I - L0 - LINENUMBER 11 L0 - ILOAD 1 - ICONST_1 - IADD - IRETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - LOCALVARIABLE x I L0 L1 1 - MAXSTACK = 2 - MAXLOCALS = 2 - } - ``` - - -##### JAssignStmt -assigns a Value from the right hand-side to the left hand-side. -Left hand-side of an assignment can be a Local referencing a variable (i.e. a Local) or a FieldRef referencing a Field. -Right hand-side of an assignment can be an expression (Expr), a Local, a FieldRef or a Constant. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - this. = 0; - return; - } - - public int updateCounter() - { - target.exercise1.DemoClass this; - int $stack1, $stack2, $stack3; - - this := @this: target.exercise1.DemoClass; - - $stack1 = this.; - $stack2 = $stack1 + 1; - this. = $stack2; - $stack3 = this.; - - return $stack3; - } - } - /* - "this. = 0", - "$stack1 = this.", - "$stack2 = $stack1 + 1" - "this. = $stack2" - "$stack3 = this." - are JAssignStmts. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - private int counter = 0; - public int updateCounter(){ - counter = counter + 1; - return counter; - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x2 - private I counter - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - L1 - LINENUMBER 4 L1 - ALOAD 0 - ICONST_0 - PUTFIELD target/exercise1/DemoClass.counter : I - RETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - MAXSTACK = 2 - MAXLOCALS = 1 - - // access flags 0x1 - public updateCounter()I - L0 - LINENUMBER 6 L0 - ALOAD 0 - ALOAD 0 - GETFIELD target/exercise1/DemoClass.counter : I - ICONST_1 - IADD - PUTFIELD target/exercise1/DemoClass.counter : I - L1 - LINENUMBER 7 L1 - ALOAD 0 - GETFIELD target/exercise1/DemoClass.counter : I - IRETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - MAXSTACK = 3 - MAXLOCALS = 1 - } - ``` - - -##### JIdentityStmt -is semantically like the JAssignStmt and handles assignments of IdentityRef's to make implicit assignments explicit into the StmtGraph. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void DemoClass(int) - { - target.exercise1.DemoClass this; - int counter; - - this := @this: target.exercise1.DemoClass; - counter := @parameter0: int; - this. = counter; - return; - } - } - /* - "this := @this: target.exercise1.DemoClass" and - "counter := @parameter0: int" are JIdentityStmts - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - private int counter; - public void DemoClass(int counter){ - this.counter = counter; - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x2 - private I counter - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public DemoClass(I)V - L0 - LINENUMBER 6 L0 - ALOAD 0 - ILOAD 1 - PUTFIELD target/exercise1/DemoClass.counter : I - L1 - LINENUMBER 7 L1 - RETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - LOCALVARIABLE counter I L0 L2 1 - MAXSTACK = 2 - MAXLOCALS = 2 - } - ``` - - -#####JEnterMonitorStmt & JExitMonitorStmt -marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - this. = 0; - return; - } - - public int updateCounter() - { - target.exercise1.DemoClass this; - int $stack4, $stack5, $stack7; - java.lang.Throwable $stack8; - - this := @this: target.exercise1.DemoClass; - - entermonitor this; - - label1: - $stack4 = this.; - $stack5 = $stack4 + 1; - this. = $stack5; - - exitmonitor this; - - label2: - goto label5; - - label3: - $stack8 := @caughtexception; - - exitmonitor this; - - label4: - throw $stack8; - - label5: - $stack7 = this.; - return $stack7; - - catch java.lang.Throwable from label1 to label2 with label3; - catch java.lang.Throwable from label3 to label4 with label3; - } - } - /* - "entermonitor this" is JEnterMonitorStmt. - "exitmonitor this" is JExitMonitorStmt. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - private int counter = 0; - public int updateCounter(){ - synchronized (this) { - counter = counter + 1; - } - return counter; - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x2 - private I counter - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - L1 - LINENUMBER 4 L1 - ALOAD 0 - ICONST_0 - PUTFIELD target/exercise1/DemoClass.counter : I - RETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - MAXSTACK = 2 - MAXLOCALS = 1 - - // access flags 0x1 - public updateCounter()I - TRYCATCHBLOCK L0 L1 L2 null - TRYCATCHBLOCK L2 L3 L2 null - L4 - LINENUMBER 6 L4 - ALOAD 0 - DUP - ASTORE 1 - MONITORENTER - L0 - LINENUMBER 7 L0 - ALOAD 0 - ALOAD 0 - GETFIELD target/exercise1/DemoClass.counter : I - ICONST_1 - IADD - PUTFIELD target/exercise1/DemoClass.counter : I - L5 - LINENUMBER 8 L5 - ALOAD 1 - MONITOREXIT - L1 - GOTO L6 - L2 - FRAME FULL [target/exercise1/DemoClass java/lang/Object] - [java/lang/Throwable] - ASTORE 2 - ALOAD 1 - MONITOREXIT - L3 - ALOAD 2 - ATHROW - L6 - LINENUMBER 9 L6 - FRAME CHOP 1 - ALOAD 0 - GETFIELD target/exercise1/DemoClass.counter : I - IRETURN - L7 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L4 L7 0 - MAXSTACK = 3 - MAXLOCALS = 3 - } - ``` - - -##### JRetStmt -##### JBreakpointStmt -models a Breakpoint set by a Debugger (usually not relevant for static analyses) - - -### Immediate -An Immediate has a [**given**]{as in constant or immutable} Type and consists of a Local ("a Variable", "Something that contains a Value") or a Constant ("Something that is a Value"). - - -### Type -VoidType - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void voidMethod() - { - java.io.PrintStream $stack1; - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - $stack1 = ; - virtualinvoke $stack1.("In voidMethod()."); - return; - } - } - /* - For the SootMethod - , - returnType is instance of VoidType. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void voidMethod(){ - System.out.println("In voidMethod()."); - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public voidMethod()V - L0 - LINENUMBER 5 L0 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "In voidMethod()." - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L1 - LINENUMBER 6 L1 - RETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - MAXSTACK = 2 - MAXLOCALS = 1 - } - ``` - - -#### PrimaryType -BooleanType, ByteType, CharType, ShortType, IntType, LongType, DoubleType, FloatType - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - - public void display() - { - java.io.PrintStream $stack11, $stack13, $stack15, - $stack17, $stack19, $stack21, $stack23, $stack25; - int $stack12, $stack14, $stack16, $stack18; - long $stack20; - double $stack22; - float $stack24; - target.exercise1.DemoClass this; - boolean $stack26; - - this := @this: target.exercise1.DemoClass; - - $stack11 = ; - - goto label1; - - label1: - $stack26 = 0; - virtualinvoke $stack11.($stack26); - - $stack13 = ; - $stack12 = 127 - 1; - virtualinvoke $stack13.($stack12); - - $stack15 = ; - $stack14 = 97 + 1; - virtualinvoke $stack15.($stack14); - - $stack17 = ; - $stack16 = 1123 + 1; - virtualinvoke $stack17.($stack16); - - $stack19 = ; - $stack18 = 123456 + 1; - virtualinvoke $stack19.($stack18); - - $stack21 = ; - $stack20 = 10L + 1L; - virtualinvoke $stack21.($stack20); - - $stack23 = ; - $stack22 = 10.1 + 1.0; - virtualinvoke $stack23.($stack22); - - $stack25 = ; - $stack24 = 10.1F + 1.0F; - virtualinvoke $stack25.($stack24); - - return; - } - } - /* - The JimpleLocal $stack12, $stack14, $stack16, $stack18 are of IntType. - Similarly, $stack20 is of LongType, $stack22 is of DoubleType and so on. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void display(){ - boolean varBoolean = true; - byte varByte = 127; - char varChar = 'a'; - short varShort = 1123; - int varInt = 123456; - long varLong = 10L; - double varDouble = 10.10; - float varFloat = 10.10f; - - System.out.println(!varBoolean); - System.out.println(varByte-1); - System.out.println(varChar+1); - System.out.println(varShort+1); - System.out.println(varInt+1); - System.out.println(varLong+1); - System.out.println(varDouble+1); - System.out.println(varFloat+1); - - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public display()V - L0 - LINENUMBER 5 L0 - ICONST_1 - ISTORE 1 - L1 - LINENUMBER 6 L1 - BIPUSH 127 - ISTORE 2 - L2 - LINENUMBER 7 L2 - BIPUSH 97 - ISTORE 3 - L3 - LINENUMBER 8 L3 - SIPUSH 1123 - ISTORE 4 - L4 - LINENUMBER 9 L4 - LDC 123456 - ISTORE 5 - L5 - LINENUMBER 10 L5 - LDC 10 - LSTORE 6 - L6 - LINENUMBER 11 L6 - LDC 10.1 - DSTORE 8 - L7 - LINENUMBER 12 L7 - LDC 10.1 - FSTORE 10 - L8 - LINENUMBER 14 L8 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 1 - IFNE L9 - ICONST_1 - GOTO L10 - L9 - FRAME FULL [target/exercise1/DemoClass I I I I I J D F] - [java/io/PrintStream] - ICONST_0 - L10 - FRAME FULL [target/exercise1/DemoClass I I I I I J D F] - [java/io/PrintStream I] - INVOKEVIRTUAL java/io/PrintStream.println (Z)V - L11 - LINENUMBER 15 L11 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 2 - ICONST_1 - ISUB - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L12 - LINENUMBER 16 L12 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 3 - ICONST_1 - IADD - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L13 - LINENUMBER 17 L13 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 4 - ICONST_1 - IADD - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L14 - LINENUMBER 18 L14 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 5 - ICONST_1 - IADD - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L15 - LINENUMBER 19 L15 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LLOAD 6 - LCONST_1 - LADD - INVOKEVIRTUAL java/io/PrintStream.println (J)V - L16 - LINENUMBER 20 L16 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - DLOAD 8 - DCONST_1 - DADD - INVOKEVIRTUAL java/io/PrintStream.println (D)V - L17 - LINENUMBER 21 L17 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - FLOAD 10 - FCONST_1 - FADD - INVOKEVIRTUAL java/io/PrintStream.println (F)V - L18 - LINENUMBER 23 L18 - RETURN - L19 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L19 0 - LOCALVARIABLE varBoolean Z L1 L19 1 - LOCALVARIABLE varByte B L2 L19 2 - LOCALVARIABLE varChar C L3 L19 3 - LOCALVARIABLE varShort S L4 L19 4 - LOCALVARIABLE varInt I L5 L19 5 - LOCALVARIABLE varLong J L6 L19 6 - LOCALVARIABLE varDouble D L7 L19 8 - LOCALVARIABLE varFloat F L8 L19 10 - MAXSTACK = 5 - MAXLOCALS = 11 - } - ``` - - -#### ReferenceType -ClassType, -ArrayType -NullType - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public target.exercise1.DemoClass getObject(target.exercise1.DemoClass) - { - target.exercise1.DemoClass obj, this; - this := @this: target.exercise1.DemoClass; - obj := @parameter0: target.exercise1.DemoClass; - return obj; - } - - public void compute(boolean) - { - int[] b; - java.io.PrintStream $stack5, $stack6; - boolean check; - target.exercise1.DemoClass this; - int i; - null_type r0; - java.lang.NullPointerException soot0; - this := @this: target.exercise1.DemoClass; - check := @parameter0: boolean; - b = newarray (int)[5]; - i = 0; - - label1: - if i >= 5 goto label3; - if check == 0 goto label2; - r0 = (null_type) i; - soot0 = new java.lang.NullPointerException; - specialinvoke soot0.(java.lang.String)> - ("This statement would have triggered an Exception: a[i#1] = r0"); - throw soot0; - - label2: - b[i] = i; - i = i + 1; - goto label1; - - label3: - $stack5 = ; - virtualinvoke $stack5.(b); - $stack6 = ; - virtualinvoke $stack6.(null); - return; - } - } - /* - The JimpleLocal b is of ArrayType, - and JimpleLocal r0 is of NullType. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - - public DemoClass getObject(DemoClass obj){ - return obj; - } - - public void compute(boolean check){ - int a[] = null; - int b[] = new int[5]; - for (int i = 0; i < 5; i++) { - if(check){ - a[i] = i; - } - b[i] = i; - } - System.out.println(b); - System.out.println(a); - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public getObject(Ltarget/exercise1/DemoClass;)Ltarget/exercise1/DemoClass; - L0 - LINENUMBER 6 L0 - ALOAD 1 - ARETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - LOCALVARIABLE obj Ltarget/exercise1/DemoClass; L0 L1 1 - MAXSTACK = 1 - MAXLOCALS = 2 - - // access flags 0x1 - public compute(Z)V - L0 - LINENUMBER 10 L0 - ACONST_NULL - ASTORE 2 - L1 - LINENUMBER 11 L1 - ICONST_5 - NEWARRAY T_INT - ASTORE 3 - L2 - LINENUMBER 12 L2 - ICONST_0 - ISTORE 4 - L3 - FRAME APPEND [[I [I I] - ILOAD 4 - ICONST_5 - IF_ICMPGE L4 - L5 - LINENUMBER 13 L5 - ILOAD 1 - IFEQ L6 - L7 - LINENUMBER 14 L7 - ALOAD 2 - ILOAD 4 - ILOAD 4 - IASTORE - L6 - LINENUMBER 16 L6 - FRAME SAME - ALOAD 3 - ILOAD 4 - ILOAD 4 - IASTORE - L8 - LINENUMBER 12 L8 - IINC 4 1 - GOTO L3 - L4 - LINENUMBER 18 L4 - FRAME CHOP 1 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ALOAD 3 - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V - L9 - LINENUMBER 19 L9 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ALOAD 2 - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V - L10 - LINENUMBER 20 L10 - RETURN - L11 - LOCALVARIABLE i I L3 L4 4 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L11 0 - LOCALVARIABLE check Z L0 L11 1 - LOCALVARIABLE a [I L1 L11 2 - LOCALVARIABLE b [I L2 L11 3 - MAXSTACK = 3 - MAXLOCALS = 5 - } - ``` - - -#### Local -```jimple -i0 -``` -A Local is a variable and its scope is inside its method i.e. no referencing from outside a method. -Values can be assigned to Locals via JIdentityStmt or JAssignStmt. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void compute() - { - java.io.PrintStream $stack2, $stack3; - target.exercise1.DemoClass this; - int local#2; - - this := @this: target.exercise1.DemoClass; - $stack2 = ; - virtualinvoke $stack2.(1); - - local#2 = this.; - $stack3 = ; - virtualinvoke $stack3.(local#2); - return; - } - } - /* - $stack2, this, $stack3, local#2 are all JimpleLocal. - - "this := @this: target.exercise1.DemoClass" is JIdentityStmt - - "$stack2 = ", - "local#2 = this.", - "$stack3 = " - are JAssignStmt - - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - - private int global; - - public void compute(){ - int local; - local = 1; - System.out.println(local); - local = this.global; - System.out.println(local); - } - } - ``` - -=== "Byte Code" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x2 - private I global - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public compute()V - L0 - LINENUMBER 9 L0 - ICONST_1 - ISTORE 1 - L1 - LINENUMBER 10 L1 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 1 - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L2 - LINENUMBER 11 L2 - ALOAD 0 - GETFIELD target/exercise1/DemoClass.global : I - ISTORE 1 - L3 - LINENUMBER 12 L3 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 1 - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L4 - LINENUMBER 14 L4 - RETURN - L5 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L5 0 - LOCALVARIABLE local I L1 L5 1 - MAXSTACK = 2 - MAXLOCALS = 2 - } - ``` - - - -#### Constant -represents a value itself. don't confuse it with a variable/Local which has a immutable (i.e. final) attribute. - -There exists a constant entity for every Type - that way all value types can have a representation. - - -### Expr -An expression is a language construct that returns a value. E.g. a binary operation such as addition. - - -### Ref -#### JArrayRef -```jimple -$arr[1] -``` -referencing a position inside an array. - -#### JFieldRef (JStaticFieldRef & JInstanceFieldRef) -```jimple - -// or -r1. -``` -referencing a Field via its FieldSignature and if necessary (i.e. with JInstanceFieldRef) the corresponding Local instance that points to the object instance. - -#### IdentityRef -The IdentityRef makes those implicit special value assignments explicit. - -##### JThisRef -```jimple -@this: package.fruit.Banana -``` -represents the this pointer of the current class. - -##### JCaughtExceptionRef -```jimple -@caughtexception -``` -represents the value of the thrown exception (caught by this exceptionhandler). - -##### JParameterRef -```jimple -i0 := @parameter0 -i1 := @parameter1 -``` -represents a parameter of a method, identified by its index. - diff --git a/mkdocs.yml b/mkdocs.yml index b2a88399d17..8045d12d043 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,6 +14,11 @@ nav: - Basics: - Jimple IR: jimple.md + - Jimple Body: jimple-body.md + - Jimple Statements: jimple-stmts.md + - Jimple Types: jimple-types.md + - Jimple Values: jimple-values.md + - BodyInterceptors: bodyinterceptors.md - Callgraph Construction: call-graph-construction.md - Shipped Analyses: advanced-topics.md From 610c531e386851d9254d2d37f2be6c881b52bc0b Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Mon, 17 Jun 2024 14:57:33 +0200 Subject: [PATCH 117/145] update doc --- docs/css/customizetheme.css | 15 ++-- docs/jimple-stmts.md | 2 +- docs/overrides/partials/header.html | 106 -------------------------- docs/overrides/partials/outdated.html | 8 ++ 4 files changed, 18 insertions(+), 113 deletions(-) delete mode 100644 docs/overrides/partials/header.html create mode 100644 docs/overrides/partials/outdated.html diff --git a/docs/css/customizetheme.css b/docs/css/customizetheme.css index e3652403932..56d694ec604 100644 --- a/docs/css/customizetheme.css +++ b/docs/css/customizetheme.css @@ -83,6 +83,8 @@ .md-typeset code { padding:0.2em; margin:0.2em; + font-size: 10pt; + background-color: #FCFCFC; } .tabbed-set.tabbed-alternate{ @@ -115,19 +117,20 @@ html .md-footer-meta.md-typeset a{ } .highlighttable{ + border-left:1px solid rgba(255,140,0, 0.1); border-bottom:1px solid rgba(255,140,0, 0.1); border-right:1px solid rgba(255,140,0, 0.1); } .highlighttable .linenos{ - background-color:#EEE; - border-color: rgba(255,140,0, 0.1); -} - -.md-typeset code { - background-color: #FFF; + background-color: #FCFCFC;; + font-size: 10pt; } #developedBy{ font-size: 11pt; +} + +.tooltip{ + color: rgba(255,140,0, 0.8); } \ No newline at end of file diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md index 0fb058a1665..ea068877bc2 100644 --- a/docs/jimple-stmts.md +++ b/docs/jimple-stmts.md @@ -1,5 +1,5 @@ # Jimple Stmt ("Statements") -The main piece of Jimple is a Statement (Stmt). [**Stmts**]{formerly known as Units} represent that can be executed by the JVM. +[Stmts]{formerly known as Units} represent instructions of the JVM. ## Branching Statements diff --git a/docs/overrides/partials/header.html b/docs/overrides/partials/header.html deleted file mode 100644 index cf74cabac7e..00000000000 --- a/docs/overrides/partials/header.html +++ /dev/null @@ -1,106 +0,0 @@ - - - -{% set class = "md-header" %} -{% if "navigation.tabs.sticky" in features %} -{% set class = class ~ " md-header--shadow md-header--lifted" %} -{% elif "navigation.tabs" not in features %} -{% set class = class ~ " md-header--shadow" %} -{% endif %} - - -
- - - - {% if "navigation.tabs.sticky" in features %} - {% if "navigation.tabs" in features %} - {% include "partials/tabs.html" %} - {% endif %} - {% endif %} -
diff --git a/docs/overrides/partials/outdated.html b/docs/overrides/partials/outdated.html new file mode 100644 index 00000000000..36a4967d7de --- /dev/null +++ b/docs/overrides/partials/outdated.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% block outdated %} +You're not viewing the latest version. + + Click here to go to latest version. + +{% endblock %} \ No newline at end of file From f2f8fcb220ed85ecd0480f7e457037c49d31a867 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Mon, 17 Jun 2024 15:52:59 +0200 Subject: [PATCH 118/145] improve readability --- docs/css/customizetheme.css | 17 +++++++++-- docs/getting-started.md | 59 ++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/docs/css/customizetheme.css b/docs/css/customizetheme.css index 56d694ec604..273eec6f066 100644 --- a/docs/css/customizetheme.css +++ b/docs/css/customizetheme.css @@ -116,10 +116,21 @@ html .md-footer-meta.md-typeset a{ border:none; } + +.admonition .highlighttable{ + margin: 0; + border: none; +} +.md-typeset .admonition .highlighttable, .md-typeset details .highlighttable{ + +} + .highlighttable{ - border-left:1px solid rgba(255,140,0, 0.1); - border-bottom:1px solid rgba(255,140,0, 0.1); - border-right:1px solid rgba(255,140,0, 0.1); + border:1px solid rgba(255,140,0, 0.1); +} + +.admonition .highlighttable, .tabbed-set .highlighttable{ + border-top:none; } .highlighttable .linenos{ diff --git a/docs/getting-started.md b/docs/getting-started.md index acb45e7ece4..8dd6b44160b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,20 +1,10 @@ -# General Usage of SootUp -This page walks you through the core data structures, as well as shows how to get started with SootUp. - -## The core datastructures +# First Steps with SootUp Before you get started with the SootUp library, it helps to learn about the following core data structures: -- `AnalysisInputLocation`: points to the target code to be analyzed. - -!!! info "Soot Equivalent" - - It corresponds to the `cp` option, which specifies the classpath for Soot to find classes to be analyzed. - -- `View`: presents the code/classes under analysis. +- [`AnalysisInputLocation`]{It corresponds to the `cp` option, which specifies the classpath for Soot to find classes to be analyzed.} + : points to the target code to be analyzed. -!!! info "Soot Equivalent" - - It corresponds to the `Scene` class, but it is not a singleton. So it is possible to instantiate multiple views simultaneously. +- [`View`]{Corresponds to the `Scene` class, but it is not a singleton. So it is possible to instantiate multiple views simultaneously.}: presents the code/classes under analysis. - `SootClass`: represents a class loaded into the `View`. @@ -56,7 +46,7 @@ If you have access to the source code, it is also possible to create a view for If you have a [Jimple](../jimple) file, you can create a view for analyzing jimple code directly. Following example shows how to create a view for analyzing jimple code. -!!! example "Create a project to analyze jimple code" +!!! example "Create a view to analyze jimple code" ~~~java Path pathToJimple = Paths.get("path2Jimple"); @@ -132,17 +122,25 @@ Once we have a `ClassType` that identifies the `HelloWorld` class, we can use it Like the classes, methods also have an identifier which we call `MethodSignature`. For instance, we can define the method signature for identifying the `main` method of the `HelloWorld` class as follows: !!! example "Defining a MethodSignature" - - ```java - MethodSignature methodSignature = - view - .getIdentifierFactory() - .getMethodSignature( - "main", // method name - classType, - "void", // return type - Collections.singletonList("java.lang.String[]")); // args - ``` + === "Pure" + ```java + MethodSignature methodSignature = + view + .getIdentifierFactory() + .getMethodSignature( + "main", // method name + classType, + "void", // return type + Collections.singletonList("java.lang.String[]")); // args + ``` + === "Parse from String" + ```java + MethodSignature methodSignature = + view + .getIdentifierFactory() + .parseMethodSignature( + ""); + ``` Once we have a `MethodSignature` that identifies the `main` method of the `HelloWorld` class, we can use it to retrieve the corresponding `SootMethod` object from the `view` as shown below: @@ -160,7 +158,8 @@ Alternatively, we can also retrieve a `SootMethod` from `SootClass` that contain !!! example "Retrieving a SootMethod from a SootClass" ```java - Optional opt = sootClass.getMethod(methodSignature.getSubSignature()); + MethodSubSignature mss = methodSignature.getSubSignature() + Optional opt = sootClass.getMethod(mss); if(opt.isPresent()){ JavaSootMethod method = opt.get(); @@ -174,11 +173,11 @@ Each `SootMethod` contains a Control-Flow Graph (CFG) which is represented via t !!! example "Retrieving the CFG of a SootMethod" ```java - sootMethod.getBody().getStmts(); + sootMethod.getBody().getStmtGraph(); ``` -!!! info "Access or Download all of the code used above" +!!! info "Access a complete example of the code used above" - [BasicSetup.java](https://github.com/secure-software-engineering/soot-reloaded/blob/develop/sootup.examples/src/test/java/sootup/examples/basicSetup/BasicSetup.java) + Download [BasicSetup.java](https://github.com/secure-software-engineering/soot-reloaded/blob/develop/sootup.examples/src/test/java/sootup/examples/basicSetup/BasicSetup.java) From 365160f2e911a8bf908d06acd39782646362875c Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Mon, 17 Jun 2024 16:47:44 +0200 Subject: [PATCH 119/145] fix ci --- .github/workflows/gh-pages.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 9aefa61be04..463ccc35a2b 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -64,8 +64,8 @@ jobs: git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" - # sanitive head_ref name - - run: echo "DOC_VERSION_NAME=$(echo ${{ github.head_ref }} | sed "s/[^([[:alnum:]_.-]/_/g"" )" >> $GITHUB_ENV + # sanitize head_ref name + - run: echo "DOC_VERSION_NAME=$(echo ${{ github.head_ref }} | sed "s/[^([[:alnum:]_.-]/_/g" )" >> $GITHUB_ENV # on push to develop branch - keep a doc around for develop to show the current state - name: deploy doc in subdirectory From c6e176b4615cf8e345cc77a89d7d7727e443db97 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 08:06:22 +0200 Subject: [PATCH 120/145] progress --- docs/css/customizetheme.css | 13 +- docs/jimple-stmts.md | 537 +++++++++--------- docs/jimple.md | 8 +- docs/tool_ux.md | 14 +- .../jimple/javabytecode/stmt/JRetStmt.java | 4 +- 5 files changed, 299 insertions(+), 277 deletions(-) diff --git a/docs/css/customizetheme.css b/docs/css/customizetheme.css index 273eec6f066..2ecd037a9a7 100644 --- a/docs/css/customizetheme.css +++ b/docs/css/customizetheme.css @@ -11,6 +11,10 @@ --md-accent-fg-color: rgba(255,140,0, 1); } +.md-typeset{ + font-size: 12pt; +} + .md-typeset a { color: rgba(255,140,0, 0.8); } @@ -46,6 +50,8 @@ } .md-typeset .admonition, .md-typeset details { border-color: rgba(255,140,0, 1); + box-shadow: none; + } .md-nav label.md-nav__title{ @@ -90,6 +96,7 @@ .tabbed-set.tabbed-alternate{ background: rgba(255,140,0, 0.1); color: rgba(255,140,0, 1); + margin-bottom: 3em; } .md-typeset .tabbed-labels>label>[href]:first-child{ @@ -116,7 +123,6 @@ html .md-footer-meta.md-typeset a{ border:none; } - .admonition .highlighttable{ margin: 0; border: none; @@ -127,6 +133,7 @@ html .md-footer-meta.md-typeset a{ .highlighttable{ border:1px solid rgba(255,140,0, 0.1); + border-top: 6px solid rgba(255,140,0, 0.1); } .admonition .highlighttable, .tabbed-set .highlighttable{ @@ -144,4 +151,8 @@ html .md-footer-meta.md-typeset a{ .tooltip{ color: rgba(255,140,0, 0.8); +} + +p{ + margin-bottom:1.5em; } \ No newline at end of file diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md index ea068877bc2..6066ae39f60 100644 --- a/docs/jimple-stmts.md +++ b/docs/jimple-stmts.md @@ -1,12 +1,16 @@ # Jimple Stmt ("Statements") [Stmts]{formerly known as Units} represent instructions of the JVM. +Stmts can be roughly grouped by the amount of successors (in the `StmtGraph` of a `Body` of a `Method`). +- A `FallsThroughStmt` has always one successor - it basically represents `program counter++`. +- A `BranchingStmt` can have one, two or even n successors. +- All others (neither FallsThrough nor BranchingStmt) have no successors and therefore end the execution of the current method. -## Branching Statements +## Branching Stmts A BranchingStmt's job is to model the jumps or conditional branching flow between Stmts. ##### JGotoStmt -for unconditional flow. +represents unconditional jumps to another Stmt. === "Jimple" @@ -118,8 +122,9 @@ for unconditional flow. ``` ##### JIfStmt -for conditional flow depending on boolean Expression (AbstractConditionExpr) so they have two successor Stmt's. -note: The JIfStmt is also a FallsthroughStmt if the branching condition is not met. +For conditional jumps depending on the result of the conditional expression `AbstractConditionExpr` which needs to have boolean result. +If the conditional expression is false, the next Stmt is the successor as the JIFStmt is also a `FallsthroughStmt`. +Therefore, the JIfStmt has two successor Stmt's. === "Jimple" @@ -237,8 +242,6 @@ note: The JIfStmt is also a FallsthroughStmt if the branching condition is not m ##### JSwitchStmt for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's. -All other Stmts are not manipulating the flow, which means they have a single successor Stmt as long as they are not exiting the flow inside a method. - === "Jimple" ```jimple @@ -402,264 +405,8 @@ All other Stmts are not manipulating the flow, which means they have a single su } ``` -## FallsThrough Statements -The execution of a FallsthroughStmt goes on with the following Stmt (when no exception was thrown). - -##### JReturnStmt & JReturnVoidStmt -They end the execution/flow inside the current method and return (a value) to its caller. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public int increment(int) - { - int x, $stack2; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - - $stack2 = x + 1; - return $stack2; - } - - public void print() - { - java.io.PrintStream $stack1; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - $stack1 = ; - virtualinvoke $stack1.("Inside method print"); - return; - } - } - /* - "return $stack2" is JReturnStmt. - "return" is JReturnVoidStmt. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public int increment(int x){ - return x + 1; - } - public void print(){ - System.out.println("Inside method print"); - } - } - ``` - -=== "Bytecode" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public increment(I)I - L0 - LINENUMBER 5 L0 - ILOAD 1 - ICONST_1 - IADD - IRETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - LOCALVARIABLE x I L0 L1 1 - MAXSTACK = 2 - MAXLOCALS = 2 - - // access flags 0x1 - public print()V - L0 - LINENUMBER 8 L0 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Inside method print" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L1 - LINENUMBER 9 L1 - RETURN - L2 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 - MAXSTACK = 2 - MAXLOCALS = 1 - } - ``` - - -##### JThrowStmt -Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler. - - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void divideExample(int, int) - { - int y, x, $stack6; - java.lang.StringBuilder $stack3, $stack5, $stack7; - java.io.PrintStream $stack4; - java.lang.String $stack8; - java.lang.RuntimeException $stack9; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - y := @parameter1: int; - - if y != 0 goto label1; - - $stack9 = new java.lang.RuntimeException; - specialinvoke $stack9.(java.lang.String)>("Divide by zero error"); - throw $stack9; - - label1: - $stack4 = ; - $stack3 = new java.lang.StringBuilder; - specialinvoke $stack3.()>(); - - $stack5 = virtualinvoke $stack3.("Divide result : "); - $stack6 = x / y; - $stack7 = virtualinvoke $stack5.($stack6); - $stack8 = virtualinvoke $stack7.(); - - virtualinvoke $stack4.($stack8); - return; - } - } - /* - "throw $stack9" is JThrowStmt. - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void divideExample(int x, int y){ - if(y == 0){ - throw new RuntimeException("Divide by zero error"); - } - System.out.println("Divide result : " + x / y); - } - } - ``` - -=== "Bytecode" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public divideExample(II)V - L0 - LINENUMBER 5 L0 - ILOAD 2 - IFNE L1 - L2 - LINENUMBER 6 L2 - NEW java/lang/RuntimeException - DUP - LDC "Divide by zero error" - INVOKESPECIAL java/lang/RuntimeException. - (Ljava/lang/String;)V - ATHROW - L1 - LINENUMBER 8 L1 - FRAME SAME - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - NEW java/lang/StringBuilder - DUP - INVOKESPECIAL java/lang/StringBuilder. ()V - LDC "Divide result : " - INVOKEVIRTUAL java/lang/StringBuilder.append - (Ljava/lang/String;)Ljava/lang/StringBuilder; - ILOAD 1 - ILOAD 2 - IDIV - INVOKEVIRTUAL java/lang/StringBuilder.append - (I)Ljava/lang/StringBuilder; - INVOKEVIRTUAL java/lang/StringBuilder.toString - ()Ljava/lang/String; - INVOKEVIRTUAL java/io/PrintStream.println - (Ljava/lang/String;)V - L3 - LINENUMBER 9 L3 - RETURN - L4 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0 - LOCALVARIABLE x I L0 L4 1 - LOCALVARIABLE y I L0 L4 2 - MAXSTACK = 4 - MAXLOCALS = 3 - } - ``` - +## FallsThrough Stmts +The execution of a FallsthroughStmt goes on with the following Stmt (if no exception was thrown). ##### JInvokeStmt transfers the control flow to another method until the called method returns. @@ -1160,7 +907,265 @@ marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt. } ``` - ##### JRetStmt +// TODO: [java 1.6 spec](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.ret) + ##### JBreakpointStmt -models a Breakpoint set by a Debugger (usually not relevant for static analyses) +models a Breakpoint set by a Debugger. Therefore, not really relevant for static analyses but useful for code generation. + +## Other Stmts + +##### JReturnStmt & JReturnVoidStmt +They end the execution/flow inside the current method and return (a value) to its caller. + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public int increment(int) + { + int x, $stack2; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + + $stack2 = x + 1; + return $stack2; + } + + public void print() + { + java.io.PrintStream $stack1; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + $stack1 = ; + virtualinvoke $stack1.("Inside method print"); + return; + } + } + /* + "return $stack2" is JReturnStmt. + "return" is JReturnVoidStmt. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public int increment(int x){ + return x + 1; + } + public void print(){ + System.out.println("Inside method print"); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public increment(I)I + L0 + LINENUMBER 5 L0 + ILOAD 1 + ICONST_1 + IADD + IRETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + LOCALVARIABLE x I L0 L1 1 + MAXSTACK = 2 + MAXLOCALS = 2 + + // access flags 0x1 + public print()V + L0 + LINENUMBER 8 L0 + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + LDC "Inside method print" + INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V + L1 + LINENUMBER 9 L1 + RETURN + L2 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L2 0 + MAXSTACK = 2 + MAXLOCALS = 1 + } + ``` + + +##### JThrowStmt +Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler. + + +=== "Jimple" + + ```jimple + public class target.exercise1.DemoClass extends java.lang.Object + { + public void () + { + target.exercise1.DemoClass this; + this := @this: target.exercise1.DemoClass; + specialinvoke this.()>(); + return; + } + + public void divideExample(int, int) + { + int y, x, $stack6; + java.lang.StringBuilder $stack3, $stack5, $stack7; + java.io.PrintStream $stack4; + java.lang.String $stack8; + java.lang.RuntimeException $stack9; + target.exercise1.DemoClass this; + + this := @this: target.exercise1.DemoClass; + x := @parameter0: int; + y := @parameter1: int; + + if y != 0 goto label1; + + $stack9 = new java.lang.RuntimeException; + specialinvoke $stack9.(java.lang.String)>("Divide by zero error"); + throw $stack9; + + label1: + $stack4 = ; + $stack3 = new java.lang.StringBuilder; + specialinvoke $stack3.()>(); + + $stack5 = virtualinvoke $stack3.("Divide result : "); + $stack6 = x / y; + $stack7 = virtualinvoke $stack5.($stack6); + $stack8 = virtualinvoke $stack7.(); + + virtualinvoke $stack4.($stack8); + return; + } + } + /* + "throw $stack9" is JThrowStmt. + */ + ``` + +=== "Java" + + ```java + package target.exercise1; + + public class DemoClass { + public void divideExample(int x, int y){ + if(y == 0){ + throw new RuntimeException("Divide by zero error"); + } + System.out.println("Divide result : " + x / y); + } + } + ``` + +=== "Bytecode" + + ``` + // class version 52.0 (52) + // access flags 0x21 + public class target/exercise1/DemoClass { + + // compiled from: DemoClass.java + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x1 + public divideExample(II)V + L0 + LINENUMBER 5 L0 + ILOAD 2 + IFNE L1 + L2 + LINENUMBER 6 L2 + NEW java/lang/RuntimeException + DUP + LDC "Divide by zero error" + INVOKESPECIAL java/lang/RuntimeException. + (Ljava/lang/String;)V + ATHROW + L1 + LINENUMBER 8 L1 + FRAME SAME + GETSTATIC java/lang/System.out : Ljava/io/PrintStream; + NEW java/lang/StringBuilder + DUP + INVOKESPECIAL java/lang/StringBuilder. ()V + LDC "Divide result : " + INVOKEVIRTUAL java/lang/StringBuilder.append + (Ljava/lang/String;)Ljava/lang/StringBuilder; + ILOAD 1 + ILOAD 2 + IDIV + INVOKEVIRTUAL java/lang/StringBuilder.append + (I)Ljava/lang/StringBuilder; + INVOKEVIRTUAL java/lang/StringBuilder.toString + ()Ljava/lang/String; + INVOKEVIRTUAL java/io/PrintStream.println + (Ljava/lang/String;)V + L3 + LINENUMBER 9 L3 + RETURN + L4 + LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L4 0 + LOCALVARIABLE x I L0 L4 1 + LOCALVARIABLE y I L0 L4 2 + MAXSTACK = 4 + MAXLOCALS = 3 + } + ``` diff --git a/docs/jimple.md b/docs/jimple.md index a0ffe406f2e..9e90f7c7dad 100644 --- a/docs/jimple.md +++ b/docs/jimple.md @@ -10,7 +10,7 @@ For this purpose Jimple was designed as a representation of JVM bytecode which i To learn more about jimple, refer to the [thesis](https://courses.cs.washington.edu/courses/cse501/01wi/project/sable-thesis.pdf) by Raja Vallee-Rai. -It might help to visualize how the Jimple version of a Java code looks like. Have a look at the following example on the `HelloWorld` class. +Lets have a look at the following Jimple code representing Java code of a `HelloWorld` class. === "Jimple" @@ -95,6 +95,12 @@ It might help to visualize how the Jimple version of a Java code looks like. Hav } ``` +The Java Sourcecode is the easiest representation - So why all the fuzz and just use that? +Sometimes we have no access to the sourcecode but have a binary with the bytecode. +For most People reading bytecode is not that intuitive. So SootUp generates Jimple from the bytecode. +Jimple is very verbose, but makes everything explicit, that the JVM does implicitly and transforms the stack-machine strategy by a register-machine strategy i.e. Variable (`Local`) handling . + + ## Jimple Grammar Structure Jimple mimics the JVMs class file structure. Therefore it is object oriented. diff --git a/docs/tool_ux.md b/docs/tool_ux.md index 8528055cd3d..730979ba32e 100644 --- a/docs/tool_ux.md +++ b/docs/tool_ux.md @@ -25,12 +25,12 @@ Dependencies: ### Java Code -```java - -class SootUpConfiguration{ - // TODO incorporate -} - -``` + ```java + + class SootUpConfiguration{ + // TODO incorporate + } + + ``` We are happy if you steal the following code to create a tool where the setup is just simple. diff --git a/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java b/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java index d2e1fcc36a7..d62b7a2f0fa 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java @@ -34,8 +34,8 @@ import sootup.core.util.printer.StmtPrinter; /** - * Represents the deprecated JVM ret statement - which is used in JSR Context - which - * is deprecated as well + * Represents the deprecated JVM ret statement (< java 1.6) - which is used in JSR Context - which + * is deprecated as well. */ public final class JRetStmt extends AbstractStmt implements FallsThroughStmt { From ad06e076f90325e4130a7bf7cd6694e5ba3ae77e Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 09:41:16 +0200 Subject: [PATCH 121/145] more doc --- docs/analysisinputlocations.md | 14 ++-- docs/css/customizetheme.css | 13 ++- docs/jimple-body.md | 12 +-- docs/jimple-stmts.md | 60 +++++++------- docs/jimple-types.md | 46 ++++++----- docs/jimple-values.md | 21 +++-- docs/jimple.md | 147 ++------------------------------- 7 files changed, 99 insertions(+), 214 deletions(-) diff --git a/docs/analysisinputlocations.md b/docs/analysisinputlocations.md index 520dc5d3890..f64da9983af 100644 --- a/docs/analysisinputlocations.md +++ b/docs/analysisinputlocations.md @@ -2,23 +2,23 @@ An AnalysisInputLocation tells SootUp what code input it should analyze. ### Java Runtime -- Java <9: DefaultRTJaAnalysisInputLocation current rt.jar (or point to any rt.jar as its just a usual .jar file) -- Java >8: JRTFilesystemAnalysisInputLocation +- Java <9: `DefaultRTJaAnalysisInputLocation` current rt.jar (or point to any rt.jar as its just a usual .jar file) +- Java >8: `JRTFilesystemAnalysisInputLocation` If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInput. ### Java Bytecode .class, .jar, .war -- JavaClassPathAnalysisInputLocation - its the equivalent of the classpath you would pass to the java executable i.e. point to root(s) of package(s). +- `JavaClassPathAnalysisInputLocation` - its the equivalent of the classpath you would pass to the java executable i.e. point to root(s) of package(s). ### Java Sourcecode .java -- OTFCompileAnalysisInputLocation - you can point directly to .java files or pass a String with Java sourcecode -- JavaSourcePathInputLocation - points to a directory that is the root source directory (containing the package directory structure) +- `OTFCompileAnalysisInputLocation` - you can point directly to .java files or pass a String with Java sourcecode, SootUp delegates to the `JavaCompiler` and transform the bytecode from the compiler to Jimple +- `JavaSourcePathInputLocation` [***experimental!***]{Has huge problems with exceptional flow!} - points to a directory that is the root source directory (containing the package directory structure). ### Jimple .jimple -- JimpleAnalysisInputLocation - needs a Path to a .jimple file or a directory. +- `JimpleAnalysisInputLocation` - needs a Path to a .jimple file or a directory. ### Android Bytecode .dex -- ApkAnalysisInputLocation - currenlty uses dex2jar internally - SootUp solution is WIP! +- `ApkAnalysisInputLocation` - currenlty uses dex2jar internally - SootUp solution is WIP! ### Java cli arguments to configure SootUp diff --git a/docs/css/customizetheme.css b/docs/css/customizetheme.css index 2ecd037a9a7..ac31584dcce 100644 --- a/docs/css/customizetheme.css +++ b/docs/css/customizetheme.css @@ -37,7 +37,7 @@ } .md-typeset .admonition, .md-typeset .admonition.info, .md-typeset .admonition.example, .md-typeset .admonition{ - border-color: rgba(255,140,0, 0.2); + border-color: rgba(255,140,0, 0.1); margin-bottom: 3em; } @@ -46,7 +46,8 @@ } .md-typeset .admonition>.admonition-title, .md-typeset .admonition>.admonition-title{ - background: rgba(255,140,0, 0.2); + background: rgba(255,140,0, 0.1); + color: rgba(255,140,0, 1); } .md-typeset .admonition, .md-typeset details { border-color: rgba(255,140,0, 1); @@ -82,6 +83,14 @@ padding-left: 2em; } +.md-sidebar.md-sidebar--secondary .md-nav__item a { + padding: 0; +} + +.md-sidebar.md-sidebar--secondary .md-nav__item .md-nav{ + padding-bottom: 1em; +} + .md-search__form{ background: #EEE; } diff --git a/docs/jimple-body.md b/docs/jimple-body.md index 10ae286516d..39ed9a06dd3 100644 --- a/docs/jimple-body.md +++ b/docs/jimple-body.md @@ -1,6 +1,6 @@ -# Jimple MethodBody -A Methodbody consists of the Modifiers and its StmtGraph - SootUps Control Flow Graph Structure. -The StmtGraph organizes the flow of [Stmts](jimple-stmts.md). +# Jimple Body +A SootMethod `Body` consists of the `Modifiers` and its `StmtGraph` - SootUps Control Flow Graph Structure. +The StmtGraph models the flow of [Stmts](jimple-stmts.md). ### Control Flow Graph - unexceptional flow -> like FallsThroughStmts and BranchingStmts for if,goto etc. @@ -11,10 +11,12 @@ Learn more about the types of [Stmts](jimple-stmts.md). ### Traps A Trap is a mechanism to model exceptional flow. +A Trap represents the try-catch (finally) construct and therefore defines the type of the caught exception, the try-catch range (from-to) and the actual code that handles the exception (handler). +In serialized(!) Jimple Labels are used to denote from,to and handler Stmts. === "Jimple" - ```jimple + ```jimple hl_lines="39" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -57,7 +59,7 @@ A Trap is a mechanism to model exceptional flow. } } /* - By calling getTraps() method, we can get the Trap. + By calling getTraps() method, we can get the Traip chain. For the above jimple code, we have the below trap: Trap : begin : $stack5 = diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md index 6066ae39f60..2a5f8a8cf22 100644 --- a/docs/jimple-stmts.md +++ b/docs/jimple-stmts.md @@ -1,5 +1,7 @@ # Jimple Stmt ("Statements") [Stmts]{formerly known as Units} represent instructions of the JVM. +Jimple is a 3-address form code so there are max 3 operands used in a ("manipulating") Stmt - i.e. this does not apply to invokes as this is just operand/parameter passing. + Stmts can be roughly grouped by the amount of successors (in the `StmtGraph` of a `Body` of a `Method`). - A `FallsThroughStmt` has always one successor - it basically represents `program counter++`. @@ -9,12 +11,12 @@ Stmts can be roughly grouped by the amount of successors (in the `StmtGraph` of ## Branching Stmts A BranchingStmt's job is to model the jumps or conditional branching flow between Stmts. -##### JGotoStmt +### JGotoStmt represents unconditional jumps to another Stmt. === "Jimple" - ```jimple + ```jimple hl_lines="18 22" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -121,14 +123,14 @@ represents unconditional jumps to another Stmt. } ``` -##### JIfStmt +### JIfStmt For conditional jumps depending on the result of the conditional expression `AbstractConditionExpr` which needs to have boolean result. If the conditional expression is false, the next Stmt is the successor as the JIFStmt is also a `FallsthroughStmt`. Therefore, the JIfStmt has two successor Stmt's. === "Jimple" - ```jimple + ```jimple hl_lines="19" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -239,12 +241,12 @@ Therefore, the JIfStmt has two successor Stmt's. } ``` -##### JSwitchStmt +### JSwitchStmt for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels+1 (for default) successor Stmt's. === "Jimple" - ```jimple + ```jimple hl_lines="20-25" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -408,12 +410,12 @@ for conditional flow that behaves like a switch-case. It has #numberOfCaseLabels ## FallsThrough Stmts The execution of a FallsthroughStmt goes on with the following Stmt (if no exception was thrown). -##### JInvokeStmt +### JInvokeStmt transfers the control flow to another method until the called method returns. === "Jimple" - ```jimple + ```jimple hl_lines="7 20 22 24 26" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -433,17 +435,13 @@ transfers the control flow to another method until the called method returns. this := @this: target.exercise1.DemoClass; x := @parameter0: int; - a = virtualinvoke this.(x); + a = virtualinvoke this.(x); $stack4 = ; - virtualinvoke $stack4.(a); + virtualinvoke $stack4.(a); - a = virtualinvoke this.(a); + a = virtualinvoke this.(a); $stack6 = ; - virtualinvoke $stack6.(a); + virtualinvoke $stack6.(a); return; } @@ -558,14 +556,14 @@ transfers the control flow to another method until the called method returns. ``` -##### JAssignStmt +### JAssignStmt assigns a Value from the right hand-side to the left hand-side. Left hand-side of an assignment can be a Local referencing a variable (i.e. a Local) or a FieldRef referencing a Field. Right hand-side of an assignment can be an expression (Expr), a Local, a FieldRef or a Constant. === "Jimple" - ```jimple + ```jimple hl_lines="8 19-22" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -668,12 +666,16 @@ Right hand-side of an assignment can be an expression (Expr), a Local, a FieldRe ``` -##### JIdentityStmt -is semantically like the JAssignStmt and handles assignments of IdentityRef's to make implicit assignments explicit into the StmtGraph. +### JIdentityStmt +is similar to the `JAssignStmt` and but handles assignments of `IdentityRef`s to make implicit assignments explicit into the `StmtGraph`. + +- Assigns parameters to a `Local` via `JParameterRef` like `@parameter0: int` refering to the first argument of the method (which is of Type int in this case). +- Assigns exceptions to a `Local` via `JCaughtExceptionRef` like `@caughtexception: java.lang.NullpointerException` +- Assigns the `this` Variable to a `Local` via a `JThisRef` === "Jimple" - ```jimple + ```jimple hl_lines="16 17" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -757,12 +759,12 @@ is semantically like the JAssignStmt and handles assignments of IdentityRef's to ``` -#####JEnterMonitorStmt & JExitMonitorStmt +###JEnterMonitorStmt & JExitMonitorStmt marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt. === "Jimple" - ```jimple + ```jimple hl_lines="20 27 35" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -907,20 +909,20 @@ marks synchronized blocks of code from JEnterMonitorStmt to JExitMonitorStmt. } ``` -##### JRetStmt +### JRetStmt // TODO: [java 1.6 spec](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.ret) -##### JBreakpointStmt +### JBreakpointStmt models a Breakpoint set by a Debugger. Therefore, not really relevant for static analyses but useful for code generation. ## Other Stmts -##### JReturnStmt & JReturnVoidStmt +### JReturnStmt & JReturnVoidStmt They end the execution/flow inside the current method and return (a value) to its caller. === "Jimple" - ```jimple + ```jimple hl_lines="20 32" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -1029,13 +1031,13 @@ They end the execution/flow inside the current method and return (a value) to it ``` -##### JThrowStmt +### JThrowStmt Ends the execution inside the current Method if the thrown exception is not caught by a Trap, which redirects the execution to an exceptionhandler. === "Jimple" - ```jimple + ```jimple hl_lines="29" public class target.exercise1.DemoClass extends java.lang.Object { public void () diff --git a/docs/jimple-types.md b/docs/jimple-types.md index fc073396599..1cfcff8f327 100644 --- a/docs/jimple-types.md +++ b/docs/jimple-types.md @@ -1,18 +1,20 @@ -#Jimple Types - -#### PrimaryType -- BooleanType -- ByteType -- CharType -- ShortType -- IntType -- LongType -- DoubleType -- FloatType +# Jimple Types +represents primary types i.e. non-reference types and non-void + +### PrimaryType + +- `BooleanType` +- `ByteType` +- `CharType` +- `ShortType` +- `IntType` +- `LongType` +- `DoubleType` +- `FloatType` === "Jimple" - ```jimple + ```jimple hl_lines="14-21" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -257,14 +259,14 @@ ``` -#### ReferenceType -- ClassType -- ArrayType -- NullType +### ReferenceType +- `(Java)ClassType` - represents the type of a Class. +- `ArrayType` - represents an array. +- `NullType` - assignable to one of the other ReferenceTypes. === "Jimple" - ```jimple + ```jimple hl_lines="21 24 26" public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -323,8 +325,8 @@ } } /* - The JimpleLocal b is of ArrayType, - and JimpleLocal r0 is of NullType. + The Local b is of ArrayType, + and Local r0 is of NullType. */ ``` @@ -454,12 +456,12 @@ ``` -#### VoidType -Only used as a possible return type of a method. +### VoidType +Used as a possible return type of a method. === "Jimple" - ```jimple + ```jimple hl_lines="11" public class target.exercise1.DemoClass extends java.lang.Object { public void () diff --git a/docs/jimple-values.md b/docs/jimple-values.md index fa49fd97c8f..ef45d4ecec2 100644 --- a/docs/jimple-values.md +++ b/docs/jimple-values.md @@ -130,10 +130,9 @@ Values can be assigned to Locals via JIdentityStmt or JAssignStmt. #### Constant -represents a value itself. don't confuse it with a variable/Local which has a immutable (i.e. final) attribute. - -There exists a constant entity for every Type - that way all value types can have a representation. - +represents an actual value itself like `42` or `"This is a String"`. +Constants are usually assigned to `Local`s or `Ref`s. +There exists a constant entity for every [Primitive Type](jimple-types.md). ### Expr An expression is a language construct that returns a value. E.g. a binary operation such as addition. @@ -146,13 +145,13 @@ $arr[1] ``` referencing a position inside an array. -#### JFieldRef (JStaticFieldRef & JInstanceFieldRef) -```jimple - -// or -r1. -``` -referencing a Field via its FieldSignature and if necessary (i.e. with JInstanceFieldRef) the corresponding Local instance that points to the object instance. +#### JFieldRef +`JFieldRef`s are referencing a `SootField` via its FieldSignature + +- `JStaticFieldRef` like `#!jimple ` +- `JInstanceFieldRef` like `#!jimple r1.` + You can see the JInstanceFieldRef has the corresponding Local instance that points to the instance of the object which is holding the field. + #### IdentityRef The IdentityRef makes those implicit special value assignments explicit. diff --git a/docs/jimple.md b/docs/jimple.md index 9e90f7c7dad..8b86014413f 100644 --- a/docs/jimple.md +++ b/docs/jimple.md @@ -247,9 +247,9 @@ Sidenote: Locals, do not have a signature, since they are referenced within meth } ``` -### Class (or Interface) -A class consists of Fields and Methods. -It is referenced by its ClassType. +### SootClass +A `SootClass` consists of SootFields and SootMethods. +It is referenced by its global identifier the `ClassType` like `java.lang.String`. === "Jimple" @@ -298,9 +298,9 @@ It is referenced by its ClassType. ``` -### Field -A Field is a piece of memory which can store a value that is accessible according to its visibility modifier. -It is referenced by its FieldSignature. +### SootField +A SootField is a piece of memory which can store a value that is accessible according to its visibility modifier. +It is referenced by its FieldSignature like `#!jimple `. === "Jimple" @@ -363,9 +363,9 @@ It is referenced by its FieldSignature. ``` -### Method and its Body +### SootMethod and its Body The interesting part is a method. A method is a "piece of code" that can be executed. -It is referenced by its MethodSignature and contains a [**StmtGraph**]{a control flow graph} that models the sequence of single instructions/statements (Stmts). +It is referenced by its MethodSignature like `#!jimple `. === "Jimple" @@ -461,133 +461,4 @@ It is referenced by its MethodSignature and contains a [**StmtGraph**]{a control } ``` - -### Traps -A Trap is a mechanism to model exceptional flow. - -=== "Jimple" - - ```jimple - public class target.exercise1.DemoClass extends java.lang.Object - { - public void () - { - target.exercise1.DemoClass this; - this := @this: target.exercise1.DemoClass; - specialinvoke this.()>(); - return; - } - - public void divideExample(int, int) - { - int x, y, $stack4; - java.io.PrintStream $stack5, $stack7; - java.lang.Exception $stack6; - target.exercise1.DemoClass this; - - this := @this: target.exercise1.DemoClass; - x := @parameter0: int; - y := @parameter1: int; - - label1: - $stack5 = ; - $stack4 = x / y; - virtualinvoke $stack5.($stack4); - - label2: - goto label4; - - label3: - $stack6 := @caughtexception; - $stack7 = ; - virtualinvoke $stack7.("Exception caught"); - - label4: - return; - - catch java.lang.Exception from label1 to label2 with label3; - } - } - /* - By calling getTraps() method, we can get the Traip chain. - For the above jimple code, we have the below trap: - Trap : - begin : $stack5 = - end : goto [?= return] - handler: $stack6 := @caughtexception - */ - ``` - -=== "Java" - - ```java - package target.exercise1; - - public class DemoClass { - public void divideExample(int x, int y){ - try { - System.out.println(x / y); - }catch (Exception e){ - System.out.println("Exception caught"); - } - } - } - ``` - -=== "Bytecode" - - ``` - // class version 52.0 (52) - // access flags 0x21 - public class target/exercise1/DemoClass { - - // compiled from: DemoClass.java - - // access flags 0x1 - public ()V - L0 - LINENUMBER 3 L0 - ALOAD 0 - INVOKESPECIAL java/lang/Object. ()V - RETURN - L1 - LOCALVARIABLE this Ltarget/exercise1/DemoClass; L0 L1 0 - MAXSTACK = 1 - MAXLOCALS = 1 - - // access flags 0x1 - public divideExample(II)V - TRYCATCHBLOCK L0 L1 L2 java/lang/Exception - L0 - LINENUMBER 6 L0 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - ILOAD 1 - ILOAD 2 - IDIV - INVOKEVIRTUAL java/io/PrintStream.println (I)V - L1 - LINENUMBER 9 L1 - GOTO L3 - L2 - LINENUMBER 7 L2 - FRAME SAME1 java/lang/Exception - ASTORE 3 - L4 - LINENUMBER 8 L4 - GETSTATIC java/lang/System.out : Ljava/io/PrintStream; - LDC "Exception caught" - INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V - L3 - LINENUMBER 10 L3 - FRAME SAME - RETURN - L5 - LOCALVARIABLE e Ljava/lang/Exception; L4 L3 3 - LOCALVARIABLE this Land Ttarget/exercise1/DemoClass; L0 L5 0 - LOCALVARIABLE x I L0 L5 1 - LOCALVARIABLE y I L0 L5 2 - MAXSTACK = 3 - MAXLOCALS = 4 - } - ``` +More about the [Body](jimple-body.md) of the SootMethod. \ No newline at end of file From cc958adeaa2ac4d4462cd407d84def44ed1ef277 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 09:59:27 +0200 Subject: [PATCH 122/145] improve callgraph examples --- docs/call-graph-construction.md | 44 +++++++++++++++++++-------------- docs/jimple-stmts.md | 2 +- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/docs/call-graph-construction.md b/docs/call-graph-construction.md index 79d87e55622..e589b5736c9 100644 --- a/docs/call-graph-construction.md +++ b/docs/call-graph-construction.md @@ -43,23 +43,31 @@ Below, we show how to create a type hierarchy: ## Defining an Entry Method All the call graph construction algorithms require an entry method to start with. In java application, you usually define the main method. However, it is possible to define arbitrary entry methods depending on your needs. Below, we show how to define such an entry method: -=== "SootUp" +=== "SootUp (performant)" ```java - JavaClassType classTypeA = view.getIdentifierFactory().getClassType("A"); + JavaClassType classTypeA = view.getIdentifierFactory().getClassType("packageNameA.A"); MethodSignature entryMethodSignature = view.getIdentifierFactory() .getMethodSignature( classTypeA, - JavaIdentifierFactory.getInstance() - .getMethodSubSignature( - "calc", VoidType.getInstance(), Collections.singletonList(classTypeA))); + "calc", + VoidType.getInstance(), + Collections.singletonList(classTypeA) + ); ``` - + +=== "SootUp (alternative)" + + ```java + MethodSignature entryMethodSignature = view.getIdentifierFactory().parseMethodSignature(" System.out.println(entryMethodSignature + " may call " + tgt); ``` === "Soot" @@ -90,7 +97,7 @@ You can construct a call graph with CHA as follows: while (targets.hasNext()) { SootMethod tgt = (SootMethod)targets.next(); System.out.println(src + " may call " + tgt); - } + } ``` ## Rapid Type Analysis @@ -100,13 +107,12 @@ You can construct a call graph with RTA as follows: === "SootUp" ```java - CallGraphAlgorithm rta = - new RapidTypeAnalysisAlgorithm(view); + CallGraphAlgorithm rta = new RapidTypeAnalysisAlgorithm(view); - CallGraph cg = - rta.initialize(Collections.singletonList(entryMethodSignature)); + CallGraph cg = rta.initialize(Collections.singletonList(entryMethodSignature)); - System.out.println(cg); + cg.callsFrom(entryMethodSignature).stream() + .forEach(tgt -> System.out.println(entryMethodSignature + " may call " + tgt); ``` === "Soot" @@ -128,6 +134,8 @@ You can construct a call graph with RTA as follows: ``` ## Variable Type Analysis +(**WIP!**) + Variable Type Analysis (VTA) algorithm further refines the call graph that the RTA constructs. It refines RTA by considering only the assigned instantiations of the implementers of an interface, when resolving a method call on an interface. When considering assignments, we usually need to consider **pointer** (points-to) relationship. diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md index 2a5f8a8cf22..d739eeb01da 100644 --- a/docs/jimple-stmts.md +++ b/docs/jimple-stmts.md @@ -1,4 +1,4 @@ -# Jimple Stmt ("Statements") +# Jimple Stmt ("Statement") [Stmts]{formerly known as Units} represent instructions of the JVM. Jimple is a 3-address form code so there are max 3 operands used in a ("manipulating") Stmt - i.e. this does not apply to invokes as this is just operand/parameter passing. From 065d77eade513a7b93deeb6d443a70b6a73bf2b2 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 11:16:29 +0200 Subject: [PATCH 123/145] docs --- docs/analysisinputlocations.md | 2 +- docs/jimple-values.md | 5 +++-- docs/{advanced-topics.md => shipped-analyses.md} | 0 docs/{tool_ux.md => tool_setup.md} | 2 +- docs/write_analyses.md | 6 +++++- mkdocs.yml | 4 ++-- .../java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java | 4 ++-- 7 files changed, 14 insertions(+), 9 deletions(-) rename docs/{advanced-topics.md => shipped-analyses.md} (100%) rename docs/{tool_ux.md => tool_setup.md} (95%) diff --git a/docs/analysisinputlocations.md b/docs/analysisinputlocations.md index f64da9983af..9c9cb70a1c6 100644 --- a/docs/analysisinputlocations.md +++ b/docs/analysisinputlocations.md @@ -22,4 +22,4 @@ If you have errors like Java.lang.String, Java.lang.Object, ... you are most lik ### Java cli arguments to configure SootUp -We created a [Utility](tool_ux.md) that parses a String of java command line arguments and configures SootUp respectively. \ No newline at end of file +We created a [Utility](tool_setup) that parses a String of java command line arguments and configures SootUp respectively. \ No newline at end of file diff --git a/docs/jimple-values.md b/docs/jimple-values.md index ef45d4ecec2..3da17f8a88f 100644 --- a/docs/jimple-values.md +++ b/docs/jimple-values.md @@ -135,8 +135,9 @@ Constants are usually assigned to `Local`s or `Ref`s. There exists a constant entity for every [Primitive Type](jimple-types.md). ### Expr -An expression is a language construct that returns a value. E.g. a binary operation such as addition. - +An expression is a language construct that calculates an operation and returns a value. +E.g. a binary operation `AbstracBinopExpr` such as an addition `a + b`, an `AbstractInvokeExpr` such as `virtualinvoke $stack2.(1);` or an `UnaryExpr` such as `!valid`. +And a bunch more! ### Ref #### JArrayRef diff --git a/docs/advanced-topics.md b/docs/shipped-analyses.md similarity index 100% rename from docs/advanced-topics.md rename to docs/shipped-analyses.md diff --git a/docs/tool_ux.md b/docs/tool_setup.md similarity index 95% rename from docs/tool_ux.md rename to docs/tool_setup.md index 730979ba32e..c4d0f4d96cf 100644 --- a/docs/tool_ux.md +++ b/docs/tool_setup.md @@ -1,4 +1,4 @@ -# From Prototype to user friendly tool +# From Prototype to a user friendly tool `How was the parameter order again?` For a lot of cli tools we see an arbitrary order of cli parameters, different options for giving a working directory etc.. diff --git a/docs/write_analyses.md b/docs/write_analyses.md index 914b008d803..5604ea1e47c 100644 --- a/docs/write_analyses.md +++ b/docs/write_analyses.md @@ -25,6 +25,10 @@ Taint Analysis, TypeState Analysis, Linear Constant Propagation, ... ``` // TODO incorporate & guide through examples + +In the meantime please have a look into the test cases of the +analysis submodule to see example implementations of interprocedural +data-flow analysis via the IFDS or IDE Framework. + ``` -If you wish to implement an interprocedural data-flow analysis via the IFDS or IDE Framework please have a look at the test cases in the sootup.analysis submodule. diff --git a/mkdocs.yml b/mkdocs.yml index 8045d12d043..261fac16d31 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,7 +21,7 @@ nav: - BodyInterceptors: bodyinterceptors.md - Callgraph Construction: call-graph-construction.md - - Shipped Analyses: advanced-topics.md + - Shipped Analyses: shipped-analyses.md - How to..: - Write a Dataflow analysis: write_analyses.md @@ -30,7 +30,7 @@ nav: # - Modify a View: mutable_view.md # - Implement a BodyInterceptor: body_interceptor.md # - Implement an AnalysisTool: write_analysis_tool.md - - From Prototype to Tool: tool_ux.md + # - From Prototype to Tool: tool_setup.md - Misc: - Announcements: announce.md diff --git a/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java b/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java index d62b7a2f0fa..3a70f99745c 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/javabytecode/stmt/JRetStmt.java @@ -34,8 +34,8 @@ import sootup.core.util.printer.StmtPrinter; /** - * Represents the deprecated JVM ret statement (< java 1.6) - which is used in JSR Context - which - * is deprecated as well. + * Represents the deprecated JVM ret statement (< java 1.6) - which is used in JSR + * Context - which is deprecated as well. */ public final class JRetStmt extends AbstractStmt implements FallsThroughStmt { From 6b1ac22ba52ddbd53795580d884b5e8346a19111 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 11:53:56 +0200 Subject: [PATCH 124/145] add StmtVisitor doc --- docs/analysisinputlocations.md | 4 ++-- docs/jimple-stmts.md | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/docs/analysisinputlocations.md b/docs/analysisinputlocations.md index 9c9cb70a1c6..450b55139c2 100644 --- a/docs/analysisinputlocations.md +++ b/docs/analysisinputlocations.md @@ -2,8 +2,8 @@ An AnalysisInputLocation tells SootUp what code input it should analyze. ### Java Runtime -- Java <9: `DefaultRTJaAnalysisInputLocation` current rt.jar (or point to any rt.jar as its just a usual .jar file) -- Java >8: `JRTFilesystemAnalysisInputLocation` +- Java <=8: `DefaultRTJaAnalysisInputLocation` current rt.jar (or point to any rt.jar as its just a usual .jar file) +- Java >=9: `JRTFilesystemAnalysisInputLocation` If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInput. diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md index d739eeb01da..25b53cca1c6 100644 --- a/docs/jimple-stmts.md +++ b/docs/jimple-stmts.md @@ -1171,3 +1171,45 @@ Ends the execution inside the current Method if the thrown exception is not caug MAXLOCALS = 3 } ``` + +## Good to know +A lot of the SootUp APIs return the `Stmt` Interface. To determine and handle its subtypes you can make use of instanceof. +=== "Stmt If-Else forest" + ```java + + List stmts = ... ; + for( Stmt stms : stmts ){ + if(stmt instanceof JAssignStmt){ + // found a JAssignStmt + Value rhsOp = ((JAssignStmt) stmt).getRightOp(); + ... + }else if(stmt instanceof JInvokeStmt){ + // found a JInvokeStmt + JInvokeStmt ivkStmt = ((JInvokeStmt) stmt); + MethodSignature rhsOp = ivkStmt.getInvokeExpr().getMethodSignature(); + ... + } + } + + ``` + +But this could escalate to a huge if-else-tree - almost a forest. To mitigate such scenario you can implement a subclass of `AbstractStmtVisitor`. +Just subclass the methods to the respective Stmts you need to handle. +=== "StmtVisitor" + ```java + + List stmts = ...; + AbstractStmtVisitor visitor = new AbstractStmtVisitor() { + private int countAssignStmts = 0; + @Override + public void caseIfStmt(@Nonnull JAssignStmt stmt) { + countAssignStmts++; + } + }; + + for( Stmt stms : stmts ){ + stmt.accept(visitor); + } + + int amountOfAssignStmts = visitor.getResult(); + ``` \ No newline at end of file From 31d52bf208b53e131aa43049b89fbebc0d752756 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 15:17:41 +0200 Subject: [PATCH 125/145] add StmtGraph doc --- docs/{announce.md => announcement.md} | 15 ++-- ...hipped-analyses.md => builtin-analyses.md} | 0 ...ll-graph-construction.md => callgraphs.md} | 0 docs/css/customizetheme.css | 5 ++ docs/getting-started.md | 78 ++++++++++++++----- mkdocs.yml | 13 ++-- 6 files changed, 77 insertions(+), 34 deletions(-) rename docs/{announce.md => announcement.md} (81%) rename docs/{shipped-analyses.md => builtin-analyses.md} (100%) rename docs/{call-graph-construction.md => callgraphs.md} (100%) diff --git a/docs/announce.md b/docs/announcement.md similarity index 81% rename from docs/announce.md rename to docs/announcement.md index 76ecf8b2fe8..98c0ccaa89f 100644 --- a/docs/announce.md +++ b/docs/announcement.md @@ -12,17 +12,18 @@ SootUp is a library that can easily be included in other projects, leaving those Below is an overview of what’s new. -* Library by default, framework as an option -* Modular Architecture, no more singletons -* New source code frontend -* Immutable Jimple IR -* Greatly increased testability and test coverage +- Library by default, framework as an option +- Modular Architecture, no more singletons +- New source code frontend +- Immutable Jimple IR +- Greatly increased testability and test coverage ![Coverage](https://camo.githubusercontent.com/adc4ab244f7c0c2b2f3fec0a6e5d778421ddc0be7f89a608c16533c9a964766f/68747470733a2f2f636f6465636f762e696f2f67682f736f6f742d6f73732f536f6f7455702f6272616e63682f646576656c6f702f67726170682f62616467652e7376673f746f6b656e3d454c4137553749415744) SootUp is not a drop-in replacement for Soot! Due to its completely new architecture and API it is essentially an almost complete rewrite. For a while, Soot and SootUp will coexist, as many existing tools depend on Soot, yet our maintenance efforts will henceforth be focused on SootUp, not Soot, and on extending SootUp with those capabilities that people still find missing. For now, we recommend using SootUp for greenfield projects. For more details, check out -* The SootUp home page: https://soot-oss.github.io/SootUp/, and -* The SootUp repository: https://github.com/soot-oss/SootUp/ +- +- The SootUp home page: [This Page](https://soot-oss.github.io/SootUp/), and +- The SootUp repository: [https://github.com/soot-oss/SootUp/](https://soot-oss.github.io/SootUp/) We are very much looking forward to your feedback and feature requests. To this end, best create appropriate issues in the repository. diff --git a/docs/shipped-analyses.md b/docs/builtin-analyses.md similarity index 100% rename from docs/shipped-analyses.md rename to docs/builtin-analyses.md diff --git a/docs/call-graph-construction.md b/docs/callgraphs.md similarity index 100% rename from docs/call-graph-construction.md rename to docs/callgraphs.md diff --git a/docs/css/customizetheme.css b/docs/css/customizetheme.css index ac31584dcce..53d080d46d5 100644 --- a/docs/css/customizetheme.css +++ b/docs/css/customizetheme.css @@ -11,6 +11,11 @@ --md-accent-fg-color: rgba(255,140,0, 1); } +.md-main__inner { + margin-top: 0; + margin-bottom: 5em; +} + .md-typeset{ font-size: 12pt; } diff --git a/docs/getting-started.md b/docs/getting-started.md index 8dd6b44160b..6ca98dbe806 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -2,19 +2,16 @@ Before you get started with the SootUp library, it helps to learn about the following core data structures: - [`AnalysisInputLocation`]{It corresponds to the `cp` option, which specifies the classpath for Soot to find classes to be analyzed.} - : points to the target code to be analyzed. + : points to the target code that shall be loaded into the `View`. -- [`View`]{Corresponds to the `Scene` class, but it is not a singleton. So it is possible to instantiate multiple views simultaneously.}: presents the code/classes under analysis. +- [`View`]{Corresponds to the `Scene` class, but it is not a singleton. So it is possible to instantiate multiple views simultaneously.}: +handles the representation of the code you configured it to analyze. -- `SootClass`: represents a class loaded into the `View`. - -- `SootMethod`: represents a method of a class. - -- `SootField`: represents a field of a class. - -- `Body`: represents a method body in Jimple. - -- `StmtGraph`: represents the control flow graph of a method body in Jimple statements. +- `SootClass`: represents a class. Can be loaded from the View via a `ClassType` identifier. +- `SootMethod`: represents a method of a class - loaded from the View via a `MethodSignature` identifier. +- `SootField`: represents a field of a class - loaded from the View via a `FieldSignature` identifier. +- `Body`: represents a method body of a `SootMethod`. +- `StmtGraph`: represents the control flow graph of a `Body`. `Stmt`'s represent actual Instructions. ## Creating a View @@ -31,11 +28,10 @@ You can use bytecode analysis typically when you do not have access to the sourc If you have access to the source code, it is also possible to create a view for analyzing source code. Following example shows how to create view for analyzing Java source code. -!!! info "Experimental" - - The source code frontend is experimental and should only be used for testing purposes. You should compile the code for analysis first and use the bytecode frontend instead. +!!! info "Experimental! - Create a view to analyze Java source code" -!!! example "Create a view to analyze Java source code" + The source code frontend is experimental and should only be used for testing purposes. + Usually you should compile the code for analysis first and use the bytecode frontend instead (see above). ~~~java AnalysisInputLocation inputLocation = @@ -65,10 +61,10 @@ If you have a [Jimple](../jimple) file, you can create a view for analyzing jimp By default, whenever a class is retrieved, it will be permanently stored in a cache. If you do not want retrieved classes to be stored indefinetly, you can instead provide a different `CacheProvider` to the created view. -To for example use an `LRUCache` instead, which stores at most 50 classes, and always replaces the least recently used class by a newly retrieved one, use the following call: +To for example use an `LRUCache` instead, which stores at most e.g. 50 classes, and always replaces the least recently used class by a newly retrieved one, use the following call: ```java -JavaView view = new JavaView(Collections.singletonList(inputLocation), new LRUCacheProvider(50)); +JavaView view = new JavaView(inputLocations, new LRUCacheProvider(50)); ``` @@ -149,9 +145,11 @@ Once we have a `MethodSignature` that identifies the `main` method of the `Hello ```java Optional opt = view.getMethod(methodSignature); - if(opt.isPresent()){ - SootMethod method = opt.get(); + if(!opt.isPresent()){ + return; } + SootMethod method = opt.get(); + System.out.println(method.getModifiers()); ``` Alternatively, we can also retrieve a `SootMethod` from `SootClass` that contains it. @@ -173,7 +171,47 @@ Each `SootMethod` contains a Control-Flow Graph (CFG) which is represented via t !!! example "Retrieving the CFG of a SootMethod" ```java - sootMethod.getBody().getStmtGraph(); + StmtGraph graph = sootMethod.getBody().getStmtGraph(); + ``` + + +## Using the StmtGraph + +=== "StmtGraph Stmts" + ```java + for( Stmt stmt : graph.nodes()){ + // pseudo topological order as Stmts would be serialized to a Jimple file. + } + + for( Stmt stmt : graph.nodes()){ + // Stmts are unordered! + } + ``` +=== "StmtGraph Blocks" + ```java + List> blocks = graph.getBlocks(); + for( BasicBlock block : blocks){ + // e.g. check if its a merge point + if(block.getPredecessors().size() > 1){ + ... + } + + // e.g. check if its a branching point + if(block.getSuccessors().size() > 1){ + // or use block.getTail() instanceof BranchingStmt + ... + } + + // e.g. check if thrown exceptions would be caught in this method + if(!block.getExceptionalSuccessors().isEmpty()){ + ... + } + } + ``` +=== "StmtGraph DotExport" + ```java + String urlToWebeditor = DotExporter.createUrlToWebeditor(this); + System.out.println(urlToWebeditor); ``` diff --git a/mkdocs.yml b/mkdocs.yml index 261fac16d31..c2cf7395a97 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,27 +1,26 @@ -site_name: SootUp +site_name: "" site_url: https://soot-oss.github.io/SootUp/ repo_url: https://github.com/soot-oss/SootUp/ edit_uri: edit/develop/docs/ nav: - - Home: index.md - - Getting Started: - Installation: installation.md - First Steps: getting-started.md - Examples: examples.md - Configure your Inputs: analysisinputlocations.md - - Basics: + - Basics I: - Jimple IR: jimple.md - Jimple Body: jimple-body.md - Jimple Statements: jimple-stmts.md - Jimple Types: jimple-types.md - Jimple Values: jimple-values.md + - Basics II: - BodyInterceptors: bodyinterceptors.md - - Callgraph Construction: call-graph-construction.md - - Shipped Analyses: shipped-analyses.md + - Callgraphs: callgraphs.md + - BuiltIn Analyses: builtin-analyses.md - How to..: - Write a Dataflow analysis: write_analyses.md @@ -33,7 +32,7 @@ nav: # - From Prototype to Tool: tool_setup.md - Misc: - - Announcements: announce.md + - Announcements: announcement.md - Design Decisions: whatsnew.md - Migration Help: migrating.md From 9f67b3426f0713c74fbdc2417cd109f843066449 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 15:55:12 +0200 Subject: [PATCH 126/145] progress --- docs/bodyinterceptors.md | 9 ++++----- docs/builtin-analyses.md | 7 ++++--- docs/callgraphs.md | 11 +++++++---- docs/examples.md | 25 ++++++++++++++++--------- docs/faq.md | 6 ++++-- docs/jimple.md | 3 +-- mkdocs.yml | 14 ++++++-------- 7 files changed, 42 insertions(+), 33 deletions(-) diff --git a/docs/bodyinterceptors.md b/docs/bodyinterceptors.md index 4f98e8e1fac..4039ee4508e 100644 --- a/docs/bodyinterceptors.md +++ b/docs/bodyinterceptors.md @@ -9,7 +9,8 @@ The "raw" generated Jimple from the Bytecodefrontend needs a lot improvements - - The Locals we get from the Java bytecode are typically untyped. Therefore we have to augment the Local types which is done by the TypeAssigner. - t.b.c. -Method scoped optimisations: +Optimizations (method scope) + - ConditionalBranchFolder: removes tautologic ifs that are always true/false - if we can determine it in the scope of the method. - EmptySwitchEliminator: removes switches that are not really switching - ConstantPropagatorAndFolder: calculates constant values before runtime @@ -17,16 +18,14 @@ Method scoped optimisations: - UnreachableCodeEliminator: speaks for itself. - TrapTightener -Make Local names standardized: +Standardize Jimple appearance + - LocalNameStandardizer: numbers Locals with the scheme: type-initial + number of type occurence !!! info "Soot Equivalent" - [BodyTransformer](https://github.com/soot-oss/soot/blob/develop/src/main/java/soot/BodyTransformer.java) -Below, we show how these BodyInterceptors work for the users who are interested in their internal workings. - ### LocalSplitter LocalSplitter is aBodyInterceptorthat attempts to identify and separate uses of a local variable (as definition) that are independent of each other by renaming local variables. diff --git a/docs/builtin-analyses.md b/docs/builtin-analyses.md index 273912b3b93..6878e646810 100644 --- a/docs/builtin-analyses.md +++ b/docs/builtin-analyses.md @@ -1,6 +1,7 @@ -# Functionalities and Utilities +# BuiltIn Analyses +More to come! -#### LocalLivenessAnalyser +### LocalLivenessAnalyser LocalLivenessAnalyser is used for querying for the list of live local variables before and after a given Stmt. @@ -10,7 +11,7 @@ Example: The live local variables before and after each Stmt will be calculated after generating an instance of LocalLivenessAnalyser as shown the example above. They can be queried by using the methods getLiveLocalsBeforeStmt and getLiveLocalsAfterStmt. -#### DominanceFinder +### DominanceFinder DomianceFinder is used for querying for the immediate dominator and dominance frontiers for a given basic block. diff --git a/docs/callgraphs.md b/docs/callgraphs.md index e589b5736c9..dbfb503481d 100644 --- a/docs/callgraphs.md +++ b/docs/callgraphs.md @@ -10,8 +10,9 @@ Below, we show how to create a type hierarchy: === "SootUp" ```java + String cpString = "src/test/resources/Callgraph/binary"; List inputLocations = new ArrayList(); - inputLocations.add(new JavaClassPathAnalysisInputLocation("src/test/resources/Callgraph/binary")); + inputLocations.add(new JavaClassPathAnalysisInputLocation(cpStr)); inputLocations.add(new DefaultRTJarAnalysisInputLocation()); JavaView view = new JavaView(inputLocations); @@ -61,7 +62,9 @@ All the call graph construction algorithms require an entry method to start with === "SootUp (alternative)" ```java - MethodSignature entryMethodSignature = view.getIdentifierFactory().parseMethodSignature(" \ No newline at end of file diff --git a/docs/faq.md b/docs/faq.md index f9c75c88b54..e7f2efa5e51 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -42,12 +42,14 @@ or create a convenient link with the exported stmtgraph as HTTP GET Parameter DotExporter.createUrlToWebeditor( stmtgraph ); ``` +### The Sourcecodefrontend... +is in a experimental state! If you wish to use it, please consider to contribute. ### Is there a way to use code exploration and syntax highlighting features in my IDE for .jimple files? -Try [JimpeLsp](https://github.com/swissiety/JimpleLsp). +Try [JimpeLsp](https://github.com/swissiety/JimpleLsp) or the [vscode plugin](https://marketplace.visualstudio.com/items?itemName=swissiety.jimplelsp) ### Is there a way to use syntax highlighting of .jimple in my paper, thesis, ...? -Have a look at [LspLexer4Pygments](https://github.com/swissiety/LspLexer4Pygments). +Have a look at [LspLexer4Pygments](https://github.com/swissiety/LspLexer4Pygments). Its the same syntax highlighting you see here in the documentation. You can export it to LaTex as well. ### How to ... add an entry in this list? i.e. Your question is not answered here? Feel free to start a [Discussion](https://github.com/soot-oss/SootUp/discussions). diff --git a/docs/jimple.md b/docs/jimple.md index 8b86014413f..74ad683fdec 100644 --- a/docs/jimple.md +++ b/docs/jimple.md @@ -6,8 +6,7 @@ Therefore, Jimple aims to bring the best of both worlds, a non-stack-based and f For this purpose Jimple was designed as a representation of JVM bytecode which is human readable. !!! info - - To learn more about jimple, refer to the [thesis](https://courses.cs.washington.edu/courses/cse501/01wi/project/sable-thesis.pdf) by Raja Vallee-Rai. + To learn more about jimple, refer to the [thesis](https://courses.cs.washington.edu/courses/cse501/01wi/project/sable-thesis.pdf) by Raja Vallee-Rai. Lets have a look at the following Jimple code representing Java code of a `HelloWorld` class. diff --git a/mkdocs.yml b/mkdocs.yml index c2cf7395a97..0ed35eb015f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,14 +10,14 @@ nav: - Examples: examples.md - Configure your Inputs: analysisinputlocations.md - - Basics I: + - Basics: - Jimple IR: jimple.md - Jimple Body: jimple-body.md - Jimple Statements: jimple-stmts.md - Jimple Types: jimple-types.md - Jimple Values: jimple-values.md - - Basics II: + - Advanced Topics: - BodyInterceptors: bodyinterceptors.md - Callgraphs: callgraphs.md - BuiltIn Analyses: builtin-analyses.md @@ -31,12 +31,10 @@ nav: # - Implement an AnalysisTool: write_analysis_tool.md # - From Prototype to Tool: tool_setup.md - - Misc: - - Announcements: announcement.md - - Design Decisions: whatsnew.md - - Migration Help: migrating.md - - - More information: + - Misc & More information: + - Announcements: announcement.md + - Design Decisions: whatsnew.md + - Migration Help: migrating.md - Latest Javadoc: /SootUp/apidocs - Troubleshooting & FAQ: faq.md # - Based on SootUp: tools.md From c881926bc3675fcbb12ad817a3ea4c1bc769bb36 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 16:00:36 +0200 Subject: [PATCH 127/145] more progress --- docs/analysisinputlocations.md | 2 +- docs/announcement.md | 5 ++--- docs/migrating.md | 6 +++--- docs/tool_setup.md | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/analysisinputlocations.md b/docs/analysisinputlocations.md index 450b55139c2..77c04c71a65 100644 --- a/docs/analysisinputlocations.md +++ b/docs/analysisinputlocations.md @@ -22,4 +22,4 @@ If you have errors like Java.lang.String, Java.lang.Object, ... you are most lik ### Java cli arguments to configure SootUp -We created a [Utility](tool_setup) that parses a String of java command line arguments and configures SootUp respectively. \ No newline at end of file +We created a [Utility](tool_setup.md) that parses a String of java command line arguments and configures SootUp respectively. \ No newline at end of file diff --git a/docs/announcement.md b/docs/announcement.md index 98c0ccaa89f..78941b91c18 100644 --- a/docs/announcement.md +++ b/docs/announcement.md @@ -21,9 +21,8 @@ Below is an overview of what’s new. SootUp is not a drop-in replacement for Soot! Due to its completely new architecture and API it is essentially an almost complete rewrite. For a while, Soot and SootUp will coexist, as many existing tools depend on Soot, yet our maintenance efforts will henceforth be focused on SootUp, not Soot, and on extending SootUp with those capabilities that people still find missing. For now, we recommend using SootUp for greenfield projects. For more details, check out -- -- The SootUp home page: [This Page](https://soot-oss.github.io/SootUp/), and -- The SootUp repository: [https://github.com/soot-oss/SootUp/](https://soot-oss.github.io/SootUp/) + +[This Page ;-)](https://soot-oss.github.io/SootUp/) and The SootUp repository: [https://github.com/soot-oss/SootUp/](https://soot-oss.github.io/SootUp/) We are very much looking forward to your feedback and feature requests. To this end, best create appropriate issues in the repository. diff --git a/docs/migrating.md b/docs/migrating.md index c7302e738a0..dc2eca2059c 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -2,8 +2,7 @@ ### Version 1.3.0 - The Typehierarchy API is now returning `Stream` instead of `Collection`. The simplest fix to have the same behaviour as before would be to collect the Stream on your own ( e.g. via `.collect(Collectors.toList())` ). -- Default Bodyinterceptors are added to improve Jimple. To mitigate that adapt the List of BodyInterceptors to your needs. -- +- Default BytecodeBodyinterceptors are enabled to improve Jimple. To mitigate that adapt the List of BodyInterceptors to your needs. ### Version 1.2.0 - The (Java)Project structure was removed. You can configure the (Java)View directly. @@ -36,7 +35,8 @@ Below we show a comparison of the code so far with the same functionality in soo JavaSootClass sootClass = view.getClass(classType).get(); - JavaSootMethod sootMethod = sootClass.getMethod(methodSignature.getSubSignature()).get(); + MethodSubSignature mss = methodSignature.getSubSignature(); + JavaSootMethod sootMethod = sootClass.getMethod(mss).get(); sootMethod.getBody().getStmts(); ``` diff --git a/docs/tool_setup.md b/docs/tool_setup.md index c4d0f4d96cf..ee4445427f8 100644 --- a/docs/tool_setup.md +++ b/docs/tool_setup.md @@ -1,4 +1,4 @@ -# From Prototype to a user friendly tool +# From Prototype to an intuitive Tool `How was the parameter order again?` For a lot of cli tools we see an arbitrary order of cli parameters, different options for giving a working directory etc.. From bba530951e74779bc12462fb02edcb5fa8d52818 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 16:07:27 +0200 Subject: [PATCH 128/145] more more progress --- docs/analysisinputlocations.md | 7 ++++--- mkdocs.yml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/analysisinputlocations.md b/docs/analysisinputlocations.md index 77c04c71a65..3c2773364b4 100644 --- a/docs/analysisinputlocations.md +++ b/docs/analysisinputlocations.md @@ -1,5 +1,6 @@ -# AnalysisInputLocations -An AnalysisInputLocation tells SootUp what code input it should analyze. +# Analysis Input +i.e. What should be analyzed - an `AnalysisInputLocation` points to code input SootUp can analyze. +We ship multiple Subclasses that can handle different code input. ### Java Runtime - Java <=8: `DefaultRTJaAnalysisInputLocation` current rt.jar (or point to any rt.jar as its just a usual .jar file) @@ -18,7 +19,7 @@ If you have errors like Java.lang.String, Java.lang.Object, ... you are most lik - `JimpleAnalysisInputLocation` - needs a Path to a .jimple file or a directory. ### Android Bytecode .dex -- `ApkAnalysisInputLocation` - currenlty uses dex2jar internally - SootUp solution is WIP! +- `ApkAnalysisInputLocation` - currenlty uses dex2jar internally - A SootUp solution to directly generate Jimple is WIP! ### Java cli arguments to configure SootUp diff --git a/mkdocs.yml b/mkdocs.yml index 0ed35eb015f..1ad408272cc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,8 +7,8 @@ nav: - Getting Started: - Installation: installation.md - First Steps: getting-started.md + - Possible Analysis Input: analysisinputlocations.md - Examples: examples.md - - Configure your Inputs: analysisinputlocations.md - Basics: - Jimple IR: jimple.md From 5d7f716814aed50f5693f46016ff89464815e528 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 17:12:12 +0200 Subject: [PATCH 129/145] try fixing code block --- docs/jimple-values.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/jimple-values.md b/docs/jimple-values.md index 3da17f8a88f..dadaafe5153 100644 --- a/docs/jimple-values.md +++ b/docs/jimple-values.md @@ -1,18 +1,19 @@ # Jimple Values -### Immediate -An Immediate has a [**given**]{as in constant or immutable} Type and consists of a Local ("a Variable", "Something that contains a Value") or a Constant ("Something that is a Value"). +### Immediates +An `Immediate` has a [**given**]{as in constant or immutable} Type and consists of a Local ("a Variable", "Something that contains a Value") or a Constant ("Something that is a Value"). #### Local ```jimple i0 ``` + A Local is a variable and its scope is inside its method i.e. no referencing from outside a method. Values can be assigned to Locals via JIdentityStmt or JAssignStmt. -=== "Jimple" +=== "Jimple" - ```jimple + ``` public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -40,14 +41,14 @@ Values can be assigned to Locals via JIdentityStmt or JAssignStmt. } } /* - $stack2, this, $stack3, local#2 are all JimpleLocal. + $stack2, this, $stack3, local#2 are all Locals. - "this := @this: target.exercise1.DemoClass" is JIdentityStmt + "this := @this: target.exercise1.DemoClass" is a JIdentityStmt assigning to a Local. "$stack2 = ", "local#2 = this.", "$stack3 = " - are JAssignStmt + are JAssignStmts assigning to a Local. */ ``` @@ -142,9 +143,10 @@ And a bunch more! ### Ref #### JArrayRef ```jimple -$arr[1] +$arr[1] = 42; +$anotherLocal = arr[99]; ``` -referencing a position inside an array. +referencing an array position. #### JFieldRef `JFieldRef`s are referencing a `SootField` via its FieldSignature From 4d58c4bff79f73d8d1ffae08aad50310713cbdd0 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 17:19:43 +0200 Subject: [PATCH 130/145] try fixing code block --- docs/jimple-stmts.md | 13 +++++++------ docs/jimple-values.md | 18 +++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md index 25b53cca1c6..c3ae5f0d6b4 100644 --- a/docs/jimple-stmts.md +++ b/docs/jimple-stmts.md @@ -1174,7 +1174,7 @@ Ends the execution inside the current Method if the thrown exception is not caug ## Good to know A lot of the SootUp APIs return the `Stmt` Interface. To determine and handle its subtypes you can make use of instanceof. -=== "Stmt If-Else forest" +=== "instanceOf & If-Else" ```java List stmts = ... ; @@ -1188,7 +1188,7 @@ A lot of the SootUp APIs return the `Stmt` Interface. To determine and handle it JInvokeStmt ivkStmt = ((JInvokeStmt) stmt); MethodSignature rhsOp = ivkStmt.getInvokeExpr().getMethodSignature(); ... - } + }else ... } ``` @@ -1200,10 +1200,11 @@ Just subclass the methods to the respective Stmts you need to handle. List stmts = ...; AbstractStmtVisitor visitor = new AbstractStmtVisitor() { - private int countAssignStmts = 0; + private int ifStmtsCounter = 0; @Override - public void caseIfStmt(@Nonnull JAssignStmt stmt) { - countAssignStmts++; + public void caseIfStmt(@Nonnull JIfStmt stmt) { + ifStmtsCounter++; + setResult(ifStmtCounter); } }; @@ -1211,5 +1212,5 @@ Just subclass the methods to the respective Stmts you need to handle. stmt.accept(visitor); } - int amountOfAssignStmts = visitor.getResult(); + int amountOfIfStmts = visitor.getResult(); ``` \ No newline at end of file diff --git a/docs/jimple-values.md b/docs/jimple-values.md index dadaafe5153..0c7a4b84ba0 100644 --- a/docs/jimple-values.md +++ b/docs/jimple-values.md @@ -13,7 +13,7 @@ Values can be assigned to Locals via JIdentityStmt or JAssignStmt. === "Jimple" - ``` + ```jimple public class target.exercise1.DemoClass extends java.lang.Object { public void () @@ -23,30 +23,30 @@ Values can be assigned to Locals via JIdentityStmt or JAssignStmt. specialinvoke this.()>(); return; } - + public void compute() { java.io.PrintStream $stack2, $stack3; target.exercise1.DemoClass this; - int local#2; - + int local2; + this := @this: target.exercise1.DemoClass; $stack2 = ; virtualinvoke $stack2.(1); - - local#2 = this.; + + local2 = this.; $stack3 = ; - virtualinvoke $stack3.(local#2); + virtualinvoke $stack3.(local2); return; } } /* - $stack2, this, $stack3, local#2 are all Locals. + $stack2, this, $stack3, local2 are all Locals. "this := @this: target.exercise1.DemoClass" is a JIdentityStmt assigning to a Local. "$stack2 = ", - "local#2 = this.", + "local2 = this.", "$stack3 = " are JAssignStmts assigning to a Local. From 6194af7a106ed3d83ba42a50ae3415cc92af78fc Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 18:10:40 +0200 Subject: [PATCH 131/145] dont print language tag of code block if the styling fails --- docs/jimple-values.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/jimple-values.md b/docs/jimple-values.md index 0c7a4b84ba0..017712b8574 100644 --- a/docs/jimple-values.md +++ b/docs/jimple-values.md @@ -4,7 +4,7 @@ An `Immediate` has a [**given**]{as in constant or immutable} Type and consists of a Local ("a Variable", "Something that contains a Value") or a Constant ("Something that is a Value"). #### Local -```jimple +``` i0 ``` @@ -142,7 +142,7 @@ And a bunch more! ### Ref #### JArrayRef -```jimple +``` $arr[1] = 42; $anotherLocal = arr[99]; ``` @@ -160,19 +160,19 @@ referencing an array position. The IdentityRef makes those implicit special value assignments explicit. ##### JThisRef -```jimple +``` @this: package.fruit.Banana ``` represents the this pointer of the current class. ##### JCaughtExceptionRef -```jimple +``` @caughtexception ``` represents the value of the thrown exception (caught by this exceptionhandler). ##### JParameterRef -```jimple +``` i0 := @parameter0 i1 := @parameter1 ``` From 069143091f58930995783e2eec77712e3d703a5c Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 18 Jun 2024 18:11:57 +0200 Subject: [PATCH 132/145] dont print language tag of code block if the styling fails --- docs/jimple-values.md | 4 ++-- docs/jimple.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/jimple-values.md b/docs/jimple-values.md index 017712b8574..4b98e5d31c4 100644 --- a/docs/jimple-values.md +++ b/docs/jimple-values.md @@ -151,8 +151,8 @@ referencing an array position. #### JFieldRef `JFieldRef`s are referencing a `SootField` via its FieldSignature -- `JStaticFieldRef` like `#!jimple ` -- `JInstanceFieldRef` like `#!jimple r1.` +- `JStaticFieldRef` like ` ` +- `JInstanceFieldRef` like ` r1.` You can see the JInstanceFieldRef has the corresponding Local instance that points to the instance of the object which is holding the field. diff --git a/docs/jimple.md b/docs/jimple.md index 74ad683fdec..7370de698ae 100644 --- a/docs/jimple.md +++ b/docs/jimple.md @@ -6,7 +6,7 @@ Therefore, Jimple aims to bring the best of both worlds, a non-stack-based and f For this purpose Jimple was designed as a representation of JVM bytecode which is human readable. !!! info - To learn more about jimple, refer to the [thesis](https://courses.cs.washington.edu/courses/cse501/01wi/project/sable-thesis.pdf) by Raja Vallee-Rai. + To learn more about jimple, refer to the [thesis](https://courses.cs.washington.edu/courses/cse501/01wi/project/sable-thesis.pdf) by Raja Vallee-Rai. Lets have a look at the following Jimple code representing Java code of a `HelloWorld` class. @@ -246,7 +246,7 @@ Sidenote: Locals, do not have a signature, since they are referenced within meth } ``` -### SootClass +### SootClass A `SootClass` consists of SootFields and SootMethods. It is referenced by its global identifier the `ClassType` like `java.lang.String`. @@ -299,7 +299,7 @@ It is referenced by its global identifier the `ClassType` like `java.lang.String ### SootField A SootField is a piece of memory which can store a value that is accessible according to its visibility modifier. -It is referenced by its FieldSignature like `#!jimple `. +It is referenced by its FieldSignature like ` `. === "Jimple" @@ -364,7 +364,7 @@ It is referenced by its FieldSignature like `#!jimple `. +It is referenced by its MethodSignature like ` `. === "Jimple" From fbe539be32bab492374e6b3f54685aacce522d52 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Wed, 19 Jun 2024 11:07:10 +0200 Subject: [PATCH 133/145] add more visitor examples --- docs/jimple-stmts.md | 6 ++++-- docs/jimple-values.md | 41 +++++++++++++++++++++++++++++++++++++++-- mkdocs.yml | 39 +++++++++++++++++++-------------------- 3 files changed, 62 insertions(+), 24 deletions(-) diff --git a/docs/jimple-stmts.md b/docs/jimple-stmts.md index c3ae5f0d6b4..06bc1c8a233 100644 --- a/docs/jimple-stmts.md +++ b/docs/jimple-stmts.md @@ -1194,7 +1194,7 @@ A lot of the SootUp APIs return the `Stmt` Interface. To determine and handle it ``` But this could escalate to a huge if-else-tree - almost a forest. To mitigate such scenario you can implement a subclass of `AbstractStmtVisitor`. -Just subclass the methods to the respective Stmts you need to handle. +Just subclass the methods to the respective Stmts you need to handle. This is visitor acts like a switch-case, implemented via two dynamic calls. === "StmtVisitor" ```java @@ -1213,4 +1213,6 @@ Just subclass the methods to the respective Stmts you need to handle. } int amountOfIfStmts = visitor.getResult(); - ``` \ No newline at end of file + ``` + + Sidenote: Of course its possible can create a subclass instead of an anonymous class. \ No newline at end of file diff --git a/docs/jimple-values.md b/docs/jimple-values.md index 4b98e5d31c4..cdcb1cc35b8 100644 --- a/docs/jimple-values.md +++ b/docs/jimple-values.md @@ -1,6 +1,6 @@ # Jimple Values -### Immediates +### Immediate An `Immediate` has a [**given**]{as in constant or immutable} Type and consists of a Local ("a Variable", "Something that contains a Value") or a Constant ("Something that is a Value"). #### Local @@ -11,7 +11,7 @@ i0 A Local is a variable and its scope is inside its method i.e. no referencing from outside a method. Values can be assigned to Locals via JIdentityStmt or JAssignStmt. -=== "Jimple" +=== "Jimple" ```jimple public class target.exercise1.DemoClass extends java.lang.Object @@ -178,3 +178,40 @@ i1 := @parameter1 ``` represents a parameter of a method, identified by its index. +## Good to know +A lot of the SootUp APIs return the `Value` Interface. To determine and handle its subtypes you can make use of instanceof. +=== "instanceOf & If-Else" + ```java + + Value op = assignStmt.getRightOp(); + if(op instanceof Local){ + // found a Local + ... + }else if(stmt instanceof Constant){ + // found a Constant + ... + }else ... + + ``` + +But this could escalate to a huge if-else-tree - almost a forest. To mitigate such scenario you can implement a subclass of `AbstractValueVisitor`. +Just subclass the methods to the respective `Value`s you need to handle. This is visitor acts like a switch-case, implemented via two dynamic calls. +=== "StmtVisitor" + ```java + + Value op = assignStmt.getRightOp() ; + AbstractValueVisitor visitor = new AbstractValueVisitor() { + private int intConstantCounter = 0; + @Override + public void caseConstant(@Nonnull Constant c) { + intConstantCounter++; + setResult(intConstantCounter); + } + }; + + op.accept(visitor); + int amountOfIfStmts = visitor.getResult(); + ``` + + If you only need a visitor for a subset of Value, you can consider ImmediateVisitor, ConstantVisitor, ExprVisitor, RefVisitor. + Sidenote: Of course its possible can create a subclass instead of an anonymous class. diff --git a/mkdocs.yml b/mkdocs.yml index 1ad408272cc..87633845ac6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,52 +4,55 @@ repo_url: https://github.com/soot-oss/SootUp/ edit_uri: edit/develop/docs/ nav: - - Getting Started: - - Installation: installation.md - - First Steps: getting-started.md - - Possible Analysis Input: analysisinputlocations.md - - Examples: examples.md + - Getting Started: + - Installation: installation.md + - First Steps: getting-started.md + - Analysis Input: analysisinputlocations.md + - Examples: examples.md - - Basics: + - Basics: - Jimple IR: jimple.md - Jimple Body: jimple-body.md - Jimple Statements: jimple-stmts.md - Jimple Types: jimple-types.md - Jimple Values: jimple-values.md - - Advanced Topics: + - Advanced Topics: - BodyInterceptors: bodyinterceptors.md - Callgraphs: callgraphs.md - BuiltIn Analyses: builtin-analyses.md - - How to..: + - How to..: - Write a Dataflow analysis: write_analyses.md - Incorporate Pointer Analysis: qilin.md - # - Modify a StmtGraph: mutable_stmtgraph.md - # - Modify a View: mutable_view.md - # - Implement a BodyInterceptor: body_interceptor.md - # - Implement an AnalysisTool: write_analysis_tool.md - # - From Prototype to Tool: tool_setup.md + # - Modify a StmtGraph: mutable_stmtgraph.md + # - Modify a View: mutable_view.md + # - Implement a BodyInterceptor: body_interceptor.md + # - Implement an AnalysisTool: write_analysis_tool.md + # - From Prototype to Tool: tool_setup.md - - Misc & More information: + - Misc & More information: - Announcements: announcement.md - Design Decisions: whatsnew.md - Migration Help: migrating.md - Latest Javadoc: /SootUp/apidocs - Troubleshooting & FAQ: faq.md - # - Based on SootUp: tools.md + # - Based on SootUp: tools.md theme: + name: material logo: ./img/SootUpLogo.svg favicon: ./img/icon.svg palette: primary: custom custom_dir: ./docs/overrides - name: material features: - navigation.sections +extra_css: + - css/customizetheme.css + - css/hint.min.css plugins: - tooltips @@ -57,10 +60,6 @@ plugins: - include: src_path: 'sootup.examples/src/test/java/sootup/examples' -extra_css: - - css/customizetheme.css - - css/hint.min.css - markdown_extensions: - pymdownx.highlight: linenums: true From b68a67f22ea8106f4e146193547161e87b83c0d4 Mon Sep 17 00:00:00 2001 From: Stefan Schott <64211065+stschott@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:35:53 +0200 Subject: [PATCH 134/145] Fix link to SootUp logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8bb2535dd1..c1d5f8c158e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

# SootUp library ![Java CI with Maven](https://github.com/soot-oss/SootUp/workflows/Java%20CI%20with%20Maven/badge.svg?branch=develop) [![codecov](https://codecov.io/gh/soot-oss/SootUp/branch/develop/graph/badge.svg?token=ELA7U7IAWD)](https://codecov.io/gh/soot-oss/SootUp) [![javadoc](https://javadoc.io/badge2/org.soot-oss/sootup.core/javadoc.svg)](https://javadoc.io/doc/org.soot-oss/sootup.core) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.soot-oss/sootup.core/badge.svg)](https://central.sonatype.com/artifact/org.soot-oss/sootup) From dcc56b3bee35487529547859319efbea795433d0 Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Fri, 21 Jun 2024 21:41:06 +0200 Subject: [PATCH 135/145] add TypeHierarchy doc, and more --- ...ysisinputlocations.md => analysisinput.md} | 28 ++++-- docs/callgraphs.md | 8 +- docs/tool_setup.md | 10 +- docs/typehierarchy.md | 91 +++++++++++++++++++ mkdocs.yml | 3 +- .../core/typehierarchy/TypeHierarchy.java | 1 + .../core/typehierarchy/ViewTypeHierarchy.java | 2 +- 7 files changed, 126 insertions(+), 17 deletions(-) rename docs/{analysisinputlocations.md => analysisinput.md} (57%) create mode 100644 docs/typehierarchy.md diff --git a/docs/analysisinputlocations.md b/docs/analysisinput.md similarity index 57% rename from docs/analysisinputlocations.md rename to docs/analysisinput.md index 3c2773364b4..ad530b175b2 100644 --- a/docs/analysisinputlocations.md +++ b/docs/analysisinput.md @@ -2,24 +2,38 @@ i.e. What should be analyzed - an `AnalysisInputLocation` points to code input SootUp can analyze. We ship multiple Subclasses that can handle different code input. +You can specify a SourceType - which e.g. determines how far an analysis will go. +Additionally you can specify a List of [BodyInterceptors](bodyinterceptors.md), which will optimize the raw Jimple IR that was transformed from the input. + ### Java Runtime -- Java <=8: `DefaultRTJaAnalysisInputLocation` current rt.jar (or point to any rt.jar as its just a usual .jar file) -- Java >=9: `JRTFilesystemAnalysisInputLocation` +points to the runtime library of the executing JVM. + +- Java <=8: `DefaultRTJaAnalysisInputLocation` points to the rt.jar of the executing JVM. +- To include a different Java Runtime library point to any rt.jar via a `JavaClassPathAnalysisInputLocation` as its a usual .jar file. +- Java >=9: `JRTFilesystemAnalysisInputLocation` points to the jigsawed java runtime of the executing jvm. If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInput. -### Java Bytecode .class, .jar, .war +### Java Bytecode +File-Extensions: `.class, .jar, .war` + - `JavaClassPathAnalysisInputLocation` - its the equivalent of the classpath you would pass to the java executable i.e. point to root(s) of package(s). -### Java Sourcecode .java +### Java Sourcecode +File-Extensions: `.java` + - `OTFCompileAnalysisInputLocation` - you can point directly to .java files or pass a String with Java sourcecode, SootUp delegates to the `JavaCompiler` and transform the bytecode from the compiler to Jimple - `JavaSourcePathInputLocation` [***experimental!***]{Has huge problems with exceptional flow!} - points to a directory that is the root source directory (containing the package directory structure). -### Jimple .jimple +### Jimple +File-Extensions: `.jimple` + - `JimpleAnalysisInputLocation` - needs a Path to a .jimple file or a directory. -### Android Bytecode .dex -- `ApkAnalysisInputLocation` - currenlty uses dex2jar internally - A SootUp solution to directly generate Jimple is WIP! +### Android Bytecode +File-Extensions: `.apk` + +- `ApkAnalysisInputLocation` - currently uses dex2jar internally - A SootUp solution to directly generate Jimple is WIP! ### Java cli arguments to configure SootUp diff --git a/docs/callgraphs.md b/docs/callgraphs.md index dbfb503481d..35debb251ca 100644 --- a/docs/callgraphs.md +++ b/docs/callgraphs.md @@ -21,10 +21,10 @@ Below, we show how to create a type hierarchy: === "Soot" ```java - String targetTestClassName = target.exercise1.Hierarchy.class.getName(); - G.reset(); String userdir = System.getProperty("user.dir"); String sootCp = userdir + File.separator + "target" + File.separator + "test-classes"+ File.pathSeparator + "lib"+File.separator+"rt.jar"; + String targetTestClassName = target.exercise1.Hierarchy.class.getName(); + G.reset(); Options.v().set_whole_program(true); Options.v().set_soot_classpath(sootCp); Options.v().set_no_bodies_for_excluded(true); @@ -42,7 +42,7 @@ Below, we show how to create a type hierarchy: ``` ## Defining an Entry Method -All the call graph construction algorithms require an entry method to start with. In java application, you usually define the main method. However, it is possible to define arbitrary entry methods depending on your needs. Below, we show how to define such an entry method: +All call graph construction algorithms require an entry method to start with. In java application, you usually define the main method. However, it is possible to define arbitrary entry methods depending on your needs. Below, we show how to define such an entry method: === "SootUp (performant)" @@ -136,6 +136,7 @@ You can construct a call graph with RTA as follows: } ``` + diff --git a/docs/tool_setup.md b/docs/tool_setup.md index ee4445427f8..93c6d00dda8 100644 --- a/docs/tool_setup.md +++ b/docs/tool_setup.md @@ -1,14 +1,14 @@ # From Prototype to an intuitive Tool - -`How was the parameter order again?` +**How was the parameter order again?** For a lot of cli tools we see an arbitrary order of cli parameters, different options for giving a working directory etc.. -So in the wild you can see a lot from run.sh/run.bat to make files just to reorder arguments and calling a tool. +So in the wild you can see a lot from run.sh/run.bat to make files just to reorder arguments to execute a tool. In SootUp we thought we could help on improving this madness while saving your time. The command line parser mimics the options the java executable accepts - at least for what is supported by SootUp. +This makes it very simple to just copy the execution paramaters you use for execution, to use them more or less as is four the analysis tool. -Dependencies: +### Dependencies === "Maven" ```maven @@ -28,7 +28,7 @@ Dependencies: ```java class SootUpConfiguration{ - // TODO incorporate + // TODO incorporate from downstream } ``` diff --git a/docs/typehierarchy.md b/docs/typehierarchy.md new file mode 100644 index 00000000000..7c07b3c983d --- /dev/null +++ b/docs/typehierarchy.md @@ -0,0 +1,91 @@ +# TypeHierarchy +The TypeHierarchy models the relationship of Classes or Interfaces of a OOP program. + +## Creating TypeHierarchy + +=== "SootUp" + + ```java + String cpString = "src/test/resources/Callgraph/binary"; + List inputLocations = new ArrayList(); + inputLocations.add(new JavaClassPathAnalysisInputLocation(cpStr)); + inputLocations.add(new DefaultRTJarAnalysisInputLocation()); + + JavaView view = new JavaView(inputLocations); + TypeHierarchy typehierarchy = view.getTypeHierarchy(); + ``` + +=== "Soot" + + ```java + String userdir = System.getProperty("user.dir"); + String sootCp = userdir + File.separator + "target" + File.separator + "test-classes"+ File.pathSeparator + "lib"+File.separator+"rt.jar"; + + String targetTestClassName = target.exercise1.Hierarchy.class.getName(); + G.reset(); + Options.v().set_whole_program(true); + Options.v().set_soot_classpath(sootCp); + Options.v().set_no_bodies_for_excluded(true); + Options.v().process_dir(); + Options.v().set_allow_phantom_refs(true); + Options.v().setPhaseOption("jb", "use-original-names:true"); + Options.v().set_prepend_classpath(false); + SootClass c = Scene.v().forceResolve(targetTestClassName, SootClass.BODIES); + if (c != null) + c.setApplicationClass(); + Scene.v().loadNecessaryClasses(); + + Hierarchy hierarchy = new Hierarchy(); + + ``` + +## Create a JavaClassType + +=== "SootUp" + + ```java + JavaClassType classTypeA = view.getIdentifierFactory().getClassType("packageName.A"); + JavaClassType classTypeB = view.getIdentifierFactory().getClassType("packageName.B"); + JavaClassType classTypeC = view.getIdentifierFactory().getClassType("packageName.C"); + + ``` +=== "Soot" + + ```java + String targetTestClassName = "packageNameA.A"; + SootClass methodA = Scene.v().getSootClass(targetTestClassName); + + ``` + +## Query the TypeHierarchy +### Classes +```java + // if the assertion fails, the following methods will throw an Exception (you don't have to call it - it's just to illustrate the assumption) + assert typehierarchy.contains(classTypeA); + + typehierarchy.superclassOf(classTypeA); + + typehierarchy.subclassesOf(classTypeA); + + typehierarchy.isSubtypeOf(classTypeA, classTypeB); + +``` + +### Interfaces + +```java + JavaClassType iterableInterface = view.getIdentifierFactory().getClassType("java.lang.Iterable"); + + // if any of the assertions fail, the following methods will throw an Exception (you don't have to call these - it's just to illustrate the assumptions) + assert typehierarchy.contains(iterableInterface); + assert typehierarchy.isInterface(iterableInterface); + + // transitive relations as well + typehierarchy.implementedInterfacesOf(iterableInterface); + typehierarchy.implementersOf(iterableInterface); + + // only the direct related relations + typehierarchy.directlyImplementedInterfacesOf(iterableInterface); + typehierarchy.directlyExtendedInterfacesOf(iterableInterface); + +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 87633845ac6..c20dbc5db63 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,7 +7,7 @@ nav: - Getting Started: - Installation: installation.md - First Steps: getting-started.md - - Analysis Input: analysisinputlocations.md + - Analysis Input: analysisinput.md - Examples: examples.md - Basics: @@ -19,6 +19,7 @@ nav: - Advanced Topics: - BodyInterceptors: bodyinterceptors.md + - TypeHierarchy: typehierarchy.md - Callgraphs: callgraphs.md - BuiltIn Analyses: builtin-analyses.md diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java b/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java index d3fdd18d6e5..4dfa5a53a4b 100644 --- a/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java +++ b/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java @@ -75,6 +75,7 @@ public interface TypeHierarchy { * For an interface type, this does the same as {@link #implementersOf(ClassType)}. For a class * type, this does the same as {@link #subclassesOf(ClassType)}. */ + // TODO: [ms] check! not sure this method makes sense in the interface.. @Nonnull Stream subtypesOf(@Nonnull ClassType type); diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java b/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java index 192110019b5..6f7392529be 100644 --- a/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java +++ b/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java @@ -183,7 +183,7 @@ public Stream directlyExtendedInterfacesOf(@Nonnull ClassType interfa throw new IllegalArgumentException("Could not find " + interfaceType + " in hierarchy."); } if (vertex.type != VertexType.Interface) { - throw new IllegalArgumentException(interfaceType + " is not a class."); + throw new IllegalArgumentException(interfaceType + " is not an interface."); } return directExtendedInterfacesOf(vertex).map(v -> v.javaClassType); } From 7ba24ca3451fd293341bba0453ef8f5a1791d52b Mon Sep 17 00:00:00 2001 From: DongjieHe Date: Tue, 25 Jun 2024 15:43:21 +0800 Subject: [PATCH 136/145] update qilin docs --- docs/callgraphs.md | 14 +++++++++ docs/qilin.md | 71 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/docs/callgraphs.md b/docs/callgraphs.md index 35debb251ca..a28fb696935 100644 --- a/docs/callgraphs.md +++ b/docs/callgraphs.md @@ -177,3 +177,17 @@ Spark requires an initial call graph to begin with. You can use one of the call ``` --> +## Qilin Pointer Analysis + +Qilin builds a call graph on the fly with the pointer analysis. +You can construct a call graph with Qilin as follows: + +==="SootUp" + +```java +String MAINCLASS = "dacapo.antlr.Main"; // just an example +PTAPattern ptaPattern = new PTAPattern("insens"); // "2o"=>2OBJ, "1c"=>1CFA, etc. +PTA pta = PTAFactory.createPTA(ptaPattern, view, MAINCLASS); +pta.run(); +CallGraph cg = pta.getCallGraph(); +``` \ No newline at end of file diff --git a/docs/qilin.md b/docs/qilin.md index 9c9971adbae..03617c81352 100644 --- a/docs/qilin.md +++ b/docs/qilin.md @@ -17,6 +17,73 @@ see [QilinPTA](https://github.com/QilinPTA/Qilin). compile "org.soot-oss:sootup.qilin:{{ git_latest_release }}" ``` -### How to +### How to create a pointer analysis + +One can create an Andersen's context-insensitive analysis with following code: + +=== "Java" + + ```Java + String MAINCLASS = "dacapo.antlr.Main"; // just an example + PTAPattern ptaPattern = new PTAPattern("insens"); + PTA pta = PTAFactory.createPTA(ptaPattern, view, MAINCLASS); + pta.run(); + ``` + +Users must specify the program's `View`, select a `PTAPattern` +(indicating the desired types of pointer analyses to perform), +and designate the `MAINCLASS` (serving as the entry point for the analysis). + +### How to use pointer analysis results + +First, we can use Qilin's pointer analysis to get a On-the-Fly constructed callgraph: + +```java + OnFlyCallGraph cg = pta.getCallGraph(); +``` + +Second, we can use it to get the points-to results for some interested local variables, fields, etc. + +```java + PointsToSet pts0 = pta.reachingObjects(method, v0); + PointsToSet pts1 = pta.reachingObjects(method, v1, f); // PTS(v1.f) +``` + +Third, we can check whether two variables, `a` and `b`, are aliases by checking +whether there is an object that exists in both of their points-to sets. + +Qilin does not currently offer a `isMayAlias` API within the PTA class. +However, a similar functionality can be found +in `qilin.test.util.AliasAssertion` with the method: +`boolean isMayAlias(PTA pta, Value va, Value vb)`. +This method allows users to check for potential aliasing between two values +given a PTA instance. + +### A Full list of Point Analyses + +Qilin's toolbox includes a rich set of pointer analyses, which are given below: + +Note that the symbol k used in the table should be replaced with a concrete small constant like 1 or 2. + +| PTA patterns | Description | Reference | +|--------------------------------------|-------------------------------------------------------------------------|---| +| -pta=insens | Andersen's context-insensitive analysis | https://link.springer.com/chapter/10.1007/3-540-36579-6_12 | +| -pta=kc | k-callsite-sensitive pointer analysis (denoted kCFA). | https://www.cse.psu.edu/~trj1/cse598-f11/docs/sharir_pnueli1.pdf| +| -pta=ko | k-object-sensitive pointer analysis (denoted kOBJ). | https://dl.acm.org/doi/abs/10.1145/1044834.1044835 | +| -pta=kt | k-type-sensitive pointer analysis (denoted kTYPE). | https://dl.acm.org/doi/abs/10.1145/1926385.1926390 | +| -pta=kh | hybrid k-object-sensitive pointer analysis. | https://dl.acm.org/doi/10.1145/2499370.2462191 | +| -pta=kht | hybrid k-type-sensitive pointer analysis. | https://dl.acm.org/doi/10.1145/2499370.2462191 | +| -pta=B-2o | BEAN-guided 2OBJ. Only k=2 is supported. | https://link.springer.com/chapter/10.1007/978-3-662-53413-7_24 | +| -pta=D-2o | Data-driven 2OBJ. Only k=2 is supported. | https://dl.acm.org/doi/10.1145/3133924 | +| -pta=D-2c | Data-driven 2CFA. Only k=2 is supported. | https://dl.acm.org/doi/10.1145/3133924 | +| -pta=M-ko | MAHJONG-guided kOBJ. | https://dl.acm.org/doi/10.1145/3062341.3062360 | +| -pta=M-kc | MAHJONG-guided kCFA. | https://dl.acm.org/doi/10.1145/3062341.3062360 | +| -pta=E-ko | EAGLE-guided kOBJ. | https://dl.acm.org/doi/10.1145/3360574 | +| -pta=T-ko | TURNER-guided kOBJ. | https://drops.dagstuhl.de/opus/volltexte/2021/14059/ | +| -pta=Z-ko | ZIPPER-guided kOBJ. | https://dl.acm.org/doi/10.1145/3276511 | +| -pta=Z-kc | ZIPPER-guided kCFA. | https://dl.acm.org/doi/10.1145/3276511 | +| -pta=Z-ko -cd | The context debloated version of ZIPPER-guided kOBJ. | https://doi.org/10.1109/ASE51524.2021.9678880 | +| -pta=ko -cd -cda=CONCH | The context debloated version of kOBJ using Conch. | https://doi.org/10.1109/ASE51524.2021.9678880 | +| -pta=ko -cd -cda=DEBLOATERX | The context debloated version of kOBJ using DebloaterX. | https://dl.acm.org/doi/10.1145/3622832 | +| -pta=s-kc | SELECTX-guided kCFA. | https://doi.org/10.1007/978-3-030-88806-0_13 | -// TODO \ No newline at end of file From 23356f99e0fad38274382aa4c3f42fae46d0653a Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Mon, 1 Jul 2024 16:42:44 +0200 Subject: [PATCH 137/145] adapt doc --- docs/qilin.md | 66 ++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/docs/qilin.md b/docs/qilin.md index 03617c81352..b562d100466 100644 --- a/docs/qilin.md +++ b/docs/qilin.md @@ -1,13 +1,11 @@ # Incorporate Qilin Pointer Analysis -see [QilinPTA](https://github.com/QilinPTA/Qilin). - ### Dependencies === "Maven" ```maven org.soot-oss sootup.java.sourcecode - + {{ git_latest_release }} ``` @@ -24,15 +22,15 @@ One can create an Andersen's context-insensitive analysis with following code: === "Java" ```Java - String MAINCLASS = "dacapo.antlr.Main"; // just an example + String entrypoint = "dacapo.antlr.Main"; PTAPattern ptaPattern = new PTAPattern("insens"); - PTA pta = PTAFactory.createPTA(ptaPattern, view, MAINCLASS); + PTA pta = PTAFactory.createPTA(ptaPattern, view, entrypoint); pta.run(); ``` Users must specify the program's `View`, select a `PTAPattern` (indicating the desired types of pointer analyses to perform), -and designate the `MAINCLASS` (serving as the entry point for the analysis). +and designate the `entrypoint` - which is serving as the entry point for the analysis. ### How to use pointer analysis results @@ -52,38 +50,36 @@ Second, we can use it to get the points-to results for some interested local var Third, we can check whether two variables, `a` and `b`, are aliases by checking whether there is an object that exists in both of their points-to sets. -Qilin does not currently offer a `isMayAlias` API within the PTA class. -However, a similar functionality can be found +Qilin does not currently offer a `isMayAlias` API within the PTA class. However, a similar functionality can be found in `qilin.test.util.AliasAssertion` with the method: -`boolean isMayAlias(PTA pta, Value va, Value vb)`. +```boolean isMayAlias(PTA pta, Value va, Value vb)```. This method allows users to check for potential aliasing between two values given a PTA instance. ### A Full list of Point Analyses - -Qilin's toolbox includes a rich set of pointer analyses, which are given below: - -Note that the symbol k used in the table should be replaced with a concrete small constant like 1 or 2. - -| PTA patterns | Description | Reference | -|--------------------------------------|-------------------------------------------------------------------------|---| -| -pta=insens | Andersen's context-insensitive analysis | https://link.springer.com/chapter/10.1007/3-540-36579-6_12 | -| -pta=kc | k-callsite-sensitive pointer analysis (denoted kCFA). | https://www.cse.psu.edu/~trj1/cse598-f11/docs/sharir_pnueli1.pdf| -| -pta=ko | k-object-sensitive pointer analysis (denoted kOBJ). | https://dl.acm.org/doi/abs/10.1145/1044834.1044835 | -| -pta=kt | k-type-sensitive pointer analysis (denoted kTYPE). | https://dl.acm.org/doi/abs/10.1145/1926385.1926390 | -| -pta=kh | hybrid k-object-sensitive pointer analysis. | https://dl.acm.org/doi/10.1145/2499370.2462191 | -| -pta=kht | hybrid k-type-sensitive pointer analysis. | https://dl.acm.org/doi/10.1145/2499370.2462191 | -| -pta=B-2o | BEAN-guided 2OBJ. Only k=2 is supported. | https://link.springer.com/chapter/10.1007/978-3-662-53413-7_24 | -| -pta=D-2o | Data-driven 2OBJ. Only k=2 is supported. | https://dl.acm.org/doi/10.1145/3133924 | -| -pta=D-2c | Data-driven 2CFA. Only k=2 is supported. | https://dl.acm.org/doi/10.1145/3133924 | -| -pta=M-ko | MAHJONG-guided kOBJ. | https://dl.acm.org/doi/10.1145/3062341.3062360 | -| -pta=M-kc | MAHJONG-guided kCFA. | https://dl.acm.org/doi/10.1145/3062341.3062360 | -| -pta=E-ko | EAGLE-guided kOBJ. | https://dl.acm.org/doi/10.1145/3360574 | -| -pta=T-ko | TURNER-guided kOBJ. | https://drops.dagstuhl.de/opus/volltexte/2021/14059/ | -| -pta=Z-ko | ZIPPER-guided kOBJ. | https://dl.acm.org/doi/10.1145/3276511 | -| -pta=Z-kc | ZIPPER-guided kCFA. | https://dl.acm.org/doi/10.1145/3276511 | -| -pta=Z-ko -cd | The context debloated version of ZIPPER-guided kOBJ. | https://doi.org/10.1109/ASE51524.2021.9678880 | -| -pta=ko -cd -cda=CONCH | The context debloated version of kOBJ using Conch. | https://doi.org/10.1109/ASE51524.2021.9678880 | -| -pta=ko -cd -cda=DEBLOATERX | The context debloated version of kOBJ using DebloaterX. | https://dl.acm.org/doi/10.1145/3622832 | -| -pta=s-kc | SELECTX-guided kCFA. | https://doi.org/10.1007/978-3-030-88806-0_13 | +[Qilin](https://github.com/QilinPTA/Qilin)'s toolbox includes a rich set of pointer analyses, which are given below: + +Note that the symbol **k** used in the table should be replaced with a concrete small constant like 1 or 2. + +| PTA patterns | Description | Reference | +|----------------------------|---------------------------------------------------------------|---------------------------------------------------------------------------| +| **insens** | Andersen's context-insensitive analysis | [Paper](https://link.springer.com/chapter/10.1007/3-540-36579-6_12) | +| **k**c | **k**-callsite-sensitive pointer analysis (denoted **k**CFA). | [Paper](https://www.cse.psu.edu/~trj1/cse598-f11/docs/sharir_pnueli1.pdf) | +| **k**o | **k**-object-sensitive pointer analysis (denoted **k**OBJ). | [Paper](https://dl.acm.org/doi/abs/10.1145/1044834.1044835) | +| **k**t | **k**-type-sensitive pointer analysis (denoted **k**TYPE). | [Paper](https://dl.acm.org/doi/abs/10.1145/1926385.1926390) | +| **k**h | hybrid **k**-object-sensitive pointer analysis. | [Paper](https://dl.acm.org/doi/10.1145/2499370.2462191) | +| **k**ht | hybrid **k**-type-sensitive pointer analysis. | [Paper](https://dl.acm.org/doi/10.1145/2499370.2462191) | +| B-2o | BEAN-guided 2OBJ. Only k=2 is supported. | [Paper](https://link.springer.com/chapter/10.1007/978-3-662-53413-7_24) | +| D-2o | Data-driven 2OBJ. Only k=2 is supported. | [Paper](https://dl.acm.org/doi/10.1145/3133924) | +| D-2c | Data-driven 2CFA. Only k=2 is supported. | [Paper](https://dl.acm.org/doi/10.1145/3133924) | +| M-**k**o | MAHJONG-guided **k**OBJ. | [Paper](https://dl.acm.org/doi/10.1145/3062341.3062360) | +| M-**k**c | MAHJONG-guided **k**CFA. | [Paper](https://dl.acm.org/doi/10.1145/3062341.3062360) | +| E-**k**o | EAGLE-guided **k**OBJ. | [Paper](https://dl.acm.org/doi/10.1145/3360574) | +| T-**k**o | TURNER-guided **k**OBJ. | [Paper](https://drops.dagstuhl.de/opus/volltexte/2021/14059/) | +| Z-**k**o | ZIPPER-guided **k**OBJ. | [Paper](https://dl.acm.org/doi/10.1145/3276511) | +| Z-**k**c | ZIPPER-guided **k**CFA. | [Paper](https://dl.acm.org/doi/10.1145/3276511) | +| Z-**k**o -cd | The context debloated version of ZIPPER-guided **k**OBJ. | [Paper](https://doi.org/10.1109/ASE51524.2021.9678880) | +| **k**o -cd -cda=CONCH | The context debloated version of **k**OBJ using Conch. | [Paper](https://doi.org/10.1109/ASE51524.2021.9678880) | +| **k**o -cd -cda=DEBLOATERX | The context debloated version of **k**OBJ using DebloaterX. | [Paper](https://dl.acm.org/doi/10.1145/3622832) | +| s-**k**c | SELECTX-guided **k**CFA. | [Paper](https://doi.org/10.1007/978-3-030-88806-0_13) | From 20fd72e2e5b04e1cd5c81cbb404e515658d187c4 Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Thu, 4 Jul 2024 15:54:25 +0200 Subject: [PATCH 138/145] fix markdown --- docs/css/customizetheme.css | 2 +- docs/qilin.md | 42 ++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/docs/css/customizetheme.css b/docs/css/customizetheme.css index 53d080d46d5..00a4cb6d4ea 100644 --- a/docs/css/customizetheme.css +++ b/docs/css/customizetheme.css @@ -41,7 +41,7 @@ font-weight: normal; } -.md-typeset .admonition, .md-typeset .admonition.info, .md-typeset .admonition.example, .md-typeset .admonition{ +.md-typeset .admonition, .md-typeset .admonition.info, .md-typeset .admonition.example, .md-typeset .admonition, .md-typeset .admonition.note{ border-color: rgba(255,140,0, 0.1); margin-bottom: 3em; } diff --git a/docs/qilin.md b/docs/qilin.md index b562d100466..cc424b81e4f 100644 --- a/docs/qilin.md +++ b/docs/qilin.md @@ -1,31 +1,35 @@ # Incorporate Qilin Pointer Analysis + ### Dependencies + === "Maven" ```maven - - org.soot-oss - sootup.java.sourcecode - {{ git_latest_release }} - + + org.soot-oss + sootup.java.sourcecode + {{ git_latest_release }} + ``` === "Gradle" ```groovy - compile "org.soot-oss:sootup.qilin:{{ git_latest_release }}" + compile "org.soot-oss:sootup.qilin:{{ git_latest_release }}" ``` ### How to create a pointer analysis +!!! note "WIP: Beware most likely the API will change so you only need to specify SootUp objects!" + One can create an Andersen's context-insensitive analysis with following code: === "Java" ```Java - String entrypoint = "dacapo.antlr.Main"; - PTAPattern ptaPattern = new PTAPattern("insens"); - PTA pta = PTAFactory.createPTA(ptaPattern, view, entrypoint); - pta.run(); + String entrypoint = "dacapo.antlr.Main"; + PTAPattern ptaPattern = new PTAPattern("insens"); + PTA pta = PTAFactory.createPTA(ptaPattern, view, entrypoint); + pta.run(); ``` Users must specify the program's `View`, select a `PTAPattern` @@ -37,26 +41,26 @@ and designate the `entrypoint` - which is serving as the entry point for the ana First, we can use Qilin's pointer analysis to get a On-the-Fly constructed callgraph: ```java - OnFlyCallGraph cg = pta.getCallGraph(); +OnFlyCallGraph cg = pta.getCallGraph(); ``` Second, we can use it to get the points-to results for some interested local variables, fields, etc. ```java - PointsToSet pts0 = pta.reachingObjects(method, v0); - PointsToSet pts1 = pta.reachingObjects(method, v1, f); // PTS(v1.f) +PointsToSet pts0 = pta.reachingObjects(method, v0); +PointsToSet pts1 = pta.reachingObjects(method, v1, f); // PTS(v1.f) ``` Third, we can check whether two variables, `a` and `b`, are aliases by checking whether there is an object that exists in both of their points-to sets. -Qilin does not currently offer a `isMayAlias` API within the PTA class. However, a similar functionality can be found -in `qilin.test.util.AliasAssertion` with the method: -```boolean isMayAlias(PTA pta, Value va, Value vb)```. -This method allows users to check for potential aliasing between two values -given a PTA instance. +Qilin does not currently offer a `isMayAlias` API within the PTA class. +However, a similar functionality can be found in `qilin.test.util.AliasAssertion` with the method: +```boolean isMayAlias(PTA pta, Value va, Value vb)``` +This method allows to check for potential aliasing between two values given a PTA instance. + +### A Full list of Pointer Analyses -### A Full list of Point Analyses [Qilin](https://github.com/QilinPTA/Qilin)'s toolbox includes a rich set of pointer analyses, which are given below: Note that the symbol **k** used in the table should be replaced with a concrete small constant like 1 or 2. From bde17ccc5b43a11bb5735753006ec16bf635d73e Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Fri, 5 Jul 2024 12:34:25 +0200 Subject: [PATCH 139/145] add code examples --- docs/analysisinput.md | 137 ++++++++++++++++-- .../DefaultRTJarAnalysisInputLocation.java | 3 + .../OTFCompileAnalysisInputLocation.java | 1 - 3 files changed, 125 insertions(+), 16 deletions(-) diff --git a/docs/analysisinput.md b/docs/analysisinput.md index ad530b175b2..4bcd03312b6 100644 --- a/docs/analysisinput.md +++ b/docs/analysisinput.md @@ -1,40 +1,147 @@ # Analysis Input -i.e. What should be analyzed - an `AnalysisInputLocation` points to code input SootUp can analyze. -We ship multiple Subclasses that can handle different code input. +i.e. What should be analyzed. An `AnalysisInputLocation` points to code input SootUp can analyze. +We ship multiple Implementations that can handle different input. -You can specify a SourceType - which e.g. determines how far an analysis will go. -Additionally you can specify a List of [BodyInterceptors](bodyinterceptors.md), which will optimize the raw Jimple IR that was transformed from the input. +Additionally you can specify a SourceType. This determines what is considered e.g. in the CallGraphs generation. +Further you can specify a List of [BodyInterceptors](bodyinterceptors.md), which will optimize the raw Jimple IR that was transformed from the input. ### Java Runtime -points to the runtime library of the executing JVM. - -- Java <=8: `DefaultRTJaAnalysisInputLocation` points to the rt.jar of the executing JVM. -- To include a different Java Runtime library point to any rt.jar via a `JavaClassPathAnalysisInputLocation` as its a usual .jar file. -- Java >=9: `JRTFilesystemAnalysisInputLocation` points to the jigsawed java runtime of the executing jvm. +#### Java <=8 +The `DefaultRTJaAnalysisInputLocation` points to the rt.jar of the executing JVM. -If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInput. + +```java +AnalysisInputLocation inputLocation = new DefaultRTJaAnalysisInputLocation(); +JavaView view = new JavaView(inputLocation); +``` + +To include a different Java Runtime library point to any rt.jar via a `JavaClassPathAnalysisInputLocation` as its a usual .jar file. + +#### Java >=9 +The `JRTFilesystemAnalysisInputLocation` points to the jigsawed java runtime of the executing JVM. + +```java +AnalysisInputLocation inputLocation = new JrtFileSystemAnalysisInputLocation(); +JavaView view = new JavaView(inputLocation); +``` + + +!!! info "If you have errors like Java.lang.String, Java.lang.Object, ... you are most likely missing this AnalysisInputLocation." ### Java Bytecode File-Extensions: `.class, .jar, .war` -- `JavaClassPathAnalysisInputLocation` - its the equivalent of the classpath you would pass to the java executable i.e. point to root(s) of package(s). +The `JavaClassPathAnalysisInputLocation` is the equivalent of the classpath you would pass to the java executable i.e. point to root(s) of package(s). + +=== "Directory" + ```java + AnalysisInputLocation inputLocation = + new JavaClassPathAnalysisInputLocation("target/"); // points to + JavaView view = new JavaView(inputLocation); + ``` + +=== ".jar File" + ```java + AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation("myCode.jar"); + JavaView view1 = new JavaView(inputLocation); + + // if you want to analyze a specific language level of a multi release jar + AnalysisInputLocation inputLocation = + new MultiReleaseJarAnalysisInputLocation("myCode.jar", new JavaLanguage(10) ); + JavaView view2 = new JavaView(inputLocation); + ``` + +=== ".class File" + ```java + // if you omit the package structure while pointing to a file, + // you have to pass the omitted directories as a parameter + AnalysisInputLocation inputLocation = new PathBasedAnalysisInputLocation. + ClassFileBasedAnalysisInputLocation("Banana.class", "packageName.subPackage", SourceType.Application); + JavaView view = new JavaView(inputLocation); + ``` + +=== "Complete class path" + ```java + String cp = "myCode.jar" + File.pathSeparator + "dependency.jar" + File.pathSeparator + "target/classes/"; + AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation(cp); + JavaView view = new JavaView(inputLocation); + ``` ### Java Sourcecode File-Extensions: `.java` -- `OTFCompileAnalysisInputLocation` - you can point directly to .java files or pass a String with Java sourcecode, SootUp delegates to the `JavaCompiler` and transform the bytecode from the compiler to Jimple -- `JavaSourcePathInputLocation` [***experimental!***]{Has huge problems with exceptional flow!} - points to a directory that is the root source directory (containing the package directory structure). +With the `OTFCompileAnalysisInputLocation` you can point directly to .java files or pass a String with Java sourcecode. +The AnalysisInputLocation delegates the data to the `JavaCompiler` and transform the bytecode from the compiler to Jimple. + +=== "Single File" + ```java + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation("Banana.java"); + JavaView view = new JavaView(inputLocation); + ``` + +=== "Multiple Files" + ```java + List files = Arrays.asList(Paths.get("Apple.java"), Paths.get("Banana.java")); + AnalysisInputLocation inputLocation = new OTFCompileAnalysisInputLocation(files); + JavaView view = new JavaView(inputLocation); + ``` +=== "File as String" + ```java + String content = "public class B{ }"; + AnalysisInputLocation location = new OTFCompileAnalysisInputLocation("B.java", content ); + JavaView view = new JavaView(location); + ``` + +`JavaSourcePathInputLocation` [***experimental!***]{Has huge problems with exceptional flow!} - points to a directory that is the root source directory (containing the package directory structure). ### Jimple File-Extensions: `.jimple` -- `JimpleAnalysisInputLocation` - needs a Path to a .jimple file or a directory. +The `JimpleAnalysisInputLocation` needs a Path to a .jimple file or a directory. + +```java +Path path = Paths.get("Banana.java"); +AnalysisInputLocation jimpleLocation = new JimpleAnalysisInputLocation(path); +JavaView view = new JavaView(jimpleLocation); +``` + ### Android Bytecode File-Extensions: `.apk` -- `ApkAnalysisInputLocation` - currently uses dex2jar internally - A SootUp solution to directly generate Jimple is WIP! +The `ApkAnalysisInputLocation` currently uses dex2jar internally + +```java +Path path = Paths.get("Banana.apk"); +AnalysisInputLocation inputLocation = new ApkAnalysisInputLocation(path); +JavaView view = new JavaView(inputLocation); +``` + +!!! info "A SootUp solution to directly generate Jimple is WIP!" + + +### Combining Multiple AnalysisInputLocations +But what if I want to point to multiple AnalysisInputLocations? + +```java +AnalysisInputLocation mainJar = new JavaClassPathAnalysisInputLocation("myCode.jar"); +AnalysisInputLocation jarA = new JavaClassPathAnalysisInputLocation("dependencyA.jar"); +AnalysisInputLocation jarB = new JavaClassPathAnalysisInputLocation("dependencyB.jar"); + +List inputlocationList = Arrays.asList(mainJar, jarA, jarB); + +JavaView view = new JavaView(inputlocationList); +``` +!!! note "Of course you can combine different types of `AnalysisInputLocation`s as well!" + + +### Maven Project as Analysis Input in SootUp +This uses `#!shell mvn compile` + `JavaClassPathAnalysisInputLocation` under the hood to include a maven project. +```java + TODO: let the code sail with the upstream boat to this doc. +``` +Unfortunately its harder to extract the path of the binary result of Gradle projects in a unified way for all kinds of models - If you have a solution are looking forward to merge your contribution :-). ### Java cli arguments to configure SootUp We created a [Utility](tool_setup.md) that parses a String of java command line arguments and configures SootUp respectively. \ No newline at end of file diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/DefaultRTJarAnalysisInputLocation.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/DefaultRTJarAnalysisInputLocation.java index 98850dbfbfb..c913764fc52 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/DefaultRTJarAnalysisInputLocation.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/DefaultRTJarAnalysisInputLocation.java @@ -31,6 +31,9 @@ * Refers to the rt.jar from <=Java8 as an AnalysisInputLocation requires: JAVA_HOME to be set * and expects the jar in the "lib/" subdirectory. If you need to include the rt.jar from a custom * Location please make use of JavaClassPathAnalysisInputLocation. + * + *

Info: This only works if you are running java 8 or older. Otherwise use {@link + * JrtFileSystemAnalysisInputLocation}. */ public class DefaultRTJarAnalysisInputLocation extends ArchiveBasedAnalysisInputLocation { diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/OTFCompileAnalysisInputLocation.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/OTFCompileAnalysisInputLocation.java index 6bee2df6a38..c629fff6f11 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/OTFCompileAnalysisInputLocation.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/inputlocation/OTFCompileAnalysisInputLocation.java @@ -108,7 +108,6 @@ public SourceType getSourceType() { @Nonnull @Override public List getBodyInterceptors() { - // hint: all referenced inputlocations have the same settings return inputLocation.getBodyInterceptors(); } From 62a249e4d4484d3348ee892bfb433cae21bd2d54 Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Fri, 5 Jul 2024 16:28:02 +0200 Subject: [PATCH 140/145] fix bug /porting --- .../sootup/core/jimple/common/expr/JUshrExpr.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java index f7b9e7cf1e7..e6cc0fd1637 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/JUshrExpr.java @@ -54,16 +54,15 @@ public Type getType() { Value op2 = getOp2(); if (Type.isIntLikeType(op2.getType())) { - return UnknownType.getInstance(); - } - if (Type.isIntLikeType(op1.getType())) { - return PrimitiveType.getInt(); - } - if (op1.getType().equals(PrimitiveType.getLong())) { - return PrimitiveType.getLong(); + if (Type.isIntLikeType(op1.getType())) { + return PrimitiveType.getInt(); + } + final PrimitiveType.LongType longType = PrimitiveType.getLong(); + if (op1.getType() == longType) { + return longType; + } } - return UnknownType.getInstance(); } From 651c4e61a9e77ef8dee2dcef5b1a76b4ed683edd Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Fri, 5 Jul 2024 16:29:56 +0200 Subject: [PATCH 141/145] simplify --- .../common/expr/AbstractFloatBinopExpr.java | 21 ++++++++++++------- .../src/main/java/sootup/core/types/Type.java | 12 ++++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java index 5c834a32808..4967506f19d 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java @@ -44,14 +44,19 @@ public Type getType() { if (Type.isIntLikeType(op1t) && Type.isIntLikeType(op2t)) { return PrimitiveType.getInt(); - } else if (op1t.equals(PrimitiveType.getLong()) || op2t.equals(PrimitiveType.getLong())) { - return PrimitiveType.getLong(); - } else if (op1t.equals(PrimitiveType.getDouble()) || op2t.equals(PrimitiveType.getDouble())) { - return PrimitiveType.getDouble(); - } else if (op1t.equals(PrimitiveType.getFloat()) || op2t.equals(PrimitiveType.getFloat())) { - return PrimitiveType.getFloat(); - } else { - return UnknownType.getInstance(); } + final PrimitiveType.LongType longType = PrimitiveType.getLong(); + if (op1t == longType || op2t == longType) { + return longType; + } + final PrimitiveType.DoubleType aDouble = PrimitiveType.getDouble(); + if (op1t == aDouble || op2t == aDouble) { + return aDouble; + } + final PrimitiveType.FloatType aFloat = PrimitiveType.getFloat(); + if (op1t == aFloat || op2t == aFloat) { + return aFloat; + } + return UnknownType.getInstance(); } } diff --git a/sootup.core/src/main/java/sootup/core/types/Type.java b/sootup.core/src/main/java/sootup/core/types/Type.java index dd18f122862..805da414e0d 100644 --- a/sootup.core/src/main/java/sootup/core/types/Type.java +++ b/sootup.core/src/main/java/sootup/core/types/Type.java @@ -36,11 +36,13 @@ public static boolean isObjectLikeType(Type type) { } public static boolean isIntLikeType(Type type) { - return type == PrimitiveType.IntType.getInstance() - || type == PrimitiveType.ByteType.getInstance() - || type == PrimitiveType.ShortType.getInstance() - || type == PrimitiveType.CharType.getInstance() - || type == PrimitiveType.BooleanType.getInstance(); + return type instanceof PrimitiveType.IntType; + /* type == PrimitiveType.IntType.getInstance() + || type == PrimitiveType.ByteType.getInstance() + || type == PrimitiveType.ShortType.getInstance() + || type == PrimitiveType.CharType.getInstance() + || type == PrimitiveType.BooleanType.getInstance(); + */ } public static boolean isObject(Type type) { From 482f23bb006ff0f852e247414bb91d19c5ebd61a Mon Sep 17 00:00:00 2001 From: sahil Date: Fri, 5 Jul 2024 20:19:13 +0530 Subject: [PATCH 142/145] Empty strings, strings consisting only whitespaces, are not permissible when an attribute expects a string. --- .github/ISSUE_TEMPLATE/FEATURE_TEMPLATE.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/FEATURE_TEMPLATE.yml b/.github/ISSUE_TEMPLATE/FEATURE_TEMPLATE.yml index 3671d2e510a..0d4f4039bf0 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE_TEMPLATE.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE_TEMPLATE.yml @@ -13,7 +13,7 @@ body: attributes: label: Missing Feature description: Please describe the wanted functionality in detail. If possible enhance it with examples and/or scientific publications. - value: "" + value: Please describe the missing feature here.. validations: required: true From cbf66df3a4fe8e731bae9941757d8c5edabc116a Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Mon, 8 Jul 2024 10:28:36 +0200 Subject: [PATCH 143/145] consistent naming --- .../jimple/common/expr/AbstractFloatBinopExpr.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java index 4967506f19d..ce8987fe707 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/expr/AbstractFloatBinopExpr.java @@ -49,13 +49,13 @@ public Type getType() { if (op1t == longType || op2t == longType) { return longType; } - final PrimitiveType.DoubleType aDouble = PrimitiveType.getDouble(); - if (op1t == aDouble || op2t == aDouble) { - return aDouble; + final PrimitiveType.DoubleType doubleType = PrimitiveType.getDouble(); + if (op1t == doubleType || op2t == doubleType) { + return doubleType; } - final PrimitiveType.FloatType aFloat = PrimitiveType.getFloat(); - if (op1t == aFloat || op2t == aFloat) { - return aFloat; + final PrimitiveType.FloatType floatType = PrimitiveType.getFloat(); + if (op1t == floatType || op2t == floatType) { + return floatType; } return UnknownType.getInstance(); } From 5cd83a4ceaf3463bde25edc2cfc049af1e35268c Mon Sep 17 00:00:00 2001 From: Stefan Schott Date: Thu, 11 Jul 2024 14:00:18 +0200 Subject: [PATCH 144/145] fix ReplaceUseStmtVisitor --- .../jimple/visitor/ReplaceUseStmtVisitor.java | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java index 35d5bc6b130..bf935bc9698 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java @@ -114,12 +114,20 @@ public void caseIdentityStmt(@Nonnull JIdentityStmt stmt) { @Override public void caseEnterMonitorStmt(@Nonnull JEnterMonitorStmt stmt) { - setResult(stmt.withOp((Immediate) newUse)); + if (stmt.getOp() == oldUse) { + setResult(stmt.withOp((Immediate) newUse)); + } else { + defaultCaseStmt(stmt); + } } @Override public void caseExitMonitorStmt(@Nonnull JExitMonitorStmt stmt) { - setResult(stmt.withOp((Immediate) newUse)); + if (stmt.getOp() == oldUse) { + setResult(stmt.withOp((Immediate) newUse)); + } else { + defaultCaseStmt(stmt); + } } @Override @@ -146,12 +154,20 @@ public void caseNopStmt(@Nonnull JNopStmt stmt) { @Override public void caseRetStmt(@Nonnull JRetStmt stmt) { - setResult(stmt.withStmtAddress(newUse)); + if (stmt.getStmtAddress() == oldUse) { + setResult(stmt.withStmtAddress(newUse)); + } else { + defaultCaseStmt(stmt); + } } @Override public void caseReturnStmt(@Nonnull JReturnStmt stmt) { - setResult(stmt.withReturnValue((Immediate) newUse)); + if (stmt.getOp() == oldUse) { + setResult(stmt.withReturnValue((Immediate) newUse)); + } else { + setResult(stmt); + } } @Override @@ -161,12 +177,20 @@ public void caseReturnVoidStmt(@Nonnull JReturnVoidStmt stmt) { @Override public void caseSwitchStmt(@Nonnull JSwitchStmt stmt) { - setResult(stmt.withKey((Immediate) newUse)); + if (stmt.getKey() == oldUse) { + setResult(stmt.withKey((Immediate) newUse)); + } else { + defaultCaseStmt(stmt); + } } @Override public void caseThrowStmt(@Nonnull JThrowStmt stmt) { - setResult(stmt.withOp((Immediate) newUse)); + if (stmt.getOp() == oldUse) { + setResult(stmt.withOp((Immediate) newUse)); + } else { + defaultCaseStmt(stmt); + } } public void defaultCaseStmt(@Nonnull Stmt stmt) { From ca94d2d5caef420221827028c0fb9184551b0711 Mon Sep 17 00:00:00 2001 From: Stefan Schott Date: Thu, 11 Jul 2024 16:09:55 +0200 Subject: [PATCH 145/145] some small changes --- .../sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java index bf935bc9698..7719bd2ca52 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java @@ -104,7 +104,7 @@ public void caseAssignStmt(@Nonnull JAssignStmt stmt) { } } - setResult(stmt); + defaultCaseStmt(stmt); } @Override @@ -143,7 +143,7 @@ public void caseIfStmt(@Nonnull JIfStmt stmt) { if (exprVisitor.getResult() != conditionExpr) { setResult(stmt.withCondition((AbstractConditionExpr) exprVisitor.getResult())); } else { - setResult(stmt); + defaultCaseStmt(stmt); } } @@ -166,7 +166,7 @@ public void caseReturnStmt(@Nonnull JReturnStmt stmt) { if (stmt.getOp() == oldUse) { setResult(stmt.withReturnValue((Immediate) newUse)); } else { - setResult(stmt); + defaultCaseStmt(stmt); } }