From 703725335bde40b26a33285942dad483450f02b2 Mon Sep 17 00:00:00 2001 From: Teng Zhang Date: Tue, 28 May 2024 19:10:41 +0800 Subject: [PATCH] Refactor --- .../taie/analysis/pta/PointerAnalysis.java | 3 +- .../pta/core/cs/element/AbstractPointer.java | 16 +- .../analysis/pta/core/cs/element/Pointer.java | 14 +- .../analysis/pta/plugin/CompositePlugin.java | 2 +- .../pta/plugin/taint/SinkHandler.java | 78 +++---- .../pta/plugin/taint/TaintAnalysis.java | 215 ++++++------------ .../analysis/pta/pts/DelegatePointsToSet.java | 4 +- .../taie/analysis/pta/pts/PointsToSet.java | 5 +- src/main/resources/tai-e-analyses.yml | 1 + .../pascal/taie/analysis/pta/TaintTest.java | 87 ++++--- 10 files changed, 175 insertions(+), 250 deletions(-) diff --git a/src/main/java/pascal/taie/analysis/pta/PointerAnalysis.java b/src/main/java/pascal/taie/analysis/pta/PointerAnalysis.java index f9d99bf44..9eac87966 100644 --- a/src/main/java/pascal/taie/analysis/pta/PointerAnalysis.java +++ b/src/main/java/pascal/taie/analysis/pta/PointerAnalysis.java @@ -38,6 +38,7 @@ import pascal.taie.analysis.pta.plugin.EntryPointHandler; import pascal.taie.analysis.pta.plugin.Plugin; import pascal.taie.analysis.pta.plugin.ReferenceHandler; +import pascal.taie.analysis.pta.plugin.ResultProcessor; import pascal.taie.analysis.pta.plugin.ThreadHandler; import pascal.taie.analysis.pta.plugin.exception.ExceptionAnalysis; import pascal.taie.analysis.pta.plugin.invokedynamic.InvokeDynamicAnalysis; @@ -153,7 +154,7 @@ private static void setPlugin(Solver solver, AnalysisOptions options) { if (options.getString("taint-config") != null) { plugin.addPlugin(new TaintAnalysis()); } -// plugin.addPlugin(new ResultProcessor()); + plugin.addPlugin(new ResultProcessor()); // add plugins specified in options // noinspection unchecked addPlugins(plugin, (List) options.get("plugins")); diff --git a/src/main/java/pascal/taie/analysis/pta/core/cs/element/AbstractPointer.java b/src/main/java/pascal/taie/analysis/pta/core/cs/element/AbstractPointer.java index d72bc153c..1d406345c 100644 --- a/src/main/java/pascal/taie/analysis/pta/core/cs/element/AbstractPointer.java +++ b/src/main/java/pascal/taie/analysis/pta/core/cs/element/AbstractPointer.java @@ -67,16 +67,9 @@ public void setPointsToSet(PointsToSet pointsToSet) { } @Override - public void rmFromPointsToIf(Predicate predicate) { + public void removeObjsIf(Predicate filter) { if (pointsToSet != null) { - pointsToSet.removeIf(predicate); - } - } - - @Override - public void rmFromOutEdgesIf(Predicate predicate) { - if (! outEdges.isEmpty()) { - outEdges.removeIf(predicate); + pointsToSet.removeIf(filter); } } @@ -122,6 +115,11 @@ public PointerFlowEdge addEdge(PointerFlowEdge edge) { return null; } + @Override + public void removeEdgesIf(Predicate filter) { + outEdges.removeIf(filter); + } + @Override public Set getOutEdges() { return Collections.unmodifiableSet(new ArraySet<>(outEdges, true)); diff --git a/src/main/java/pascal/taie/analysis/pta/core/cs/element/Pointer.java b/src/main/java/pascal/taie/analysis/pta/core/cs/element/Pointer.java index a2f5abd78..9c2e5d368 100644 --- a/src/main/java/pascal/taie/analysis/pta/core/cs/element/Pointer.java +++ b/src/main/java/pascal/taie/analysis/pta/core/cs/element/Pointer.java @@ -52,15 +52,16 @@ public interface Pointer extends Indexable { @Nullable PointsToSet getPointsToSet(); - void rmFromPointsToIf(Predicate predicate); - - void rmFromOutEdgesIf(Predicate predicate); - /** * Sets the associated points-to set of this pointer. */ void setPointsToSet(PointsToSet pointsToSet); + /** + * Removes objects pointed to by this pointer if they satisfy the filter. + */ + void removeObjsIf(Predicate filter); + /** * Adds filter to filter out objects pointed to by this pointer. */ @@ -101,6 +102,11 @@ public interface Pointer extends Indexable { */ PointerFlowEdge addEdge(PointerFlowEdge edge); + /** + * Removes out edges of this pointer if they satisfy the filter. + */ + void removeEdgesIf(Predicate filter); + /** * @return out edges of this pointer in pointer flow graph. */ diff --git a/src/main/java/pascal/taie/analysis/pta/plugin/CompositePlugin.java b/src/main/java/pascal/taie/analysis/pta/plugin/CompositePlugin.java index 00e51ad04..ebbd1f937 100644 --- a/src/main/java/pascal/taie/analysis/pta/plugin/CompositePlugin.java +++ b/src/main/java/pascal/taie/analysis/pta/plugin/CompositePlugin.java @@ -89,7 +89,7 @@ private void addPlugin(Plugin plugin, List plugins, } } - public void clearAllPlugins() { + public void clearPlugins() { allPlugins.clear(); onNewPointsToSetPlugins.clear(); onNewCallEdgePlugins.clear(); diff --git a/src/main/java/pascal/taie/analysis/pta/plugin/taint/SinkHandler.java b/src/main/java/pascal/taie/analysis/pta/plugin/taint/SinkHandler.java index 4a2a2d3e8..0509754d9 100644 --- a/src/main/java/pascal/taie/analysis/pta/plugin/taint/SinkHandler.java +++ b/src/main/java/pascal/taie/analysis/pta/plugin/taint/SinkHandler.java @@ -25,22 +25,22 @@ import pascal.taie.analysis.graph.callgraph.CallKind; import pascal.taie.analysis.graph.callgraph.Edge; import pascal.taie.analysis.pta.PointerAnalysisResult; -import pascal.taie.analysis.pta.core.cs.element.*; -import pascal.taie.analysis.pta.core.heap.HeapModel; +import pascal.taie.analysis.pta.core.cs.element.ArrayIndex; +import pascal.taie.analysis.pta.core.cs.element.CSObj; +import pascal.taie.analysis.pta.core.cs.element.InstanceField; +import pascal.taie.analysis.pta.core.cs.element.Pointer; import pascal.taie.analysis.pta.core.heap.Obj; import pascal.taie.analysis.pta.plugin.util.InvokeUtils; import pascal.taie.ir.exp.Var; import pascal.taie.ir.stmt.Invoke; -import pascal.taie.language.classes.JField; import pascal.taie.language.classes.JMethod; -import pascal.taie.util.Canonicalizer; -import pascal.taie.util.collection.*; +import pascal.taie.util.collection.MultiMap; +import pascal.taie.util.collection.MultiMapCollector; +import pascal.taie.util.collection.Sets; -import java.util.Collections; import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * Handles sinks in taint analysis. @@ -49,17 +49,9 @@ class SinkHandler extends Handler { private final List sinks; - private final CSManager csManager; - - private final HeapModel heapModel; - - private final PointerToSetManager ptsManager = new PointerToSetManager(); - SinkHandler(HandlerContext context) { super(context); sinks = context.config().sinks(); - csManager = context.solver().getCSManager(); - heapModel = context.solver().getHeapModel(); } Set collectTaintFlows() { @@ -100,9 +92,25 @@ private Set collectTaintFlows( SinkPoint sinkPoint = new SinkPoint(sinkCall, indexRef); // obtain objects to check for different IndexRef.Kind Set objs = switch (indexRef.kind()) { - case VAR -> ptsManager.getPointsToSet(arg); - case ARRAY -> ptsManager.getPointsToSet(arg, (Var) null); - case FIELD -> ptsManager.getPointsToSet(arg, indexRef.field()); + case VAR -> csManager.getCSVarsOf(arg) + .stream() + .flatMap(Pointer::objects) + .map(CSObj::getObject) + .collect(Collectors.toUnmodifiableSet()); + case ARRAY -> csManager.getCSVarsOf(arg) + .stream() + .flatMap(Pointer::objects) + .map(csManager::getArrayIndex) + .flatMap(ArrayIndex::objects) + .map(CSObj::getObject) + .collect(Collectors.toUnmodifiableSet()); + case FIELD -> csManager.getCSVarsOf(arg) + .stream() + .flatMap(Pointer::objects) + .map(o -> csManager.getInstanceField(o, indexRef.field())) + .flatMap(InstanceField::objects) + .map(CSObj::getObject) + .collect(Collectors.toUnmodifiableSet()); }; return objs.stream() .filter(manager::isTaint) @@ -111,38 +119,4 @@ private Set collectTaintFlows( .collect(Collectors.toSet()); } - class PointerToSetManager { - // todo: don't repeat urself! - - private static final Canonicalizer> canonicalizer = new Canonicalizer<>(); - - private Set removeContexts(Stream objects) { - Set set = new HybridBitSet<>(heapModel, true); - objects.map(CSObj::getObject).forEach(set::add); - return canonicalizer.get(Collections.unmodifiableSet(set)); - } - - Set getPointsToSet(Var var) { - return removeContexts(csManager.getCSVarsOf(var) - .stream() - .flatMap(Pointer::objects)); - } - - Set getPointsToSet(Var base, JField field) { - return removeContexts(csManager.getCSVarsOf(base) - .stream() - .flatMap(Pointer::objects) - .map(o -> csManager.getInstanceField(o, field)) - .flatMap(InstanceField::objects)); - } - - Set getPointsToSet(Var base, Var index) { - return removeContexts(csManager.getCSVarsOf(base) - .stream() - .flatMap(Pointer::objects) - .map(csManager::getArrayIndex) - .flatMap(ArrayIndex::objects)); - } - - } } diff --git a/src/main/java/pascal/taie/analysis/pta/plugin/taint/TaintAnalysis.java b/src/main/java/pascal/taie/analysis/pta/plugin/taint/TaintAnalysis.java index a0b0e74bb..d4d85dba3 100644 --- a/src/main/java/pascal/taie/analysis/pta/plugin/taint/TaintAnalysis.java +++ b/src/main/java/pascal/taie/analysis/pta/plugin/taint/TaintAnalysis.java @@ -25,15 +25,17 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import pascal.taie.World; +import pascal.taie.analysis.pta.core.cs.context.Context; import pascal.taie.analysis.pta.core.cs.element.CSManager; import pascal.taie.analysis.pta.core.cs.element.CSVar; import pascal.taie.analysis.pta.core.solver.Solver; import pascal.taie.analysis.pta.plugin.CompositePlugin; +import pascal.taie.config.AnalysisOptions; +import pascal.taie.ir.IR; +import pascal.taie.language.classes.JMethod; import pascal.taie.util.Timer; import java.io.File; -import java.io.IOException; -import java.nio.file.*; import java.util.Scanner; import java.util.Set; @@ -43,14 +45,21 @@ public class TaintAnalysis extends CompositePlugin { private static final String TAINT_FLOW_GRAPH_FILE = "taint-flow-graph.dot"; - private HandlerContext context; + private Solver solver; - private boolean callSiteMode; + private boolean isInteractive; - private TaintRestarter restarter; + private HandlerContext context; @Override public void setSolver(Solver solver) { + this.solver = solver; + AnalysisOptions options = solver.getOptions(); + isInteractive = options.getBoolean("taint-interactive"); + initilize(); + } + + private void initilize() { TaintManager manager = new TaintManager(solver.getHeapModel()); TaintConfig config = TaintConfig.loadConfig( solver.getOptions().getString("taint-config"), @@ -61,16 +70,63 @@ public void setSolver(Solver solver) { addPlugin(new SourceHandler(context), new TransferHandler(context), new SanitizerHandler(context)); + } + + private boolean reInitilize() { + clearPlugins(); + initilize(); + CSManager csManager = solver.getCSManager(); + TaintManager taintManager = context.manager(); + csManager.pointers().forEach(p -> { + p.removeObjsIf(csObj -> taintManager.isTaint(csObj.getObject())); + p.removeEdgesIf(TaintTransferEdge.class::isInstance); + }); + solver.getCallGraph().reachableMethods().forEach(csMethod -> { + JMethod method = csMethod.getMethod(); + Context ctxt = csMethod.getContext(); + IR ir = csMethod.getMethod().getIR(); + if (context.config().callSiteMode()) { + ir.forEach(stmt -> onNewStmt(stmt, method)); + } + csMethod.getEdges().forEach(this::onNewCallEdge); + this.onNewCSMethod(csMethod); + ir.getParams().forEach(param -> { + CSVar csParam = csManager.getCSVar(ctxt, param); + onNewPointsToSet(csParam, csParam.getPointsToSet()); + }); + }); + return !taintManager.getTaintObjs().isEmpty(); + } - callSiteMode = config.callSiteMode(); - restarter = new TaintRestarter(this, context.solver()); + @Override + public void onPhaseFinish() { + reportTaintFlows(); + if (isInteractive) { + Scanner scan = new Scanner(System.in); + while (true) { + logger.info("Change your taint config, and input 'r' to continue, 'e' to exit:"); + if (!scan.hasNextLine()) { + break; + } + String input = scan.nextLine().strip(); + if ("r".equals(input)) { + if (reInitilize()) { + break; + } + } else if ("e".equals(input)) { + isInteractive = false; + break; + } else { + logger.error("Invalid input"); + } + } + } } - private void sinkAndReport() { + private void reportTaintFlows() { Set taintFlows = new SinkHandler(context).collectTaintFlows(); logger.info("Detected {} taint flow(s):", taintFlows.size()); taintFlows.forEach(logger::info); - Solver solver = context.solver(); solver.getResult().storeResult(getClass().getName(), taintFlows); TaintManager manager = context.manager(); Timer.runAndCount(() -> new TFGDumper().dump( @@ -79,145 +135,4 @@ private void sinkAndReport() { "TFGDumper"); } - - public void startFileWatcher(Path filePath) throws IOException, InterruptedException { - WatchService watchService = FileSystems.getDefault().newWatchService(); - filePath.getParent().register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE); - - WatchKey key; - while (true) { - key = watchService.take(); // block until a file event occur - - for (WatchEvent event : key.pollEvents()) { - WatchEvent.Kind kind = event.kind(); - - if (kind == StandardWatchEventKinds.OVERFLOW) { - continue; - } else { - WatchEvent ev = (WatchEvent) event; - Path fileName = ev.context(); - - if (fileName.toFile().getName().equals(filePath.toFile().getName())) { - logger.info("File has been modified: " + filePath); - reloadConfigAndRestart(); - return; - } - } - } - - boolean valid = key.reset(); - if (!valid) { - break; - } - } - } - - private void reloadConfigAndRestart() { - logger.info("Reloading configuration and restarting..."); - // ... 读取配置文件 ... - restarter.start(); - } - - @Override - public void onPhaseFinish() { - boolean dynamicConfigured = true; - if (dynamicConfigured) { - // report taint flows: - sinkAndReport(); - - // wait for user's input, if `exit`, skip; if `continue`, then try file listen - System.out.println("Change your taint config and continue."); - String path = (String) context.solver().getOptions().get("taint-config"); - Path configPath = Paths.get(path); - try { - startFileWatcher(configPath); - } catch (Exception e) { - e.printStackTrace(); - } - -// Scanner scanner = new Scanner(System.in); -// while (true) { -// if (scanner.hasNextLine()) { -// String line = scanner.nextLine(); -// if (line.equals("exit") || line.equals("q")) { -// scanner.close(); -// return; -// } else if (line.equals("continue") || line.equals("c")) { -// scanner.close(); -// break; -// } else { -// System.out.println("Unknown command: " + line); -// } -// } -// } - - // gen taints - logger.info("Dynamic configuration is enabled."); - restarter.start(); - } - } - - @Override - public void onFinish() { - sinkAndReport(); - } - - class TaintRestarter { - private final TaintAnalysis taintAnalysis; - - private final Solver solver; - - private final CSManager csManager; - - TaintRestarter(TaintAnalysis taintAnalysis, Solver solver) { - csManager = solver.getCSManager(); - this.taintAnalysis = taintAnalysis; - this.solver = solver; - } - - private void reset() { - csManager.pointers().forEach(p -> { - p.rmFromPointsToIf(csObj -> context.manager().isTaint(csObj.getObject())); - p.rmFromOutEdgesIf(TaintTransferEdge.class::isInstance); - }); - } - - private void prepare() { - // clear its compositing plugins - taintAnalysis.clearAllPlugins(); - taintAnalysis.setSolver(solver); - - // add entries to WL (for taint analysis) - // SourceHandler/TransferHandler/... used - - // you have to call this earlier than onNewCSMethod, and it's designed for Call Site Mode - if (callSiteMode) { - // Must do it before anything!!! - solver.getCallGraph().reachableMethods().forEach( - m -> m.getMethod().getIR().forEach(stmt -> taintAnalysis.onNewStmt(stmt, m.getMethod())) - ); - } - - // perhaps use `edges()` ? - solver.getCallGraph().reachableMethods().forEach(m -> - m.getEdges().forEach(taintAnalysis::onNewCallEdge)); - - solver.getCallGraph().reachableMethods().forEach(m -> { - // field taint - taintAnalysis.onNewCSMethod(m); - // para taints handled here: - m.getMethod().getIR().getParams() - .forEach(para -> { - CSVar csPara = csManager.getCSVar(m.getContext(), para); - taintAnalysis.onNewPointsToSet(csPara, csPara.getPointsToSet()); - }); - }); - } - - void start() { - reset(); - prepare(); - logger.info("Start taint analysis!"); - } - } } diff --git a/src/main/java/pascal/taie/analysis/pta/pts/DelegatePointsToSet.java b/src/main/java/pascal/taie/analysis/pta/pts/DelegatePointsToSet.java index 2f0a642d0..8a57b4773 100644 --- a/src/main/java/pascal/taie/analysis/pta/pts/DelegatePointsToSet.java +++ b/src/main/java/pascal/taie/analysis/pta/pts/DelegatePointsToSet.java @@ -60,8 +60,8 @@ public boolean addAll(PointsToSet pts) { } @Override - public void removeIf(Predicate predicate) { - set.removeIf(predicate); + public void removeIf(Predicate filter) { + set.removeIf(filter); } @Override diff --git a/src/main/java/pascal/taie/analysis/pta/pts/PointsToSet.java b/src/main/java/pascal/taie/analysis/pta/pts/PointsToSet.java index af191b568..6277658a8 100644 --- a/src/main/java/pascal/taie/analysis/pta/pts/PointsToSet.java +++ b/src/main/java/pascal/taie/analysis/pta/pts/PointsToSet.java @@ -58,7 +58,10 @@ public interface PointsToSet extends Iterable, Copyable { */ PointsToSet addAllDiff(PointsToSet pts); - void removeIf(Predicate predicate); + /** + * Removes objects from this set if they satisfy the filter. + */ + void removeIf(Predicate filter); /** * @return true if this set contains given object, otherwise false. diff --git a/src/main/resources/tai-e-analyses.yml b/src/main/resources/tai-e-analyses.yml index df5bc5007..b7cfcc540 100644 --- a/src/main/resources/tai-e-analyses.yml +++ b/src/main/resources/tai-e-analyses.yml @@ -28,6 +28,7 @@ reflection-log: null # path to reflection log, required when reflection option is log taint-config: null # path to config file of taint analysis, # when this file is given, taint analysis will be enabled + taint-interactive: false # whether enable interactive taint analysis plugins: [ ] # | [ pluginClass, ... ] time-limit: -1 # set time limit (in seconds) for pointer analysis, # -1 means no time limit diff --git a/src/test/java/pascal/taie/analysis/pta/TaintTest.java b/src/test/java/pascal/taie/analysis/pta/TaintTest.java index b1dbeeff5..32d5cbda8 100644 --- a/src/test/java/pascal/taie/analysis/pta/TaintTest.java +++ b/src/test/java/pascal/taie/analysis/pta/TaintTest.java @@ -22,10 +22,15 @@ package pascal.taie.analysis.pta; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import pascal.taie.Main; import pascal.taie.analysis.Tests; import pascal.taie.util.MultiStringsSource; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + public class TaintTest { static final String DIR = "taint"; @@ -36,38 +41,60 @@ public class TaintTest { @ParameterizedTest @MultiStringsSource({"ArrayTaint", TAINT_CONFIG}) -// @MultiStringsSource({"CharArray", TAINT_CONFIG}) -// @MultiStringsSource({"FieldTaint", TAINT_CONFIG}) -// @MultiStringsSource({"LinkedQueue", TAINT_CONFIG}) -// @MultiStringsSource({"CSTaint", "cs:1-obj", TAINT_CONFIG}) -// @MultiStringsSource({"TwoObjectTaint", "cs:2-obj", TAINT_CONFIG}) -// @MultiStringsSource({"TaintCorner", TAINT_CONFIG}) -// @MultiStringsSource({"CycleTaint", TAINT_CONFIG}) -// @MultiStringsSource({"ComplexTaint", TAINT_CONFIG}) -// @MultiStringsSource({"SimpleTaint", TAINT_CONFIG}) -// @MultiStringsSource({"ArgToResult", TAINT_CONFIG}) -// @MultiStringsSource({"BaseToResult", TAINT_CONFIG}) -// @MultiStringsSource({"StringAppend", TAINT_CONFIG}) -// @MultiStringsSource({"Java9StringConcat", TAINT_CONFIG}) -// @MultiStringsSource({"OneCallTaint", "cs:1-call", TAINT_CONFIG}) -// @MultiStringsSource({"InterTaintTransfer", "cs:2-call", TAINT_CONFIG}) -// @MultiStringsSource({"TaintInList", "cs:2-obj", TAINT_CONFIG}) -// @MultiStringsSource({"BackPropagation", TAINT_CONFIG}) -// @MultiStringsSource({"CSBackPropagation", "cs:1-obj", TAINT_CONFIG}) -// @MultiStringsSource({"StaticTaintTransfer", -// TAINT_CONFIG_PREFIX + "taint-config-static-taint-transfer.yml"}) -// @MultiStringsSource({"InstanceSourceSink", -// TAINT_CONFIG_PREFIX + "taint-config-instance-source-sink.yml"}) -// @MultiStringsSource({"ArrayFieldTransfer", -// TAINT_CONFIG_PREFIX + "taint-config-array-field-transfer.yml"}) -// @MultiStringsSource({"TaintParam", -// TAINT_CONFIG_PREFIX + "taint-config-param-source.yml"}) -// @MultiStringsSource({"TaintCall", -// TAINT_CONFIG_PREFIX + "taint-config-call-source.yml"}) -// @MultiStringsSource({"CallSiteMode", -// TAINT_CONFIG_PREFIX + "taint-config-call-site-model.yml"}) + @MultiStringsSource({"CharArray", TAINT_CONFIG}) + @MultiStringsSource({"FieldTaint", TAINT_CONFIG}) + @MultiStringsSource({"LinkedQueue", TAINT_CONFIG}) + @MultiStringsSource({"CSTaint", "cs:1-obj", TAINT_CONFIG}) + @MultiStringsSource({"TwoObjectTaint", "cs:2-obj", TAINT_CONFIG}) + @MultiStringsSource({"TaintCorner", TAINT_CONFIG}) + @MultiStringsSource({"CycleTaint", TAINT_CONFIG}) + @MultiStringsSource({"ComplexTaint", TAINT_CONFIG}) + @MultiStringsSource({"SimpleTaint", TAINT_CONFIG}) + @MultiStringsSource({"ArgToResult", TAINT_CONFIG}) + @MultiStringsSource({"BaseToResult", TAINT_CONFIG}) + @MultiStringsSource({"StringAppend", TAINT_CONFIG}) + @MultiStringsSource({"Java9StringConcat", TAINT_CONFIG}) + @MultiStringsSource({"OneCallTaint", "cs:1-call", TAINT_CONFIG}) + @MultiStringsSource({"InterTaintTransfer", "cs:2-call", TAINT_CONFIG}) + @MultiStringsSource({"TaintInList", "cs:2-obj", TAINT_CONFIG}) + @MultiStringsSource({"BackPropagation", TAINT_CONFIG}) + @MultiStringsSource({"CSBackPropagation", "cs:1-obj", TAINT_CONFIG}) + @MultiStringsSource({"StaticTaintTransfer", + TAINT_CONFIG_PREFIX + "taint-config-static-taint-transfer.yml"}) + @MultiStringsSource({"InstanceSourceSink", + TAINT_CONFIG_PREFIX + "taint-config-instance-source-sink.yml"}) + @MultiStringsSource({"ArrayFieldTransfer", + TAINT_CONFIG_PREFIX + "taint-config-array-field-transfer.yml"}) + @MultiStringsSource({"TaintParam", + TAINT_CONFIG_PREFIX + "taint-config-param-source.yml"}) + @MultiStringsSource({"TaintCall", + TAINT_CONFIG_PREFIX + "taint-config-call-source.yml"}) + @MultiStringsSource({"CallSiteMode", + TAINT_CONFIG_PREFIX + "taint-config-call-site-model.yml"}) void test(String mainClass, String... opts) { Tests.testPTA(DIR, mainClass, opts); } + @Test + void testInteractiveTaintAnalysis() { + InputStream originalSystemIn = System.in; + try { + InputStream testIn = new ByteArrayInputStream("r\ne\n".getBytes()); + System.setIn(testIn); + Main.main( + "-pp", + "-cp", "src/test/resources/pta/taint", + "-m", "ArrayTaint", + "-a", "pta=" + + "implicit-entries:false;" + + "only-app:true;" + + "distinguish-string-constants:all;" + + "interactive-taint-analysis:true;" + + TAINT_CONFIG + ); + } finally { + System.setIn(originalSystemIn); + } + } + }