From 73d1bd37e6dbdc5e5a731c2f0e6b02f6114a194f Mon Sep 17 00:00:00 2001 From: "Achim D. Brucker" Date: Sun, 14 Jun 2015 09:04:57 +0200 Subject: [PATCH] Initial commit. --- .../eu/aniketos/dasca/dataflow/Activator.java | 60 ++ .../dataflow/actions/AnalyzeSourceCode.java | 151 +++ .../dasca/dataflow/tests/AllTests.java | 120 +++ .../aniketos/dasca/dataflow/tests/Test01.java | 46 + .../aniketos/dasca/dataflow/tests/Test02.java | 47 + .../aniketos/dasca/dataflow/tests/Test03.java | 39 + .../aniketos/dasca/dataflow/tests/Test04.java | 39 + .../aniketos/dasca/dataflow/tests/Test05.java | 39 + .../aniketos/dasca/dataflow/tests/Test06.java | 44 + .../aniketos/dasca/dataflow/tests/Test07.java | 39 + .../aniketos/dasca/dataflow/tests/Test08.java | 55 ++ .../aniketos/dasca/dataflow/tests/Test09.java | 55 ++ .../aniketos/dasca/dataflow/tests/Test10.java | 55 ++ .../aniketos/dasca/dataflow/tests/Test11.java | 71 ++ .../aniketos/dasca/dataflow/tests/Test12.java | 39 + .../aniketos/dasca/dataflow/tests/Test13.java | 47 + .../aniketos/dasca/dataflow/tests/Test14.java | 46 + .../aniketos/dasca/dataflow/tests/Test15.java | 55 ++ .../aniketos/dasca/dataflow/tests/Test16.java | 31 + .../aniketos/dasca/dataflow/tests/Test17.java | 31 + .../aniketos/dasca/dataflow/tests/Test18.java | 31 + .../aniketos/dasca/dataflow/tests/Test19.java | 31 + .../dasca/dataflow/util/AnalysisUtil.java | 512 ++++++++++ .../dasca/dataflow/util/PlugInUtil.java | 121 +++ .../dasca/dataflow/util/SMTChecker.java | 291 ++++++ .../dasca/dataflow/util/SuperGraphUtil.java | 872 ++++++++++++++++++ 26 files changed, 2967 insertions(+) create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/Activator.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/actions/AnalyzeSourceCode.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/AllTests.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test01.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test02.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test03.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test04.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test05.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test06.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test07.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test08.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test09.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test10.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test11.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test12.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test13.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test14.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test15.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test16.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test17.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test18.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test19.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/AnalysisUtil.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/PlugInUtil.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/SMTChecker.java create mode 100644 src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/SuperGraphUtil.java diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/Activator.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/Activator.java new file mode 100644 index 0000000..3f85c23 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/Activator.java @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "com.sap.research.analysis.wala.sourcecode"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/actions/AnalyzeSourceCode.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/actions/AnalyzeSourceCode.java new file mode 100644 index 0000000..c73cf41 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/actions/AnalyzeSourceCode.java @@ -0,0 +1,151 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.actions; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +import eu.aniketos.dasca.dataflow.util.AnalysisUtil; +import eu.aniketos.dasca.dataflow.util.PlugInUtil; +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +import com.ibm.wala.cast.java.client.JDTJavaSourceAnalysisEngine; +import com.ibm.wala.dataflow.IFDS.ICFGSupergraph; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.util.CancelException; + +/** + * Our sample action implements workbench action delegate. + * The action proxy will be created by the workbench and + * shown in the UI. When the user tries to use the action, + * this delegate will be created and execution will be + * delegated to it. + * @see IWorkbenchWindowActionDelegate + */ +public class AnalyzeSourceCode implements IWorkbenchWindowActionDelegate { + Logger log = AnalysisUtil.getLogger(AnalyzeSourceCode.class); + /** + * The constructor. + */ + public AnalyzeSourceCode() { + } + + + /** + * The action has been activated. The argument of the + * method represents the 'real' action sitting + * in the workbench UI. + * @see IWorkbenchWindowActionDelegate#run + */ + public void run(IAction action) { + + List javaProjects = new ArrayList(); + + IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + for(IProject project: projects) { + try { + project.open(null /* IProgressMonitor */); + } catch (CoreException e) { + e.printStackTrace(); + } + IJavaProject javaProject = JavaCore.create(project); + javaProjects.add(javaProject); + } + + IJavaProject javaProject = null; + String testProject = AnalysisUtil.getPropertyString(AnalysisUtil.CONFIG_ENTRY_CLASS); + + for (IJavaProject iJavaProject : javaProjects) { + boolean bool = iJavaProject.exists(); + if(bool && iJavaProject.getElementName().startsWith(testProject)) { + javaProject = iJavaProject; + } + } + + if(javaProject == null) { + javaProject = PlugInUtil.getSelectedIJavaProject(); + } + + if (javaProject != null) { + + try { + JDTJavaSourceAnalysisEngine engine = PlugInUtil.createEngine(javaProject); + + CallGraph cg = engine.buildDefaultCallGraph(); + + log.debug("callgraph generated (size:" + cg.getNumberOfNodes() + ")"); + + AnalysisCache ac = new AnalysisCache(); + ICFGSupergraph sg = ICFGSupergraph.make(cg, ac); + log.debug("supergraph generated (size:" + sg.getNumberOfNodes() + ")"); + + String entryClass = AnalysisUtil.getPropertyString(AnalysisUtil.CONFIG_ENTRY_CLASS); + String entryMethods = AnalysisUtil.getPropertyString(AnalysisUtil.CONFIG_ENTRY_METHOD); + + String[] methods = entryMethods.split(","); + for (int i = 0; i < methods.length; i++) { + String entryMethod = methods[i].trim(); + SuperGraphUtil.analyzeAndSaveSuperGraph(sg, entryClass, entryMethod); + } + + } catch (IOException e) { + e.printStackTrace(); + } catch (CoreException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (CancelException e) { + e.printStackTrace(); + } + } else { + log.error("Warning: You did not select a project or something failed while getting the project"); + } + } + + /** + * Selection in the workbench has been changed. We + * can change the state of the 'real' action here + * if we want, but this can only happen after + * the delegate has been created. + * @see IWorkbenchWindowActionDelegate#selectionChanged + */ + public void selectionChanged(IAction action, ISelection selection) { + } + + /** + * We can use this method to dispose of any system + * resources we previously allocated. + * @see IWorkbenchWindowActionDelegate#dispose + */ + public void dispose() { + } + + /** + * We will cache window object in order to + * be able to provide parent shell for the message dialog. + * @see IWorkbenchWindowActionDelegate#init + */ + public void init(IWorkbenchWindow window) { + } +} \ No newline at end of file diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/AllTests.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/AllTests.java new file mode 100644 index 0000000..c2f024a --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/AllTests.java @@ -0,0 +1,120 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import java.io.IOException; + +import org.apache.log4j.Logger; +import org.apache.log4j.chainsaw.Main; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +import eu.aniketos.dasca.dataflow.util.AnalysisUtil; +import eu.aniketos.dasca.dataflow.util.PlugInUtil; +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +import com.ibm.wala.cast.java.client.JDTJavaSourceAnalysisEngine; +import com.ibm.wala.cast.java.client.JavaSourceAnalysisEngine; +import com.ibm.wala.dataflow.IFDS.ICFGSupergraph; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.util.CancelException; + +@RunWith(Suite.class) +@SuiteClasses({ + /* Test01.class, Test02.class, Test03.class, Test04.class, + Test05.class, */ Test06.class /*, Test07.class, Test08.class, + Test09.class, Test10.class, Test11.class, Test12.class, + Test13.class, Test14.class, Test15.class, Test16.class, + Test17.class, Test18.class, Test19.class +*/ +}) + +public class AllTests { + private static final Logger log = AnalysisUtil.getLogger(SuperGraphUtil.class); + protected static ICFGSupergraph superGraph = null; + protected static ICFGSupergraph superGraph2 = null; + + @BeforeClass + public static void init() { +// +// IJavaProject javaProject = null; +// IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); +// for (IProject project : projects) { +// try { +// project.open(null /* IProgressMonitor */); +// } catch (CoreException e) { +// e.printStackTrace(); +// } +// IJavaProject javaProjectintern = JavaCore.create(project); +// if(javaProjectintern.getElementName().equals("TestCases")){ +// log.warn("Found project with name 'TestCases' ("+javaProjectintern+")"); +// javaProject = javaProjectintern; +// } +// } +// + + try { + /* log.warn("javaProject = "+javaProject); + JDTJavaSourceAnalysisEngine engine = PlugInUtil.createEngine(javaProject); + log.warn("Engine = "+engine); + CallGraph cg = engine.buildDefaultCallGraph(); + log.warn("CallGraph = "+cg); + */ String [] classes= { + /* "Ltests/Test01" + ,"Ltests/Test02" + ,"Ltests/Test03" + ,"Ltests/Test04" + ,"Ltests/Test05" + ,*/ + "Ltests/Test06" + /* ,"Ltests/Test07" + ,"Ltests/Test08" + ,"Ltests/Test09" + ,"Ltests/Test10" + ,"Ltests/Test11" + ,"Ltests/Test12" + ,"Ltests/Test13" + ,"Ltests/Test14" + ,"Ltests/Test15" + ,"Ltests/Test16" + ,"Ltests/Test17" + ,"Ltests/Test18" + ,"Ltests/Test19" + */ + }; + CallGraph cg = com.sap.research.wala.cross.javajs.SingleLanguageBuilders.makeJavaCG("test.jar", classes).fst; + AnalysisCache ac = new AnalysisCache(); + log.warn("AnalsyisCache = "+ac); +// CallGraph cg = Main.makeJavaCG(); + superGraph = ICFGSupergraph.make(cg, ac); + superGraph2 = superGraph; + log.warn("SuperGraph = "+superGraph); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (CancelException e) { + e.printStackTrace(); + } catch (ClassHierarchyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test01.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test01.java new file mode 100644 index 0000000..1445175 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test01.java @@ -0,0 +1,46 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test01 { + + String entryClass = "Test01"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test02.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test02.java new file mode 100644 index 0000000..45bf0cf --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test02.java @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test02 { + + String entryClass = "Test02"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test03.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test03.java new file mode 100644 index 0000000..79b8afa --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test03.java @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test03 { + + String entryClass = "Test03"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test04.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test04.java new file mode 100644 index 0000000..b734ce9 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test04.java @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test04 { + + String entryClass = "Test04"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test05.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test05.java new file mode 100644 index 0000000..9080d54 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test05.java @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test05 { + + String entryClass = "Test05"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test06.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test06.java new file mode 100644 index 0000000..148eb7e --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test06.java @@ -0,0 +1,44 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test06 { + + String entryClass = "Test06"; + + @Test + public void testBad() { + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test07.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test07.java new file mode 100644 index 0000000..5ac4adb --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test07.java @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test07 { + + String entryClass = "Test07"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test08.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test08.java new file mode 100644 index 0000000..3a1906e --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test08.java @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test08 { + + String entryClass = "Test08"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + + @Test + public void testGood03() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good03"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test09.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test09.java new file mode 100644 index 0000000..642fab2 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test09.java @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test09 { + + String entryClass = "Test09"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + + @Test + public void testGood03() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good03"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test10.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test10.java new file mode 100644 index 0000000..55839f7 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test10.java @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test10 { + + String entryClass = "Test10"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + + @Test + public void testGood03() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good03"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test11.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test11.java new file mode 100644 index 0000000..8af4477 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test11.java @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test11 { + + String entryClass = "Test11"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + + @Test + public void testGood03() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good03"); + assertEquals(0, result); + return; + } + + @Test + public void testGood04() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good04"); + assertEquals(0, result); + return; + } + + @Test + public void testGood05() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good05"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test12.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test12.java new file mode 100644 index 0000000..7d6b9c5 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test12.java @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test12 { + + String entryClass = "Test12"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test13.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test13.java new file mode 100644 index 0000000..a389131 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test13.java @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test13 { + + String entryClass = "Test13"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test14.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test14.java new file mode 100644 index 0000000..54c038e --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test14.java @@ -0,0 +1,46 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test14 { + + String entryClass = "Test14"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test15.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test15.java new file mode 100644 index 0000000..1bb4c85 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test15.java @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test15 { + + String entryClass = "Test15"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + + @Test + public void testGood01() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good01"); + assertEquals(0, result); + return; + } + + @Test + public void testGood02() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good02"); + assertEquals(0, result); + return; + } + + @Test + public void testGood03() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "good03"); + assertEquals(0, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test16.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test16.java new file mode 100644 index 0000000..cf69ba3 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test16.java @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test16 { + + String entryClass = "Test16"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test17.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test17.java new file mode 100644 index 0000000..b532113 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test17.java @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test17 { + + String entryClass = "Test17"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(2, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test18.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test18.java new file mode 100644 index 0000000..7c754ee --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test18.java @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test18 { + + String entryClass = "Test18"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(1, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test19.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test19.java new file mode 100644 index 0000000..5578bd2 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/tests/Test19.java @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.tests; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import eu.aniketos.dasca.dataflow.util.SuperGraphUtil; + +public class Test19 { + + String entryClass = "Test19"; + + @Test + public void testBad() { + AllTests.init(); + int result = SuperGraphUtil.analyzeAndSaveSuperGraph(AllTests.superGraph, entryClass, "bad"); + assertEquals(2, result); + return; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/AnalysisUtil.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/AnalysisUtil.java new file mode 100644 index 0000000..50a6885 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/AnalysisUtil.java @@ -0,0 +1,512 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.util; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Properties; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.osgi.framework.Bundle; + +import eu.aniketos.dasca.dataflow.Activator; + +import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl.ConcreteJavaMethod; +import com.ibm.wala.cast.java.ssa.AstJavaInvokeInstruction; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.DefaultEntrypoint; +import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; +import com.ibm.wala.ipa.cfg.BasicBlockInContext; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.SSABinaryOpInstruction; +import com.ibm.wala.ssa.SSAConditionalBranchInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.ssa.analysis.IExplodedBasicBlock; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.TypeName; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.config.AnalysisScopeReader; + +/** + * static class for graph independent helper methods and constants + * + */ +public class AnalysisUtil { + + private static final Logger log = AnalysisUtil.getLogger(AnalysisUtil.class); + + /** + * Relative path to the main configuration file + */ + public static final String PLUGIN_MAIN_CONFIG = "config/main.config"; + + /** + * Relative path to the logging configuration file + */ + public static final String LOGGING_FILE = "logging_properties_file"; + + /** + * Boolean value of configuration file, if subgraphs should be included into the DOT file + */ + public static final String CONFIG_BOOLEAN_PRINT_SUBGRAPHS = "bool_print_subgraphs"; + + /** + * DOT files will be generated into the specified sub directory of the working directory + */ + public static final String CONFIG_DOT_PATH = "dot_path"; + + /** + * DOT files will be generated into the specified sub directory of the working directory + */ + public static final String CONFIG_DOT_REMOVE_EMPTY_NODES = "dot_remove_empty_nodes"; + + /** + * Specifies which project contains the entry class + */ + public static final String CONFIG_ANALYSIS_PROJECT = "analysis_project"; + + /** + * Specifies which class contains the entry method + */ + public static final String CONFIG_ENTRY_CLASS = "analysis_entry_class"; + + /** + * Specifies the entry methods of the analysis + */ + public static final String CONFIG_ENTRY_METHOD = "analysis_entry_method"; + + /** + * Specifies sanitizing methods of the analysis + */ + public static final String CONFIG_SANITIZER = "analysis_sanitizer"; + + /** + * Specifies bad source methods of the analysis + */ + public static final String CONFIG_BAD_SRC = "analysis_bad_src"; + + /** + * Specifies the depth (precision) of the analysis + */ + public static final String CONFIG_ANALYSIS_DEPTH = "analysis_depth"; + public static final int ANALYSIS_DEPTH_DETECTION = 0; + public static final int ANALYSIS_DEPTH_EXCLUSIVE = 1; + public static final int ANALYSIS_DEPTH_SANITIZING = 2; + + /** + * Specifies where to find the exclusion file + */ + public static final String CONFIG_EXCLUSION_FILE = "analysis_exclusion_file"; + + /** + * Gets callgraph for given parameters (binary analysis only) + * @param exclusionFilePath + * @param classPath + * @param entryClass + * @param entryMethod + * @return + */ + public static CallGraph getCallGraph(String exclusionFilePath, String classPath, String entryClass, String entryMethod) { + AnalysisScope scope = null; + ClassHierarchy cha = null; + HashSet entryPoints = null; + try { + File exclusionFile = new File(exclusionFilePath); + scope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(classPath, exclusionFile); // works with class and jar files + cha = ClassHierarchy.make(scope); + + ClassLoaderReference clr = scope.getApplicationLoader(); + entryPoints = HashSetFactory.make(); + for(IClass class1 : cha) { + if(class1.getClassLoader().getReference().equals(clr)) { + Collection allMethods = class1.getDeclaredMethods(); + for(IMethod m : allMethods) { + if(m.isPrivate()) { + continue; + } + TypeName tn = m.getDeclaringClass().getName();//MainApplication + if(tn.toString().contains("/" + entryClass) && m.getName().toString().contains(entryMethod)) { // TODO: too weak + entryPoints.add(new DefaultEntrypoint(m, cha)); + } + } + } + } + // Iterable result1 = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha); // uses the static main methods as entry methods + if(entryPoints.size() == 0) { + log.error("Could not find specified entry point for analysis.\n" + + " path: " + classPath + "\n" + + " class: " + entryClass + "\n" + + " method: " + entryMethod); + System.exit(1); + } + AnalysisOptions options = new AnalysisOptions(scope, entryPoints); + + // CallGraphBuilder builder = com.ibm.wala.ipa.callgraph.impl.Util.makeRTABuilder(options, new AnalysisCache(), cha, scope); // Rapid Type Analysis + SSAPropagationCallGraphBuilder builder = com.ibm.wala.ipa.callgraph.impl.Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); // 0-CFA = context-insensitive, class-based heap + // CallGraphBuilder builder = com.ibm.wala.ipa.callgraph.impl.Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); // 0-1-CFA = context-insensitive, allocation-site-based heap + // CallGraphBuilder builder = com.ibm.wala.ipa.callgraph.impl.Util.makeZeroOneContainerCFABuilder(options, new AnalysisCache(), cha, scope); // 0-1-Container-CFA = object-sensitive container + + return builder.makeCallGraph(options); + } catch (Exception e) { + log.error("Error while building the call graph"); + e.printStackTrace(); + System.exit(1); + return null; + } + } + + /** + * Gets the corresponding integer value of the given property name, or 0 if no integer value was found + * @param name + * @return + */ + public static int getPropertyInteger(String name) { + String value = getPropertyString(name); + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return 0; + } + } + + /** + * Gets the corresponding boolean value of the given property name, or false if no value was found + * @param name + * @return + */ + public static boolean getPropertyBoolean(String name) { + String value = getPropertyString(name); + return value.equalsIgnoreCase("yes") | value.equalsIgnoreCase("true"); + } + + /** + * Gets the corresponding value of the given property name, or an empty String if no value was found + * @param name + * @return + */ + public static String getPropertyString(String name) { + Properties properties = new Properties(); + BufferedInputStream stream; + try { + Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID); + Path path = new Path(PLUGIN_MAIN_CONFIG); + InputStream in; + if(bundle!=null) { // Util is called from eclipse PlugIn + URL fileURL = FileLocator.find(bundle, path, null); + in = fileURL.openStream(); + } else { // Util is called from java Application + File f = new File("config/main.config"); + in = new FileInputStream(f); + } + stream = new BufferedInputStream(in); + properties.load(stream); + stream.close(); + } catch (FileNotFoundException e) { + System.err.println("no config file found"); + return ""; + } catch (IOException e) { + e.printStackTrace(); + return ""; + } + String value = properties.getProperty(name); + + return value == null ? "" : value; + } + + /** + * Removes all chars from the string which confuse dotty
+ * Currently '<' and '>'
+ * Expand this if you run into trouble with other chars + * @param input + * @return + */ + public static String sanitize(String input) { + String output = ""; + + for (char c : input.toCharArray()) { + if (!(c == '<' || c == '>')) { + output += c; + } else { + output += ' '; + } + } + return output; + } + + /** + * Get root logger + * @param class + * @return + */ + public static org.apache.log4j.Logger getLogger(Class class1) { + Logger log = Logger.getLogger(class1); + PropertyConfigurator.configure(getPropertyString(LOGGING_FILE)); + return log; + } + + /** + * Get source code line number for each instruction + * @param sgNodes + * @param print + * @return + */ + public static HashMap getLineNumbers(HashMap> sgNodes) { + log.debug("** get source code line number for each instruction"); + HashMap map = new HashMap(); + for(BasicBlockInContext bbic : sgNodes.values()) { + SSAInstruction inst = bbic.getLastInstruction(); + if(inst == null) { + continue; + } + IMethod method = bbic.getMethod(); + int lineNumber = method.getLineNumber(bbic.getLastInstructionIndex()); + map.put(inst, lineNumber); + log.debug(lineNumber + ". " + inst); + } + return map; + } + + /** + * Get corresponding instruction for the definition of each SSA value + * @param sgNodes + * @return + */ + public static HashMap getDefs(HashMap> sgNodes) { + log.debug("** get definition instruction for each SSA value"); + HashMap map = new HashMap(); + for(BasicBlockInContext bbic : sgNodes.values()) { + SymbolTable symbolTable = bbic.getNode().getIR().getSymbolTable(); + DefUse du = bbic.getNode().getDU(); + + for (int i = 0; i <= symbolTable.getMaxValueNumber(); i++) { + log.debug(i + " [" + symbolTable.getValueString(i) + "] " + du.getDef(i)); + map.put(i, du.getDef(i)); + } + break; // there are the same definitions in each basic block, iff there is only one method FIXME: read different scopes, if multiple methods are required + } + return map; + } + + /** + * Get the corresponding instruction for each SQL execution (java.sql) + * @return + */ + public static ArrayList getSQLExecutes(HashMap> sgNodes) { + log.debug("** get SQL execution instructions"); + ArrayList list = new ArrayList(); + for(BasicBlockInContext bbic : sgNodes.values()) { + SSAInstruction inst = bbic.getLastInstruction(); + if(inst != null && inst instanceof AstJavaInvokeInstruction && inst.toString().contains("java/sql") && inst.toString().contains("execute")) { + log.debug("SQL execution instruction: " + inst.toString()); + list.add(inst); + } + } + return list; + } + + /** + * Get the corresponding instruction for each conditional branch + * @return + */ + public static ArrayList getConditions(HashMap> sgNodes) { + log.debug("** get conditional branch instructions"); + ArrayList list = new ArrayList(); + for(BasicBlockInContext bbic : sgNodes.values()) { + SSAInstruction inst = bbic.getLastInstruction(); + if(inst != null && inst instanceof SSAConditionalBranchInstruction) { + log.debug("conditional branch instruction: " + inst.toString()); + list.add(inst); + } + } + return list; + } + + + /** + * Prints adjacency list to log using debug level + * @param adjList + */ + public static void printAdjList(HashMap> adjList, Logger log) { + ArrayList keySet1 = new ArrayList(adjList.keySet()); + Collections.sort(keySet1); + for (Integer src: keySet1) { + log.debug(" " + src + ":"); + StringBuffer sb = new StringBuffer(); + for(Integer dest : adjList.get(src)) { + sb.append(", " + dest); + } + sb.append(" "); + log.debug(" " + sb.substring(1)); + } + } + + public static ArrayList analyzeStatementExecute( + SSAInstruction ssaInstruction, + HashMap definitions, + boolean prepared, + HashSet badMethods) { + + if(prepared) { + ssaInstruction = definitions.get(ssaInstruction.getUse(0)); + } + + ArrayList sources = new ArrayList(); + int use = ssaInstruction.getUse(1); // use 0 is the createStatement, use 1 is the SQL String + SSAInstruction inst = definitions.get(use); + if(inst != null) { + String instString = inst.toString(); + if(isBadSource(instString, badMethods)) { + if(!sources.contains(inst)) { + log.debug("SINK [bad]: " + ssaInstruction); + sources.add(inst); + } + } + if(inst instanceof SSABinaryOpInstruction) { + if(isBadBinaryOpSource(use, definitions, sources, badMethods)) { + log.debug("SINK [bad]: " + ssaInstruction); + return sources; + } else { + log.debug("SINK [good]: " + ssaInstruction); + } + } else if(inst instanceof SSAPhiInstruction) { + if(isBadPhiInstruction(use, definitions, sources, badMethods)) { + log.debug("SINK [bad]: " + ssaInstruction); + return sources; + } else { + log.debug("SINK [good]: " + ssaInstruction); + } + } else { //FIXME: rewrite to according procedure + log.debug("unidentified instruction [" + instString + "], handled like phi function"); + if(isBadPhiInstruction(use, definitions, sources, badMethods)) { + log.debug("SINK [bad]: " + ssaInstruction); + return sources; + } else { + log.debug("SINK [good]: " + ssaInstruction); + } + } + + } else { // is constant String + log.debug("SINK [good]: " + ssaInstruction.toString()); + } + return sources; + } + + public static boolean isBadSource(String instString, HashSet badMethods) { + if(instString != null) { + for (String src : badMethods) { + if(instString.contains(src)) { + return true; + } + } + } + return false; + } + + private static boolean isBadBinaryOpSource(int use, HashMap definitions, ArrayList badSources, HashSet badMethods) { + SSAInstruction inst = definitions.get(use); + int part1 = inst.getUse(0); + SSAInstruction inst1 = definitions.get(part1); + String inst1String = ""; + if(inst1 != null) { + inst1String = inst1.toString(); + } + + int part2 = inst.getUse(1); + SSAInstruction inst2 = definitions.get(part2); + String inst2String = ""; + if(inst2 != null) { + inst2String = inst2.toString(); + } + + boolean isBad = false; + if(inst1 == null) { + isBad = isBad | false; + } else if(inst1 instanceof SSABinaryOpInstruction) { + isBad = isBad | isBadBinaryOpSource(part1, definitions, badSources, badMethods); + } else if(inst1 instanceof SSAPhiInstruction) { + isBad = isBad | isBadPhiInstruction(part1, definitions, badSources, badMethods); + } else if(isBadSource(inst1String, badMethods)) { + if(!badSources.contains(inst1)) { + log.debug("SOURCE [bad]: " + inst1String); + badSources.add(inst1); + } + isBad = true; + } + if(inst2 == null) { + isBad = isBad | false; + } else if(inst2 instanceof SSABinaryOpInstruction) { + isBad = isBad | isBadBinaryOpSource(part2, definitions, badSources, badMethods); + } else if(inst2 instanceof SSAPhiInstruction) { + isBad = isBad | isBadPhiInstruction(part2, definitions, badSources, badMethods); + } else if(isBadSource(inst2String, badMethods)) { + if(!badSources.contains(inst2)) { + log.debug("SOURCE [bad]: " + inst2String); + badSources.add(inst2); + } + isBad = true; + } + return isBad; + } + + + private static boolean isBadPhiInstruction(int use, + HashMap definitions, + ArrayList badSources, HashSet badMethods) { + SSAInstruction inst = definitions.get(use); + boolean isBad = false; + SSAPhiInstruction phiInst = (SSAPhiInstruction) inst; + for(int i=0; i makeDefaultEntrypoints(AnalysisScope scope, IClassHierarchy cha) { + String [] classes= { + "Ltests/Test01" + ,"Ltests/Test02" + ,"Ltests/Test03" + ,"Ltests/Test04" + ,"Ltests/Test05" + ,"Ltests/Test06" + ,"Ltests/Test07" + ,"Ltests/Test08" + ,"Ltests/Test09" + ,"Ltests/Test10" + ,"Ltests/Test11" + ,"Ltests/Test12" + ,"Ltests/Test13" + ,"Ltests/Test14" + ,"Ltests/Test15" + ,"Ltests/Test16" + ,"Ltests/Test17" + ,"Ltests/Test18" + ,"Ltests/Test19" + }; + + + return Util.makeMainEntrypoints(JavaSourceAnalysisScope.SOURCE,cha, classes); + + } + }; + engine.setExclusionsFile(REGRESSION_EXCLUSIONS); + + return engine; + } + +} diff --git a/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/SMTChecker.java b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/SMTChecker.java new file mode 100644 index 0000000..c3d4467 --- /dev/null +++ b/src/eu.aniketos.dasca.dataflow/src/main/java/eu/aniketos/dasca/dataflow/util/SMTChecker.java @@ -0,0 +1,291 @@ +/* + * (C) Copyright 2010-2015 SAP SE. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + */ + +package eu.aniketos.dasca.dataflow.util; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.ibm.wala.cast.ir.ssa.AstConstants; +import com.ibm.wala.cast.java.ssa.AstJavaInvokeInstruction; +import com.ibm.wala.shrikeBT.BinaryOpInstruction; +import com.ibm.wala.shrikeBT.IBinaryOpInstruction.IOperator; +import com.ibm.wala.ssa.ConstantValue; +import com.ibm.wala.ssa.DefUse; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSABinaryOpInstruction; +import com.ibm.wala.ssa.SSACFG.BasicBlock; +import com.ibm.wala.ssa.SSAConditionalBranchInstruction; +import com.ibm.wala.ssa.SSAConversionInstruction; +import com.ibm.wala.ssa.SSAGetInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SSAUnaryOpInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.FieldReference; +import com.ibm.wala.types.TypeReference; + +import cvc3.Expr; +import cvc3.ValidityChecker; + +public class SMTChecker { + + private static Logger log = AnalysisUtil.getLogger(SMTChecker.class); + + public static Expr getExprForCondition(ValidityChecker vc, BasicBlock basicBlock, IR entryIR) { + // According to WALA documentation these blocks contain exactly one instruction + SSAConditionalBranchInstruction inst = (SSAConditionalBranchInstruction) basicBlock.getLastInstruction(); + int var = inst.getUse(0); // This Instruction contains exactly two uses (0, 1) and use 1 is always 0. + Expr expr = getExprForInstruction(vc, var, entryIR, null); + + return expr; + } + + /** + * Returns simple expression for loop-condition. Expects for-loop with simple comparison with constant on the right hand side + * + *
TODO: implement correct for all kinds of loops + * @param vc + * @param inst + * @param entryIR + * @return + */ + public static Expr getExprForLoop(ValidityChecker vc, SSAInstruction inst, IR entryIR) { + // According to WALA documentation these blocks contain exactly one instruction + SSAConditionalBranchInstruction condInst = (SSAConditionalBranchInstruction) inst; + int var = condInst.getUse(0); // This Instruction contains exactly the two uses 0 and 1. Use 1 has always the value 0, since it stands for TRUE. + SymbolTable symTab = entryIR.getSymbolTable(); + DefUse du = new DefUse(entryIR); + + SSAInstruction useInst = du.getDef(var); + SSABinaryOpInstruction binOpInstruction = (SSABinaryOpInstruction) useInst; + + int varNo0 = useInst.getUse(0); // value at the left hand side + + Expr exprLhs = null; + SSAInstruction leftInstruction = du.getDef(varNo0); + SSAPhiInstruction phiInstruction = (SSAPhiInstruction) leftInstruction; + for(int i = 0; i< phiInstruction.getNumberOfUses(); i++) { // TODO: use bit array to identify overflows + int varNo = phiInstruction.getUse(i); + if(symTab.isIntegerConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Integer integer = (Integer) value.getValue(); + exprLhs = vc.exprFromString("" + integer.intValue()); + break; + } else if(symTab.isLongConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Long longValue = (Long) value.getValue(); + exprLhs = vc.exprFromString("" + longValue.longValue()); + break; + } else if(symTab.isDoubleConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Double doubleValue = (Double) value.getValue(); + exprLhs = vc.exprFromString("" + doubleValue.doubleValue()); + break; + } else if(symTab.isFloatConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Float floatValue = (Float) value.getValue(); + exprLhs = vc.exprFromString("" + floatValue.floatValue()); + break; + } + } + + int varNo1 = useInst.getUse(1); // value at the right hand side + + Expr exprRhs; + if(symTab.isIntegerConstant(varNo1)) { // TODO: use bit array to identify overflows + ConstantValue value = (ConstantValue) symTab.getValue(varNo1); + Integer integer = (Integer) value.getValue(); + exprRhs = vc.exprFromString("" + integer.intValue()); + } else if(symTab.isLongConstant(varNo1)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo1); + Long longValue = (Long) value.getValue(); + exprRhs = vc.exprFromString("" + longValue.longValue()); + } else if(symTab.isDoubleConstant(varNo1)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo1); + Double doubleValue = (Double) value.getValue(); + exprRhs = vc.exprFromString("" + doubleValue.doubleValue()); + } else if(symTab.isFloatConstant(varNo1)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo1); + Float floatValue = (Float) value.getValue(); + exprRhs = vc.exprFromString("" + floatValue.floatValue()); + } else { + exprRhs = vc.varExpr(String.format("v%d",varNo1), vc.realType()); + } + + IOperator op = binOpInstruction.getOperator(); + + if(op == BinaryOpInstruction.Operator.OR) { + return vc.orExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.AND) { + return vc.andExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.SUB) { + return vc.minusExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.ADD) { + return vc.plusExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.DIV) { + return vc.divideExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.MUL) { + return vc.multExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.LT) { + return vc.ltExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.LE) { + return vc.leExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.EQ) { + return vc.eqExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.GE) { + return vc.geExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.GT) { + return vc.gtExpr(exprLhs, exprRhs); + } else { + return vc.notExpr(vc.eqExpr(exprLhs, exprRhs)); + } + } + + public static Expr getExprForConditionalBranchInstruction(ValidityChecker vc, SSAInstruction inst, IR entryIR) { + // According to WALA documentation these blocks contain exactly one instruction + SSAConditionalBranchInstruction condInst = (SSAConditionalBranchInstruction) inst; + int var = condInst.getUse(0); // This Instruction contains exactly two uses (0, 1) and use 1 is always 0. + Expr expr = getExprForInstruction(vc, var, entryIR, BinaryOpInstruction.Operator.AND); // The AND operator identifies the expression as a boolean type + + return expr; + } + + private static Expr getExprForInstruction(ValidityChecker vc, int varNo, IR ir, IOperator op2) { + SymbolTable symTab = ir.getSymbolTable(); + if(symTab.isConstant(varNo)) { + if(symTab.isBooleanConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + boolean isTrueConstant = value.isTrueConstant(); + if(symTab.isTrue(varNo)) { + return vc.trueExpr(); + } else if(symTab.isFalse(varNo)) { + return vc.falseExpr(); + } + return vc.varExpr(String.format("v%d",varNo), vc.boolType(), (isTrueConstant) ? vc.trueExpr() : vc.falseExpr()); + } else if(symTab.isNumberConstant(varNo)) { // TODO: use bit array to identify overflows + if(symTab.isIntegerConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Integer integer = (Integer) value.getValue(); + return vc.exprFromString("" + integer.intValue()); + } else if(symTab.isLongConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Long longValue = (Long) value.getValue(); + return vc.exprFromString("" + longValue.longValue()); + } else if(symTab.isDoubleConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Double doubleValue = (Double) value.getValue(); + return vc.exprFromString("" + doubleValue.doubleValue()); + } else if(symTab.isFloatConstant(varNo)) { + ConstantValue value = (ConstantValue) symTab.getValue(varNo); + Float floatValue = (Float) value.getValue(); + return vc.exprFromString("" + floatValue.floatValue()); + } + } else if(symTab.isTrue(varNo)) { + return vc.trueExpr(); + } else if(symTab.isFalse(varNo)) { + return vc.falseExpr(); + } else if(symTab.isNullConstant(varNo)) { + return vc.nullExpr(); + } + } else { + DefUse du = new DefUse(ir); + SSAInstruction defInst = du.getDef(varNo); + if(defInst == null) { + if(op2 == BinaryOpInstruction.Operator.OR || op2 == BinaryOpInstruction.Operator.AND) { + return vc.varExpr(String.format("v%d",varNo), vc.boolType()); + } else { + return vc.varExpr(String.format("v%d",varNo), vc.realType()); + } + } else if(defInst instanceof SSAGetInstruction) { // def refers to static value + SSAGetInstruction inst = (SSAGetInstruction) defInst; + FieldReference fr = inst.getDeclaredField(); + TypeReference tr = fr.getFieldType(); + if(tr.equals(TypeReference.Boolean)) { + return vc.varExpr(String.format("v%d",varNo), vc.boolType()); + } + } + if(defInst instanceof SSABinaryOpInstruction) { + SSABinaryOpInstruction binaryInst = (SSABinaryOpInstruction) defInst; + + IOperator op = binaryInst.getOperator(); + + // BinaryInstructions always contain exactly two uses + + // left hand side + int var1 = binaryInst.getUse(0); + Expr exprLhs = getExprForInstruction(vc, var1, ir, op); + + // right hand side + int var2 = binaryInst.getUse(1); + Expr exprRhs = getExprForInstruction(vc, var2, ir, op); + + if(op == BinaryOpInstruction.Operator.OR) { + return vc.orExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.AND) { + return vc.andExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.SUB) { + return vc.minusExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.ADD) { + return vc.plusExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.DIV) { + return vc.divideExpr(exprLhs, exprRhs); + } else if(op == BinaryOpInstruction.Operator.MUL) { + return vc.multExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.LT) { + return vc.ltExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.LE) { + return vc.leExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.EQ) { + return vc.eqExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.GE) { + return vc.geExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.GT) { + return vc.gtExpr(exprLhs, exprRhs); + } else if(op == AstConstants.BinaryOp.NE) { + return vc.notExpr(vc.eqExpr(exprLhs, exprRhs)); + } + } else if(defInst instanceof SSAUnaryOpInstruction) { // WALA uses unary operation ONLY for negation + SSAUnaryOpInstruction unaryInst = (SSAUnaryOpInstruction) defInst; + + int var = unaryInst.getUse(0); + Expr expr = getExprForInstruction(vc, var, ir, BinaryOpInstruction.Operator.AND); + return vc.notExpr(expr); + } else if(defInst instanceof SSAConversionInstruction) { + SSAConversionInstruction conversionInst = (SSAConversionInstruction) defInst; + + // ConversionInstructions always contain exactly one use + int var = conversionInst.getUse(0); + return getExprForInstruction(vc, var, ir, op2); + } else if(defInst instanceof SSAPhiInstruction) { + SSAPhiInstruction phiInst = (SSAPhiInstruction) defInst; + List expr = new ArrayList(); + for(int i = 0; i iDs, + ICFGSupergraph sg, + HashMap> sgNodes, + HashMap, Integer> sgNodesReverse, + ArrayList acceptedMethods, + int currentId, + int endId) { + if(iDs.contains(currentId)) { + return; + } + iDs.add(currentId); + if(currentId == endId) { + return; + } + BasicBlockInContext bbic = sgNodes.get(currentId); + boolean isInvoke = bbic.getLastInstruction() instanceof SSAInvokeInstruction; + boolean isStringConcat = isInvoke && bbic.getLastInstruction().toString().contains("StringBuilder") && (bbic.getLastInstruction().toString().contains("append") | bbic.getLastInstruction().toString().contains("toString")); + + Iterator> sucIt = sg.getSuccNodes(bbic); + while(sucIt.hasNext()) { + BasicBlockInContext nextChild = sucIt.next(); + + if(isStringConcat) { + if(!sucIt.hasNext()) { // last association of a String concatenation is java intern + continue; + } + } + + MethodReference method = nextChild.getMethod().getReference(); + if(isInvoke) { + if(!acceptedMethods.contains(method)) { + acceptedMethods.add(method); + } + } else { + if(!acceptedMethods.contains(method)) { + log.debug("supergraph cut at '" + bbic.getNumber() + " -> " + nextChild.getNumber() + " (" + nextChild.toString() + ")'"); + continue; + } + } + + IExplodedBasicBlock del = nextChild.getDelegate(); + if(del.isEntryBlock() && del.toString().contains("init")) { + log.debug("supergraph cut at '" + bbic.getNumber() + " -> " + nextChild.getNumber() + " (" + nextChild.toString() + ")'"); + continue; + } + relevantPathSearch(iDs, sg, sgNodes, sgNodesReverse, acceptedMethods, sgNodesReverse.get(nextChild), endId); + } + } + + /** + * Analyzes the supergraph and saves the relevant part as a dot file to the location <graphs folder>/> completeIterator = sg.iterator(); + int analysisLevel = AnalysisUtil.getPropertyInteger(AnalysisUtil.CONFIG_ANALYSIS_DEPTH); + + HashMap> sgNodes = new HashMap>(); + HashMap, Integer> sgNodesReversed = new HashMap, Integer>(); + HashMap sgNodesInstId = new HashMap(); + ArrayList acceptedMethods = new ArrayList(); + + // Add all blocks into a Map with a unique identifier in both directions and find entry/exit node + int i = 0; + int mainEntryId = 0; + int mainExitId = 0; + while (completeIterator.hasNext()) { + BasicBlockInContext current = completeIterator.next(); + sgNodes.put(i, current); + sgNodesReversed.put(current, i); + Iterator instIt = current.iterator(); + while (instIt.hasNext()) { + SSAInstruction inst = instIt.next(); + sgNodesInstId.put(inst, i); + /* add to include other required methods into CFG + if(inst instanceof AstJavaInvokeInstruction){ + AstJavaInvokeInstruction in = (AstJavaInvokeInstruction) inst; + MethodReference meth = in.getDeclaredTarget(); + if(meth.toString().contains("calledMethod")){ // check for required method + acceptedMethods.add(meth); + } + } + //*/ + + } + String signature = current.getMethod().getSignature(); + // find entry and exit nodes + if(signature.contains(entryClass) && signature.contains(entryMethod) && current.isEntryBlock()) { // FIXME: entry/exit nodes definition via name is too weak + mainEntryId = i; + } else if(signature.contains(entryClass) && signature.contains(entryMethod) && current.isExitBlock()) { + mainExitId = i; + } + i++; + } + if(mainEntryId == 0 && mainExitId == 0) { + log.error("empty entry method, ensure invocation in main method"); + return 0; + } + HashSet relevantIDs = new HashSet(); + BasicBlockInContext bbic = sgNodes.get(mainEntryId); + acceptedMethods.add(bbic.getMethod().getReference()); + log.debug("start recursive graph building"); + relevantPathSearch(relevantIDs, sg, sgNodes, sgNodesReversed, acceptedMethods, mainEntryId, mainExitId); + + // remove irrelevant nodes (not on at least one path between entry and exit node) + log.debug("remove irrelevant nodes"); + for (int j = 0; j < i; j++) { + BasicBlockInContext tmp = sgNodes.get(j); + if(!relevantIDs.contains(j)) { + sgNodesReversed.remove(tmp); + sgNodes.remove(j); + } + } + + // build separate adjacency list + log.debug("build seperate adjacency list"); + HashMap> adjList = new HashMap>(); + HashMap> adjListReverse = new HashMap>(); + + boolean removeEmptyNodes = AnalysisUtil.getPropertyBoolean(AnalysisUtil.CONFIG_DOT_REMOVE_EMPTY_NODES); + ArrayList emptyNodes = new ArrayList(); + + buildAdjacencyLists(sg, sgNodes, sgNodesReversed, adjList, adjListReverse, emptyNodes, relevantIDs); + + /* <<< print original adjacency list to log + log.debug("adjacency list before removing empty nodes:"); + AnalysisUtil.printAdjList(adjList, log); + //*/ + if(removeEmptyNodes) { + removeEmptyNodes(emptyNodes, adjList, adjListReverse, sgNodes, sgNodesReversed); + } + + log.debug("add conditions to graph nodes"); + ArrayList visited = new ArrayList(); + ArrayList currentConditions = new ArrayList(); + HashMap currentConditionsEndId = new HashMap(); + HashMap> finalConditions = new HashMap>(); + HashMap loops = new HashMap(); + addConditionsToGraph(sgNodes, adjList, mainEntryId, visited, mainExitId, currentConditions, currentConditionsEndId, finalConditions, loops); + + // remove goto statements for later analysis steps + for (int loopId : loops.keySet()) { + int gotoId = loops.get(loopId); + int gotoTargetId = adjList.get(gotoId).get(0); // goto has exact one child + int afterLoopId = 0; + for(int id : adjList.get(loopId)) { + afterLoopId = Math.max(afterLoopId, id); + } + ArrayList newList = new ArrayList(); + newList.add(afterLoopId); + adjList.put(gotoId, newList); + adjListReverse.get(afterLoopId).add(gotoId); + ArrayList gotoTargetReverseList = adjListReverse.get(gotoTargetId); + ArrayList newGotoTargetReverseList = new ArrayList(); + for (int child : gotoTargetReverseList) { + if(child != gotoId) { + newGotoTargetReverseList.add(child); + } + } + adjListReverse.put(gotoTargetId, newGotoTargetReverseList); + } + + /* <<< print required conditions for each node + for (Integer key : finalConditions.keySet()) { + StringBuffer sb = new StringBuffer(); + for(int condition : finalConditions.get(key)){ + sb.append(", " + condition); + }sb.append(" "); + log.debug(key + ": " + sb.substring(2)); + } + //*/ + + /* <<< print changed adjacency list to log + log.debug("adjacency list after removing empty nodes:"); + AnalysisUtil.printAdjList(adjList, log); + //*/ + +//* <<< get definition instruction for each SSA value + HashMap definitions = AnalysisUtil.getDefs(sgNodes); +//*/ + +//* <<< get source code line number for each instruction + HashMap lineNumbers = AnalysisUtil.getLineNumbers(sgNodes); +//*/ + +//* <<< get the corresponding instruction for each condition inside the callgraph + ArrayList conditionsList = AnalysisUtil.getConditions(sgNodes); + ArrayList conditionsIdList = new ArrayList(); + for (SSAInstruction cond : conditionsList) { + conditionsIdList.add(sgNodesInstId.get(cond)); + } +//*/ +//* <<< get the corresponding source code line number for each condition (node id) inside the callgraph + HashMap conditionLineNumber = new HashMap(); + for (SSAInstruction instCondition : conditionsList) { + int nodeId = sgNodesInstId.get(instCondition); + int lineNumber = lineNumbers.get(instCondition); + conditionLineNumber.put(nodeId, lineNumber); + } + +//*/ + +//* <<< build CVC3 expressions from conditional instruction + + log.debug("** get CVC3 expressions for each conditional branch instruction"); + HashMap expressions = new HashMap(); + IR entryIR = sgNodes.values().iterator().next().getNode().getIR(); + vc.pop(); + vc.push(); + for (SSAInstruction instCondition : conditionsList) { + int condId = sgNodesInstId.get(instCondition); + if(loops.keySet().contains(condId)) { + Expr expr = SMTChecker.getExprForLoop(vc , instCondition, entryIR); + expressions.put(sgNodesInstId.get(instCondition), expr); + } else { + Expr expr = SMTChecker.getExprForConditionalBranchInstruction(vc , instCondition, entryIR); + expressions.put(sgNodesInstId.get(instCondition), expr); + } + vc.pop(); + vc.push(); + } + vc.pop(); + vc.push(); +//*/ + + ArrayList sqlExecutes = AnalysisUtil.getSQLExecutes(sgNodes); + + log.debug("** get source/sink pairs for each SQL instruction"); + + String sanitizerMethods = AnalysisUtil.getPropertyString(AnalysisUtil.CONFIG_SANITIZER); // good sources are specified as sanitizer + + String[] methods = sanitizerMethods.split(","); + HashSet sanitizer = new HashSet(); + for (int k = 0; k < methods.length; k++) { + String sanitizerMethod = methods[k].trim(); + sanitizer.add(sanitizerMethod); + } + + String badSourceMethods = AnalysisUtil.getPropertyString(AnalysisUtil.CONFIG_BAD_SRC); + + methods = badSourceMethods.split(","); + HashSet badMethods = new HashSet(); + for (int k = 0; k < methods.length; k++) { + String badMethod = methods[k].trim() + "()"; + badMethods.add(badMethod); + } + + //* <<< get possible vulnerabilities for each SQL execute + + HashMap> sinkSources = new HashMap>(); + for (SSAInstruction ssaInstruction : sqlExecutes) { + boolean isPreparedStmt = ssaInstruction.toString().contains("Prepared"); + sinkSources.put(ssaInstruction, AnalysisUtil.analyzeStatementExecute(ssaInstruction, definitions, isPreparedStmt, badMethods)); + } + boolean containsVulnerability = false; + for (SSAInstruction sink : sqlExecutes) { + if(!sinkSources.containsKey(sink)) { // no vulnerability possible + continue; + } + ArrayList badSources = sinkSources.get(sink); + if(badSources != null) { + for (SSAInstruction source : badSources) { + boolean isNotMutuallyExclusive = true; + if(analysisLevel >= AnalysisUtil.ANALYSIS_DEPTH_EXCLUSIVE) { + isNotMutuallyExclusive = isNotMutuallyExclusive(sink, source, sgNodesInstId, finalConditions, expressions, vc); + } + if(isNotMutuallyExclusive) { + boolean isNotSanitized = true; + if(analysisLevel >= AnalysisUtil.ANALYSIS_DEPTH_SANITIZING) { + isNotSanitized = isNotSanitized(sgNodesInstId.get(source), sgNodesInstId.get(sink), adjList, finalConditions, expressions, vc, conditionsIdList, sanitizer, sgNodes); + } + if(isNotSanitized) { + weaknessCount++; + containsVulnerability = true; + log.warn("SQL execute [" + lineNumbers.get(sink) + "] with bad source readLine [" + lineNumbers.get(source) + "] (" + entryClass + "." + entryMethod + ")"); + } + } + } + } + } + if(!containsVulnerability) { + log.info("(" + entryClass + "." + entryMethod + ") is save"); + } +//*/ + + + String filePath = String.format("%s_SG.dot", entryMethod); + generateDotFile(sgNodes, adjList, entryClass, filePath, finalConditions); + return weaknessCount; + } + + /** + * Computes all possible control flows between source and sink and checks, if every single path is sanitized. + * @return true, iff there exists at least one direct unsanitized path between source and sink + */ + private static boolean isNotSanitized(int sourceId, + int sinkId, HashMap> adjList, + HashMap> finalConditions, + HashMap expressions, + ValidityChecker vc, + ArrayList conditionsIdList, + HashSet sanitizer, + HashMap> sgNodes) { + + log.debug("** get possible control flows from source to sink"); + HashMap>> paths = new HashMap>>(); + + calculatePaths(sourceId, sinkId, adjList, paths); + HashSet> pathList = paths.get(sourceId); + HashSet> possibleFlowPaths = new HashSet>(); + + for (ArrayList path : pathList) { + boolean isPossibleFlow = isPossibleFlow(path, finalConditions, expressions, vc, conditionsIdList); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < path.size(); i++) { + sb.append(" -> " + path.get(i)); + } + sb.append(" "); + if(isPossibleFlow) { + log.debug("FLOW [possible]: " + sb.substring(3)); // cut off the last arrow + possibleFlowPaths.add(path); + } else { + log.debug("FLOW [impossible]: " + sb.substring(3)); + } + } + loopPossiblePaths: + for (ArrayList possibleFlowPath : possibleFlowPaths) { + boolean containsSanitizer = false; + for (String sanitizerMethod : sanitizer) { + for(int nodeId : possibleFlowPath) { + BasicBlockInContext node = sgNodes.get(nodeId); + SSAInstruction inst = node.getLastInstruction(); + if(inst != null) { + if(inst.toString().contains(sanitizerMethod)) { + containsSanitizer = true; + continue loopPossiblePaths; + } + } + } + } + if(!containsSanitizer) { + return true; // path contains no sanitizer => is direct path between bad source and bad sink + } + } + return false; // every possible path contained at least one sanitizer + } + + private static boolean isPossibleFlow(ArrayList path, + HashMap> finalConditions, + HashMap expressions, + ValidityChecker vc, + ArrayList conditionsIdList) { + vc.pop(); + vc.push(); + List allExpr = new ArrayList(); + ArrayList allConditions = new ArrayList(); + for (int i=0; i conditions = finalConditions.get(node); + if(conditionsIdList.contains(node)) { + ArrayList childConditions = finalConditions.get(path.get(i+1).intValue()); + if(childConditions == null || childConditions.isEmpty() || !(childConditions.contains(node) | childConditions.contains(-node))) { // jump over if-block without else part => else condition needs to be set + allExpr.add(vc.notExpr(expressions.get(node))); + } + } + if(conditions != null) { + for (int condId : conditions) { + if(!allConditions.contains(condId)) { + allConditions.add(condId); + if(condId < 0) { + allExpr.add(vc.notExpr(expressions.get(Math.abs(condId)))); + } else { + allExpr.add(expressions.get(condId)); + } + } + } + } + } + if(allExpr.isEmpty()) { + return true; + } + Expr completeExpr = vc.andExpr(allExpr); + SatResult satResult = vc.checkUnsat(completeExpr); + boolean satisfiable = satResult.equals(SatResult.SATISFIABLE); + log.info("checking expression [" + (satisfiable?"SAT":"UNSAT") + "]: " + completeExpr); + return satisfiable; + } + + private static void calculatePaths(int currentId, int target, + HashMap> adjList, + HashMap>> paths) { + + ArrayList children = adjList.get(currentId); + HashSet> currentPaths = new HashSet>(); + + for(int child : children) { + if(child == target) { + ArrayList last = new ArrayList(); + last.add(child); + currentPaths.add(last); + continue; + } + calculatePaths(child, target, adjList, paths); + HashSet> childPaths = paths.get(child); + if(childPaths!= null) { + for (ArrayList childPath : childPaths) { + ArrayList newPath = new ArrayList(); + newPath.add(child); + newPath.addAll(childPath); + currentPaths.add(newPath); + } + } + } + paths.put(currentId, currentPaths); + } + + /** + * Checks, if sink and source node are mutually excluded because of the respective conditions + * @param sink + * @param source + * @param sgNodesInstId + * @param finalConditions + * @param expressions + * @param vc + * @return + */ + private static boolean isNotMutuallyExclusive(SSAInstruction sink, + SSAInstruction source, + HashMap sgNodesInstId, + HashMap> finalConditions, + HashMap expressions, ValidityChecker vc) { + vc.pop(); + vc.push(); + int sourceId = sgNodesInstId.get(source); + int sinkId = sgNodesInstId.get(sink); + ArrayList combinedConditions = new ArrayList(); + if(finalConditions.containsKey(sourceId)) { + combinedConditions.addAll(finalConditions.get(sourceId)); + } + if(finalConditions.containsKey(sinkId)) { + combinedConditions.addAll(finalConditions.get(sinkId)); + } + Expr expr = getConditionExpression(combinedConditions, expressions, vc); + vc.pop(); + vc.push(); + if(expr.toString().equalsIgnoreCase("null")) { + return true; + } + SatResult satResult = vc.checkUnsat(expr); + boolean satisfiable = satResult.equals(SatResult.SATISFIABLE); + return satisfiable; + } + + private static Expr getConditionExpression(ArrayList nodeIds, HashMap expressions, ValidityChecker vc) { + if(nodeIds.isEmpty()) { + return vc.nullExpr(); + } + List exprList = new ArrayList(); + for (int i=0; i emptyNodes, + HashMap> adjList, + HashMap> adjListReverse, HashMap> sgNodes, HashMap,Integer> sgNodesReversed) { + + Collections.sort(emptyNodes); + StringBuffer sb = new StringBuffer(); + for (int integer : emptyNodes) { + sb.append(", " + integer); + } + sb.append(" "); + log.debug("empty nodes in supergraph:" + sb.substring(1)); + + // remove empty nodes from supergraph + log.debug("remove empty nodes from supergraph"); + for (Integer kill: emptyNodes) { + ArrayList children = adjList.get(kill); + if(children == null) { + children = new ArrayList(); + } + // insert new edges around removed nodes + for(Integer father : adjListReverse.get(kill)) { + ArrayList tmpList = adjList.get(father); + if(tmpList==null) { + tmpList = new ArrayList(); + } + tmpList.remove(kill); + tmpList.addAll(children); + for (Integer childId : children) { + ArrayList childFathers = adjListReverse.get(childId); + if(childFathers==null) { + childFathers = new ArrayList(); + } + childFathers.remove(kill); + childFathers.add(father); + adjListReverse.put(childId, childFathers); + } + adjList.put(father, tmpList); + } + } + for (Integer kill: emptyNodes) { // requires two loops to build the new edges correct + adjList.remove(kill); + sgNodesReversed.remove(sgNodes.get(kill)); + sgNodes.remove(kill); + } + + } + + private static void buildAdjacencyLists( + ICFGSupergraph sg, HashMap> sgNodes, + HashMap, Integer> sgNodesReversed, + HashMap> adjList, + HashMap> adjListReverse, + ArrayList emptyNodes, HashSet relevantIDs) { + + for (int key1 : sgNodes.keySet()) { + BasicBlockInContext val1 = sgNodes.get(key1); + Iterator> sucIt = sg.getSuccNodes(val1); + // add 'key1->sucId' to adjList + ArrayList list = adjList.get(key1); + if(list == null) { + list = new ArrayList(); + } + while (sucIt.hasNext()) { + BasicBlockInContext suc = sucIt.next(); + if(!sgNodesReversed.containsKey(suc)) { + continue; + } + int sucId = sgNodesReversed.get(suc); + + if(!list.contains(sucId)) { + list.add(sucId); + } + + // add 'sucId->key1' to adjListReverse + ArrayList listReverse = adjListReverse.get(sucId); + if(listReverse == null) { + listReverse = new ArrayList(); + } + if(!listReverse.contains(key1)) { + listReverse.add(key1); + } + adjListReverse.put(sucId, listReverse); + + // add empty nodes to list + Iterator it = suc.iterator(); + if(relevantIDs.contains(sucId)) { + if(!emptyNodes.contains(sucId)) { + if(!it.hasNext() && !suc.isEntryBlock() && !suc.isExitBlock() && !suc.isCatchBlock()) { + emptyNodes.add(sucId); + } + } + } + } + adjList.put(key1, list); + } + } + + /** + * Analyzes the given nodes of the supergraph and fills the list finalConditions + * @param sgNodes + * @param adjList + * @param currentId + * @param visited + * @param mainEndId + * @param currentConditions + * @param currentConditionsEndId + * @param finalConditions + * @param loops + * @return + */ + private static boolean addConditionsToGraph( // boolean return is used in recursion to signalize the existence of an else block + HashMap> sgNodes, + HashMap> adjList, + Integer currentId, + ArrayList visited, + Integer mainEndId, + ArrayList currentConditions, + HashMap currentConditionsEndId, + HashMap> finalConditions, + HashMap loops) { + + if(!visited.contains(currentId)) { + visited.add(currentId); + } + + if(currentId == mainEndId) { + finalConditions.put(mainEndId, new ArrayList()); + return false; + } + SSAInstruction currentInstruction = sgNodes.get(currentId).getLastInstruction(); + ArrayList children = adjList.get(currentId); + + Integer ifStart = 0; + Integer ifEnd = 0; + + if(!currentConditions.isEmpty()) { // inside an if-block + + ifStart = currentConditions.get(currentConditions.size()-1); // last condition is the most inner condition + ifEnd = currentConditionsEndId.get(ifStart); + + if(currentId > Math.abs(ifEnd) && sgNodes.get(currentId).isCatchBlock()) { // most inner if block has else AND current node is join + return false; + } + + if(currentId > Math.abs(ifEnd) && Math.abs(ifEnd) != mainEndId) { // most inner if block has else AND current node is join + currentConditionsEndId.put(ifStart,currentId); + return true; + } + + if(currentId.intValue() == ifEnd.intValue()) { // end of single if block + return false; + } + + if(currentId == (-ifEnd)) { // end of else block + ArrayList tmpCond = new ArrayList(currentConditions); + HashMap tmpCondEnd = new HashMap(currentConditionsEndId); + int lastId = currentConditions.size(); + while(lastId > 0 && currentId == -tmpCondEnd.get(tmpCond.get(--lastId))) { // delete all conditions, which end at this node + Integer del = currentConditions.get(lastId); + currentConditions.remove(del); + currentConditionsEndId.remove(del); + } + } + } // END IF inside an if-block + if(currentInstruction instanceof SSAConditionalBranchInstruction) { + + Integer childTrue = Math.min(children.get(0), children.get(1)); // WALA always takes the true branch first + Integer childFalse = Math.max(children.get(0), children.get(1)); + + ArrayList conditions = new ArrayList(); + for(int i =0; i its an if block without else and without any instructions after it + if(isLastIfBlock) { + childTrue = Math.max(children.get(0), children.get(1)); + currentConditionsEndId.put(currentId, mainEndId); + } else { + currentConditionsEndId.put(currentId, childFalse); + } + + boolean isRealIfElse = addConditionsToGraph(sgNodes, adjList, childTrue, visited, mainEndId, currentConditions, currentConditionsEndId, finalConditions, loops); + + currentConditions.remove(currentId); + Integer newEnd = currentConditionsEndId.remove(currentId); + + if(isRealIfElse) { + currentConditions.add(-currentId); + currentConditionsEndId.put(-currentId, -newEnd); // last visited is the reached join from if-block + } + if(!isLastIfBlock) { + return addConditionsToGraph(sgNodes, adjList, childFalse, visited, mainEndId, currentConditions, currentConditionsEndId, finalConditions, loops); + } + return isRealIfElse; + } // END IF conditional branch instruction + else if(currentInstruction instanceof SSAGotoInstruction) { + int child = children.get(0); // goto always points to exactly one child node + + if(currentId == Math.abs(ifEnd)-1) { // last node of if block + ArrayList conditions = new ArrayList(); + for(int i =0; i conditions = new ArrayList(); + for(int i =0; i> sgNodes, + HashMap> adjList, String entryClass, + String filePath, HashMap> finalConditions) { + FileWriter fstream; + try { + log.debug("start generating dot file"); + String path = AnalysisUtil.getPropertyString(AnalysisUtil.CONFIG_DOT_PATH) + File.separator; + path += "java" + File.separator; + + File sgDir = new File(path + entryClass); + sgDir.mkdirs(); + File sgFile = new File(path + entryClass + File.separator + filePath); + fstream = new FileWriter(sgFile); + BufferedWriter out = new BufferedWriter(fstream); + + out.write("digraph SuperGraph {"); + out.newLine(); + out.write("node [shape=record];"); + out.newLine(); + + // add relevant nodes to dot + log.debug("add nodes to dot file"); + for (Integer key : sgNodes.keySet()) { + BasicBlockInContext val = sgNodes.get(key); + Iterator insIt = val.iterator(); + + IExplodedBasicBlock del = val.getDelegate(); + + + int key2 = del.getGraphNodeId(); //cfg.getNumber(val); + + // print the labels and define the id (key) + out.write(key + " ["); + out.write("label = \" " + key + "-" + key2 + "| " + AnalysisUtil.sanitize(val.getMethod().getSignature())); + + IR ir = val.getNode().getIR(); + SymbolTable symTab = ir.getSymbolTable(); + + int j = 2; + + // print the instruction field of the label + while (insIt.hasNext()) { +// insCount++; + SSAInstruction ins = insIt.next(); + if(ins instanceof SSAConditionalBranchInstruction) { + ins = (SSAConditionalBranchInstruction) ins; + SSAInstruction cmp = val.getNode().getDU().getDef(ins.getUse(0)); + if(cmp instanceof SSABinaryOpInstruction) { + SSABinaryOpInstruction bCmp = (SSABinaryOpInstruction) cmp; + out.write(" | " + bCmp.toString(symTab)); + } + } else if(ins instanceof SSAInvokeInstruction) { + //TODO + } + out.write(" | " + AnalysisUtil.sanitize(ins.toString(symTab))); + } + if(finalConditions.containsKey(key)) { + StringBuffer sb = new StringBuffer(); + for(int condition : finalConditions.get(key)) { + sb.append(", " + condition); + } + sb.append(" "); + out.write(" | " + sb.substring(2)); + } + if(val.isEntryBlock()) { + out.write(" | [ENTRY]"); + } else if(val.isExitBlock()) { + out.write(" | [EXIT]"); + } else if(val.isCatchBlock()) { + out.write(" | [CATCH]"); + } + out.write("\"];"); + out.newLine(); + } + + // add relevant edges to dot + log.debug("add edges to dot file"); + for (Integer src : adjList.keySet()) { + for(int dest : adjList.get(src)) { + out.write(src + "->" + dest + ";"); + out.newLine(); + } + } + + // write dot file to file system + out.write("}"); + out.close(); + log.info("dot file generated (" + sgFile.getAbsolutePath() + ")"); + } catch (IOException e) { + e.printStackTrace(); + } + } +}