Check for duplicate field/method definitions in ClassDataItem
diff --git a/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java b/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
index 708e66e..a675061 100644
--- a/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
+++ b/dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
@@ -33,9 +33,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
public class ClassDataItem extends Item<ClassDataItem> {
@Nullable
@@ -95,27 +93,71 @@
EncodedMethod[] virtualMethodsArray = null;
if (staticFields != null && staticFields.size() > 0) {
- staticFieldsArray = new EncodedField[staticFields.size()];
- staticFieldsArray = staticFields.toArray(staticFieldsArray);
- Arrays.sort(staticFieldsArray);
+ SortedSet<EncodedField> staticFieldsSet = new TreeSet<EncodedField>();
+ for (EncodedField staticField: staticFields) {
+ if (staticFieldsSet.contains(staticField)) {
+ System.err.println(String.format("Ignoring duplicate static field definition: %s",
+ staticField.field.getFieldString()));
+ continue;
+ }
+ staticFieldsSet.add(staticField);
+ }
+
+ staticFieldsArray = new EncodedField[staticFieldsSet.size()];
+ staticFieldsArray = staticFieldsSet.toArray(staticFieldsArray);
}
if (instanceFields != null && instanceFields.size() > 0) {
- instanceFieldsArray = new EncodedField[instanceFields.size()];
- instanceFieldsArray = instanceFields.toArray(instanceFieldsArray);
- Arrays.sort(instanceFieldsArray);
+ SortedSet<EncodedField> instanceFieldsSet = new TreeSet<EncodedField>();
+ for (EncodedField instanceField: instanceFields) {
+ if (instanceFieldsSet.contains(instanceField)) {
+ System.err.println(String.format("Ignoring duplicate instance field definition: %s",
+ instanceField.field.getFieldString()));
+ continue;
+ }
+ instanceFieldsSet.add(instanceField);
+ }
+
+ instanceFieldsArray = new EncodedField[instanceFieldsSet.size()];
+ instanceFieldsArray = instanceFieldsSet.toArray(instanceFieldsArray);
}
+ TreeSet<EncodedMethod> directMethodSet = new TreeSet<EncodedMethod>();
+
if (directMethods != null && directMethods.size() > 0) {
- directMethodsArray = new EncodedMethod[directMethods.size()];
- directMethodsArray = directMethods.toArray(directMethodsArray);
- Arrays.sort(directMethodsArray);
+ for (EncodedMethod directMethod: directMethods) {
+ if (directMethodSet.contains(directMethod)) {
+ System.err.println(String.format("Ignoring duplicate direct method definition: %s",
+ directMethod.method.getMethodString()));
+ continue;
+ }
+ directMethodSet.add(directMethod);
+ }
+
+ directMethodsArray = new EncodedMethod[directMethodSet.size()];
+ directMethodsArray = directMethodSet.toArray(directMethodsArray);
}
if (virtualMethods != null && virtualMethods.size() > 0) {
- virtualMethodsArray = new EncodedMethod[virtualMethods.size()];
- virtualMethodsArray = virtualMethods.toArray(virtualMethodsArray);
- Arrays.sort(virtualMethodsArray);
+ TreeSet<EncodedMethod> virtualMethodSet = new TreeSet<EncodedMethod>();
+ for (EncodedMethod virtualMethod: virtualMethods) {
+ if (directMethodSet.contains(virtualMethod)) {
+ // If both a direct and virtual definition is present, dalvik's behavior seems to be undefined,
+ // so we can't gracefully handle this case, like we can if the duplicates are all direct or all
+ // virtual -- in which case, we ignore all but the first definition
+ throw new RuntimeException(String.format("Duplicate direct+virtual method definition: %s",
+ virtualMethod.method.getMethodString()));
+ }
+ if (virtualMethodSet.contains(virtualMethod)) {
+ System.err.println(String.format("Ignoring duplicate virtual method definition: %s",
+ virtualMethod.method.getMethodString()));
+ continue;
+ }
+ virtualMethodSet.add(virtualMethod);
+ }
+
+ virtualMethodsArray = new EncodedMethod[virtualMethodSet.size()];
+ virtualMethodsArray = virtualMethodSet.toArray(virtualMethodsArray);
}
ClassDataItem classDataItem = new ClassDataItem(dexFile, staticFieldsArray, instanceFieldsArray,
@@ -597,6 +639,19 @@
}
/**
+ * Determines if this <code>EncodedField</code> is equal to other, based on the equality of the associated
+ * <code>FieldIdItem</code>
+ * @param other The <code>EncodedField</code> to test for equality
+ * @return true if other is equal to this instance, otherwise false
+ */
+ public boolean equals(Object other) {
+ if (other instanceof EncodedField) {
+ return compareTo((EncodedField)other) == 0;
+ }
+ return false;
+ }
+
+ /**
* @return true if this is a static field
*/
public boolean isStatic() {
@@ -718,6 +773,19 @@
}
/**
+ * Determines if this <code>EncodedMethod</code> is equal to other, based on the equality of the associated
+ * <code>MethodIdItem</code>
+ * @param other The <code>EncodedMethod</code> to test for equality
+ * @return true if other is equal to this instance, otherwise false
+ */
+ public boolean equals(Object other) {
+ if (other instanceof EncodedMethod) {
+ return compareTo((EncodedMethod)other) == 0;
+ }
+ return false;
+ }
+
+ /**
* @return true if this is a direct method
*/
public boolean isDirect() {