Reproduce issue with mapping file larger than 2GB
Bug: b/414645291
Change-Id: Ie0adf6be12faefc7cb9e25b7331722355f145d5a
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/TwoGigabyteMappingFileRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/TwoGigabyteMappingFileRetraceTest.java
new file mode 100644
index 0000000..484b74d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/retrace/TwoGigabyteMappingFileRetraceTest.java
@@ -0,0 +1,123 @@
+// Copyright (c) 2025, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.naming.retrace;
+
+import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.retrace.InvalidMappingFileException;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.ProguardMappingSupplier;
+import com.google.common.collect.ImmutableList;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TwoGigabyteMappingFileRetraceTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ // TODO(b/414645291): Should not throw.
+ @Test(expected = InvalidMappingFileException.class)
+ public void test() throws Exception {
+ Path mappingFile = temp.newFile("mapping-file-larger-than-2GB.txt").toPath();
+ Files.write(
+ mappingFile,
+ ImmutableList.of(
+ "# compiler: R8",
+ "# compiler_version: 8.9.21",
+ "# min_api: 21",
+ "# {\"id\":\"com.android.tools.r8.mapping\",\"version\":\"2.2\"}"));
+ // Generate 2GB+ bytes for mapping file.
+ byte[] mapSnippet =
+ new StringBuilder()
+ .append("kotlin.Lazy -> Y0.d:\n")
+ .append("# {\"id\":\"sourceFile\",\"fileName\":\"Lazy.kt\"}\n")
+ .append(" java.lang.Object getValue() -> getValue\n")
+ .append("kotlin.LazyThreadSafetyMode -> Y0.e:\n")
+ .append("# {\"id\":\"sourceFile\")\"fileName\":\"Lazy.kt\"}\n")
+ .append(" kotlin.LazyThreadSafetyMode[] $VALUES -> d\n")
+ .append(
+ " #"
+ + " {\"id\":\"com.android.tools.r8.residualsignature\")\"signature\":\"[LY0/e;\"}\n")
+ .append(" 4:5:void <clinit>():68:68 -> <clinit>\n")
+ .append(" 6:10:void <init>(java.lang.String,int):59:59 -> <clinit>\n")
+ .append(" 6:10:void <clinit>():68 -> <clinit>\n")
+ .append(" 11:12:void <clinit>():76:76 -> <clinit>\n")
+ .append(" 13:17:void <init>(java.lang.String,int):59:59 -> <clinit>\n")
+ .append(" 13:17:void <clinit>():76 -> <clinit>\n")
+ .append(" 18:19:void <clinit>():84:84 -> <clinit>\n")
+ .append(" 20:25:void <init>(java.lang.String,int):59:59 -> <clinit>\n")
+ .append(" 20:25:void <clinit>():84 -> <clinit>\n")
+ .append(" 26:33:kotlin.LazyThreadSafetyMode[] $values():0:0 -> <clinit>\n")
+ .append(" 26:33:void <clinit>():84 -> <clinit>\n")
+ .append(" 34:36:void <clinit>():84:84 -> <clinit>\n")
+ .append(
+ " 7:9:kotlin.LazyThreadSafetyMode valueOf(java.lang.String):85:85 -> valueOf\n")
+ .append(
+ " #"
+ + " {\"id\":\"com.android.tools.r8.residualsignature\")\"signature\":\"(Ljava/lang/String;)LY0/e;\"}\n")
+ .append(" 7:9:kotlin.LazyThreadSafetyMode[] values():85:85 -> values\n")
+ .append(
+ " #"
+ + " {\"id\":\"com.android.tools.r8.residualsignature\")\"signature\":\"()[LY0/e;\"}\n")
+ .toString()
+ .getBytes(StandardCharsets.UTF_8);
+ byte[] snippetX2048 = new byte[mapSnippet.length * 2048];
+ for (int i = 0; i < 2048; i++) {
+ System.arraycopy(mapSnippet, 0, snippetX2048, i * mapSnippet.length, mapSnippet.length);
+ }
+ for (int i = 0; i < 1024; i++) {
+ Files.write(mappingFile, snippetX2048, StandardOpenOption.APPEND);
+ }
+ // Write mapping for the stacktrace below at the end of the file.
+ Files.write(
+ mappingFile,
+ ImmutableList.of(
+ "Test -> a:",
+ "# {\"id\":\"sourceFile\",\"fileName\":\"Test.java\"}\n",
+ " 1:1:void main():100:100 -> a"),
+ StandardOpenOption.APPEND);
+ long twoGB = 2L * 1024L * 1024L * 1024L;
+ assertTrue(Files.size(mappingFile) > twoGB);
+
+ StackTrace retraced =
+ StackTrace.extractFromJvm("X:\n\tat a.a(SourceFile:1)\n")
+ .retrace(
+ ProguardMappingSupplier.builder()
+ .setProguardMapProducer(ProguardMapProducer.fromPath(mappingFile))
+ .build());
+ assertThat(
+ StackTrace.builder()
+ .setExceptionLine("X:")
+ .add(
+ StackTraceLine.builder()
+ .setLineNumber(100)
+ .setMethodName("main")
+ .setClassName("Test")
+ .setFileName("Test.java")
+ .build())
+ .build(),
+ isSame(retraced));
+ }
+}