summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/check_jni.cc4
-rw-r--r--runtime/indirect_reference_table.cc2
-rw-r--r--runtime/jni_internal.cc19
-rw-r--r--runtime/thread-inl.h16
-rw-r--r--runtime/thread.cc2
-rw-r--r--test/JniTest/JniTest.java3
-rw-r--r--test/JniTest/jni_test.cc12
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);
+}