Add flag for asm verification of inputs
Change-Id: Ic3f3019435c818de6d44f440c463848eab30a7e7
diff --git a/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java b/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java
index 7bf11e0..524b6bc 100644
--- a/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java
+++ b/src/main/java/com/android/tools/r8/cf/CfVerifierTool.java
@@ -25,6 +25,7 @@
builder.addProgramFile(Paths.get(arg));
}
InternalOptions options = new InternalOptions();
+ options.testing.verifyInputs = true;
DexApplication dexApplication =
new ApplicationReader(builder.build(), options, Timing.empty()).read();
AppView<AppInfo> appView = AppView.createForD8(AppInfo.createInitialAppInfo(dexApplication));
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 31d40bb..b231b6e 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -142,6 +142,11 @@
if (shouldDump) {
dumpApplication();
}
+
+ if (options.testing.verifyInputs) {
+ inputApp.validateInputs();
+ }
+
timing.begin("DexApplication.read");
final LazyLoadedDexApplication.Builder builder =
DexApplication.builder(options, timing, resolver);
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index d58387f..b1a2757 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -75,7 +75,11 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
+import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.util.CheckClassAdapter;
/**
* Collection of program files needed for processing.
@@ -762,6 +766,30 @@
return extractor.getDescriptor();
}
+ public void validateInputs() {
+ for (ProgramResourceProvider programResourceProvider : getProgramResourceProviders()) {
+ try {
+ for (ProgramResource programResource : programResourceProvider.getProgramResources()) {
+ try {
+ Kind kind = programResource.getKind();
+ if (kind == Kind.DEX) {
+ continue;
+ }
+ byte[] bytes = programResource.getBytes();
+ ClassReader classReader = new ClassReader(bytes);
+ classReader.accept(
+ new CheckClassAdapter(Opcodes.ASM9, new ClassNode(), true) {},
+ ClassReader.EXPAND_FRAMES);
+ } catch (Throwable e) {
+ throw new CompilationError("Failed validating " + programResource.getOrigin(), e);
+ }
+ }
+ } catch (ResourceException e) {
+ throw new CompilationError("Resource exception in validation", e);
+ }
+ }
+ }
+
/**
* Builder interface for constructing an AndroidApp.
*/
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index c0c5504..2334765 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1571,6 +1571,7 @@
public boolean disableMappingToOriginalProgramVerification = false;
public boolean allowInvalidCfAccessFlags =
System.getProperty("com.android.tools.r8.allowInvalidCfAccessFlags") != null;
+ public boolean verifyInputs = System.getProperty("com.android.tools.r8.verifyInputs") != null;
// TODO(b/177333791): Set to true
public boolean checkForNotExpandingMainDexTracingResult = false;
public Set<String> allowedUnusedDontWarnPatterns = new HashSet<>();
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
index 71b6637..9fffa07 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
@@ -6,6 +6,8 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
@@ -88,6 +90,23 @@
.assertSuccessWithOutputLines(EXPECTED);
}
+ @Test()
+ public void testR8InputVerification() throws Exception {
+ try {
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(getMainWithChangedMaxStackHeight())
+ .enableInliningAnnotations()
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.testing.verifyInputs = true)
+ .compile();
+ } catch (CompilationFailedException e) {
+ assertTrue(e.getCause().getMessage().contains("Insufficient maximum stack size"));
+ return;
+ }
+ fail("Should always throw");
+ }
+
public byte[] getMainWithChangedMaxStackHeight() throws Exception {
return transformer(Main.class).setMaxStackHeight(MethodPredicate.onName("main"), 1).transform();
}