diff options
| -rw-r--r-- | runtime/check_jni.cc | 4 | ||||
| -rw-r--r-- | runtime/indirect_reference_table.cc | 2 | ||||
| -rw-r--r-- | runtime/jni_internal.cc | 19 | ||||
| -rw-r--r-- | runtime/thread-inl.h | 16 | ||||
| -rw-r--r-- | runtime/thread.cc | 2 | ||||
| -rw-r--r-- | test/JniTest/JniTest.java | 3 | ||||
| -rw-r--r-- | test/JniTest/jni_test.cc | 12 |
7 files changed, 40 insertions, 18 deletions
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc index a84e18acc8..09c48b1220 100644 --- a/runtime/check_jni.cc +++ b/runtime/check_jni.cc @@ -1754,8 +1754,8 @@ PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); if (address == NULL) { JniAbortF(__FUNCTION__, "non-nullable address is NULL"); } - if (capacity <= 0) { - JniAbortF(__FUNCTION__, "capacity must be greater than 0: %lld", capacity); + if (capacity < 0) { + JniAbortF(__FUNCTION__, "capacity must be non negative: %lld", capacity); } return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity)); } diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc index 2bd83538ac..8194a0d767 100644 --- a/runtime/indirect_reference_table.cc +++ b/runtime/indirect_reference_table.cc @@ -80,7 +80,7 @@ IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) { prevState.all = cookie; size_t topIndex = segment_state_.parts.topIndex; - DCHECK(obj != NULL); + CHECK(obj != NULL); // TODO: stronger sanity check on the object (such as in heap) DCHECK_ALIGNED(reinterpret_cast<uintptr_t>(obj), 8); DCHECK(table_ != NULL); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 6690519eba..bbe5fda62f 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -844,13 +844,14 @@ class JNI { } static jobject NewGlobalRef(JNIEnv* env, jobject obj) { - if (obj == NULL) { - return NULL; - } ScopedObjectAccess soa(env); + Object* decoded_obj = soa.Decode<Object*>(obj); + // Check for null after decoding the object to handle cleared weak globals. + if (decoded_obj == nullptr) { + return nullptr; + } JavaVMExt* vm = soa.Vm(); IndirectReferenceTable& globals = vm->globals; - Object* decoded_obj = soa.Decode<Object*>(obj); WriterMutexLock mu(soa.Self(), vm->globals_lock); IndirectRef ref = globals.Add(IRT_FIRST_SEGMENT, decoded_obj); return reinterpret_cast<jobject>(ref); @@ -884,11 +885,13 @@ class JNI { } static jobject NewLocalRef(JNIEnv* env, jobject obj) { - if (obj == NULL) { - return NULL; - } ScopedObjectAccess soa(env); - return soa.AddLocalReference<jobject>(soa.Decode<Object*>(obj)); + mirror::Object* decoded_obj = soa.Decode<Object*>(obj); + // Check for null after decoding the object to handle cleared weak globals. + if (decoded_obj == nullptr) { + return nullptr; + } + return soa.AddLocalReference<jobject>(decoded_obj); } static void DeleteLocalRef(JNIEnv* env, jobject obj) { diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h index 6f3c117a59..b87a8ec3ca 100644 --- a/runtime/thread-inl.h +++ b/runtime/thread-inl.h @@ -87,18 +87,22 @@ inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) { DCHECK_EQ(GetState(), kRunnable); union StateAndFlags old_state_and_flags; union StateAndFlags new_state_and_flags; - do { + while (true) { old_state_and_flags.as_int = state_and_flags_.as_int; if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) { RunCheckpointFunction(); continue; } - // Copy over flags and try to clear the checkpoint bit if it is set. - new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags & ~kCheckpointRequest; + // Change the state but keep the current flags (kCheckpointRequest is clear). + DCHECK_EQ((old_state_and_flags.as_struct.flags & kCheckpointRequest), 0); + new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags; new_state_and_flags.as_struct.state = new_state; - // CAS the value without a memory barrier, that will occur in the unlock below. - } while (UNLIKELY(android_atomic_cas(old_state_and_flags.as_int, new_state_and_flags.as_int, - &state_and_flags_.as_int) != 0)); + int status = android_atomic_cas(old_state_and_flags.as_int, new_state_and_flags.as_int, + &state_and_flags_.as_int); + if (LIKELY(status == 0)) { + break; + } + } // Release share on mutator_lock_. Locks::mutator_lock_->SharedUnlock(this); } diff --git a/runtime/thread.cc b/runtime/thread.cc index bc252deecc..9faa60dbf8 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1147,7 +1147,7 @@ mirror::Object* Thread::DecodeJObject(jobject obj) const { result = Runtime::Current()->GetJavaVM()->DecodeWeakGlobal(const_cast<Thread*>(this), ref); if (result == kClearedJniWeakGlobal) { // This is a special case where it's okay to return NULL. - return NULL; + return nullptr; } } diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java index 9194da581f..d53cf5e564 100644 --- a/test/JniTest/JniTest.java +++ b/test/JniTest/JniTest.java @@ -23,6 +23,7 @@ class JniTest { testFindFieldOnAttachedNativeThread(); testCallStaticVoidMethodOnSubClass(); testGetMirandaMethod(); + testZeroLengthByteBuffers(); } private static native void testFindClassOnAttachedNativeThread(); @@ -67,6 +68,8 @@ class JniTest { } } + private static native void testZeroLengthByteBuffers(); + private static abstract class testGetMirandaMethod_MirandaAbstract implements testGetMirandaMethod_MirandaInterface { public boolean inAbstract() { return true; diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc index d15e180c02..33af94b2ab 100644 --- a/test/JniTest/jni_test.cc +++ b/test/JniTest/jni_test.cc @@ -17,6 +17,7 @@ #include <assert.h> #include <stdio.h> #include <pthread.h> +#include <vector> #include "jni.h" @@ -125,3 +126,14 @@ extern "C" JNIEXPORT jobject JNICALL Java_JniTest_testGetMirandaMethodNative(JNI assert(miranda_method != NULL); return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE); } + +// https://code.google.com/p/android/issues/detail?id=63055 +extern "C" void JNICALL Java_JniTest_testZeroLengthByteBuffers(JNIEnv* env, jclass) { + std::vector<uint8_t> buffer(1); + jobject byte_buffer = env->NewDirectByteBuffer(&buffer[0], 0); + assert(byte_buffer != NULL); + assert(!env->ExceptionCheck()); + + assert(env->GetDirectBufferAddress(byte_buffer) == &buffer[0]); + assert(env->GetDirectBufferCapacity(byte_buffer) == 0); +} |