From eb3b01f31887576e859a378ac3abe1462437a9be Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Mon, 16 Mar 2015 20:36:34 -0700 Subject: [PATCH] Make sure the elements are sorted in an encoded annotation --- .../java/org/jf/dexlib2/iface/Annotation.java | 4 +- .../java/org/jf/dexlib2/writer/DexWriter.java | 1 - .../jf/dexlib2/writer/EncodedValueWriter.java | 11 ++++- .../org/jf/dexlib2/writer/DexWriterTest.java | 46 +++++++++++++++++++ 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/Annotation.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/Annotation.java index 251ac123..7c107a45 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/Annotation.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/iface/Annotation.java @@ -55,7 +55,7 @@ public interface Annotation extends BasicAnnotation, Comparable { * * @return The type of this annotation */ - @Nonnull String getType(); + @Nonnull @Override String getType(); /** * Gets a set of the name/value elements associated with this annotation. @@ -64,7 +64,7 @@ public interface Annotation extends BasicAnnotation, Comparable { * * @return A set of AnnotationElements */ - @Nonnull Set getElements(); + @Nonnull @Override Set getElements(); /** * Returns a hashcode for this Annotation. diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java index dd6ec9f1..0650ab3c 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java @@ -572,7 +572,6 @@ public abstract class DexWriter< } } - private void writeAnnotationSets(@Nonnull DexDataWriter writer) throws IOException { writer.align(); annotationSetSectionOffset = writer.getPosition(); diff --git a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/EncodedValueWriter.java b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/EncodedValueWriter.java index 53d77b39..def326c6 100644 --- a/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/EncodedValueWriter.java +++ b/brut.apktool.smali/dexlib2/src/main/java/org/jf/dexlib2/writer/EncodedValueWriter.java @@ -31,7 +31,9 @@ package org.jf.dexlib2.writer; +import com.google.common.collect.Ordering; import org.jf.dexlib2.ValueType; +import org.jf.dexlib2.base.BaseAnnotationElement; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; @@ -40,7 +42,8 @@ import java.io.IOException; import java.util.Collection; public abstract class EncodedValueWriter { + MethodRefKey extends MethodReference, AnnotationElement extends org.jf.dexlib2.iface.AnnotationElement, + EncodedValue> { @Nonnull private final DexDataWriter writer; @Nonnull private final StringSection stringSection; @Nonnull private final TypeSection typeSection; @@ -70,7 +73,11 @@ public abstract class EncodedValueWriter sortedElements = Ordering.from(BaseAnnotationElement.BY_NAME) + .immutableSortedCopy(elements); + + for (AnnotationElement element: sortedElements) { writer.writeUleb128(stringSection.getItemIndex(annotationSection.getElementName(element))); writeEncodedValue(annotationSection.getElementValue(element)); } diff --git a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java b/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java index 66abe06a..8ba975a1 100644 --- a/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java +++ b/brut.apktool.smali/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java @@ -41,10 +41,12 @@ import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.AnnotationElement; import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.value.AnnotationEncodedValue; import org.jf.dexlib2.immutable.ImmutableAnnotation; import org.jf.dexlib2.immutable.ImmutableAnnotationElement; import org.jf.dexlib2.immutable.ImmutableClassDef; import org.jf.dexlib2.immutable.ImmutableDexFile; +import org.jf.dexlib2.immutable.value.ImmutableAnnotationEncodedValue; import org.jf.dexlib2.immutable.value.ImmutableNullEncodedValue; import org.jf.dexlib2.writer.io.MemoryDataStore; import org.jf.dexlib2.writer.pool.DexPool; @@ -87,4 +89,48 @@ public class DexWriterTest { Assert.assertEquals("blah", dbElements.get(0).getName()); Assert.assertEquals("zabaglione", dbElements.get(1).getName()); } + + @Test + public void testEncodedAnnotationElementOrder() { + // Elements are out of order wrt to the element name + ImmutableSet encodedElements = + ImmutableSet.of(new ImmutableAnnotationElement("zabaglione", ImmutableNullEncodedValue.INSTANCE), + new ImmutableAnnotationElement("blah", ImmutableNullEncodedValue.INSTANCE)); + + ImmutableAnnotationEncodedValue encodedAnnotations = + new ImmutableAnnotationEncodedValue("Lan/encoded/annotation", encodedElements); + + ImmutableSet elements = + ImmutableSet.of(new ImmutableAnnotationElement("encoded_annotation", encodedAnnotations)); + + ImmutableAnnotation annotation = new ImmutableAnnotation(AnnotationVisibility.RUNTIME, + "Lorg/test/anno;", elements); + + ImmutableClassDef classDef = new ImmutableClassDef("Lorg/test/blah;", + 0, "Ljava/lang/Object;", null, null, ImmutableSet.of(annotation), null, null); + + MemoryDataStore dataStore = new MemoryDataStore(); + + try { + DexPool.writeTo(dataStore, new ImmutableDexFile(ImmutableSet.of(classDef))); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dataStore.getData()); + ClassDef dbClassDef = Iterables.getFirst(dexFile.getClasses(), null); + Assert.assertNotNull(dbClassDef); + Annotation dbAnnotation = Iterables.getFirst(dbClassDef.getAnnotations(), null); + Assert.assertNotNull(dbAnnotation); + + AnnotationElement element = Iterables.getFirst(dbAnnotation.getElements(), null); + AnnotationEncodedValue dbAnnotationEncodedValue = (AnnotationEncodedValue)element.getValue(); + + List dbElements = Lists.newArrayList(dbAnnotationEncodedValue.getElements()); + + // Ensure that the elements were written out in sorted order + Assert.assertEquals(2, dbElements.size()); + Assert.assertEquals("blah", dbElements.get(0).getName()); + Assert.assertEquals("zabaglione", dbElements.get(1).getName()); + } }