diff options
author | mikaelpeltier <mikaelpeltier@google.com> | 2015-04-13 17:55:06 +0200 |
---|---|---|
committer | mikaelpeltier <mikaelpeltier@google.com> | 2015-04-28 12:09:39 +0200 |
commit | 88ac57db8ef6442d2a87aacad089104b488052e0 (patch) | |
tree | 02658f780e4ea5692a6d3749e09ec93c7931f30c | |
parent | 923fed570156cb3e14ae2cb21829bc0e70d3f9be (diff) | |
download | toolchain_jack-88ac57db8ef6442d2a87aacad089104b488052e0.zip toolchain_jack-88ac57db8ef6442d2a87aacad089104b488052e0.tar.gz toolchain_jack-88ac57db8ef6442d2a87aacad089104b488052e0.tar.bz2 |
During shrinking generate error if they are unknow types
- When shrinking all used types must be passed into classpath,
without these types into classpath, Jack could shrink class members that it
should not.
Bug: 20135591
Change-Id: I4b4b03581141df0e40b1f27ccfc2f3a481b5d069
6 files changed, 258 insertions, 1 deletions
diff --git a/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java b/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java index 44128a9..a31cc2c 100644 --- a/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java +++ b/jack-tests/tests/com/android/jack/fileconflict/FileConflictTests.java @@ -577,6 +577,8 @@ public class FileConflictTests { toolchain = getToolchain(isApiTest); toolchain.addProguardFlags(new File(TEST001_DIR, "proguard.flags")); toolchain.addStaticLibs(jackImport1, jackImport2); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); + if (collisionPolicy != null) { toolchain.addProperty(JayceFileImporter.COLLISION_POLICY.getName(), collisionPolicy); } diff --git a/jack-tests/tests/com/android/jack/resource/ResourceTests.java b/jack-tests/tests/com/android/jack/resource/ResourceTests.java index a5d46ff..ca8ee9b 100644 --- a/jack-tests/tests/com/android/jack/resource/ResourceTests.java +++ b/jack-tests/tests/com/android/jack/resource/ResourceTests.java @@ -143,6 +143,7 @@ public class ResourceTests { File shrobbedJackAr = AbstractTestTools.createTempFile("shrobbedJackAr", toolchain.getLibraryExtension()); toolchain.addProguardFlags(new File(FILE, "proguard.flags")); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); toolchain.libToLib(jackAr, shrobbedJackAr, /* zipFiles = */ true); // check that resources are contained in dex archive @@ -170,6 +171,7 @@ public class ResourceTests { File shrobbedJackAr = AbstractTestTools.createTempFile("shrobbedJackAr", toolchain.getLibraryExtension()); toolchain.addProguardFlags(new File(FILE, "proguard.flags")); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); toolchain.libToLib(jackFolder, shrobbedJackAr, /* zipFiles = */ true); // check that resources are contained in Jack archive @@ -189,6 +191,7 @@ public class ResourceTests { File shrobbedJackDir = AbstractTestTools.createTempDir(); JackBasedToolchain toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); toolchain.addProguardFlags(new File(FILE, "proguard.flags")); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); toolchain.libToLib(jackAr, shrobbedJackDir, /* zipFiles = */ false); // check that resources are contained in Jack dir @@ -215,6 +218,7 @@ public class ResourceTests { File shrobbedJackDir = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); toolchain.addProguardFlags(new File(FILE, "proguard.flags")); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); toolchain.libToLib(jackFolder, shrobbedJackDir, /* zipFiles = */ false); // check that resources are contained in Jack dir diff --git a/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java b/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java index 6ffa637..8e03f6a 100644 --- a/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java +++ b/jack-tests/tests/com/android/jack/shrob/ShrinkTests.java @@ -16,18 +16,25 @@ package com.android.jack.shrob; +import com.google.common.io.NullOutputStream; + +import com.android.jack.JackAbortException; import com.android.jack.Main; import com.android.jack.Options; import com.android.jack.ProguardFlags; import com.android.jack.shrob.shrink.ShrinkStructurePrinter; +import com.android.jack.shrob.shrink.ShrinkingException; import com.android.jack.test.comparator.ComparatorMapping; import com.android.jack.test.helper.SourceToDexComparisonTestHelper; import com.android.jack.test.toolchain.AbstractTestTools; import com.android.jack.test.toolchain.DummyToolchain; +import com.android.jack.test.toolchain.IToolchain; import com.android.jack.test.toolchain.JackApiToolchainBase; import com.android.jack.test.toolchain.JackBasedToolchain; import com.android.jack.util.TextUtils; +import junit.framework.Assert; + import org.junit.BeforeClass; import org.junit.Test; @@ -113,6 +120,7 @@ public class ShrinkTests extends AbstractTest { toolchain.addProguardFlags( dontObfuscateFlagFile, new ProguardFlags(new File(shrobTestsDir, "test020"),"proguard.flags")); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); toolchain.libToLib( testOut, shrinkOut, @@ -162,6 +170,7 @@ public class ShrinkTests extends AbstractTest { dontObfuscateFlagFile, new ProguardFlags(new File( shrobTestsDir, "test021"),"proguard.flags001")); shrinkOut = AbstractTestTools.createTempDir(); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); toolchain.libToLib(jackOut, shrinkOut, /* zipFiles = */ false); new ComparatorMapping(candidateNodeListing, @@ -169,6 +178,7 @@ public class ShrinkTests extends AbstractTest { dexOut = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()); toolchain.libToExe(shrinkOut, dexOut, /* zipFile = */ false); } catch (Exception e) { @@ -228,4 +238,118 @@ public class ShrinkTests extends AbstractTest { public void test42_003() throws Exception { runTest("042", "003", ""); } + + /** + * Check that a program importing a library using another library is well shrinked, if the used + * library is on the classpath. If the used library is not on the classpath, Jack must generate + * an error otherwise it could shrink class members that are needed. + */ + @Test + public void test45_001() throws Exception { + String testNumber = "045"; + String flagNumber = "001"; + + File lib2Out = AbstractTestTools.createTempDir(); + JackBasedToolchain toolchainLib2 = + AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); + toolchainLib2.addToClasspath(toolchainLib2.getDefaultBootClasspath()).srcToLib(lib2Out, + /* zipFiles = */false, new File(shrobTestsDir, "test" + testNumber + "/lib2")); + + File lib1Out = AbstractTestTools.createTempDir(); + JackBasedToolchain toolchainLib1 = + AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); + toolchainLib1.addToClasspath(lib2Out); + toolchainLib1.addToClasspath(toolchainLib1.getDefaultBootClasspath()).srcToLib(lib1Out, + /* zipFiles = */false, new File(shrobTestsDir, "test" + testNumber + "/lib1")); + + JackBasedToolchain toolchain = + AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); + + File testFolder = new File(shrobTestsDir, "test" + testNumber); + File refFolder = new File(testFolder, "refsShrinking"); + + File candidateNodeListing = AbstractTestTools.createTempFile("nodeListing", ".txt"); + toolchain.addProperty(ShrinkStructurePrinter.STRUCTURE_PRINTING.getName(), "true"); + toolchain.addProperty(ShrinkStructurePrinter.STRUCTURE_PRINTING_FILE.getName(), + candidateNodeListing.getPath()); + toolchain.addProperty(Options.METHOD_FILTER.getName(), "supported-methods"); + toolchain.disableDxOptimizations(); + toolchain.addStaticLibs(lib1Out); + toolchain.addToClasspath(lib2Out); + + File outFolder = AbstractTestTools.createTempDir(); + + SourceToDexComparisonTestHelper env = + new SourceToDexComparisonTestHelper(new File(testFolder, "jack")); + + env.setWithDebugInfo(true); + env.setCandidateTestTools(toolchain); + env.setReferenceTestTools(new DummyToolchain()); + env.setProguardFlags(dontObfuscateFlagFile, + new ProguardFlags(testFolder, "proguard.flags" + flagNumber)); + + env.runTest(new ComparatorMapping(new File(refFolder, "expected-" + flagNumber + ".txt"), + candidateNodeListing)); + } + + /** + * Check that a program importing a library using another library generate an error if the use + * library is not into the classpath. If the used library is not on the classpath, Jack must + * generate an error otherwise it could shrink class members that are needed. + */ + @Test + public void test45_001_bis() throws Exception { + String testNumber = "045"; + String flagNumber = "001"; + + File lib2Out = AbstractTestTools.createTempDir(); + JackApiToolchainBase toolchainLib2 = + AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); + toolchainLib2.addToClasspath(toolchainLib2.getDefaultBootClasspath()).srcToLib(lib2Out, + /* zipFiles = */false, new File(shrobTestsDir, "test" + testNumber + "/lib2")); + + File lib1Out = AbstractTestTools.createTempDir(); + JackApiToolchainBase toolchainLib1 = + AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); + toolchainLib1.addToClasspath(lib2Out); + toolchainLib1.addToClasspath(toolchainLib1.getDefaultBootClasspath()).srcToLib(lib1Out, + /* zipFiles = */false, new File(shrobTestsDir, "test" + testNumber + "/lib1")); + + JackApiToolchainBase toolchain = + AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); + + File testFolder = new File(shrobTestsDir, "test" + testNumber); + File refFolder = new File(testFolder, "refsShrinking"); + + File candidateNodeListing = AbstractTestTools.createTempFile("nodeListing", ".txt"); + toolchain.addProperty(ShrinkStructurePrinter.STRUCTURE_PRINTING.getName(), "true"); + toolchain.addProperty(ShrinkStructurePrinter.STRUCTURE_PRINTING_FILE.getName(), + candidateNodeListing.getPath()); + toolchain.addProperty(Options.METHOD_FILTER.getName(), "supported-methods"); + toolchain.disableDxOptimizations(); + toolchain.addStaticLibs(lib1Out); + toolchain.setErrorStream(new NullOutputStream()); + File outFolder = AbstractTestTools.createTempDir(); + + SourceToDexComparisonTestHelper env = + new SourceToDexComparisonTestHelper(new File(testFolder, "jack")); + + env.setWithDebugInfo(true); + env.setCandidateTestTools(toolchain); + env.setReferenceTestTools(new DummyToolchain()); + env.setProguardFlags(dontObfuscateFlagFile, + new ProguardFlags(testFolder, "proguard.flags" + flagNumber)); + + try { + env.runTest(new ComparatorMapping(new File(refFolder, "expected-" + flagNumber + ".txt"), + candidateNodeListing)); + } catch (JackAbortException e) { + Assert.assertTrue(e.getCause() instanceof ShrinkingException); + Assert + .assertEquals( + "Error during the skrinking: Unknown referenced type 'com.android.jack.shrob.test045." + + "lib2.A'. Add type into your classpath.", + e.getMessage()); + } + } } diff --git a/jack-tests/tests/com/android/jack/withphantom/WithPhantomTests.java b/jack-tests/tests/com/android/jack/withphantom/WithPhantomTests.java index 8967a4d..e3918ef 100644 --- a/jack-tests/tests/com/android/jack/withphantom/WithPhantomTests.java +++ b/jack-tests/tests/com/android/jack/withphantom/WithPhantomTests.java @@ -77,21 +77,26 @@ public class WithPhantomTests { File tempOut1 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class, exclude); toolchain.addProguardFlags(new ProguardFlags(testFolder, "shrink1.flags")) + .addToClasspath(toolchain.getDefaultBootClasspath()) .libToLib(tempJackFolder, tempOut1, /* zipFiles = */ false); File tempOut2 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class, exclude); - toolchain.addProguardFlags(new ProguardFlags(testFolder, "shrink2.flags")) + toolchain.addToClasspath(toolchain.getDefaultBootClasspath()) + .addProguardFlags(new ProguardFlags(testFolder, "shrink2.flags")) + .libToLib(tempJackFolder, tempOut2, /* zipFiles = */ false); File tempOut3 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class, exclude); toolchain.addProguardFlags(new ProguardFlags(testFolder, "obf1.flags")) + .addToClasspath(toolchain.getDefaultBootClasspath()) .libToLib(tempJackFolder, tempOut3, /* zipFiles = */ false); File tempOut4 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class, exclude); toolchain.addProguardFlags(new ProguardFlags(testFolder, "obf2.flags")) + .addToClasspath(toolchain.getDefaultBootClasspath()) .libToLib(tempJackFolder, tempOut4, /* zipFiles = */ false); File tempOut5 = AbstractTestTools.createTempDir(); @@ -126,21 +131,25 @@ public class WithPhantomTests { File tempOut1 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); toolchain.addProguardFlags(new ProguardFlags(testFolder, "shrink1.flags")) + .addToClasspath(toolchain.getDefaultBootClasspath()) .libToLib(tempJackFolder, tempOut1, /* zipFiles = */ false); File tempOut2 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); toolchain.addProguardFlags(new ProguardFlags(testFolder, "shrink2.flags")) + .addToClasspath(toolchain.getDefaultBootClasspath()) .libToLib(tempJackFolder, tempOut2, /* zipFiles = */ false); File tempOut3 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); toolchain.addProguardFlags(new ProguardFlags(testFolder, "obf1.flags")) + .addToClasspath(toolchain.getDefaultBootClasspath()) .libToLib(tempJackFolder, tempOut3, /* zipFiles = */ false); File tempOut4 = AbstractTestTools.createTempDir(); toolchain = AbstractTestTools.getCandidateToolchain(JackBasedToolchain.class); toolchain.addProguardFlags(new ProguardFlags(testFolder, "obf2.flags")) + .addToClasspath(toolchain.getDefaultBootClasspath()) .libToLib(tempJackFolder, tempOut4, /* zipFiles = */ false); File tempOutFolder = AbstractTestTools.createTempDir(); diff --git a/jack/src/com/android/jack/shrob/shrink/KeeperBrush.java b/jack/src/com/android/jack/shrob/shrink/KeeperBrush.java index d6f14c7..b323f3d 100644 --- a/jack/src/com/android/jack/shrob/shrink/KeeperBrush.java +++ b/jack/src/com/android/jack/shrob/shrink/KeeperBrush.java @@ -16,12 +16,23 @@ package com.android.jack.shrob.shrink; +import com.android.jack.Jack; +import com.android.jack.JackAbortException; import com.android.jack.analysis.tracer.AbstractTracerBrush; import com.android.jack.analysis.tracer.Tracer; +import com.android.jack.ir.ast.JClass; +import com.android.jack.ir.ast.JDefinedClass; import com.android.jack.ir.ast.JDefinedClassOrInterface; +import com.android.jack.ir.ast.JDefinedInterface; import com.android.jack.ir.ast.JField; +import com.android.jack.ir.ast.JInterface; import com.android.jack.ir.ast.JMethod; import com.android.jack.ir.ast.JNode; +import com.android.jack.ir.ast.JPhantomClass; +import com.android.jack.ir.ast.JPhantomClassOrInterface; +import com.android.jack.ir.ast.JPhantomInterface; +import com.android.jack.ir.formatter.UserFriendlyFormatter; +import com.android.jack.reporting.Reporter.Severity; import com.android.jack.shrob.seed.SeedMarker; import com.android.jack.shrob.spec.KeepModifier; import com.android.sched.item.Description; @@ -43,6 +54,26 @@ import javax.annotation.Nonnull; @HasKeyId public class KeeperBrush extends AbstractTracerBrush<KeepMarker> { + private static final class UnknownReferencedTypeException extends Exception { + + private static final long serialVersionUID = 1L; + + @Nonnull + private final JPhantomClassOrInterface phantomClOrI; + + private UnknownReferencedTypeException(@Nonnull JPhantomClassOrInterface phantomClOrI) { + this.phantomClOrI = phantomClOrI; + } + + @Override + @Nonnull + public String getMessage() { + return "Unknown referenced type '" + + UserFriendlyFormatter.getFormatter().getName(phantomClOrI) + + "'. Add type into your classpath."; + } + } + @Nonnull public static final BooleanPropertyId KEEP_ENCLOSING_METHOD = BooleanPropertyId.create( "jack.shrink.keep.enclosing.method", @@ -117,4 +148,45 @@ public class KeeperBrush extends AbstractTracerBrush<KeepMarker> { return marker != null && marker.getModifier() != KeepModifier.ALLOW_SHRINKING; } + @Override + public boolean startTrace(@Nonnull JDefinedClassOrInterface type) { + boolean traceType = markIfNecessary(type); + if (traceType) { + try { + if (type instanceof JDefinedClass) { + verifyHierarchy((JDefinedClass) type); + } else { + assert type instanceof JDefinedInterface; + verifyImplementedInterfaces(type); + } + } catch (UnknownReferencedTypeException e) { + ShrinkingException reportable = new ShrinkingException(e); + Jack.getSession().getReporter().report(Severity.FATAL, reportable); + throw new JackAbortException(reportable); + } + } + return traceType; + } + + private void verifyHierarchy(@Nonnull JDefinedClass t) throws UnknownReferencedTypeException { + JClass superClass = t.getSuperClass(); + if (superClass instanceof JPhantomClass) { + throw new UnknownReferencedTypeException((JPhantomClass) superClass); + } else if (superClass != null) { + verifyHierarchy((JDefinedClass) superClass); + } + verifyImplementedInterfaces(t); + } + + private void verifyImplementedInterfaces(@Nonnull JDefinedClassOrInterface t) + throws UnknownReferencedTypeException { + for (JInterface jInterface : t.getImplements()) { + if (jInterface instanceof JPhantomInterface) { + throw new UnknownReferencedTypeException((JPhantomInterface) jInterface); + } else { + assert jInterface instanceof JDefinedInterface; + verifyImplementedInterfaces((JDefinedInterface) jInterface); + } + } + } } diff --git a/jack/src/com/android/jack/shrob/shrink/ShrinkingException.java b/jack/src/com/android/jack/shrob/shrink/ShrinkingException.java new file mode 100644 index 0000000..b543e73 --- /dev/null +++ b/jack/src/com/android/jack/shrob/shrink/ShrinkingException.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.jack.shrob.shrink; + +import com.android.jack.reporting.ReportableException; + +import javax.annotation.Nonnull; + +/** + * A {@link ReportableException} that occurs during the shrinking. + */ +public class ShrinkingException extends ReportableException { + + private static final long serialVersionUID = 1L; + + public ShrinkingException(@Nonnull Throwable cause) { + super(cause); + } + + @Override + @Nonnull + public String getMessage() { + return "Error during skrinking: " + getCause().getMessage(); + } + + @Override + @Nonnull + public ProblemLevel getDefaultProblemLevel() { + return ProblemLevel.ERROR; + } + +} |