Exemple #1
0
/** @return true if we need to schedule a call to clear().
 */
static bool clearReference(Object *reference)
{
    /* This is what the default implementation of Reference.clear()
     * does.  We're required to clear all references to a given
     * referent atomically, so we can't pop in and out of interp
     * code each time.
     *
     * Also, someone may have subclassed one of the basic Reference
     * types, overriding clear().  We can't trust the clear()
     * implementation to call super.clear();  we cannot let clear()
     * resurrect the referent.  If we clear it here, we can safely
     * call any overriding implementations.
     */
    dvmSetFieldObject(reference,
            gDvm.offJavaLangRefReference_referent, NULL);

#if FANCY_REFERENCE_SUBCLASS
    /* See if clear() has actually been overridden.  If so,
     * we need to schedule a call to it before calling enqueue().
     */
    if (reference->clazz->vtable[gDvm.voffJavaLangRefReference_clear]->clazz !=
            gDvm.classJavaLangRefReference)
    {
        /* clear() has been overridden;  return true to indicate
         * that we need to schedule a call to the real clear()
         * implementation.
         */
        return true;
    }
#endif

    return false;
}
Exemple #2
0
	void ObjTracer::modify_intent( Object * obj)
	{
		//try to clear the action
		//action
		InstField *pF = &obj->clazz->ifields[0];
		//dvmDumpObject(obj);
		ALOG(LOG_VERBOSE,"YWB", "set action null");
		dvmSetFieldObject( obj, pF->byteOffset, NULL);
	}
/*
 * private void setField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck, Object value)
 *
 * When assigning into a primitive field we will automatically extract
 * the value from box types.
 */
static void Dalvik_java_lang_reflect_Field_setField(const u4* args,
        JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    Object* valueObj = (Object*) args[6];
    JValue* fieldPtr;
    JValue value;

    /* unwrap primitive, or verify object type */
    if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
                          "invalid value for field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
            fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else if (fieldType->primitiveType == PRIM_NOT) {
        if (slot < 0) {
            StaticField *sfield;
            sfield = (StaticField *)dvmSlotToField(declaringClass, slot);
            assert(fieldPtr == &sfield->value);
            dvmSetStaticFieldObject(sfield, value.l);
        } else {
            int offset = declaringClass->ifields[slot].byteOffset;
            assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset));
            dvmSetFieldObject(obj, offset, value.l);
        }
    } else {
        fieldPtr->i = value.i;
    }

    RETURN_VOID();
}
Exemple #4
0
/*
 * This is the constructor for a generated proxy object.
 */
static void proxyConstructor(const u4* args, JValue* pResult,
    const Method* method, Thread* self)
{
    Object* obj = (Object*) args[0];
    Object* handler = (Object*) args[1];
    ClassObject* clazz = obj->clazz;
    int fieldOffset;

    fieldOffset = dvmFindFieldOffset(clazz, "h",
                    "Ljava/lang/reflect/InvocationHandler;");
    if (fieldOffset < 0) {
        LOGE("Unable to find 'h' in Proxy object\n");
        //dvmDumpClass(clazz, kDumpClassFullDetail);
        dvmAbort();     // this should never happen
    }
    dvmSetFieldObject(obj, fieldOffset, handler);
}
Exemple #5
0
/*
 * Allocate a new instance of the class String, performing first-use
 * initialization of the class if necessary. Upon success, the
 * returned value will have all its fields except hashCode already
 * filled in, including a reference to a newly-allocated char[] for
 * the contents, sized as given. Additionally, a reference to the
 * chars array is stored to the pChars pointer. Callers must
 * subsequently call dvmReleaseTrackedAlloc() on the result pointer.
 * This function returns NULL on failure.
 */
static StringObject* makeStringObject(u4 charsLength, ArrayObject** pChars)
{
    /*
     * The String class should have already gotten found (but not
     * necessarily initialized) before making it here. We assert it
     * explicitly, since historically speaking, we have had bugs with
     * regard to when the class String gets set up. The assert helps
     * make any regressions easier to diagnose.
     */
    assert(gDvm.classJavaLangString != NULL);

    if (!dvmIsClassInitialized(gDvm.classJavaLangString)) {
        /* Perform first-time use initialization of the class. */
        if (!dvmInitClass(gDvm.classJavaLangString)) {
            LOGE("FATAL: Could not initialize class String");
            dvmAbort();
        }
    }

    Object* result = dvmAllocObject(gDvm.classJavaLangString, ALLOC_DEFAULT);
    if (result == NULL) {
        return NULL;
    }

    ArrayObject* chars = dvmAllocPrimitiveArray('C', charsLength, ALLOC_DEFAULT);
    if (chars == NULL) {
        dvmReleaseTrackedAlloc(result, NULL);
        return NULL;
    }

    dvmSetFieldInt(result, STRING_FIELDOFF_COUNT, charsLength);
    dvmSetFieldObject(result, STRING_FIELDOFF_VALUE, (Object*) chars);
    dvmReleaseTrackedAlloc((Object*) chars, NULL);
    /* Leave offset and hashCode set to zero. */

    *pChars = chars;
    return (StringObject*) result;
}
Exemple #6
0
/* All objects for stronger reference levels have been
 * marked before this is called.
 */
void dvmHeapHandleReferences(Object *refListHead, enum RefType refType)
{
    Object *reference;
    GcMarkContext *markContext = &gDvm.gcHeap->markContext;
    const int offVmData = gDvm.offJavaLangRefReference_vmData;
    const int offReferent = gDvm.offJavaLangRefReference_referent;
    bool workRequired = false;

size_t numCleared = 0;
size_t numEnqueued = 0;
    reference = refListHead;
    while (reference != NULL) {
        Object *next;
        Object *referent;

        /* Pull the interesting fields out of the Reference object.
         */
        next = dvmGetFieldObject(reference, offVmData);
        referent = dvmGetFieldObject(reference, offReferent);

        //TODO: when handling REF_PHANTOM, unlink any references
        //      that fail this initial if().  We need to re-walk
        //      the list, and it would be nice to avoid the extra
        //      work.
        if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) {
            bool schedClear, schedEnqueue;

            /* This is the strongest reference that refers to referent.
             * Do the right thing.
             */
            switch (refType) {
            case REF_SOFT:
            case REF_WEAK:
                schedClear = clearReference(reference);
                schedEnqueue = enqueueReference(reference);
                break;
            case REF_PHANTOM:
                /* PhantomReferences are not cleared automatically.
                 * Until someone clears it (or the reference itself
                 * is collected), the referent must remain alive.
                 *
                 * It's necessary to fully mark the referent because
                 * it will still be present during the next GC, and
                 * all objects that it points to must be valid.
                 * (The referent will be marked outside of this loop,
                 * after handing all references of this strength, in
                 * case multiple references point to the same object.)
                 */
                schedClear = false;

                /* A PhantomReference is only useful with a
                 * queue, but since it's possible to create one
                 * without a queue, we need to check.
                 */
                schedEnqueue = enqueueReference(reference);
                break;
            default:
                assert(!"Bad reference type");
                schedClear = false;
                schedEnqueue = false;
                break;
            }
numCleared += schedClear ? 1 : 0;
numEnqueued += schedEnqueue ? 1 : 0;

            if (schedClear || schedEnqueue) {
                uintptr_t workBits;

                /* Stuff the clear/enqueue bits in the bottom of
                 * the pointer.  Assumes that objects are 8-byte
                 * aligned.
                 *
                 * Note that we are adding the *Reference* (which
                 * is by definition already marked at this point) to
                 * this list; we're not adding the referent (which
                 * has already been cleared).
                 */
                assert(((intptr_t)reference & 3) == 0);
                assert(((WORKER_CLEAR | WORKER_ENQUEUE) & ~3) == 0);
                workBits = (schedClear ? WORKER_CLEAR : 0) |
                           (schedEnqueue ? WORKER_ENQUEUE : 0);
                if (!dvmHeapAddRefToLargeTable(
                        &gDvm.gcHeap->referenceOperations,
                        (Object *)((uintptr_t)reference | workBits)))
                {
                    LOGE_HEAP("dvmMalloc(): no room for any more "
                            "reference operations\n");
                    dvmAbort();
                }
                workRequired = true;
            }

            if (refType != REF_PHANTOM) {
                /* Let later GCs know not to reschedule this reference.
                 */
                dvmSetFieldObject(reference, offVmData,
                        SCHEDULED_REFERENCE_MAGIC);
            } // else this is handled later for REF_PHANTOM

        } // else there was a stronger reference to the referent.

        reference = next;
    }
#define refType2str(r) \
    ((r) == REF_SOFT ? "soft" : ( \
     (r) == REF_WEAK ? "weak" : ( \
     (r) == REF_PHANTOM ? "phantom" : "UNKNOWN" )))
LOGD_HEAP("dvmHeapHandleReferences(): cleared %zd, enqueued %zd %s references\n", numCleared, numEnqueued, refType2str(refType));

    /* Walk though the reference list again, and mark any non-clear/marked
     * referents.  Only PhantomReferences can have non-clear referents
     * at this point.
     */
    if (refType == REF_PHANTOM) {
        bool scanRequired = false;

        HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
        reference = refListHead;
        while (reference != NULL) {
            Object *next;
            Object *referent;

            /* Pull the interesting fields out of the Reference object.
             */
            next = dvmGetFieldObject(reference, offVmData);
            referent = dvmGetFieldObject(reference, offReferent);

            if (referent != NULL && !isMarked(ptr2chunk(referent), markContext)) {
                markObjectNonNull(referent, markContext);
                scanRequired = true;

                /* Let later GCs know not to reschedule this reference.
                 */
                dvmSetFieldObject(reference, offVmData,
                        SCHEDULED_REFERENCE_MAGIC);
            }

            reference = next;
        }
        HPROF_CLEAR_GC_SCAN_STATE();

        if (scanRequired) {
            processMarkStack(markContext);
        }
    }

    if (workRequired) {
        dvmSignalHeapWorker(false);
    }
}
/*
 * private static Class defineClass(String name, ClassLoader loader,
 *      int cookie, ProtectionDomain pd)
 *
 * Load a class from a DEX file.  This is roughly equivalent to defineClass()
 * in a regular VM -- it's invoked by the class loader to cause the
 * creation of a specific class.  The difference is that the search for and
 * reading of the bytes is done within the VM.
 *
 * The class name is a "binary name", e.g. "java.lang.String".
 *
 * Returns a null pointer with no exception if the class was not found.
 * Throws an exception on other failures.
 */
static void Dalvik_dalvik_system_DexFile_defineClass(const u4* args,
    JValue* pResult)
{
    StringObject* nameObj = (StringObject*) args[0];
    Object* loader = (Object*) args[1];
    int cookie = args[2];
    Object* pd = (Object*) args[3];
    ClassObject* clazz = NULL;
    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
    DvmDex* pDvmDex;
    char* name;
    char* descriptor;

    name = dvmCreateCstrFromString(nameObj);
    descriptor = dvmDotToDescriptor(name);
    LOGV("--- Explicit class load '%s' 0x%08x\n", descriptor, cookie);
    free(name);

    if (!validateCookie(cookie))
        RETURN_VOID();

    if (pDexOrJar->isDex)
        pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);
    else
        pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile);

    /* once we load something, we can't unmap the storage */
    pDexOrJar->okayToFree = false;

    clazz = dvmDefineClass(pDvmDex, descriptor, loader);
    Thread* self = dvmThreadSelf();
    if (dvmCheckException(self)) {
        /*
         * If we threw a "class not found" exception, stifle it, since the
         * contract in the higher method says we simply return null if
         * the class is not found.
         */
        Object* excep = dvmGetException(self);
        if (strcmp(excep->clazz->descriptor,
                   "Ljava/lang/ClassNotFoundException;") == 0 ||
            strcmp(excep->clazz->descriptor,
                   "Ljava/lang/NoClassDefFoundError;") == 0)
        {
            dvmClearException(self);
        }
        clazz = NULL;
    }

    /*
     * Set the ProtectionDomain -- do we need this to happen before we
     * link the class and make it available? If so, we need to pass it
     * through dvmDefineClass (and figure out some other
     * stuff, like where it comes from for bootstrap classes).
     */
    if (clazz != NULL) {
        //LOGI("SETTING pd '%s' to %p\n", clazz->descriptor, pd);
        dvmSetFieldObject((Object*) clazz, gDvm.offJavaLangClass_pd, pd);
    }

    free(descriptor);
    RETURN_PTR(clazz);
}
/*
 * private void setField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck, Object value)
 *
 * When assigning into a primitive field we will automatically extract
 * the value from box types.
 */
static void Dalvik_java_lang_reflect_Field_setField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    Object* valueObj = (Object*) args[6];
#ifdef WITH_TAINT_TRACKING
    /* rtaint = args[7]
     * thisPtr taint = args[8]
     * obj taint = args[9]
     * declaringClass taint = args[10]
     * fieldType taint = args[11]
     * slot taint = args[12]
     * noAccessCheck taint = args[13]
     */
    u4 valueTaint = args[14];
#endif
    JValue* fieldPtr;
    JValue value;

    /* unwrap primitive, or verify object type */
    if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "invalid value for field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else if (fieldType->primitiveType == PRIM_NOT) {
        if (slot < 0) {
            StaticField *sfield;
            sfield = (StaticField *)dvmSlotToField(declaringClass, slot);
            assert(fieldPtr == &sfield->value);
            dvmSetStaticFieldObject(sfield, value.l);
        } else {
            int offset = declaringClass->ifields[slot].byteOffset;
            assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset));
            dvmSetFieldObject(obj, offset, value.l);
        }
    } else {
        fieldPtr->i = value.i;
    }

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    dvmSetStaticFieldTaint(sfield, valueTaint);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		dvmSetFieldTaintWide(obj, ifield->byteOffset, valueTaint);
	    } else {
		dvmSetFieldTaint(obj, ifield->byteOffset, valueTaint);
	    }
	}
    }
#endif

    RETURN_VOID();
}