diff options
Diffstat (limited to 'vm/alloc/Verify.c')
-rw-r--r-- | vm/alloc/Verify.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/vm/alloc/Verify.c b/vm/alloc/Verify.c new file mode 100644 index 000000000..0d942ce61 --- /dev/null +++ b/vm/alloc/Verify.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2010 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. + */ + +#include "Dalvik.h" +#include "alloc/HeapSource.h" +#include "alloc/Verify.h" + +/* comment everything, of course! */ +#define VERIFY_REFERENCE(x) do { \ + if (!verifyReference((x), &(x))) { \ + LOGE("Verify of %p at %p failed", (x), &(x)); \ + dvmAbort(); \ + } \ + } while (0) + +/* + * Verifies that a reference points to an object header. + */ +static bool verifyReference(const void *obj, const void *addr) +{ + if (obj == NULL) { + return true; + } + return dvmIsValidObject(obj); +} + +/* + * Verifies the header, static fields references, and interface + * pointers of a class object. + */ +static void verifyClassObject(const ClassObject *obj) +{ + int i; + char ch; + + LOGV("Entering verifyClassObject(obj=%p)", obj); + if (obj == gDvm.unlinkedJavaLangClass) { + assert(obj->obj.clazz == NULL); + goto exit; + } + VERIFY_REFERENCE(obj->obj.clazz); + assert(!strcmp(obj->obj.clazz->descriptor, "Ljava/lang/Class;")); + if (IS_CLASS_FLAG_SET(obj, CLASS_ISARRAY)) { + VERIFY_REFERENCE(obj->elementClass); + } + VERIFY_REFERENCE(obj->super); + VERIFY_REFERENCE(obj->classLoader); + /* Verify static field references. */ + for (i = 0; i < obj->sfieldCount; ++i) { + ch = obj->sfields[i].field.signature[0]; + if (ch == '[' || ch == 'L') { + VERIFY_REFERENCE(obj->sfields[i].value.l); + } + } + /* Verify interface references. */ + for (i = 0; i < obj->interfaceCount; ++i) { + VERIFY_REFERENCE(obj->interfaces[i]); + } +exit: + LOGV("Exiting verifyClassObject(obj=%p)", obj); +} + +/* + * Verifies the header of all array objects. If the array object is + * specialized to a reference type, verifies the array data as well. + */ +static void verifyArrayObject(const ArrayObject *array) +{ + ClassObject *clazz; + Object **contents; + size_t i; + + LOGV("Entering verifyArrayObject(obj=%p)", obj); + /* Verify the class object reference. */ + assert(array->obj.clazz != NULL); + VERIFY_REFERENCE(array->obj.clazz); + if (IS_CLASS_FLAG_SET(array->obj.clazz, CLASS_ISOBJECTARRAY)) { + /* Verify the array contents. */ + contents = (Object **) array->contents; + for (i = 0; i < array->length; ++i) { + VERIFY_REFERENCE(contents[i]); + } + } + LOGV("Exiting verifyArrayObject(obj=%p)", obj); +} + +/* + * Verifies the header and field references of a data object. + */ +static void verifyDataObject(const DataObject *obj) +{ + ClassObject *clazz; + InstField *field; + void *addr; + size_t offset; + int i, count; + + LOGV("Entering verifyDataObject(obj=%p)", obj); + /* Verify the class object. */ + assert(obj->obj.clazz != NULL); + VERIFY_REFERENCE(obj->obj.clazz); + /* Verify the instance fields. */ + for (clazz = obj->obj.clazz; clazz != NULL; clazz = clazz->super) { + field = clazz->ifields; + count = clazz->ifieldRefCount; + for (i = 0; i < count; ++i, ++field) { + addr = BYTE_OFFSET((Object *)obj, field->byteOffset); + VERIFY_REFERENCE(((JValue *)addr)->l); + } + } + LOGV("Exiting verifyDataObject(obj=%p) %zx", obj, length); +} + +/* + * Verifies an object reference. Determines the type of the reference + * and dispatches to a specialized verification routine. + */ +void dvmVerifyObject(const Object *obj) +{ + ClassObject *clazz; + + LOGV("Entering dvmVerifyObject(obj=%p)", obj); + assert(obj != NULL); + clazz = obj->clazz; + if (clazz == gDvm.classJavaLangClass || + obj == (Object *)gDvm.unlinkedJavaLangClass) { + verifyClassObject((ClassObject *)obj); + } else { + assert(clazz != NULL); + if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) { + verifyArrayObject((ArrayObject *)obj); + } else { + verifyDataObject((DataObject *)obj); + } + } + LOGV("Exiting dvmVerifyObject(obj=%p)", obj); +} + +/* + * Helper function to call dvmVerifyObject from a bitmap walker. + */ +static bool verifyBitmapCallback(size_t numPtrs, void **ptrs, + const void *finger, void *arg) +{ + size_t i; + + for (i = 0; i < numPtrs; i++) { + dvmVerifyObject(*ptrs++); + } + return true; +} + +/* + * Verifies the object references in a heap bitmap. Assumes the heap + * is locked. + */ +void dvmVerifyBitmapUnlocked(const HeapBitmap *bitmap) +{ + /* TODO: check that locks are held and the VM is suspended. */ + dvmHeapBitmapWalk(bitmap, verifyBitmapCallback, NULL); +} + +/* + * Verifies the object references in a heap bitmap. Suspends the VM + * for the duration of verification. + */ +void dvmVerifyBitmap(const HeapBitmap *bitmap) +{ + /* Suspend the VM. */ + dvmSuspendAllThreads(SUSPEND_FOR_VERIFY); + dvmLockMutex(&gDvm.heapWorkerLock); + dvmAssertHeapWorkerThreadRunning(); + dvmLockMutex(&gDvm.heapWorkerListLock); + + dvmVerifyBitmapUnlocked(bitmap); + + /* Resume the VM. */ + dvmUnlockMutex(&gDvm.heapWorkerListLock); + dvmUnlockMutex(&gDvm.heapWorkerLock); + dvmResumeAllThreads(SUSPEND_FOR_VERIFY); +} |