OSDN Git Service

Fix handling of annotations whose classes are missing at runtime.
authorElliott Hughes <enh@google.com>
Sat, 15 Dec 2012 01:27:24 +0000 (17:27 -0800)
committerElliott Hughes <enh@google.com>
Mon, 17 Dec 2012 17:08:24 +0000 (09:08 -0800)
Bug: http://code.google.com/p/android/issues/detail?id=39854
Change-Id: I3089b693ff3084b093f991f991ac9273dea7356d

tests/004-annotations/build [new file with mode: 0644]
tests/004-annotations/src/android/test/anno/MissingAnnotation.java [new file with mode: 0644]
tests/004-annotations/src/android/test/anno/SimplyNoted.java
vm/reflect/Annotation.cpp

diff --git a/tests/004-annotations/build b/tests/004-annotations/build
new file mode 100644 (file)
index 0000000..c147cb2
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+
+# android.test.anno.MissingAnnotation is available at compile time...
+${JAVAC} -d classes `find src -name '*.java'`
+
+# ...but not at run time.
+rm classes/android/test/anno/MissingAnnotation.class
+dx -JXmx256m --debug --dex --output=test.jar classes
diff --git a/tests/004-annotations/src/android/test/anno/MissingAnnotation.java b/tests/004-annotations/src/android/test/anno/MissingAnnotation.java
new file mode 100644 (file)
index 0000000..56da15a
--- /dev/null
@@ -0,0 +1,8 @@
+package android.test.anno;
+
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Retention(RUNTIME) public @interface MissingAnnotation {
+}
+
index 95a3d24..b757465 100644 (file)
@@ -3,24 +3,30 @@ package android.test.anno;
 @AnnoSimpleType
 @AnnoSimpleType2
 @AnnoSimpleTypeInvis
+@MissingAnnotation
 public class SimplyNoted {
     @AnnoSimpleField
+    @MissingAnnotation
     public int mFoo;
 
     @AnnoSimpleField
+    @MissingAnnotation
     public static int mOneFoo;
 
     @AnnoSimpleConstructor
+    @MissingAnnotation
     SimplyNoted() {
         mFoo = 0;
     }
 
     @AnnoSimpleConstructor
+    @MissingAnnotation
     SimplyNoted(@AnnoSimpleParameter int xyzzy) {
         mFoo = xyzzy;
     }
 
     @AnnoSimpleMethod
+    @MissingAnnotation
     public int foo() {
         @AnnoSimpleLocalVariable
         int bar = 5;
index 26dea75..7b36d51 100644 (file)
@@ -758,6 +758,7 @@ static Object* processEncodedAnnotation(const ClassObject* clazz,
             ALOGE("Unable to resolve %s annotation class %d",
                 clazz->descriptor, typeIdx);
             assert(dvmCheckException(self));
+            dvmClearException(self);
             return NULL;
         }
     }
@@ -830,9 +831,6 @@ static ArrayObject* processAnnotationSet(const ClassObject* clazz,
 {
     DexFile* pDexFile = clazz->pDvmDex->pDexFile;
     const DexAnnotationItem* pAnnoItem;
-    ArrayObject* annoArray;
-    int i, count;
-    u4 dstIndex;
 
     /* we need these later; make sure they're initialized */
     if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory))
@@ -841,38 +839,56 @@ static ArrayObject* processAnnotationSet(const ClassObject* clazz,
         dvmInitClass(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember);
 
     /* count up the number of visible elements */
-    for (i = count = 0; i < (int) pAnnoSet->size; i++) {
+    size_t count = 0;
+    for (size_t i = 0; i < pAnnoSet->size; ++i) {
         pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
-        if (pAnnoItem->visibility == visibility)
+        if (pAnnoItem->visibility == visibility) {
             count++;
+        }
     }
 
-    annoArray =
-        dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
-                             count, ALLOC_DEFAULT);
-    if (annoArray == NULL)
+    ArrayObject* annoArray = dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
+                                                  count, ALLOC_DEFAULT);
+    if (annoArray == NULL) {
         return NULL;
+    }
 
     /*
      * Generate Annotation objects.  We must put them into the array
      * immediately (or add them to the tracked ref table).
+     * We may not be able to resolve all annotations, and should just
+     * ignore those we can't.
      */
-    dstIndex = 0;
-    for (i = 0; i < (int) pAnnoSet->size; i++) {
+    u4 dstIndex = 0;
+    for (int i = 0; i < (int) pAnnoSet->size; i++) {
         pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i);
         if (pAnnoItem->visibility != visibility)
             continue;
         const u1* ptr = pAnnoItem->annotation;
         Object *anno = processEncodedAnnotation(clazz, &ptr);
-        if (anno == NULL) {
-            dvmReleaseTrackedAlloc((Object*) annoArray, NULL);
-            return NULL;
+        if (anno != NULL) {
+            dvmSetObjectArrayElement(annoArray, dstIndex, anno);
+            ++dstIndex;
         }
-        dvmSetObjectArrayElement(annoArray, dstIndex, anno);
-        ++dstIndex;
     }
 
-    return annoArray;
+    // If we got as many as we expected, we're done...
+    if (dstIndex == count) {
+        return annoArray;
+    }
+
+    // ...otherwise we need to trim the trailing nulls.
+    ArrayObject* trimmedArray = dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray,
+                                                     dstIndex, ALLOC_DEFAULT);
+    if (trimmedArray == NULL) {
+        return NULL;
+    }
+    for (size_t i = 0; i < dstIndex; ++i) {
+        Object** src = (Object**)(void*) annoArray->contents;
+        dvmSetObjectArrayElement(trimmedArray, i, src[i]);
+    }
+    dvmReleaseTrackedAlloc((Object*) annoArray, NULL);
+    return trimmedArray;
 }
 
 /*
@@ -908,7 +924,12 @@ static const DexAnnotationItem* getAnnotationItemFromAnnotationSet(
         if (annoClass == NULL) {
             annoClass = dvmResolveClass(clazz, typeIdx, true);
             if (annoClass == NULL) {
-                return NULL; // an exception is pending
+                ALOGE("Unable to resolve %s annotation class %d",
+                      clazz->descriptor, typeIdx);
+                Thread* self = dvmThreadSelf();
+                assert(dvmCheckException(self));
+                dvmClearException(self);
+                continue;
             }
         }