diff --git a/patchAdapter/.gitignore b/patchAdapter/.gitignore new file mode 100644 index 0000000..6d92c47 --- /dev/null +++ b/patchAdapter/.gitignore @@ -0,0 +1,6 @@ +*~ +target +*.jar +test/ +*originalclasses.out +**/.DS_Store \ No newline at end of file diff --git a/patchAdapter/README.md b/patchAdapter/README.md new file mode 100644 index 0000000..a774edf --- /dev/null +++ b/patchAdapter/README.md @@ -0,0 +1,59 @@ +# Patch Adapter + * a tool for adjusting software patches so that they can be used for hotfixing with a Java agent that uses the Instrumentation API + * this project depends on [Soot](https://github.com/soot-oss/soot)! + + +## Motivation for a patch adapter: + * Not all changes in a patch are supported when performing hotfixing! Change types that are not supported will cause Java Agents to throw UnsupportedOperation Exceptions. If these are not handled properly it can result in JVM shutdown, and even if they are handled, it means that the patch simply cannot be used, until it is adjusted. This tool does that, automatically! + * currently follows [Instrumentation API](https://docs.oracle.com/en/java/javase/15/docs/api/java.instrument/java/lang/instrument/Instrumentation.html#redefineClasses(java.lang.instrument.ClassDefinition...)) constraints from `redefineClasses` method in JavaSE 15 + * specific class file changes supported by `redefineClasses` described in [jvmti docs](https://docs.oracle.com/en/java/javase/15/docs/specs/jvmti.html#RedefineClasses) + +## How it works: + * the tool runs in two phases, where each invokes a new run of Soot + 1) renames the set of original classes listed in x.originalclasses.out and places in to the directory specified by the `renamedOriginals` option + 2) Soot loads both the renamed originals and the classes in the patch, then : + * SemanticDiffer detects differences of interest between the versions + * SemanticDiffer passes points of interest to PatchAdapter to transform the redefinition classes + * a set of (possibly transformed) classes are emitted into the directory `adapterOutput` + * x.originalclasses.out must contain names of all classes to be analysed by the patch adapter, this includes any containing references to added/removed fields/methods, patch adapter does not currently support discovery of locations (in non-specified classes) that require adjustment + * patch class set must be located in directories, jar class loading is not currently supported + +## How to build: + * `mvn clean compile assembly:single` will build the application including dependencies + + +## How to run: +``` +java -cp $cp differ.SemanticDiffer -cp cpplaceholder -w -renameDestination tempDirectory -finalDestination adapterOutput -redefcp redefDir -runRename [true/false] -mainClass mainClass -fullDir [true/false] -originalclasslist x.originalclasses.out Example +``` + * where: + * $cp is the path to the SemanticDiffer package + * cpplaceholder contains the following (in the listed order): + * originaldir: the directory of the original version of the class + * rt.jar: a path to the jvm's rt + * jce.jar: a path to the jvms crypto library + * the directory of the patch/redefined version of the relevant classes + * tempDirectory is the name that you would like to be used for the temporary directory that will contain a set of renamed classes that are output in the first invocation of Soot in the patch adapter + * adapterOutput is the name that you would like to be used for the directory that is used for the final output of the patch adapter + * redefDir is the directory of the patch/redefined version of the relevant classes + * runrename controls whether the first invocation of Soot is run, i.e., whether the renamed set of classes will be output to the tempDirectory. If this step has already been performed for some patch, and those files are still present, then runRename can safely be set to false + * mainClass is a (currently non) optional argument and can be used to set the "main class" that is used for the second invocation of Soot in the patch adapter. If the mainClass argument is omitted, then the first class in the originalclasses file will be used, however mainClass is currently used to set the package names when loading classes in the patch adapter specific run(s) of Soot. In the future a smarter approach would be to retain package names from x.originalclasses.out, or to have a loader discover classes in the patch directory, or to load from jars. + * fullDir is an optional argument that specifies whether you would like Soot to use the redefcp option path as the directory to consider all classes from. If set to true, in Soot's callgraph (CG) generation, all classes in redefcp are considered application classes and each of their methods are modelled as entry points to the application. If set to false, only (all) methods in the mainClass class will be used as entry points for the CG, which may be unrealistic, depending on the patch structure. + * x.originalclasses.out is the file that contains the names of the classes that are relevant to the patch, and should be analysed by the patch adapter, both for diffing purposes and for fixing purposes + * Example is any class, as a placeholder to get Soot up and running in a way that it is familiar with, however Example is included in this project, so for simplicity sake, Example can be used. Currently compiled into `target/classes/`, so anything that runs needs to keep that in mind, cp-wise. + +## Testing: + * to setup the patch classes required for testing, first run `./makePatchClasses.sh` + * then tests can be run with: `mvn test` + * testing requires additional heap, currently set in `pom.xml`, minimum required is 1gb + * to run only one test: `mvn -Dtest=ValidationTest#BTestRunFieldAddition test` + * to expand the testset: + 1) create the **patch version** to use as a test class in `src/main/java/testexamples/` + 2) get the classfile for that, i.e., `mvn compile` + 3) find the classfile for the new patch (`find . -name X.class`), then copy it and its source to `src/main/java/patch/testexamples/' + 4) rename the package for the source in `src/main/java/testexamplespatch//patch/testexamples/` to `patch.testexamples.` so that when this recompiles when rebuilding the project, it does not conflict with original version of same class. Additionally they are each in a separate test dir in case the process_dir option of Soot is used during testing (set by useFullDir). + 5) now create the corresponding **original version** of that class in `src/main/java/testexamples/` + 6) add corresponding tests for this added setup (see below for important detail) + 7) add to the `makePatchClasses.sh` script to assure that setup can occur correctly + * tests are setup to run in alphabetical order, a surefire way to ensure that they are run sequentially. If they are run in parallel, Soot will share many values, as it uses several singletons to model the application and this could cause issues if it is done unintentionally + * tests additionally must use the `TestSetup.testSetupRefresh` method to refresh all Soot settings, and pause to allow for that to commence, otherwise there will likely be overlapping data in Soot's model of the application, which can cause issues. \ No newline at end of file diff --git a/patchAdapter/makePatchClasses.sh b/patchAdapter/makePatchClasses.sh new file mode 100755 index 0000000..61101b6 --- /dev/null +++ b/patchAdapter/makePatchClasses.sh @@ -0,0 +1,66 @@ +###################### +# +# Makes the set of patch classes +# necesesary due to the fact that +# maven will not allow 2 variants of +# same class, which is necessary to have +# a patch set and original set for testing +# +# If you expand the testset, add to this file! +# +# To cleanup the products of this, after testing, use: +# find resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/ -name "*.class" | xargs rm +# +# +# IF THIS SCRIPT FAILS PARTWAY THROUGH: +# you should fix the issue then run the rest of the steps copy/paste style +# if you restart the whole script you might erase the original copies of test setup classes +# +###################### + +mkdir TEMP +echo "----------------------------------------" +echo "Copying original versions of source files into TEMP" +cp -r src/main/java/testexamples TEMP/ +echo "----------------------------------------" + +echo "----------------------------------------" +echo "Copying patch sets into build location" +cp resources/testexamplespatch/fieldaddition/patch/testexamples/fieldaddition/*.java src/main/java/testexamples/fieldaddition/ +cp resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/*.java src/main/java/testexamples/methodremoval/ +cp resources/testexamplespatch/nochange/patch/testexamples/nochange/*.java src/main/java/testexamples/nochange/ +cp resources/testexamplespatch/methodadditionmonomorphic/patch/testexamples/methodadditionmonomorphic/*.java src/main/java/testexamples/methodadditionmonomorphic +cp resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/*.java src/main/java/testexamples/methodadditionpolymorphic +echo "----------------------------------------" + +echo "----------------------------------------" +echo "Compiling!" +mvn compile +echo "----------------------------------------" + +if [[ "$?" -ne 0 ]] ; then + echo 'Could not compile test setup'; exit $rc + +else + + echo "----------------------------------------" + echo "Copying patch classfiles into expected directory for patch adapter testing" + cp target/classes/testexamples/fieldaddition/* resources/testexamplespatch/fieldaddition/patch/testexamples/fieldaddition/ + cp target/classes/testexamples/methodremoval/* resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/ + cp target/classes/testexamples/nochange/* resources/testexamplespatch/nochange/patch/testexamples/nochange/ + cp target/classes/testexamples/methodadditionmonomorphic/* resources/testexamplespatch/methodadditionmonomorphic/patch/testexamples/methodadditionmonomorphic/ + cp target/classes/testexamples/methodadditionpolymorphic/* resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/ + echo "----------------------------------------" + + echo "----------------------------------------" + echo "Replacing original versions of source files" + cp -r TEMP/testexamples/ src/main/java/testexamples/ + echo "----------------------------------------" + + + echo "----------------------------------------" + echo "Cleaning up!" + rm -rf TEMP + echo "----------------------------------------" + +fi diff --git a/patchAdapter/pom.xml b/patchAdapter/pom.xml new file mode 100644 index 0000000..7cc75dd --- /dev/null +++ b/patchAdapter/pom.xml @@ -0,0 +1,105 @@ + + + + 4.0.0 + + differ + ssDiffTool + 1.0-SNAPSHOT + + ssDiffTool + + + UTF-8 + 1.8 + 1.8 + + + + + + ca.mcgill.sable + soot + 3.3.0 + + + + commons-cli + commons-cli + 1.4 + + + + + junit + junit + 4.11 + test + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + alphabetical + -Xmx1g + + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + maven-assembly-plugin + + + + differ.SemanticDiffer + + + + jar-with-dependencies + + + + + + + + diff --git a/patchAdapter/resources/testexamplespatch/fieldaddition/patch/testexamples/fieldaddition/AdditionFieldTest.java b/patchAdapter/resources/testexamplespatch/fieldaddition/patch/testexamples/fieldaddition/AdditionFieldTest.java new file mode 100644 index 0000000..9c50798 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/fieldaddition/patch/testexamples/fieldaddition/AdditionFieldTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.fieldaddition; + +public class AdditionFieldTest { + + public int newField; + public static int secondNewField = 1; + + public int returnSame(int x){ + int local = x; + newField = local; + return newField; + } + + public int returnAValue(){ + return secondNewField; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionmonomorphic/patch/testexamples/methodadditionmonomorphic/AdditionMethodMonomorphicTest.java b/patchAdapter/resources/testexamplespatch/methodadditionmonomorphic/patch/testexamples/methodadditionmonomorphic/AdditionMethodMonomorphicTest.java new file mode 100644 index 0000000..b06f5f4 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionmonomorphic/patch/testexamples/methodadditionmonomorphic/AdditionMethodMonomorphicTest.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionmonomorphic; + +/* + * Test scenarios for new methods: + * + * (old == pre-existing) + * + * 1) new instance call in old method + * 2) new static call in old method + * 3) old instance method call in new method + * 4) new instance method call in new method + * 5) old field access in new method + */ + +public class AdditionMethodMonomorphicTest { + + public int field; + + public int returnSamePlusSeven(int x){ + field = 7; + int temp = newMethod(x); //1 + thirdNewMethod(); //2 + return temp; + } + + public void testPrinter(){ + System.out.println("Hello World!"); + } + + public int newMethod(int y){ + testPrinter(); //3 + secondNewMethod(); //4 + return field + y; //5 + } + + public void secondNewMethod(){ + System.out.println("This is second new method!"); + } + + public static void thirdNewMethod(){ + System.out.println("This is third new method!"); + } +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFive.java b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFive.java new file mode 100644 index 0000000..8580e12 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFive.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) parent method in patch version + * 2) grandparent method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildFive extends AdditionMethodPolymorphicTestChildOne { + + +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFour.java b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFour.java new file mode 100644 index 0000000..6031d48 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFour.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) parent method in patch version and original version + * + */ + +public class AdditionMethodPolymorphicTestChildFour extends AdditionMethodPolymorphicTestChildTwo { + + +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildOne.java b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildOne.java new file mode 100644 index 0000000..33e01e3 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildOne.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * child class which relies on: + * 1) parent method in original version + * 2) overriding method in patch version + * + */ + +public class AdditionMethodPolymorphicTestChildOne extends AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 1; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildSix.java b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildSix.java new file mode 100644 index 0000000..19f5127 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildSix.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) parent method in original version + * 2) overriding method in patch version + */ + +public class AdditionMethodPolymorphicTestChildSix extends AdditionMethodPolymorphicTestChildTwo { + + public int emitMethod(){ + return 6; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildThree.java b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildThree.java new file mode 100644 index 0000000..6e13702 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildThree.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) overriding method in patch version + * 2) grand-parent method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildThree extends AdditionMethodPolymorphicTestChildOne { + + public int emitMethod(){ + return 3; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildTwo.java b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildTwo.java new file mode 100644 index 0000000..7515fee --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildTwo.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * child class which relies on: + * 1) overriding method in original version and patch version + */ + +public class AdditionMethodPolymorphicTestChildTwo extends AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 2; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestParent.java b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestParent.java new file mode 100644 index 0000000..3a17ac4 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodadditionpolymorphic/patch/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestParent.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +public class AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 0; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFive.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFive.java new file mode 100644 index 0000000..7669b03 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFive.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) grandparent method in patch version + * 2) parent method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildFive extends AdditionMethodPolymorphicTestChildOne { + + +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFour.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFour.java new file mode 100644 index 0000000..98c64cd --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFour.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) parent method in patch version and original version + * + */ + +public class AdditionMethodPolymorphicTestChildFour extends AdditionMethodPolymorphicTestChildTwo { + + +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildOne.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildOne.java new file mode 100644 index 0000000..07cc662 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildOne.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * child class which relies on: + * 1) overriding method in original version + * 2) parent method in patch version + * + */ + +public class AdditionMethodPolymorphicTestChildOne extends AdditionMethodPolymorphicTestParent { + + /* + public int emitMethod(){ + return 1; + } + */ +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildSix.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildSix.java new file mode 100644 index 0000000..5546691 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildSix.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) overriding method in original version + * 2) parent method in patch version + */ + +public class AdditionMethodPolymorphicTestChildSix extends AdditionMethodPolymorphicTestChildTwo { + + /* + public int emitMethod(){ + return 6; + } + */ +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildThree.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildThree.java new file mode 100644 index 0000000..6915456 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildThree.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) grand-parent method in patch version + * 2) overriding method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildThree extends AdditionMethodPolymorphicTestChildOne { + + /* + public int emitMethod(){ + return 3; + } + */ +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildTwo.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildTwo.java new file mode 100644 index 0000000..4d7db96 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestChildTwo.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * child class which relies on: + * 1) overriding method in original version and patch version + */ + +public class AdditionMethodPolymorphicTestChildTwo extends AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 2; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestParent.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestParent.java new file mode 100644 index 0000000..31448d3 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/AdditionMethodPolymorphicTestParent.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +public class AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 0; + } + +} diff --git a/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/UserPolyTest.java b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/UserPolyTest.java new file mode 100644 index 0000000..c55f0b4 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/methodremoval/patch/testexamples/methodremoval/UserPolyTest.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +public class UserPolyTest { + + public int use(int decision){ + AdditionMethodPolymorphicTestParent p; + if(decision == 1){ + p = new AdditionMethodPolymorphicTestChildOne(); + } else if(decision == 2) { + p = new AdditionMethodPolymorphicTestChildTwo(); + } else if(decision == 3) { + p = new AdditionMethodPolymorphicTestChildThree(); + } else if(decision == 4) { + p = new AdditionMethodPolymorphicTestChildFour(); + } else if(decision == 5) { + p = new AdditionMethodPolymorphicTestChildFive(); + } else if(decision == 6) { + p = new AdditionMethodPolymorphicTestChildSix(); + } else { + p = new AdditionMethodPolymorphicTestParent(); + } + return p.emitMethod(); + } + +} diff --git a/patchAdapter/resources/testexamplespatch/nochange/patch/testexamples/nochange/NoChangeTest.java b/patchAdapter/resources/testexamplespatch/nochange/patch/testexamples/nochange/NoChangeTest.java new file mode 100644 index 0000000..e450d00 --- /dev/null +++ b/patchAdapter/resources/testexamplespatch/nochange/patch/testexamples/nochange/NoChangeTest.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.nochange; +//only held in diff package so that two variants can exist simultaneous + +public class NoChangeTest { + + public String hi; + private int one; + public static final String hello = "hello"; + protected static int two = 2; + + public static int calcSquare(int x){ + return x * x; + } + + private void makeString(){ + one = 1; + System.out.println(hello + two + one); + } + +} diff --git a/patchAdapter/src/main/java/differ/CheckSummary.java b/patchAdapter/src/main/java/differ/CheckSummary.java new file mode 100644 index 0000000..9ffeb3a --- /dev/null +++ b/patchAdapter/src/main/java/differ/CheckSummary.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package differ; + +import java.util.List; +import java.util.ArrayList; + +class CheckSummary { + List addedList = new ArrayList(); + List removedList = new ArrayList(); + boolean changes; + + public void addAddedItem(T t) { + addedList.add(t); + } + + public void addRemovedItem(T t) { + removedList.add(t); + } +} diff --git a/patchAdapter/src/main/java/differ/PatchTransformer.java b/patchAdapter/src/main/java/differ/PatchTransformer.java new file mode 100644 index 0000000..2648940 --- /dev/null +++ b/patchAdapter/src/main/java/differ/PatchTransformer.java @@ -0,0 +1,1200 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package differ; + +import java.util.Arrays; +import java.util.List; +import java.util.Iterator; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.LinkedHashSet; + +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.ExplicitEdgesPred; +import soot.jimple.toolkits.callgraph.Filter; +import soot.jimple.toolkits.callgraph.Targets; + +import soot.jimple.Constant; +import soot.jimple.IntConstant; +import soot.jimple.StringConstant; +import soot.Modifier; +import soot.Scene; +import soot.SootClass; +import soot.SootField; +import soot.SootMethod; +import soot.SootMethodRef; +import soot.Body; +import soot.Unit; +import soot.PatchingChain; +import soot.util.HashChain; +import soot.jimple.InvokeExpr; +import soot.jimple.SpecialInvokeExpr; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.InstanceFieldRef; +import soot.jimple.Stmt; +import soot.jimple.AssignStmt; +import soot.jimple.DefinitionStmt; +import soot.jimple.NopStmt; +import soot.Type; +import soot.BooleanType; +import soot.VoidType; +import soot.Local; +import soot.ValueBox; +import soot.Value; +import soot.RefType; +import soot.util.Chain; +import soot.jimple.Jimple; +import soot.jimple.JimpleBody; +import soot.jimple.StaticInvokeExpr; +import soot.jimple.ThisRef; + +public class PatchTransformer { + + // might need refactor if there is not a 1:1 map + private HashMap redefToNewClassMap; + private HashMap newToRedefClassMap; + private Filter explicitInvokesFilter; + private HashMap fieldToGetter = new HashMap(); + private HashMap fieldToSetter = new HashMap(); + private HashMap oldFieldToNew = new HashMap(); + + private ArrayList newMethods = new ArrayList(); + + private static String ogToHostHashTableName = "originalToHostHashTable"; + private static String hostToOgHashTableName = "hostToOriginalHashTable"; + + public PatchTransformer(HashMap newClassMap, + HashMap newClassMapReversed) { + // just want a ref, to same structure in SemanticDiffer + this.redefToNewClassMap = newClassMap; + this.newToRedefClassMap = newClassMapReversed; + explicitInvokesFilter = new Filter(new ExplicitEdgesPred()); + } + + public void moveMethodCalls(SootClass redefinition, List addedMethods) { + // remove the added methods from redefinition class + // and place into wrapper class + for (SootMethod m : addedMethods) { + SootMethodRef oldRef = m.makeRef(); + redefinition.removeMethod(m); + // dont want to move the static initializer, will construct it later in newclass + if (!m.getName().equals("")) { + if (m.isPrivate()) { + // clear private, set protected + m.setModifiers((m.getModifiers() & (~Modifier.PRIVATE)) | Modifier.PROTECTED); + } + redefToNewClassMap.get(redefinition).addMethod(m); + newMethods.add(m); + } + System.out.println("These are the new methods list: " + newMethods); + } + } + + // checks all of the provided methods for method refs that need fixing + public void transformMethodCalls(List methods, boolean isThisARedefClass) { + // the annoying issue of adding a constructor to this class if needed, which is + // determined while looping the methods + Chain methodsChain = new HashChain(); + for (SootMethod m : methods) { + methodsChain.add(m); + } + for (Iterator iter = methodsChain.snapshotIterator(); iter.hasNext();) { + SootMethod m = iter.next(); + findMethodCalls(m, isThisARedefClass); + } + } + + private void findMethodCalls(SootMethod m, boolean isThisARedefClass) { + CallGraph cg = Scene.v().getCallGraph(); + Body body; + System.out.println("Finding method calls in : " + m.getSignature()); + body = m.retrieveActiveBody(); + + // need to be able to concurrently mod + PatchingChain units = body.getUnits(); + Iterator it = units.snapshotIterator(); + + while (it.hasNext()) { + Unit u = it.next(); + Stmt s = (Stmt) u; + Unit insnAfterInvokeInsn = units.getSuccOf(u); + + if (s.containsInvokeExpr()) { + InvokeExpr invokeExpr = s.getInvokeExpr(); + System.out.println("Found a method call: " + invokeExpr.getMethodRef()); + System.out.println("Found in stmt: " + s); + System.out.println("Printing the targets of this call: "); + System.out.println("....................................."); + Iterator targets = new Targets(explicitInvokesFilter.wrap(cg.edgesOutOf(s))); + System.out.println("....................................."); + if (targets.hasNext()) { + Iterator newTargets = new Targets(explicitInvokesFilter.wrap(cg.edgesOutOf(s))); + ArrayList sortedTargets = sortTargets(newTargets); + boolean checkForMapped = checkForMapped(sortedTargets); + + if (checkForMapped) { + // relying solely on targets in the cg, since method refs could have child + // classes that rely on parent defs + if (sortedTargets.size() == 1) { + SootMethod target = sortedTargets.get(0); + System.out.println("Replacing a method call in this statement: " + s); + System.out.println(invokeExpr.getMethodRef() + " ---> " + target.makeRef()); + // condition where the cg has only one explicit target for this call + if (invokeExpr instanceof StaticInvokeExpr) { + // if its a static invoke we can just replace ref + invokeExpr.setMethodRef(target.makeRef()); + } else { + // otherwise we gotta create a var of newClass type to invoke this on + // TODO make this safe... need to singleton the locals ugh + System.out.println("This is the redeftonewMap" + redefToNewClassMap); + System.out.println( + "This is the target decl decl class: " + target.getDeclaringClass().getName()); + SootClass newClass = target.getDeclaringClass(); + constructNewCall(newClass, invokeExpr, units, u, body, isThisARedefClass); + } + } else { + // more than one target + for (SootMethod target : sortedTargets) { + System.out.println("This target is one we are fixing: " + target); + boolean lastCheck = (sortedTargets.indexOf(target) == sortedTargets.size() - 1) ? true + : false; + constructGuard(target, body, units, insnAfterInvokeInsn, u, lastCheck); + } + System.out.println("Removing statement: " + u); + units.remove(u); + System.out.println("................................"); + } + + } else { + System.out.println("Did not do anything with this statment: " + s + + " because there were no relevant targets."); + } + } else { + System.out.println( + "Did not do anything with this statment: " + s + " because there were no targets at all."); + } + } + System.out.println("-------------------------------"); + } + } + + // determines if any of the targets correspond to moved methods, only care about + // changing calls that may have moved targets + private boolean checkForMapped(ArrayList sorted) { + for (SootMethod target : sorted) { + if (newMethods.contains(target)) { + return true; + } + } + return false; + } + + // this is a dumb way to sort things, but since the targets are implemented as + // iterator I think it needs to be this way + private ArrayList sortTargets(Iterator newTargets) { + // map of parents to possibly multiple children + HashMap> unsorted = new HashMap>(); + HashMap unsortedDeclToMethods = new HashMap(); + // targets sorted in order of children to parents + ArrayList sortedHierarchy = new ArrayList(); + ArrayList sortedHierarchyMethods = new ArrayList(); + SootClass object = Scene.v().getSootClass("java.lang.Object"); + + while (newTargets.hasNext()) { + SootMethod target = (SootMethod) newTargets.next(); + System.out.println("This is a target out of the iterator: " + target); + if (target.getDeclaringClass() != object) { + SootClass targetSuper = target.getDeclaringClass().getSuperclass(); + if (newToRedefClassMap.get(targetSuper) != null) { + targetSuper = newToRedefClassMap.get(targetSuper); + } + if (!unsorted.containsKey(targetSuper)) { + unsorted.put(targetSuper, new LinkedHashSet()); + } + SootClass toAdd = target.getDeclaringClass(); + if (newToRedefClassMap.get(toAdd) != null) { + toAdd = newToRedefClassMap.get(toAdd); + } + unsorted.get(targetSuper).add(toAdd); + unsortedDeclToMethods.put(toAdd, target); + } + } + + // start with known top of hierarchy + SootClass index = object; + traverseChildren(sortedHierarchy, unsorted, index); + + for (SootClass sootclass : sortedHierarchy) { + sortedHierarchyMethods.add(unsortedDeclToMethods.get(sootclass)); + } + + System.out.println("This is the unsorted list: " + unsorted); + System.out.println("This is the sorted hierarchy: " + sortedHierarchy); + System.out.println("This is the sorted hierarchy of methods: " + sortedHierarchyMethods); + return sortedHierarchyMethods; + } + + private void traverseChildren(ArrayList sortedHierarchy, + HashMap> unsorted, SootClass index) { + if (unsorted.get(index) != null) { + for (SootClass child : unsorted.get(index)) { + sortedHierarchy.add(0, child); + } + for (SootClass child : unsorted.get(index)) { + traverseChildren(sortedHierarchy, unsorted, child); + } + } + } + + private void constructNewCall(SootClass newClass, InvokeExpr invokeExpr, PatchingChain units, + Unit currentInsn, Body body, boolean isThisARedefClass) { + + System.out.println("This is the newclass getType: " + newClass.getType()); + Local newClassRef; + + if (isThisARedefClass) { + Value base = ((InstanceInvokeExpr) invokeExpr).getBase(); + newClassRef = lookup(newClass, newClass, body, units, currentInsn, base, ogToHostHashTableName); + } else { + newClassRef = body.getThisLocal(); + } + + SootMethodRef newClassMethod = newClass.getMethod(invokeExpr.getMethodRef().getSubSignature()).makeRef(); + System.out.println("Replacing a method call in this statement: " + (Stmt) currentInsn); + System.out.println(invokeExpr.getMethodRef() + " ---> " + newClassMethod); + if (currentInsn instanceof AssignStmt) { + // invoke in an assignment can only be right op + units.insertBefore( + Jimple.v().newAssignStmt(((AssignStmt) currentInsn).getLeftOp(), + Jimple.v().newVirtualInvokeExpr(newClassRef, newClassMethod, invokeExpr.getArgs())), + currentInsn); + } else { + units.insertBefore( + Jimple.v().newInvokeStmt( + Jimple.v().newVirtualInvokeExpr(newClassRef, newClassMethod, invokeExpr.getArgs())), + currentInsn); + } + System.out.println("Removing statement: " + currentInsn); + units.remove(currentInsn); + } + + /* + * constructs a check on the runtime type of the object that a method is invoked + * upon. if it matches type that we stole from, then execution goes to a new + * block in program that calls the new method in its new class The checks are + * instanceof AND they are ordered from CHILD -> PARENT + * + * original program: ` a.someMethod()` + * + * fixed program: ``` hostClass = mapRedefToNew[targetClass] || targetClass + * if(baseVar instanceof hostClass): hostClass.someMethod() else if: //possibly + * more checks + * + * ``` + * + */ + private void constructGuard(SootMethod target, Body body, PatchingChain units, Unit insnAfterInvokeInsn, + Unit currentInsn, boolean lastCheck) { + InvokeExpr invokeExpr = ((Stmt) currentInsn).getInvokeExpr(); + // already performed the move by now, so the current decl class is correct + SootClass newClass = target.getDeclaringClass(); + // may or may not actually be a newclass, if it is, need to instanitate and also + // know this for the instanceof check + SootClass originalClass = newToRedefClassMap.get(newClass); + Local invokeobj; + Type checkType; + + Local base = (Local) ((InstanceInvokeExpr) invokeExpr).getBase(); + NopStmt nop = Jimple.v().newNopStmt(); + + // create the check + if (!lastCheck) { + Local boolInstanceOf = Jimple.v().newLocal("boolInstanceOf", BooleanType.v()); + body.getLocals().add(boolInstanceOf); + + checkType = newClass.getType(); + if (originalClass != null) { + checkType = originalClass.getType(); + } + units.insertBefore(Jimple.v().newAssignStmt(boolInstanceOf, Jimple.v().newInstanceOfExpr(base, checkType)), + currentInsn); + units.insertBefore(Jimple.v().newIfStmt(Jimple.v().newEqExpr(boolInstanceOf, IntConstant.v(0)), nop), + currentInsn); + + // create the new block that contains the call to the new method + System.out.println("This is the newclass getType: " + newClass.getType()); + } + + // consideration: fix this for the methodrefs in the added methods, those should + // just use "this" not new local + if (originalClass == null) { + + // this is where we did not move + invokeobj = Jimple.v().newLocal("baseinvokeobj", newClass.getType()); + body.getLocals().add(invokeobj); + units.insertBefore(Jimple.v().newAssignStmt(invokeobj, Jimple.v().newCastExpr(base, newClass.getType())), + currentInsn); + if (currentInsn instanceof AssignStmt) { + units.insertBefore( + Jimple.v().newAssignStmt(((AssignStmt) currentInsn).getLeftOp(), + Jimple.v().newVirtualInvokeExpr(invokeobj, target.makeRef(), invokeExpr.getArgs())), + currentInsn); + } else { + units.insertBefore( + Jimple.v().newInvokeStmt( + Jimple.v().newVirtualInvokeExpr(invokeobj, target.makeRef(), invokeExpr.getArgs())), + currentInsn); + } + + } else { + + invokeobj = lookup(newClass, newClass, body, units, currentInsn, base, ogToHostHashTableName); + // build the new call + if (currentInsn instanceof AssignStmt) { + units.insertBefore( + Jimple.v().newAssignStmt(((AssignStmt) currentInsn).getLeftOp(), + Jimple.v().newVirtualInvokeExpr(invokeobj, target.makeRef(), invokeExpr.getArgs())), + currentInsn); + } else { + units.insertBefore( + Jimple.v().newInvokeStmt( + Jimple.v().newVirtualInvokeExpr(invokeobj, target.makeRef(), invokeExpr.getArgs())), + currentInsn); + } + + } + + units.insertBefore(Jimple.v().newGotoStmt(insnAfterInvokeInsn), currentInsn); + + System.out.println("This is the method ref: " + invokeExpr.getMethodRef()); + System.out.println("This is the method ref declaring class: " + invokeExpr.getMethodRef().getDeclaringClass()); + + // not sure if needed, might be dead code, but copied from what was in a jimple + // example + units.insertBefore(nop, currentInsn); + + System.out.println("This is the newToRedefClassMap: " + newToRedefClassMap); + } + + public void transformFields(SootClass original, SootClass redefinition, List addedFields, + List addedMethods) { + for (SootField field : addedFields) { + fixFields(field, redefinition); + } + + // bit weird to put it here, but must be called before field removal + fixClinit(redefinition); + + fixFieldRefs(redefinition, addedMethods); + + for (SootField field : addedFields) { + System.out.println( + "Removing this field: " + field.getSignature() + " from this class: " + redefinition.getName()); + redefinition.removeField(field); + } + + // fix the field refs for "the other way" - refs using "this" that refer to a + // redef class, in an added method + fixFieldRefsInAddedMethods(redefinition, addedMethods); + } + + // adds the field to the new class and if the field was private constructs an + // accessor for it + private void fixFields(SootField field, SootClass redefinition) { + // cant actually just move the same field ref, need it to exist in both classes + // simultaneously in order to fix refs + SootField newField = new SootField(field.getName(), field.getType(), field.getModifiers()); + + if (newField.isPrivate()) { + // clear private, set protected, so we can do bad direct access + // TODO fix the later accesses to all be through the accessors + newField.setModifiers((newField.getModifiers() & (~Modifier.PRIVATE)) | Modifier.PROTECTED); + } + + SootClass newClass = redefToNewClassMap.get(redefinition); + newClass.addField(newField); + System.out + .println("Adding this field: " + newField.getSignature() + " to this new class: " + newClass.getName()); + oldFieldToNew.put(field, newField); + + System.out.println("Is the newfield static?: " + newField.isStatic()); + System.out.println("Is the newfield phantom for some reason?:" + newField.isPhantom()); + + // construct getter and setter for even public fields + String methodName = "get" + field.getName(); + + // getter first + // need the acessor to be public , might need to also be static + int modifiers = Modifier.PROTECTED; + if (field.isStatic()) { + modifiers |= Modifier.STATIC; + } + SootMethod newGetter = new SootMethod(methodName, Arrays.asList(new Type[] {}), field.getType(), modifiers); + + JimpleBody getterBody = Jimple.v().newBody(newGetter); + newGetter.setActiveBody(getterBody); + Chain units = getterBody.getUnits(); + + // must create local then can return that + Local tmpref = Jimple.v().newLocal("tmpref", field.getType()); + getterBody.getLocals().add(tmpref); + if (field.isStatic()) { + units.add(Jimple.v().newAssignStmt(tmpref, Jimple.v().newStaticFieldRef(newField.makeRef()))); + } else { + // assign a local for self so we can ref our own field + Local selfref = Jimple.v().newLocal("selfref", newClass.getType()); + getterBody.getLocals().add(selfref); + units.add(Jimple.v().newIdentityStmt(selfref, new ThisRef(newClass.getType()))); + units.add(Jimple.v().newAssignStmt(tmpref, Jimple.v().newInstanceFieldRef(selfref, newField.makeRef()))); + } + + units.add(Jimple.v().newReturnStmt(tmpref)); + + newClass.addMethod(newGetter); + fieldToGetter.put(field, newGetter); + + // make setter too + String setterMethodName = "set" + field.getName(); + // may have some issue here if there was casting for stmts we will replace... + SootMethod newSetter = new SootMethod(setterMethodName, Arrays.asList(new Type[] { field.getType() }), + VoidType.v(), modifiers); + + JimpleBody setterBody = Jimple.v().newBody(newSetter); + newSetter.setActiveBody(setterBody); + Chain setterUnits = setterBody.getUnits(); + // have to assign the param to a local first, cannot go directly from param to + // assignstmt + Local paramref = Jimple.v().newLocal("paramref", field.getType()); + setterBody.getLocals().add(paramref); + setterUnits.add(Jimple.v().newIdentityStmt(paramref, Jimple.v().newParameterRef(field.getType(), 0))); + if (field.isStatic()) { + setterUnits.add(Jimple.v().newAssignStmt(Jimple.v().newStaticFieldRef(newField.makeRef()), paramref)); + } else { + // assign a local for self so we can ref our own field + Local selfref = Jimple.v().newLocal("selfref", newClass.getType()); + setterBody.getLocals().add(selfref); + setterUnits.add( + Jimple.v().newAssignStmt(Jimple.v().newInstanceFieldRef(selfref, newField.makeRef()), paramref)); + setterUnits.addFirst(Jimple.v().newIdentityStmt(selfref, new ThisRef(newClass.getType()))); + } + + setterUnits.add(Jimple.v().newReturnVoidStmt()); + newClass.addMethod(newSetter); + fieldToSetter.put(field, newSetter); + } + + // fixes the static field value changes, for preexisting fields + public void fixStaticFieldValueChanges(SootClass original, SootClass redefinition, List addedFields) { + System.out.println("Checking if all original fields' values match, in original: " + original.getName() + + " and redef: " + redefinition.getName()); + boolean foundOne = false; + for (SootField field : redefinition.getFields()) { + if (!addedFields.contains(field) && field.isStatic()) { + SootField originalfield = original.getField(field.getName(), field.getType()); + System.out.println(field.isStatic()); + System.out.println(addedFields.contains(field)); + System.out.println("---------------------------------------------------"); + System.out.println("Found a static original field, to do a value change check on. Original: " + + originalfield.getName() + " vs Redefinition: " + field.getName()); + + SootMethod clinitRedef = redefinition.getMethodUnsafe("", Arrays.asList(new Type[] {}), + VoidType.v()); + SootMethod clinitOriginal = original.getMethodUnsafe("", Arrays.asList(new Type[] {}), + VoidType.v()); + + if (clinitRedef != null && clinitOriginal != null) { + + Iterator redefit = clinitRedef.retrieveActiveBody().getUnits().snapshotIterator(); + Iterator originalit = clinitOriginal.retrieveActiveBody().getUnits().snapshotIterator(); + Value redefDef = null; + Value originalDef = null; + + while (redefit.hasNext()) { + Unit u = redefit.next(); + Stmt s = (Stmt) u; + // if its the definition statement + if (s.containsFieldRef() && s.getFieldRef().getField().equals(field) + && !containsUse(u, field)) { + redefDef = ((AssignStmt) u).getRightOp(); + } + } + while (originalit.hasNext()) { + Unit u = originalit.next(); + Stmt s = (Stmt) u; + // if its the definition statement + if (s.containsFieldRef() && s.getFieldRef().getField().equals(originalfield) + && !containsUse(u, originalfield)) { + originalDef = ((AssignStmt) u).getRightOp(); + } + } + + System.out.println("---------------------------------------------------"); + System.out.println("This is original value: " + originalDef + " of field: " + originalfield); + System.out.println("This is redef value: " + redefDef + " of field: " + field); + + // this will get it moved with the other added field initialization movement + if (originalDef != null && redefDef != null && originalDef instanceof Constant + && redefDef instanceof Constant && !originalDef.equivTo(redefDef)) { + System.out.println("Found a value change in: " + originalDef + "--->" + redefDef); + // TODO fix this for private methods, would need to build a unsafe access... + oldFieldToNew.put(field, field); + foundOne = true; + } + System.out.println("---------------------------------------------------"); + + if (addedFields.size() == 0 && foundOne) { + fixClinit(redefinition); + } + + } else { + System.out.println("Found a static field with no matching clinits. Field: " + field.getName()); + System.out.println("Original clinit: " + clinitOriginal + " and redef clinit: " + clinitRedef); + } + } + + } + } + + private void fixClinit(SootClass redefinition) { + List relevantLocals = new ArrayList(); + List changeSet = new ArrayList(); + List relevantStmts = new ArrayList(); + + SootMethod clinitRedef = redefinition.getMethodUnsafe("", Arrays.asList(new Type[] {}), VoidType.v()); + if (clinitRedef != null) { + SootClass newClass = redefToNewClassMap.get(redefinition); + createStaticInitializer(newClass); + + SootMethod clinitNew = newClass.getMethod("", Arrays.asList(new Type[] {}), VoidType.v()); + Body clinitBody = clinitNew.retrieveActiveBody(); + PatchingChain newUnits = clinitBody.getUnits(); + + Body redefBody = clinitRedef.retrieveActiveBody(); + PatchingChain redefUnits = redefBody.getUnits(); + Iterator it = redefUnits.snapshotIterator(); + + // first pass, just find the field refs for the moved fields first, and patch + // those up while at it. + while (it.hasNext()) { + Unit u = it.next(); + Stmt s = (Stmt) u; + if (s.containsFieldRef()) { + SootField ref = s.getFieldRef().getField(); + SootField newref = oldFieldToNew.get(ref); + if (newref != null) { + s.getFieldRefBox().setValue(Jimple.v().newStaticFieldRef(oldFieldToNew.get(ref).makeRef())); + relevantStmts.add(u); + relevantLocals.addAll(extractLocals(u)); + } + } + } + + changeSet.addAll(forwardPass(relevantLocals, relevantStmts, redefUnits)); + while (changeSet.size() != 0) { // loop until fixpoint + changeSet.clear(); + changeSet.addAll(forwardPass(relevantLocals, relevantStmts, redefUnits)); + } + + // add an anchor nop + NopStmt nop = Jimple.v().newNopStmt(); + newUnits.addFirst((Unit) nop); + Unit ptr = (Unit) nop; + + // move locals first + for (Local l : relevantLocals) { + if (!clinitBody.getLocals().contains(l)) { + System.out.println("Moving this local: " + l); + clinitBody.getLocals().add(l); + } + } + + // second pass is for moviing + Iterator itTwo = redefUnits.snapshotIterator(); + while (itTwo.hasNext()) { + Unit u = itTwo.next(); + if (relevantStmts.contains(u)) { + System.out.println("-----------------------------"); + System.out.println("Moving this statement: " + u); + System.out.println("-----------------------------"); + newUnits.insertAfter(u, ptr); + ptr = u; + redefUnits.remove(u); + } + } + } + } + + private void fixFieldRefs(SootClass redefinition, List addedMethods) { + for (SootMethod m : redefinition.getMethods()) { + if (!m.getName().equals("") && m.hasActiveBody()) { + boolean addedMethod = false; + if (addedMethods.contains(m)) { + addedMethod = true; + System.out.println("Finding field refs in an added method: " + m.getSignature()); + } else { + System.out.println("Finding field refs in: " + m.getSignature()); + } + System.out.println("Method name is: " + m.getName()); + System.out.println("-------------------------------"); + Body body = m.retrieveActiveBody(); + PatchingChain units = body.getUnits(); + Iterator it = units.snapshotIterator(); + + while (it.hasNext()) { + + Unit u = it.next(); + Stmt s = (Stmt) u; + if (s.containsFieldRef()) { + SootField ref = s.getFieldRef().getField(); + SootField newref = oldFieldToNew.get(ref); + + if (containsUse(u, ref)) { + System.out.println("-------------------------------"); + System.out.println("found a use of: " + ref); + System.out.println("in stmt: " + s); + System.out.println("-------------------------------"); + } else { + System.out.println("-------------------------------"); + System.out.println("must have been a def of: " + ref); + System.out.println("in stmt: " + s); + System.out.println("-------------------------------"); + } + + if (newref != null) { + ValueBox fieldref = s.getFieldRefBox(); + if (u.getUseBoxes().contains(fieldref)) { + + SootMethod newAccessor = fieldToGetter.get(ref); + System.out.println("doing a field ref replace: " + ref + " --->" + newAccessor); + System.out.println("in this statement: " + s); + Local tmpRef = Jimple.v().newLocal("tmpRef", ref.getType()); + body.getLocals().add(tmpRef); + + if (addedMethod) { + // the field ref is in a moved method + if (ref.isStatic()) { + System.out.println("building a static getter ref in added method"); + units.insertBefore(Jimple.v().newAssignStmt(tmpRef, + Jimple.v().newStaticInvokeExpr(newAccessor.makeRef())), u); + } else { + System.out.println("building an instance getter ref in added method"); + units.insertBefore(Jimple.v().newAssignStmt(tmpRef, Jimple.v() + .newVirtualInvokeExpr(body.getThisLocal(), newAccessor.makeRef())), u); + } + + } else { + SootClass newClass = redefToNewClassMap.get(redefinition); + + // the field ref is in the redefinition class still, or some other class + if (ref.isStatic()) { + System.out.println( + "building a static direct field (USE) access in non added method"); + units.insertBefore(Jimple.v().newAssignStmt(tmpRef, Jimple.v() + .newStaticFieldRef(newClass.getFieldByName(ref.getName()).makeRef())), + u); + + } else { + System.out.println( + "building a an instance field (USE) access in a non added method"); + Local newClassRef = lookup(newClass, newClass, body, units, u, + ((InstanceFieldRef) s.getFieldRef()).getBase(), ogToHostHashTableName); + units.insertBefore( + Jimple.v().newAssignStmt(tmpRef, + Jimple.v().newInstanceFieldRef(newClassRef, newref.makeRef())), + u); + } + } + System.out.println( + "This is whats in the box at the moment: " + s.getFieldRefBox().getValue()); + s.getFieldRefBox().setValue(tmpRef); + + } + + if (u.getDefBoxes().contains(fieldref)) { + SootMethod newAccessor = fieldToSetter.get(ref); + System.out.println("doing a field ref replace: " + ref + " --->" + newAccessor); + System.out.println("in this statement: " + s); + if (addedMethod) { + + // def boxes only to be nonempty on identitystmts or assignstmts + if (ref.isStatic()) { + System.out.println("building a static setter ref in added method"); + units.insertBefore( + Jimple.v().newInvokeStmt(Jimple.v() + .newStaticInvokeExpr(newAccessor.makeRef(), Arrays.asList( + new Value[] { ((DefinitionStmt) s).getRightOp() }))), + u); + } else { + System.out.println("building an instance setter ref in added method"); + units.insertBefore( + Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr( + (Local) ((InstanceFieldRef) s.getFieldRef()).getBase(), + newAccessor.makeRef(), + Arrays.asList( + new Value[] { ((DefinitionStmt) s).getRightOp() }))), + u); + } + } else { + + // the field ref is in the redefinition class still, or some other class + if (ref.isStatic()) { + System.out.println( + "building an static field setter access in a non added meethod"); + units.insertBefore( + Jimple.v().newInvokeStmt(Jimple.v() + .newStaticInvokeExpr(newAccessor.makeRef(), Arrays.asList( + new Value[] { ((DefinitionStmt) s).getRightOp() }))), + u); + + } else { + System.out.println( + "building an instance field (DEF) access in a non added meethod"); + SootClass newClass = redefToNewClassMap.get(redefinition); + Local newClassRef = lookup(newClass, newClass, body, units, u, + ((InstanceFieldRef) s.getFieldRef()).getBase(), ogToHostHashTableName); + units.insertBefore( + Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(newClassRef, + newAccessor.makeRef(), + Arrays.asList( + new Value[] { ((DefinitionStmt) s).getRightOp() }))), + u); + } + } + System.out.println("Removing statement: " + u); + units.remove(u); + + } + } + } + } + } + } + } + + private static List forwardPass(List relevantLocals, List relevantStmts, + PatchingChain units) { + List changeSet = new ArrayList(); + + Unit pointer = units.getFirst(); + Unit last = units.getLast(); + while (pointer != last) { + if (!relevantStmts.contains(pointer)) { + List inStmt = extractLocals(pointer); + List intersection = new ArrayList(); + intersection.addAll(inStmt); + intersection.retainAll(relevantLocals); + System.out.println("(FORWARD) intersection : " + intersection); + if (intersection.size() != 0) { + System.out.println("(FORWARD) found relevant statement: " + pointer); + relevantStmts.add(pointer); + changeSet.add(pointer); + + for (Local l : inStmt) { + System.out.println("(FORWARD) found this local: " + l); + relevantLocals.add(l); + + } + } + } + pointer = units.getSuccOf(pointer); + } + return changeSet; + } + + private static List extractLocals(Unit u) { + List locals = new ArrayList(); + for (ValueBox valuebox : u.getUseAndDefBoxes()) { + Value value = valuebox.getValue(); + System.out.println("Looking at this valuebox: " + valuebox + "in this statment: " + u + + " with this getvalue: " + value); + if (value instanceof Local && !locals.contains((Local) value)) { + locals.add((Local) value); + } else if (value instanceof InvokeExpr) { + if (value instanceof InstanceInvokeExpr) { + // could it not be a local somehow? + if (((InstanceInvokeExpr) value).getBase() instanceof Local + && !locals.contains((Local) ((InstanceInvokeExpr) value).getBase())) { + locals.add((Local) ((InstanceInvokeExpr) value).getBase()); + } + } + List invokeArgs = ((InvokeExpr) value).getArgs(); + for (Value arg : invokeArgs) { + if (arg instanceof Local && !locals.contains((Local) arg)) { + locals.add((Local) arg); + } + } + } + } + System.out.println("Found these locals: " + locals); + return locals; + } + + public static void createInitializer(SootClass newClass) { + // only want to create one initialization function + if (newClass.getMethodUnsafe("", Arrays.asList(new Type[] {}), VoidType.v()) == null) { + // using protected, but perhaps some other use cases need different access + SootMethod initializer = new SootMethod("", Arrays.asList(new Type[] {}), VoidType.v(), + Modifier.PROTECTED); + JimpleBody body = Jimple.v().newBody(initializer); + initializer.setActiveBody(body); + Chain units = body.getUnits(); + Local selfref = Jimple.v().newLocal("selfref", newClass.getType()); + body.getLocals().add(selfref); + units.add(Jimple.v().newIdentityStmt(selfref, new ThisRef(newClass.getType()))); + SootMethod parentConstructor = newClass.getSuperclass().getMethodUnsafe("", + Arrays.asList(new Type[] {}), VoidType.v()); + if (parentConstructor == null) { + System.out.println("The parent constructor was null..."); + // this cannot happen... the newClass is not Object... should throw here maybe + } + units.add(Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(selfref, parentConstructor.makeRef()))); + units.add(Jimple.v().newReturnVoidStmt()); + newClass.addMethod(initializer); + } + } + + private static void createStaticInitializer(SootClass newClass) { + // only want to create one static initialization function + if (newClass.getMethodUnsafe("", Arrays.asList(new Type[] {}), VoidType.v()) == null) { + SootMethod initializer = new SootMethod("", Arrays.asList(new Type[] {}), VoidType.v(), + Modifier.STATIC); + JimpleBody body = Jimple.v().newBody(initializer); + initializer.setActiveBody(body); + Chain units = body.getUnits(); + units.add(Jimple.v().newReturnVoidStmt()); + newClass.addMethod(initializer); + } + } + + private boolean containsUse(Unit u, SootField ref) { + for (ValueBox value : u.getUseBoxes()) { + if (value.getValue().equivHashCode() == ref.equivHashCode()) { + return true; + } + } + return false; + } + + /* + * builds two maps hostToOriginal object refs originalToHost object refs not + * efficient, but we need both ways + */ + public static void buildHostMaps(SootClass newClass, String fieldname) { + + createStaticInitializer(newClass); + + /* + * same beginning: java.util.Hashtable $r0; $r0 = new java.util.Hashtable; + * specialinvoke $r0.()>(); = $r0; + */ + + // add the field + RefType HT = RefType.v("java.util.Hashtable"); + SootField replacementField = new SootField(fieldname + "HashTable", HT, Modifier.PUBLIC | Modifier.STATIC); + newClass.addField(replacementField); + // initialize it bc its static + Body clinitBody = newClass.getMethod("", Arrays.asList(new Type[] {}), VoidType.v()) + .retrieveActiveBody(); + PatchingChain clinitUnits = clinitBody.getUnits(); + + Local hashtable = Jimple.v().newLocal("HTTemp", HT); + clinitBody.getLocals().add(hashtable); + + // build in bottom up order, bc we dont have any other reference point in the + // method atm + clinitUnits.addFirst( + Jimple.v().newAssignStmt(Jimple.v().newStaticFieldRef(replacementField.makeRef()), hashtable)); + SootMethod toCall = Scene.v().getMethod("()>"); + clinitUnits.addFirst(Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(hashtable, toCall.makeRef()))); + clinitUnits.addFirst(Jimple.v().newAssignStmt(hashtable, Jimple.v().newNewExpr(HT))); + } + + // we apply the same setup to all inits for the redef class + public static void setupRedefInit(SootClass newClass, SootClass redef) { + List allMethods = redef.getMethods(); + for (SootMethod m : allMethods) { + if (m.getName().equals("")) { + boolean buildHere = true; + Body body = m.retrieveActiveBody(); + PatchingChain units = body.getUnits(); + RefType HT = RefType.v("java.util.Hashtable"); + Local hashtableOGToHost = Jimple.v().newLocal("hashtableOGToHost", HT); + body.getLocals().add(hashtableOGToHost); + Local hashtableHostToOG = Jimple.v().newLocal("hashtableHostToOG", HT); + body.getLocals().add(hashtableHostToOG); + Local newclassref = Jimple.v().newLocal("newclassref", redef.getType()); + body.getLocals().add(newclassref); + + Local thisref = body.getThisLocal(); + Unit thisUnit = body.getThisUnit(); + Unit placementPoint = thisUnit; + + // find the super init in this init + Iterator it = units.snapshotIterator(); + while (it.hasNext()) { + Unit u = it.next(); + Stmt s = (Stmt) u; + if (s.containsInvokeExpr() && s.getInvokeExpr() instanceof SpecialInvokeExpr + && ((SpecialInvokeExpr) s.getInvokeExpr()).getBase().equals(thisref) + && s.getInvokeExpr().getMethodRef().getName().contains("")) { + placementPoint = u; + // actually dont want to build setup in init that calls other self initializer + // though + if (s.getInvokeExpr().getMethodRef().getDeclaringClass().getName().equals(redef.getName())) { + buildHere = false; + } + break; + } + } + if (buildHere) { + // just one more, since this is the insn AFTER super.init, and we're placing our + // hashtable inits on top of this ref + placementPoint = units.getSuccOf(placementPoint); + + SootMethodRef hashtablePut = Scene.v() + .getMethod("") + .makeRef(); + units.insertBefore(Jimple.v().newAssignStmt(newclassref, Jimple.v().newNewExpr(newClass.getType())), + placementPoint); + units.insertBefore( + Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(newclassref, newClass + .getMethod("", Arrays.asList(new Type[] {}), VoidType.v()).makeRef())), + placementPoint); + + units.insertBefore( + Jimple.v() + .newAssignStmt(hashtableOGToHost, + Jimple.v().newStaticFieldRef( + newClass.getFieldByName(ogToHostHashTableName).makeRef())), + placementPoint); + units.insertBefore(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(hashtableOGToHost, + hashtablePut, Arrays.asList(new Value[] { thisref, newclassref }))), placementPoint); + + units.insertBefore( + Jimple.v() + .newAssignStmt(hashtableHostToOG, + Jimple.v().newStaticFieldRef( + newClass.getFieldByName(hostToOgHashTableName).makeRef())), + placementPoint); + units.insertBefore(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(hashtableHostToOG, + hashtablePut, Arrays.asList(new Value[] { newclassref, thisref }))), placementPoint); + } + } + } + } + + /* + * Builds a lookup of a object referring to some redefinition class mapped to + * its host or vise versa + */ + private Local lookup(SootClass newClass, SootClass classToMakeRefOf, Body body, PatchingChain units, + Unit insertBeforeHere, Value baseOfOriginalStmt, String whichTableToUse) { + + System.out.println("Building a hashtable lookup, table: " + whichTableToUse + " using this key for the map: " + + baseOfOriginalStmt + " and adding it before this statement: " + insertBeforeHere); + + Local classToMakeRefOfRef = Jimple.v().newLocal("newClassRef", classToMakeRefOf.getType()); + body.getLocals().add(classToMakeRefOfRef); + Local objecttemp = Jimple.v().newLocal("objecttemp", RefType.v("java.lang.Object")); + body.getLocals().add(objecttemp); + Local HT = Jimple.v().newLocal("HTFieldTemp", RefType.v("java.util.Hashtable")); + body.getLocals().add(HT); + + units.insertBefore( + Jimple.v().newAssignStmt(HT, + Jimple.v().newStaticFieldRef(newClass.getFieldByName(whichTableToUse).makeRef())), + insertBeforeHere); + + SootMethodRef mapGetter = Scene.v().getMethod("") + .makeRef(); + units.insertBefore(Jimple.v().newAssignStmt(objecttemp, + Jimple.v().newVirtualInvokeExpr(HT, mapGetter, Arrays.asList(new Value[] { baseOfOriginalStmt }))), + insertBeforeHere); + + units.insertBefore(Jimple.v().newAssignStmt(classToMakeRefOfRef, + Jimple.v().newCastExpr(objecttemp, classToMakeRefOf.getType())), insertBeforeHere); + + return classToMakeRefOfRef; + + } + + private void fixFieldRefsInAddedMethods(SootClass redefinition, List addedMethods) { + SootClass newClass = redefToNewClassMap.get(redefinition); + + for (SootMethod m : addedMethods) { + Body body = m.retrieveActiveBody(); + PatchingChain units = body.getUnits(); + Iterator it = units.snapshotIterator(); + + while (it.hasNext()) { + + Unit u = it.next(); + Stmt s = (Stmt) u; + if (s.containsFieldRef()) { + SootField ref = s.getFieldRef().getField(); + // the reference is for an instance field in the redefinition class and is not + // an added field + // shouldnt have to check this last one... but? + if (!ref.isStatic() && (redefinition.getFieldUnsafe(ref.getName(), ref.getType()) != null) + && (newClass.getFieldUnsafe(ref.getName(), ref.getType()) == null)) { + System.out.println("doing a field ref replace: " + ref + " --->"); + System.out.println("in fixFieldRefsInAddedMethods, in this statement: " + s); + + Local redefinitionClassRef = lookup(newClass, redefinition, body, units, u, + ((InstanceFieldRef) s.getFieldRef()).getBase(), hostToOgHashTableName); + + System.out.println("This is wahts in the box atm: " + s.getFieldRefBox().getValue()); + s.getFieldRefBox() + .setValue(Jimple.v().newInstanceFieldRef(redefinitionClassRef, ref.makeRef())); + } + } + } + } + } + + /* + * fixes instance self ref'd method accesses in added methods, bc they will have + * been pointing to this which will need to be translated using the map + */ + public void fixMethodRefsInAddedMethods(SootClass redefinition, List addedMethods) { + System.out.println("------------------------------------------------"); + CallGraph cg = Scene.v().getCallGraph(); + List redefMethods = redefinition.getMethods(); + for (SootMethod m : addedMethods) { + + Body body = m.retrieveActiveBody(); + PatchingChain units = body.getUnits(); + Iterator it = units.snapshotIterator(); + + while (it.hasNext()) { + + Unit u = it.next(); + Stmt s = (Stmt) u; + + if (s.containsInvokeExpr()) { + InvokeExpr invokeExpr = s.getInvokeExpr(); + if (invokeExpr instanceof InstanceInvokeExpr) { + System.out.println("Looking at this instance of invoke expr, in an added method: " + s); + Iterator targets = new Targets(explicitInvokesFilter.wrap(cg.edgesOutOf(s))); + while (targets.hasNext()) { + SootMethod next = (SootMethod) targets.next(); + if (redefMethods.contains(next)) { + System.out.println( + "Patching a target in an added method: " + next + " at this statement: " + s); + SootClass newClass = redefToNewClassMap.get(redefinition); + Local redefintionClassRef = lookup(newClass, redefinition, body, units, u, + ((InstanceInvokeExpr) invokeExpr).getBase(), hostToOgHashTableName); + if (invokeExpr instanceof SpecialInvokeExpr) { + // cannot special invoke even if we make public + ValueBox invokebox = s.getInvokeExprBox(); + System.out + .println("This is whats in the box atm: " + s.getFieldRefBox().getValue()); + invokebox.setValue(Jimple.v().newVirtualInvokeExpr(redefintionClassRef, + next.makeRef(), invokeExpr.getArgs())); + } else { + ((InstanceInvokeExpr) invokeExpr).setBase(redefintionClassRef); + } + break; + } + } + } + System.out.println("------------------------------------------------"); + } + } + } + } + + /* + * Replaces a method body with a call to the super method only for the case + * where a patch removes a method and we want to preserve the intention of the + * patch, but rm'ing the method made it redefinition non-compliant in this case + * the removal of a method means calls that would have resolved to that removed + * method now resolve to the parent + * + * unless there is no parent and refs are assumed to be rm'd in which case, it + * is safe to simply re-add the method body, no harm + */ + public static void fixRemovedMethods(List methods) { + for (SootMethod m : methods) { + + SootMethodRef parentMethodRef = findNearestImplementingParent(m); + + System.out.println("Fixing method refs in a removed method: " + m.getName() + " " + m.getDeclaringClass()); + System.out.println("Using this parent method ref as replacement: " + parentMethodRef.getName() + " " + + parentMethodRef.getDeclaringClass()); + + if (parentMethodRef != null) { + + JimpleBody newBody = Jimple.v().newBody(m); + Chain units = newBody.getUnits(); + + Local selfref = Jimple.v().newLocal("selfref", m.getDeclaringClass().getType()); + newBody.getLocals().add(selfref); + units.addFirst(Jimple.v().newIdentityStmt(selfref, new ThisRef(m.getDeclaringClass().getType()))); + + List args = new ArrayList(); + + for (int i = 0; i < m.getParameterCount(); i++) { + Local paramref = Jimple.v().newLocal("paramref", m.getParameterType(i)); + newBody.getLocals().add(paramref); + units.add( + Jimple.v().newIdentityStmt(paramref, Jimple.v().newParameterRef(m.getParameterType(i), i))); + args.add(paramref); + } + + if (m.getReturnType() instanceof VoidType) { + units.add( + Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(selfref, parentMethodRef, args))); + units.add(Jimple.v().newReturnVoidStmt()); + } else { + Local ret = Jimple.v().newLocal("retValue", m.getReturnType()); + newBody.getLocals().add(ret); + units.add(Jimple.v().newAssignStmt(ret, + Jimple.v().newSpecialInvokeExpr(selfref, parentMethodRef, args))); + units.add(Jimple.v().newReturnStmt(ret)); + } + + m.setActiveBody(newBody); + } + } + } + + private static SootMethodRef findNearestImplementingParent(SootMethod m) { + SootClass obj = Scene.v().getSootClass("java.lang.Object"); + if (m.getDeclaringClass() == obj) { + return null; + } + SootClass parent = m.getDeclaringClass().getSuperclass(); + while (parent != null) { + SootMethod parentMethod = parent.getMethodUnsafe(m.getName(), m.getParameterTypes(), m.getReturnType()); + if (parentMethod != null) { + SootMethodRef parentMethodRef = parentMethod.makeRef(); + return parentMethodRef; + } else { + parent = parent.getSuperclassUnsafe(); + } + } + return null; + } +} diff --git a/patchAdapter/src/main/java/differ/RelaxedParser.java b/patchAdapter/src/main/java/differ/RelaxedParser.java new file mode 100644 index 0000000..4db5bc4 --- /dev/null +++ b/patchAdapter/src/main/java/differ/RelaxedParser.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package differ; + +import java.util.List; +import java.util.ArrayList; + +import org.apache.commons.cli.Options; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.DefaultParser; + +public class RelaxedParser extends DefaultParser { + + private static List leftoverArgs = new ArrayList(); + + @Override + public CommandLine parse(Options options, String[] arguments) throws ParseException { + leftoverArgs = new ArrayList(); // leftovers are on a per parse basis + List knownArguments = new ArrayList<>(); + // this is only ok bc we know all of our options have an arg + for (int i = 0; i < arguments.length; i++) { + if (options.hasOption(arguments[i])) { + knownArguments.add(arguments[i]); + knownArguments.add(arguments[i + 1]); + i++; + } else { + leftoverArgs.add(arguments[i]); + } + } + return super.parse(options, knownArguments.toArray(new String[knownArguments.size()])); + } + + // doesnt simply return the reference, others could then modify + public void getLeftovers(List newUnknowns) { + for (String arg : leftoverArgs) { + newUnknowns.add(arg); + } + } +} diff --git a/patchAdapter/src/main/java/differ/SemanticDiffer.java b/patchAdapter/src/main/java/differ/SemanticDiffer.java new file mode 100644 index 0000000..472d580 --- /dev/null +++ b/patchAdapter/src/main/java/differ/SemanticDiffer.java @@ -0,0 +1,698 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package differ; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.io.IOException; + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.File; +import java.io.BufferedReader; +import java.io.FileReader; +import java.nio.file.Paths; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.ParseException; + +import soot.G; +import soot.Main; +import soot.PackManager; +import soot.Scene; +import soot.SourceLocator; +import soot.Transform; +import soot.Transformer; +import soot.SceneTransformer; +import soot.SootClass; +import soot.SootField; +import soot.SootMethod; +import soot.jimple.JasminClass; +import soot.options.Options; +import soot.util.JasminOutputStream; + +public class SemanticDiffer { + + private static CommandLine options; + private static String renameResultDir = "."; + private static String originalRenameSuffix = "Original"; + private static HashMap newClassMap = new HashMap(); + private static HashMap newClassMapReversed = new HashMap(); + private static PatchTransformer patchTransformer; + private static HashMap originalToRedefinitionClassMap = new HashMap(); + private static List allEmittedClassesRedefs = new ArrayList(); + private static List allEmittedClassesHostClasses = new ArrayList(); + private static List originalClassesList = new ArrayList(); + private static List loadedRenamedClasses = new ArrayList(); + private static boolean doDiff = true; + + private static HashMap> redefToDiffSummary = new HashMap>(); + + private static ArrayList allOGNames = new ArrayList(); + private static ArrayList allOGNamesRenamed = new ArrayList(); + private static HashMap> allRemovedMethods = new HashMap>(); + + public static void main(String[] args) throws ParseException { + + // reset if previously run, in same JVM + allOGNames.clear(); + allOGNamesRenamed.clear(); + originalToRedefinitionClassMap.clear(); + + // doesnt die on unknown options, will pass them to soot + RelaxedParser parser = new RelaxedParser(); + options = parser.parse(new SemanticOptions(), args); + List options1 = new ArrayList(); + List options2 = new ArrayList(); + List options1final = new ArrayList(); + List options2final = new ArrayList(); + + if (options.hasOption("finalDestination") && !options.hasOption("renameDestination")) { + System.out.println("Using output dir for both soot runs: " + options.getOptionValue("finalDestination")); + parser.getLeftovers(options2); + options1.add("-d"); + options1.add(options.getOptionValue("finalDestination")); + renameResultDir = options.getOptionValue("finalDestination"); + } else if (!options.hasOption("finalDestination") && options.hasOption("renameDestination")) { + System.out.println("Using output dir for both soot runs: " + options.getOptionValue("renameDestination")); + parser.getLeftovers(options1); + options1.add("-d"); + options1.add(options.getOptionValue("renameDestination")); + renameResultDir = options.getOptionValue("renameDestination"); + } else if (options.hasOption("finalDestination") && options.hasOption("renameDestination")) { + parser.getLeftovers(options1); + options1.add("-d"); + options1.add(options.getOptionValue("renameDestination")); + renameResultDir = options.getOptionValue("renameDestination"); + parser.getLeftovers(options2); + options2.add("-d"); + options2.add(options.getOptionValue("finalDestination")); + } + + if (options.hasOption("runRename") && options.getOptionValue("runRename").equals("true")) { + PackManager.v().getPack("wjtp").add(new Transform("wjtp.renameTransform", createRenameTransformer())); + System.err.println("----------------------------------------------"); + System.out.println( + "SSDIFF: these were the first two options: " + options1.get(0) + " AND " + options1.get(1)); + // trust that if differ is already running with cp options, this run can share + // those, otherwise soot will fail. if not the case, run sequential runs. + if (Options.v().soot_classpath().isEmpty()) { + for (int i = 0; i < options1.size(); i++) { + options1final.add(options1.get(i)); + } + } else { + for (int i = 2; i < options1.size(); i++) { + options1final.add(options1.get(i)); + } + } + if (!Options.v().output_dir().isEmpty()) { + options1final.remove("-d"); + options1final.remove(options1final.size() - 1); + } + + System.out.println("First soot has these options: " + options1final); + System.err.println("----------------------------------------------"); + soot.Main.main(options1final.toArray(new String[0])); + // not sure if this is needed, or if it is included in the overall reset + PackManager.v().getPack("wjtp").remove("wjtp.renameTransform"); + G.reset(); + } + if (doDiff) { + // means that there was something to rename + PackManager.v().getPack("wjtp").add(new Transform("wjtp.myTransform", createDiffTransformer())); + options2final.add("-w"); + + // could handle the mainClass setting better, if useFullDir was false + if (options.hasOption("useFullDir") && options.getOptionValue("useFullDir").equals("true")) { + options2final.add("-process-dir"); + options2final.add(options.getOptionValue("redefcp")); + } else { + if (loadedRenamedClasses.size() == 1 + && !loadedRenamedClasses.contains(options.getOptionValue("mainClass"))) { + options2final.add(loadedRenamedClasses.get(0)); + } else { + options2final.add(options.getOptionValue("mainClass")); + } + } + + Options.v().set_soot_classpath(options.getOptionValue("redefcp") + ":" + options1.get(1)); + + Options.v().set_output_dir(options.getOptionValue("finalDestination")); + Options.v().set_allow_phantom_refs(true); + Options.v().setPhaseOption("cg", "all-reachable:true"); + + System.out.println("Second soot has these options: " + options2final); + System.out.println("Second soot has this classpath: " + Scene.v().getSootClassPath()); + System.err.println("----------------------------------------------"); + soot.Main.main(options2final.toArray(new String[0])); + } + } + + private static Transformer createRenameTransformer() { + return new SceneTransformer() { + protected void internalTransform(String phaseName, Map optionsFromTransform) { + if (options.hasOption("originalclasslist")) { + System.out.println("This is the classlist file to use for reading original classes to rename: " + + options.getOptionValue("originalclasslist")); + ArrayList allOG = gatherClassesFromFile(options.getOptionValue("originalclasslist")); + + Scene.v().getApplicationClasses().clear(); + for (SootClass original : allOG) { + original.rename(original.getName() + originalRenameSuffix); + Scene.v().getOrAddRefType(original.getType()); + original.setApplicationClass(); + } + System.err.println("Finished rename phase."); + System.err.println("----------------------------------------------"); + } else { + System.err.println("Did not receive a list of classes to rename."); + doDiff = false; + } + } + }; + } + + private static Transformer createDiffTransformer() { + return new SceneTransformer() { + protected void internalTransform(String phaseName, Map originalOptions) { + + List mainClassPackageNameComponents = new ArrayList(); + String[] mainClassPackageNameComponentsAll; + // TODO ideally have better way to know package names of many classes in patch + if (loadedRenamedClasses.size() == 1 + && !loadedRenamedClasses.contains(options.getOptionValue("mainClass"))) { + mainClassPackageNameComponentsAll = loadedRenamedClasses.get(0).split("\\."); + } else { + mainClassPackageNameComponentsAll = options.getOptionValue("mainClass").split("\\."); + } + + System.out.println(Arrays.toString(mainClassPackageNameComponentsAll)); + for (int i = 0; i < mainClassPackageNameComponentsAll.length - 1; i++) { + mainClassPackageNameComponents.add(mainClassPackageNameComponentsAll[i]); + } + String mainClassPackageName = String.join("/", mainClassPackageNameComponents) + "/"; + Scene.v().getApplicationClasses().clear(); + + System.out.println("-------------------------------"); + Scene.v().setSootClassPath(options.getOptionValue("redefcp") + ":" + Scene.v().getSootClassPath()); + System.err.println("Classpath before redef/patch classes load: " + Scene.v().getSootClassPath()); + ArrayList allRedefs = gatherClassesFromDir( + options.getOptionValue("redefcp") + "/" + mainClassPackageName, + mainClassPackageName.replace("/", "."), allOGNames); + for (SootClass redef : allRedefs) { + // this is so that the redef classes will also get output'd by soot + redef.setApplicationClass(); + } + + System.err.println("Classes after redef load: "); + System.err.println(Scene.v().getApplicationClasses()); + + System.out.println("-------------------------------"); + Scene.v().setSootClassPath(renameResultDir + ":" + Scene.v().getSootClassPath()); + System.err.println("Classpath before renamed/original classes load: " + Scene.v().getSootClassPath()); + ArrayList allOriginals = gatherClassesFromDir(renameResultDir + "/" + mainClassPackageName, + mainClassPackageName.replace("/", "."), allOGNamesRenamed); + + sortClasses(allOriginals, allRedefs); + System.err.println("Classes map after the sort: " + originalToRedefinitionClassMap); + + System.err.println("Resulting application classes after at beginning of diff phase: "); + System.err.println(Scene.v().getApplicationClasses()); + + patchTransformer = new PatchTransformer(newClassMap, newClassMapReversed); + + // TODO find better way to init, some of this wont work under nonequal og:redef + // ratios + System.out.println("-------------------------------"); + for (SootClass redef : allRedefs) { + System.out.println("Creating a new class with the following name: " + redef.getName() + "NewClass"); + SootClass newClass = new SootClass(redef.getName() + "NewClass", redef.getModifiers()); + newClassMap.put(redef, newClass); + newClassMapReversed.put(newClass, redef); + } + System.out.println("-------------------------------"); + + for (SootClass redef : allRedefs) { + SootClass newClass = newClassMap.get(redef); + // if there is a host for the super, set that as its host's super + if (newClassMap.get(redef.getSuperclass()) != null) { + System.out.println("New class map not null - Setting the newclass's super, new is: " + + newClass.getName() + "super is: " + newClassMap.get(redef.getSuperclass())); + newClass.setSuperclass(newClassMap.get(redef.getSuperclass())); + } else { + System.out.println("Setting the newclass's super, new is: " + newClass.getName() + "super is: " + + redef.getSuperclass().getName()); + newClass.setSuperclass(redef.getSuperclass()); + } + + PatchTransformer.createInitializer(newClass); + // all newclasses will have maps to track who they belong with + PatchTransformer.buildHostMaps(newClass, "originalToHost"); + PatchTransformer.buildHostMaps(newClass, "hostToOriginal"); + PatchTransformer.setupRedefInit(newClass, redef); + } + + for (SootClass og : originalToRedefinitionClassMap.keySet()) { + diff(og, originalToRedefinitionClassMap.get(og)); + } + // now fix all of the method references everywhere, in classes we are outputting + for (SootClass redef : allRedefs) { + + if (allRemovedMethods.get(redef) != null) { + System.out.println("-------------------------------"); + System.out.println("Fixing references in removed method: "); + System.out.println(redef.getName() + " " + allRemovedMethods.get(redef)); + patchTransformer.fixRemovedMethods(allRemovedMethods.get(redef)); + System.out.println("-------------------------------"); + } + + patchTransformer.transformMethodCalls(redef.getMethods(), true); + // might need to omit the init and clinit on this one? + patchTransformer.transformMethodCalls(newClassMap.get(redef).getMethods(), false); + } + + // weird hack to get soot/asm to fix all references in the class to align with + // renaming to OG name + for (SootClass redef : allRedefs) { + String ogRedefName = redef.getName(); + redef.rename(ogRedefName + "Original"); + redef.rename(ogRedefName); + allEmittedClassesRedefs.add(redef.getName()); + } + System.out.println("======================================================"); + for (SootClass newCls : newClassMap.values()) { + if (!Scene.v().containsClass(newCls.getName()) && !newCls.isInScene()) { + Scene.v().addClass(newCls); + allEmittedClassesHostClasses.add(newCls.getName()); + writeNewClass(newCls); + } + } + System.out.println("======================================================"); + } + }; + } + + // not currently responsible for validating that the patch contains at least the + // classes in the original set + private static void sortClasses(ArrayList allOriginals, ArrayList allRedefs) { + for (SootClass redef : allRedefs) { + // unfortunately not efficient since we're doing a name compare, but shouldnt be + // a large set... + for (SootClass og : allOriginals) { + if ((redef.getName() + "Original").equals(og.getName())) { + originalToRedefinitionClassMap.put(og, redef); + break; + } + } + } + } + + // thank you tutorial: https://www.sable.mcgill.ca/soot/tutorial/createclass/ + private static void writeNewClass(SootClass newClass) { + try { + String fileName = SourceLocator.v().getFileNameFor(newClass, Options.output_format_class); + System.out.println("Writing to file using this directory and filename: " + fileName); + File file = new File(fileName); + file.getParentFile().mkdirs(); + OutputStream streamOut = new JasminOutputStream(new FileOutputStream(file)); + PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut)); + + JasminClass jasminClass = new JasminClass(newClass); + jasminClass.print(writerOut); + writerOut.flush(); + streamOut.close(); + } catch (IOException e) { + System.out.println("Could not write a transformer redefinition file!"); + e.printStackTrace(); + } + + } + + private static void diff(SootClass original, SootClass redefinition) { + System.err.println("\n##########################################"); + System.err.println("Diff Report for original: " + original.getName() + " compared to redefinition: " + + redefinition.getName()); + CheckSummary fieldSummary = checkFields(original, redefinition); + CheckSummary methodSummary = checkMethods(original, redefinition); + List summaryList = new ArrayList(); + summaryList.add(methodSummary); + summaryList.add(fieldSummary); + redefToDiffSummary.put(redefinition, summaryList); + System.err.println("---------------------------------------"); + checkInheritance(original, redefinition); + System.err.println("---------------------------------------"); + finishFieldSummary(original, fieldSummary, redefinition, methodSummary); + System.err.println("---------------------------------------"); + finishMethodSummary(methodSummary, redefinition); + System.err.println("---------------------------------------"); + System.err.println("##########################################\n"); + } + + private static CheckSummary checkFields(SootClass original, SootClass redefinition) { + HashMap originalToRedefinitionMap = new HashMap(); + CheckSummary fieldSummary = new CheckSummary(); + + // to avoid recomputing the equivalence checks for all original fields + HashMap originalHashFields = new HashMap(); + HashMap redefinitionHashFields = new HashMap(); + + for (SootField field : original.getFields()) { + originalHashFields.put(new Integer(field.equivHashCode()), field); + } + + for (SootField field : redefinition.getFields()) { + boolean matched = false; + Integer hash = new Integer(field.equivHashCode()); + redefinitionHashFields.put(hash, field); + if (!originalHashFields.containsKey(hash)) { + // modified pre-existing field + for (SootField originalField : original.getFields()) { + + boolean sameType = originalField.getType().toString().equals(field.getType().toString()); + boolean sameName = originalField.getName().equals(field.getName()); + boolean sameModifiers = originalField.getModifiers() == field.getModifiers(); + + if (sameType && sameName) { + // modified modifiers + matched = true; + originalToRedefinitionMap.put(originalField, field); + + System.err.println("\t The following field has had modifiers altered: \n"); + System.err.println(originalField.getDeclaration() + " ---> " + field.getDeclaration()); + } else if (sameType && sameModifiers) { + matched = true; + originalToRedefinitionMap.put(originalField, field); + + System.err.println("\t The following field has had its name altered: \n"); + System.err.println(originalField.getDeclaration() + " ---> " + field.getDeclaration()); + } else if (sameModifiers && sameName) { + matched = true; + originalToRedefinitionMap.put(originalField, field); + + System.err.println("\t The following field has had its type altered: \n"); + System.err.println(originalField.getDeclaration() + " ---> " + field.getDeclaration()); + + } + + } + if (!matched) { + // added field means at least two (or even all three) of the above id factors + // are different + fieldSummary.addAddedItem(field); + } + } + } + for (SootField field : original.getFields()) { + if (!originalToRedefinitionMap.containsKey(field) + && !redefinitionHashFields.containsKey(new Integer(field.equivHashCode()))) { + fieldSummary.addRemovedItem(field); + } + } + + if (originalToRedefinitionMap.size() == 0) { + fieldSummary.changes = false; + } else { + fieldSummary.changes = true; + } + return fieldSummary; + + } + + private static void finishFieldSummary(SootClass original, CheckSummary fieldSummary, SootClass redefinition, + CheckSummary methodSummary) { + + patchTransformer.fixStaticFieldValueChanges(original, redefinition, fieldSummary.addedList); + if (fieldSummary.addedList.size() != 0) { + System.err.println("\t Field(s) have been added."); + System.err.println(fieldSummary.addedList); + } else if (fieldSummary.removedList.size() != 0) { + System.err.println("\tField(s) has been removed"); + System.err.println(fieldSummary.removedList); + for (Object generic : fieldSummary.removedList) { + SootField f = (SootField) generic; + f.setDeclared(false); + redefinition.addField(f); + } + } else if (!fieldSummary.changes) { + System.err.println("\tNo Field differences!"); + } + // fix field refs in potentially added methods even if no fields added + patchTransformer.transformFields(original, redefinition, fieldSummary.addedList, methodSummary.addedList); + + } + + private static CheckSummary checkMethods(SootClass original, SootClass redefinition) { + HashMap originalToRedefinitionMap = new HashMap(); + CheckSummary methodSummary = new CheckSummary(); + + // to avoid recomputing the equivalence checks for all original methods + HashMap originalHashMethods = new HashMap(); + HashMap redefinitionHashMethods = new HashMap(); + + for (SootMethod method : original.getMethods()) { + originalHashMethods.put(new Integer(ownEquivMethodHash(method)), method); + } + + for (SootMethod method : redefinition.getMethods()) { + + boolean matched = false; + Integer hash = new Integer(ownEquivMethodHash(method)); + redefinitionHashMethods.put(hash, method); + if (!originalHashMethods.containsKey(hash)) { + // modified pre-existing method + for (SootMethod originalMethod : original.getMethods()) { + + // if there is an exact match for this original item, dont bother to ask if it + // matches a transformed item + if (!redefinitionHashMethods.containsKey(ownEquivMethodHash(originalMethod))) { + + boolean sameType = originalMethod.getReturnType().toString() + .equals(method.getReturnType().toString()); + boolean sameName = originalMethod.getName().equals(method.getName()); + boolean sameModifiers = originalMethod.getModifiers() == method.getModifiers(); + boolean sameParameters = originalMethod.getParameterTypes().equals(method.getParameterTypes()); + + if (sameType && sameName && sameParameters && !sameModifiers) { + // modified modifiers + matched = true; + originalToRedefinitionMap.put(originalMethod, method); + + System.err.println("\t The following method has had modifiers altered: \n"); + System.err.println(originalMethod.getDeclaration() + " ---> " + method.getDeclaration()); + } + /* + * else if(sameType && sameModifiers && sameParameters){ //modified name, + * actually not sure if we can even detect this truly, currently leaving here as + * //option, but is handled as new method, not altered method matched = true; + * originalToRedefinitionMap.put(originalMethod, method); + * + * System.err.println("\t The following method has had its name altered: \n"); + * System.err.println(originalMethod.getDeclaration() + " ---> " + + * method.getDeclaration()); } + */ + else if (sameModifiers && sameName && sameParameters && !sameType) { + // modified return type + matched = true; + originalToRedefinitionMap.put(originalMethod, method); + + System.err.println("\t The following method has had its type altered: \n"); + System.err.println(originalMethod.getDeclaration() + " ---> " + method.getDeclaration()); + + } + } + } + if (!matched) { + // added method means at least two (or even all three) of the above id factors + // are different + methodSummary.addAddedItem(method); + } + } + } + for (SootMethod method : original.getMethods()) { + if (!originalToRedefinitionMap.containsKey(method) + && !redefinitionHashMethods.containsKey(new Integer(ownEquivMethodHash(method)))) { + methodSummary.addRemovedItem(method); + } + } + + if (originalToRedefinitionMap.size() == 0) { + methodSummary.changes = false; + } else { + methodSummary.changes = true; + } + + return methodSummary; + } + + private static void finishMethodSummary(CheckSummary methodSummary, SootClass redefinition) { + if (methodSummary.addedList.size() != 0) { + System.err.println("\t Method(s) have been added."); + System.err.println(methodSummary.addedList); + // do the method moving as we go + patchTransformer.moveMethodCalls(redefinition, methodSummary.addedList); + // also fix the instance method refs that exist in moved methods, since "this" + // is now wrong + patchTransformer.fixMethodRefsInAddedMethods(redefinition, methodSummary.addedList); + } else if (methodSummary.removedList.size() != 0) { + allRemovedMethods.put(redefinition, new ArrayList()); + System.err.println("\tMethod(s) has been removed"); + System.err.println(methodSummary.removedList); + for (Object generic : methodSummary.removedList) { + SootMethod m = (SootMethod) generic; + m.setDeclared(false); + redefinition.addMethod(m); + allRemovedMethods.get(redefinition).add(m); + } + } else if (!methodSummary.changes) { + System.err.println("\tNo Method differences!"); + } + } + + private static void checkInheritance(SootClass original, SootClass redefinition) { + boolean originalHasSuper = original.hasSuperclass(); + boolean redefinitionHasSuper = redefinition.hasSuperclass(); + if ((originalHasSuper && !redefinitionHasSuper) || (!originalHasSuper && redefinitionHasSuper)) { + System.err.println("\tInheritance Diff!"); + System.err.println("\tOriginal class has superclass: " + original.getSuperclassUnsafe() + + " and redefinition has superclass: " + redefinition.getSuperclassUnsafe()); + + } else if (redefinition.hasSuperclass() && original.hasSuperclass() + && !(redefinition.getSuperclass().getName().equals(original.getSuperclass().getName())) + && !(redefinition.getSuperclass().getName() + originalRenameSuffix) + .equals(original.getSuperclass().getName())) { + System.err.println("\tInheritance Diff!"); + System.err.println("\tOriginal class has superclass: " + original.getSuperclassUnsafe() + + " and redefinition has superclass: " + redefinition.getSuperclassUnsafe()); + + } else if (original.getInterfaceCount() != redefinition.getInterfaceCount()) { + System.err.println("\tInheritance Diff!"); + System.err.println("\tOriginal class has interfaces: " + original.getInterfaces() + + " and redefinition has interfaces: " + redefinition.getInterfaces()); + } else { + System.err.println("\tNo Inheritance differences!"); + } + } + + protected static int ownEquivMethodHash(SootMethod method) { + // considers the params, since they would be in a signature, unlike: + // https://github.com/Sable/soot/blob/master/src/main/java/soot/SootMethod.java#L133 + // basically we treat each definition of an overloaded method as different, + // while soot would not (for some reason) + return method.getReturnType().hashCode() * 101 + method.getModifiers() * 17 + method.getName().hashCode() + + method.getParameterTypes().hashCode(); + + } + + // resolves all of the classes in some dir that defines the patch (== set of + // classes) + private static ArrayList gatherClassesFromDir(String strdir, String packagename, + ArrayList OGList) { + System.out.println("Gathering classes from: " + strdir); + ArrayList allNames = new ArrayList(); + try { + File dir = new File(strdir); + File[] directoryListing = dir.listFiles(); + if (directoryListing != null) { + for (File file : directoryListing) { + if (file.toString().contains("class")) { + // ugly parsing, its the only way tho? + String classname = null; + if (packagename.equals(".")) { + // no package prefix + String[] namepieces = file.toString().replace(".class", "").split("/"); + classname = namepieces[namepieces.length - 1]; + if (OGList.contains(classname)) { + System.out.println("Gathering class: " + classname); + allNames.add(classname); + } + } else { + classname = file.toString().replaceFirst(strdir, "").replace(".class", "").replaceAll("\\/", + "."); + if (OGList.contains(packagename + classname)) { + System.out.println("Gathering class: " + packagename + classname); + allNames.add(packagename + classname); + } + } + } + } + } else { + System.out.println("Directory supplied is not sufficient to read."); + } + } catch (Exception e) { + System.out.println("Some issue accessing the classes to be renamed: " + e.getMessage()); + } + ArrayList allClasses = resolveClasses(allNames); + return allClasses; + } + + // reads the classes that designate the patch, from a file. One class per line, + // fqn. + // needs to exist bc each class to analyse may require many classes to be + // patched for it + private static ArrayList gatherClassesFromFile(String originalClassesList) { + ArrayList allClasses = new ArrayList(); + try { + if (new File(originalClassesList).exists()) { + System.out.println("SSDIFF: Reading patch classes from: " + originalClassesList); + BufferedReader in = new BufferedReader(new FileReader(originalClassesList)); + String str; + while ((str = in.readLine()) != null) { + String name = str.replace(".class", "").replaceAll("\\/", "."); + if (!allOGNames.contains(name)) { + allOGNames.add(name); + allOGNamesRenamed.add(name + originalRenameSuffix); + loadedRenamedClasses.add(name); + } + } + allClasses = resolveClasses(allOGNames); + } + } catch (Exception e) { + System.out.println("Some issue accessing the classes to be renamed: " + e.getMessage()); + } + return allClasses; + } + + private static ArrayList resolveClasses(ArrayList allNames) { + ArrayList allClasses = new ArrayList(); + for (String classname : allNames) { + System.out.println("Resolving class: " + classname); + SootClass resolvedClass = Scene.v().forceResolve(classname, SootClass.BODIES); + allClasses.add(resolvedClass); + } + return allClasses; + } + + public static List getGeneratedClassesRedefs() { + return allEmittedClassesRedefs; + } + + public static List getGeneratedClassesHosts() { + return allEmittedClassesHostClasses; + } + +} diff --git a/patchAdapter/src/main/java/differ/SemanticOptions.java b/patchAdapter/src/main/java/differ/SemanticOptions.java new file mode 100644 index 0000000..19588bd --- /dev/null +++ b/patchAdapter/src/main/java/differ/SemanticOptions.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package differ; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; + +public class SemanticOptions extends Options { + + public SemanticOptions() { + Option redefinitionClass = Option.builder().longOpt("redefcp").hasArg().required() + .desc("Specify the classpath of the redefinition classes.").build(); + addOption(redefinitionClass); + + Option originalClass = Option.builder().longOpt("originalclasslist").hasArg() + .desc("Specify a file containing the list of original classes.").build(); + addOption(originalClass); + + Option firstDest = Option.builder().longOpt("renameDestination").hasArg() + .desc("Specify the first directory for the renamed class to go to.").build(); + addOption(firstDest); + + Option altDest = Option.builder().longOpt("finalDestination").hasArg() + .desc("Specify the directory for the adapter output to go to.").build(); + addOption(altDest); + + // bit odd to have arg, but bc of parsing strategy in relaxed parser to sort our + // opts from soot opts. + Option runRename = Option.builder().longOpt("runRename").hasArg() + .desc("Specify whether the rename phase should be run. Default false.").build(); + addOption(runRename); + + Option mainClass = Option.builder().longOpt("mainClass").hasArg().desc( + "Specify the actual main class of the application, to be provided to Soot AFTER Soot startup has occurred.") + .build(); + addOption(mainClass); + + Option differClasspath = Option.builder().longOpt("differClasspath").hasArg().desc( + "Specify the classpath for the patch adapter's run of Soot. May be different than that of a Cogni+Soot run, if patch adapter is run from HOTFIXER.") + .build(); + addOption(differClasspath); + + Option useFullDir = Option.builder().longOpt("useFullDir").hasArg() + .desc("Specify whether Soot's process-dir option should be used or not.").build(); + addOption(useFullDir); + + } +} diff --git a/patchAdapter/src/main/java/testexamples/Example.java b/patchAdapter/src/main/java/testexamples/Example.java new file mode 100644 index 0000000..0685e81 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/Example.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +public class Example { + + //a placeholder for Soot + + +} diff --git a/patchAdapter/src/main/java/testexamples/fieldaddition/AdditionFieldTest.java b/patchAdapter/src/main/java/testexamples/fieldaddition/AdditionFieldTest.java new file mode 100644 index 0000000..e15338e --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/fieldaddition/AdditionFieldTest.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.fieldaddition; + +public class AdditionFieldTest { + + //public int newField; + //public static int secondNewField = 1; + + public int returnSame(int x){ + int local = x; + //newField = local; + //return newField; + return local + 1; + } + + public int returnAValue(){ + //return secondNewField; + return 7; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionmonomorphic/AdditionMethodMonomorphicTest.java b/patchAdapter/src/main/java/testexamples/methodadditionmonomorphic/AdditionMethodMonomorphicTest.java new file mode 100644 index 0000000..a19b81f --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionmonomorphic/AdditionMethodMonomorphicTest.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionmonomorphic; + +public class AdditionMethodMonomorphicTest { + + public int field; + + public int returnSamePlusSeven(int x){ + field = 7; + int temp = field; + //int temp = newMethod(x); + //thirdNewMethod(); //test for ref replacement, not result + return temp; + } + + public void testPrinter(){ + System.out.println("Hello World!"); + } + + /* + public int newMethod(int y){ + testPrinter(); + secondNewMethod(); //test for ref replacement, not result + return field + y; + } + + public void secondNewMethod(){ + System.out.println("This is second new method!"); + } + + public static void thirdNewMethod(){ + System.out.println("This is third new method!"); + } + */ +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFive.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFive.java new file mode 100644 index 0000000..8580e12 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFive.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) parent method in patch version + * 2) grandparent method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildFive extends AdditionMethodPolymorphicTestChildOne { + + +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFour.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFour.java new file mode 100644 index 0000000..6031d48 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildFour.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) parent method in patch version and original version + * + */ + +public class AdditionMethodPolymorphicTestChildFour extends AdditionMethodPolymorphicTestChildTwo { + + +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildOne.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildOne.java new file mode 100644 index 0000000..6ef94ce --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildOne.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * child class which relies on: + * 1) parent method in original version + * 2) overriding method in patch version + * + */ + +public class AdditionMethodPolymorphicTestChildOne extends AdditionMethodPolymorphicTestParent { + + /* + public int emitMethod(){ + return 1; + } + */ +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildSix.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildSix.java new file mode 100644 index 0000000..f9254c0 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildSix.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) parent method in original version + * 2) overriding method in patch version + */ + +public class AdditionMethodPolymorphicTestChildSix extends AdditionMethodPolymorphicTestChildTwo { + + /* + public int emitMethod(){ + return 6; + } + */ +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildThree.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildThree.java new file mode 100644 index 0000000..cdd81b2 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildThree.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * grand-child class which relies on: + * 1) overriding method in patch version + * 2) grand-parent method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildThree extends AdditionMethodPolymorphicTestChildOne { + + /* + public int emitMethod(){ + return 3; + } + */ +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildTwo.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildTwo.java new file mode 100644 index 0000000..c8b6a6a --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestChildTwo.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +/* + * child class which relies on: + * 1) overriding method in original version and patch version + */ + +public class AdditionMethodPolymorphicTestChildTwo extends AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 2; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestParent.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestParent.java new file mode 100644 index 0000000..3a17ac4 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/AdditionMethodPolymorphicTestParent.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +public class AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 0; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/UserPolyTest.java b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/UserPolyTest.java new file mode 100644 index 0000000..397d044 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodadditionpolymorphic/UserPolyTest.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodadditionpolymorphic; + +public class UserPolyTest { + + public int use(int decision){ + AdditionMethodPolymorphicTestParent p; + if(decision == 1){ + p = new AdditionMethodPolymorphicTestChildOne(); + } else if(decision == 2) { + p = new AdditionMethodPolymorphicTestChildTwo(); + } else if(decision == 3) { + p = new AdditionMethodPolymorphicTestChildThree(); + } else if(decision == 4) { + p = new AdditionMethodPolymorphicTestChildFour(); + } else if(decision == 5) { + p = new AdditionMethodPolymorphicTestChildFive(); + } else if(decision == 6) { + p = new AdditionMethodPolymorphicTestChildSix(); + } else { + p = new AdditionMethodPolymorphicTestParent(); + } + return p.emitMethod(); + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFive.java b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFive.java new file mode 100644 index 0000000..7669b03 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFive.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) grandparent method in patch version + * 2) parent method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildFive extends AdditionMethodPolymorphicTestChildOne { + + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFour.java b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFour.java new file mode 100644 index 0000000..98c64cd --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildFour.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) parent method in patch version and original version + * + */ + +public class AdditionMethodPolymorphicTestChildFour extends AdditionMethodPolymorphicTestChildTwo { + + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildOne.java b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildOne.java new file mode 100644 index 0000000..3132c0b --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildOne.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * child class which relies on: + * 1) overriding method in original version + * 2) parent method in patch version + * + */ + +public class AdditionMethodPolymorphicTestChildOne extends AdditionMethodPolymorphicTestParent { + + + public int emitMethod(){ + return 1; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildSix.java b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildSix.java new file mode 100644 index 0000000..8c88813 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildSix.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) overriding method in original version + * 2) parent method in patch version + */ + +public class AdditionMethodPolymorphicTestChildSix extends AdditionMethodPolymorphicTestChildTwo { + + + public int emitMethod(){ + return 6; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildThree.java b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildThree.java new file mode 100644 index 0000000..859145b --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildThree.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * grand-child class which relies on: + * 1) grand-parent method in patch version + * 2) overriding method in original version + * + */ + +public class AdditionMethodPolymorphicTestChildThree extends AdditionMethodPolymorphicTestChildOne { + + + public int emitMethod(){ + return 3; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildTwo.java b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildTwo.java new file mode 100644 index 0000000..4d7db96 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestChildTwo.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +/* + * child class which relies on: + * 1) overriding method in original version and patch version + */ + +public class AdditionMethodPolymorphicTestChildTwo extends AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 2; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestParent.java b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestParent.java new file mode 100644 index 0000000..31448d3 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/AdditionMethodPolymorphicTestParent.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +public class AdditionMethodPolymorphicTestParent { + + public int emitMethod(){ + return 0; + } + +} diff --git a/patchAdapter/src/main/java/testexamples/methodremoval/UserPolyTest.java b/patchAdapter/src/main/java/testexamples/methodremoval/UserPolyTest.java new file mode 100644 index 0000000..c55f0b4 --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/methodremoval/UserPolyTest.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.methodremoval; + +public class UserPolyTest { + + public int use(int decision){ + AdditionMethodPolymorphicTestParent p; + if(decision == 1){ + p = new AdditionMethodPolymorphicTestChildOne(); + } else if(decision == 2) { + p = new AdditionMethodPolymorphicTestChildTwo(); + } else if(decision == 3) { + p = new AdditionMethodPolymorphicTestChildThree(); + } else if(decision == 4) { + p = new AdditionMethodPolymorphicTestChildFour(); + } else if(decision == 5) { + p = new AdditionMethodPolymorphicTestChildFive(); + } else if(decision == 6) { + p = new AdditionMethodPolymorphicTestChildSix(); + } else { + p = new AdditionMethodPolymorphicTestParent(); + } + return p.emitMethod(); + } + +} diff --git a/patchAdapter/src/main/java/testexamples/nochange/NoChangeTest.java b/patchAdapter/src/main/java/testexamples/nochange/NoChangeTest.java new file mode 100644 index 0000000..4c9e96c --- /dev/null +++ b/patchAdapter/src/main/java/testexamples/nochange/NoChangeTest.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2020, 2020 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception + *******************************************************************************/ + +package testexamples.nochange; + +public class NoChangeTest { + + public String hi; + private int one; + public static final String hello = "hello"; + protected static int two = 2; + + public static int calcSquare(int x){ + return x * x; + } + + private void makeString(){ + one = 1; + System.out.println(hello + two + one); + } + +}