diff options
author | husky@chromium.org <husky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-30 13:40:38 +0000 |
---|---|---|
committer | husky@chromium.org <husky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-30 13:40:38 +0000 |
commit | d31afe7d7857c68d4ea8d9bccb2a70688a4f2edd (patch) | |
tree | 429d6235f45f48cfb486970b2d0c917a0829e75b /base/android | |
parent | cd1177991859a25f39dc70502ad68dae82e9ec8e (diff) | |
download | chromium_src-d31afe7d7857c68d4ea8d9bccb2a70688a4f2edd.zip chromium_src-d31afe7d7857c68d4ea8d9bccb2a70688a4f2edd.tar.gz chromium_src-d31afe7d7857c68d4ea8d9bccb2a70688a4f2edd.tar.bz2 |
Fix segfault in JNIEnv function hooks for test
On newer JB builds, the JNINativeInterface struct appears to be held
in read-only memory so attempting to repoint individual function pointers
in it causes segfault. So instead we repoint the top-level struct pointer
to refer to our own copy held in read/write memory.
BUG=137348
TEST=JNIAndroidTest
Review URL: https://chromiumcodereview.appspot.com/10828050
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148943 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/android')
-rw-r--r-- | base/android/jni_android_unittest.cc | 26 | ||||
-rw-r--r-- | base/android/scoped_java_ref_unittest.cc | 29 |
2 files changed, 33 insertions, 22 deletions
diff --git a/base/android/jni_android_unittest.cc b/base/android/jni_android_unittest.cc index 5f5165a..abecad7 100644 --- a/base/android/jni_android_unittest.cc +++ b/base/android/jni_android_unittest.cc @@ -1,9 +1,10 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/android/jni_android.h" +#include "base/at_exit.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -21,14 +22,14 @@ const char* g_last_method; const char* g_last_jni_signature; jmethodID g_last_method_id; -JNINativeInterface g_previous_functions = {0}; +const JNINativeInterface* g_previous_functions; jmethodID GetMethodIDWrapper(JNIEnv* env, jclass clazz, const char* method, const char* jni_signature) { g_last_method = method; g_last_jni_signature = jni_signature; - g_last_method_id = g_previous_functions.GetMethodID(env, clazz, method, - jni_signature); + g_last_method_id = g_previous_functions->GetMethodID(env, clazz, method, + jni_signature); return g_last_method_id; } @@ -38,15 +39,16 @@ class JNIAndroidTest : public testing::Test { protected: virtual void SetUp() { JNIEnv* env = AttachCurrentThread(); - g_previous_functions = *env->functions; - JNINativeInterface* native_interface = - const_cast<JNINativeInterface*>(env->functions); - native_interface->GetMethodID = &GetMethodIDWrapper; + g_previous_functions = env->functions; + hooked_functions = *g_previous_functions; + env->functions = &hooked_functions; + hooked_functions.GetMethodID = &GetMethodIDWrapper; } virtual void TearDown() { JNIEnv* env = AttachCurrentThread(); - *(const_cast<JNINativeInterface*>(env->functions)) = g_previous_functions; + env->functions = g_previous_functions; + Reset(); } void Reset() { @@ -54,6 +56,12 @@ class JNIAndroidTest : public testing::Test { g_last_jni_signature = 0; g_last_method_id = NULL; } + // Needed to cleanup the cached method map in the implementation between + // runs (e.g. if using --gtest_repeat) + base::ShadowingAtExitManager exit_manager; + // From JellyBean release, the instance of this struct provided in JNIEnv is + // read-only, so we deep copy it to allow individual functions to be hooked. + JNINativeInterface hooked_functions; }; TEST_F(JNIAndroidTest, GetMethodIDFromClassNameCaching) { diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc index f8bc675..36f253c 100644 --- a/base/android/scoped_java_ref_unittest.cc +++ b/base/android/scoped_java_ref_unittest.cc @@ -15,26 +15,26 @@ namespace { int g_local_refs = 0; int g_global_refs = 0; -JNINativeInterface g_previous_functions = {0}; +const JNINativeInterface* g_previous_functions; jobject NewGlobalRef(JNIEnv* env, jobject obj) { ++g_global_refs; - return g_previous_functions.NewGlobalRef(env, obj); + return g_previous_functions->NewGlobalRef(env, obj); } void DeleteGlobalRef(JNIEnv* env, jobject obj) { --g_global_refs; - return g_previous_functions.DeleteGlobalRef(env, obj); + return g_previous_functions->DeleteGlobalRef(env, obj); } jobject NewLocalRef(JNIEnv* env, jobject obj) { ++g_local_refs; - return g_previous_functions.NewLocalRef(env, obj); + return g_previous_functions->NewLocalRef(env, obj); } void DeleteLocalRef(JNIEnv* env, jobject obj) { --g_local_refs; - return g_previous_functions.DeleteLocalRef(env, obj); + return g_previous_functions->DeleteLocalRef(env, obj); } } // namespace @@ -44,21 +44,24 @@ class ScopedJavaRefTest : public testing::Test { g_local_refs = 0; g_global_refs = 0; JNIEnv* env = AttachCurrentThread(); - g_previous_functions = *env->functions; + g_previous_functions = env->functions; + hooked_functions = *g_previous_functions; + env->functions = &hooked_functions; // We inject our own functions in JNINativeInterface so we can keep track // of the reference counting ourselves. - JNINativeInterface* native_interface = - const_cast<JNINativeInterface*>(env->functions); - native_interface->NewGlobalRef = &NewGlobalRef; - native_interface->DeleteGlobalRef = &DeleteGlobalRef; - native_interface->NewLocalRef = &NewLocalRef; - native_interface->DeleteLocalRef = &DeleteLocalRef; + hooked_functions.NewGlobalRef = &NewGlobalRef; + hooked_functions.DeleteGlobalRef = &DeleteGlobalRef; + hooked_functions.NewLocalRef = &NewLocalRef; + hooked_functions.DeleteLocalRef = &DeleteLocalRef; } virtual void TearDown() { JNIEnv* env = AttachCurrentThread(); - *(const_cast<JNINativeInterface*>(env->functions)) = g_previous_functions; + env->functions = g_previous_functions; } + // From JellyBean release, the instance of this struct provided in JNIEnv is + // read-only, so we deep copy it to allow individual functions to be hooked. + JNINativeInterface hooked_functions; }; // The main purpose of this is testing the various conversions compile. |