[Bug] [Android] Random JNI errors when calling provider_data() or uid() on a valid user right after initializing Auth.
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 35/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
- 技術スタック
- android, cpp
調査の方向性
Auth::GetAuth と Auth::InitPlatformAuth から開始し、JniAuthStateListener_nativeOnAuthStateChanged を Auth::UpdateCurrentUser と SetImplFromLocalRef を通して追跡します。初期化直後に、報告された User::uid() への反復アクセスを実行します。ストレスケースで削除済み参照または null オブジェクトの JNI エラーが発生しなくなり、current_user のプロパティが引き続き使用可能であれば完了です。
索引モデルが issue の本文から書いたものです。
説明
[REQUIRED] Please fill in the following fields:
- Pre-built SDK from the website or open-source from this repo: prebuilt release
- Firebase C++ SDK version: 12.4.0 (already happened with Firebase C++ SDK 11.0.1)
- Problematic Firebase Component: Auth
- Other Firebase Components in use: Analytics, Crashlytics, Firestore, Functions, RemoteConfig
- Platform you are using the C++ SDK on: Mac
- Platform you are targeting: Android
[REQUIRED] Please describe the issue here:
Crashlytics reports some random crashes a few seconds after startup, during the initialization of our app, when accessing the state of a previously signed in user.
The stacks look like this:
JNI DETECTED ERROR IN APPLICATION: use of deleted global reference 0x3886
#00 pc 0x000000000008cdd0 /apex/com.android.runtime/lib64/bionic/libc.so (abort+164)
#01 pc 0x000000000053b0a4 /apex/com.android.art/lib64/libart.so (art::Runtime::Abort(char const*)+2340)
#02 pc 0x000000000001394c /system/lib64/libbase.so (android::base::SetAborter(std::__1::function<void (char const*)>&&)::$_3::__invoke(char const*)+76)
#03 pc 0x00000000000130cc /system/lib64/libbase.so (android::base::LogMessage::~LogMessage()+312)
#04 pc 0x0000000000372930 /apex/com.android.art/lib64/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+2596)
#05 pc 0x0000000000372aa0 /apex/com.android.art/lib64/libart.so (art::JavaVMExt::JniAbortF(char const*, char const*, ...)+188)
#06 pc 0x000000000058edbc /apex/com.android.art/lib64/libart.so (art::Thread::DecodeJObject(_jobject*) const+740)
#07 pc 0x00000000005335bc /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithVarArgs<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, std::__va_list)+72)
#08 pc 0x0000000000533918 /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithVarArgs<_jmethodID*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+92)
#09 pc 0x000000000038ca54 /apex/com.android.art/lib64/libart.so (art::JNI<false>::CallObjectMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+656)
#10 pc 0x0000000001efb0a8 /data/app/~~we2dODBK-dwTNyJ0WwgHVw==/XXX-PL2uZARhnKyZj-sBR8U9ag==/split_config.arm64_v8a.apk!libgame_android.so (_JNIEnv::CallObjectMethod(_jobject*, _jmethodID*, ...)+116) (BuildId: 49d308be143cc46526a72431ce8b6942c800f328)
#11 pc 0x0000000001db7500 /data/app/~~we2dODBK-dwTNyJ0WwgHVw==/XXX-PL2uZARhnKyZj-sBR8U9ag==/split_config.arm64_v8a.apk!libgame_android.so (firebase::auth::User::provider_data() const+112) (BuildId: 49d308be143cc46526a72431ce8b6942c800f328)
it varies a bit and sometimes the JNI error is : JNI DETECTED ERROR IN APPLICATION: obj == null
Also, sometimes it will crash in firebase::auth::User::uid() instead, there is a call right after provider_data().
Our crash is very similar to this issue, but note that we are not registering any AuthStateListener ourselves: https://github.com/firebase/firebase-cpp-sdk/issues/753
Steps to reproduce:
Have you been able to reproduce this issue with just the Firebase C++ quickstarts ?
No, rate seems low: about 1 crash per day per 10000 users.
Relevant code
Here is what happens on app launch:
Our app starts by initializing the firebase app
firebase::App::Create(env, _activity->clazz);
then about 1 second later, we initialize Auth and try to retrieve some data if the user is signed in
auth::Auth *auth = auth::Auth::GetAuth(App::GetInstance()); << First call of GetAuth
auth::User user = auth->current_user();
if (!user.is_valid())
return;
std::vector<auth::UserInfoInterface> data = user.provider_data(); << Crash here
...
All our calls to Auth are done from the same native cpp thread.
Investigation:
By looking at the SDK code, it seems this crash could happen if there is a data race where a thread calls Auth::UpdateCurrentUser (more specifically SetImplFromLocalRef(env, j_user, &auth_data->user_impl)) while our native thread is accessing the current_user's properties.
Potential culprit:
From my understanding, the initialization of Auth will synchronously call UpdateCurrentUser, so accessing the user right after should be fine.
But what I also noticed is that Auth::InitPlatformAuth will register a JniAuthStateListener.
I believe addAuthStateListener from FirebaseAuth.java will trigger a callback from a Java Thread after a random delay, which will eventually result in a call to JniAuthStateListener_nativeOnAuthStateChanged and Auth::UpdateCurrentUser from another thread, resulting in a data race.
I was not able to reproduce the crash with the production code, but I was able to get it by calling User::uid() many times right after the init of Auth. Something like this:
auth::Auth *auth = auth::Auth::GetAuth(App::GetInstance());
auth::User user = auth->current_user();
if (!user.is_valid())
return;
for (int i = 0; i < 1000000; i++)
user.uid();
...
This generates a crash similar to the one we see in production. It happens around every 5 to 10 app launches. I couldn't get it to crash with user.provider_data() though, maybe it's just less likely because it has more instructions.
Also, I haven't been able to generate the crash when Auth is initialized about 1s before the first user access.
Other notes:
- We have never seen this crash on other calls to User::uid() or User::provider_data(), only the ones right after the Auth initialization crashes.
- We also have an iOS version and have never seen any crash there when accessing a User's properties.
- 主要言語
- C++
- スター
- 326
- フォーク
- 138
- 平均マージ
- 2日 16時間
- マージ済み PR(30日)
- 3
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
firebase/firebase-cpp-sdk のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
firebase/firebase-cpp-sdk#1905 · コメント 2 件 ·
-
api: firestore
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
firebase/firebase-cpp-sdk#1920 · コメント 3 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 70/100
firebase/firebase-cpp-sdk#1904 · コメント 1 件 ·
-
new type: question
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
firebase/firebase-cpp-sdk#1892 · コメント 1 件 ·
-
nightly-testing
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
firebase/firebase-cpp-sdk#1859 ·
firebase/firebase-cpp-sdk の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
flutter-webrtc/flutter-webrtc#2206 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
google-ai-edge/LiteRT-LM#3739 ·
-
Component: GLib
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
brave/brave-browser#59300 ·
-
Mute ydb/tests/functional/dstool/test_canonical_requests.py.Test.test_group_take_snapshot in main オープンai_reviewed
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
ydb-platform/ydb#53974 · コメント 3 件 ·