Fix size in header, check header alignment and fix checksum and signature
Bug: b/249922554
Change-Id: I3cbfda7b28b3629a294798430a5a15848be731c9
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriterExperimental.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriterExperimental.java
index 77f653a..68f379f 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriterExperimental.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriterExperimental.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.utils.BitUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.ThreadUtils;
@@ -146,6 +147,7 @@
}
offset = section.getLayout().getEndOfFile();
+ assert BitUtils.isAligned(4, offset);
sections.add(section);
fileTiming.end();
timings.add(fileTiming);
@@ -192,7 +194,32 @@
List<MapItem> mapItems =
section
.getLayout()
- .generateMapInfo(section.getFileWriter(), stringIdsSize, stringIdsOffset);
+ .generateMapInfo(
+ section.getFileWriter(),
+ section.getLayout().headerOffset,
+ stringIdsSize,
+ stringIdsOffset,
+ lastSection.getLayout().getStringDataOffsets());
+ int originalSize = dexOutputBuffer.getInt();
+ int size = 0;
+ for (MapItem mapItem : mapItems) {
+ size += mapItem.write(dexOutputBuffer);
+ }
+ assert originalSize == size;
+ // Calculate signature and checksum after the map is written.
+ section.getFileWriter().writeSignature(section.getLayout(), dexOutputBuffer);
+ section.getFileWriter().writeChecksum(section.getLayout(), dexOutputBuffer);
+ } else {
+ dexOutputBuffer.moveTo(section.getLayout().getMapOffset());
+ List<MapItem> mapItems =
+ section
+ .getLayout()
+ .generateMapInfo(
+ section.getFileWriter(),
+ section.getLayout().headerOffset,
+ stringIdsSize,
+ stringIdsOffset,
+ lastSection.getLayout().getStringDataOffsets());
int originalSize = dexOutputBuffer.getInt();
int size = 0;
for (MapItem mapItem : mapItems) {
@@ -214,6 +241,7 @@
DexOutputBuffer outputBuffer,
boolean last) {
assert !virtualFile.isEmpty();
+ assert BitUtils.isAligned(4, offset);
printItemUseInfo(virtualFile);
timing.begin("Reindex for lazy strings");
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 5d8832f..86182c2 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -815,7 +815,7 @@
dest.putByte(Constants.DEX_FILE_MAGIC_SUFFIX);
// Leave out checksum and signature for now.
dest.moveTo(layout.headerOffset + Constants.FILE_SIZE_OFFSET);
- dest.putInt(layout.getEndOfFile());
+ dest.putInt(layout.getEndOfFile() - layout.headerOffset);
dest.putInt(Constants.TYPE_HEADER_ITEM_SIZE);
dest.putInt(Constants.ENDIAN_CONSTANT);
dest.putInt(0);
@@ -918,7 +918,7 @@
}
public int size() {
- return length == 0 ? 0 : 1;
+ return length == 0 && type != Constants.TYPE_STRING_DATA_ITEM ? 0 : 1;
}
}
@@ -1129,13 +1129,21 @@
public List<MapItem> generateMapInfo(FileWriter fileWriter) {
return generateMapInfo(
- fileWriter, fileWriter.mixedSectionOffsets.getStringData().size(), stringIdsOffset);
+ fileWriter,
+ 0,
+ fileWriter.mixedSectionOffsets.getStringData().size(),
+ stringIdsOffset,
+ getStringDataOffsets());
}
public List<MapItem> generateMapInfo(
- FileWriter fileWriter, int stringIdsSize, int stringIdsOffset) {
+ FileWriter fileWriter,
+ int headerOffset,
+ int stringIdsSize,
+ int stringIdsOffset,
+ int stringDataOffsets) {
List<MapItem> mapItems = new ArrayList<>();
- mapItems.add(new MapItem(Constants.TYPE_HEADER_ITEM, 0, 1));
+ mapItems.add(new MapItem(Constants.TYPE_HEADER_ITEM, headerOffset, 1));
mapItems.add(
new MapItem(
Constants.TYPE_STRING_ID_ITEM,
@@ -1188,8 +1196,8 @@
mapItems.add(
new MapItem(
Constants.TYPE_STRING_DATA_ITEM,
- getStringDataOffsets(),
- getStringDataOffsets() == 0 ? 0 : stringIdsSize));
+ stringDataOffsets,
+ stringDataOffsets == 0 ? 0 : stringIdsSize));
mapItems.add(
new MapItem(
Constants.TYPE_ANNOTATION_ITEM,
diff --git a/src/main/java/com/android/tools/r8/utils/BitUtils.java b/src/main/java/com/android/tools/r8/utils/BitUtils.java
index b264b4b..f951031 100644
--- a/src/main/java/com/android/tools/r8/utils/BitUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/BitUtils.java
@@ -13,4 +13,9 @@
public static boolean isBitInMaskSet(int value, int mask) {
return (value & mask) != 0;
}
+
+ public static boolean isAligned(int alignment, int value) {
+ assert (alignment & (alignment - 1)) == 0; // Check alignment is power of 2.
+ return (value & (alignment - 1)) == 0;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/dex/container/DexContainerFormatBasicTest.java b/src/test/java/com/android/tools/r8/dex/container/DexContainerFormatBasicTest.java
index 72f856f..41aa6d0 100644
--- a/src/test/java/com/android/tools/r8/dex/container/DexContainerFormatBasicTest.java
+++ b/src/test/java/com/android/tools/r8/dex/container/DexContainerFormatBasicTest.java
@@ -28,8 +28,10 @@
import com.android.tools.r8.maindexlist.MainDexListTests;
import com.android.tools.r8.transformers.ClassTransformer;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BitUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.DexVersion;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
@@ -160,10 +162,13 @@
IntList sections = new IntArrayList();
int offset = 0;
while (offset < buffer.capacity()) {
+ assertTrue(BitUtils.isAligned(4, offset));
sections.add(offset);
int dataSize = buffer.getInt(offset + DATA_SIZE_OFFSET);
int dataOffset = buffer.getInt(offset + DATA_OFF_OFFSET);
+ int file_size = buffer.getInt(offset + FILE_SIZE_OFFSET);
offset = dataOffset + dataSize;
+ assertEquals(file_size, offset - ListUtils.last(sections));
}
assertEquals(buffer.capacity(), offset);
@@ -229,9 +234,7 @@
int sectionSize = buffer.getInt(offset + FILE_SIZE_OFFSET);
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(
- buffer.asByteBuffer().array(),
- offset + FILE_SIZE_OFFSET,
- sectionSize - offset - FILE_SIZE_OFFSET);
+ buffer.asByteBuffer().array(), offset + FILE_SIZE_OFFSET, sectionSize - FILE_SIZE_OFFSET);
byte[] expectedSignature = new byte[20];
md.digest(expectedSignature, 0, 20);
for (int i = 0; i < expectedSignature.length; i++) {
@@ -243,9 +246,7 @@
int sectionSize = buffer.getInt(offset + FILE_SIZE_OFFSET);
Adler32 adler = new Adler32();
adler.update(
- buffer.asByteBuffer().array(),
- offset + SIGNATURE_OFFSET,
- sectionSize - offset - SIGNATURE_OFFSET);
+ buffer.asByteBuffer().array(), offset + SIGNATURE_OFFSET, sectionSize - SIGNATURE_OFFSET);
assertEquals((int) adler.getValue(), buffer.getInt(offset + CHECKSUM_OFFSET));
}