-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NullPointerException when setting StateFlow value #3820
Comments
Seeing the same crash occasionally after an upgrade to In our case the flow receives a kotlin
The same stateflow is updated with |
The last change to |
Same exceptions when I upgrade to 1.7.2 Fatal Exception: java.lang.NullPointerException: |
@mshdabiola This does not look the same at all, did you mean to paste a different trace? |
We have received another instance of this crash updating ANOTHER stateflow, this time it's much simpler, but still being run on the background thread, IO dispatcher pool in this case.
This instance of the crash is much more infrequent than the one I originally reported (that one has picking up in occurrences lately), but we have detailed analytics on how often this new crash code-path triggers. Out of 22_789_644 invocations it has triggered once, but this suggests to me that the issue is more widespread and can affect even simpler cases. Full stacktrace with more details about how the stateflow is updated. Crash occured on the first and only update to
I have been trying to reproduce with the simplified version (this new crash), but it's still very hard to hit the exact race here. Does this ring any bell at all @qwwdfsad? |
|
This has happened on another StateFlow now that holds a nullable |
@hakonschia All our crashes are occurring when the |
The original crash is happening on the main thread, and shouldn't be very close to process instantiation. The second is called from the IO dispatcher, but I don't think this should be close to process instantation either. The second is also a lot rarer, only happening 3 times compared to 80 for the original |
We have now surpassed 100 crashes. A few additional details:
|
We are also seeing this on Android 11, but not on lower versions
We have some seen some repeats, but for the most part it has only happened once per user (100 crashes for 98 users) Our crashes are mostly on Android TV and lower end phones/tablets |
Got a few reports from the the 3rd party library as well:
|
It seems like a long-standing bug in Android 12/13, as the quick search of It seems to be a bug on the edge of the DEX compiler, optimizer and specific runtime, which is almost impossible to reason about without a reproducer and access to the actual ART sources. The only change in atomicfu I see that might have affected the reproducibility of the bug is modifiers on the corresponding field updater. In |
I'm also a bit confused by the fact it only reproduces on the The biggest issue here is ensuring the problem is gone -- poking with the implementation of If anybody knows the way to reproduce it on their CI, device farm, and/or local environments, I can arrange dev-builds with changes that presumably help. |
I'm not really sure what has changed, but this has stopped happening so it is no longer an issue for us. |
I am still seeing this issue on version |
We also started seeing this crash all of a sudden. We have coroutine version of '1.7.2'. Our class is almost the same as the author produced in the beginning, but we have a slightly different stacktrace. We have it updated multiple times from coroutines with different scopes.
|
See above: #3820 (comment) It's an Android-specific problem that's not in our library but in Android's toolchain, but if someone can give us a reliable reproducer, we can look into adding a workaround in the library itself. |
Any updates? Is there a temporary solution to avoid collapse? |
@qwwdfsad Is there any workaround to fix this? Some catch blocks or what should I do to prevent crashes? |
@yangwuan55 , @Monabr , the answer is literally on the same screen, you just need to scroll up a bit to see it: no, there are no updates, as it's an Android problem, not the problem with our library; we don't know what's causing this. If you can provide a reliable reproducer (a project that consistently crashes in the emulator or at least on some specific device), please do, and we'll try to introduce a workaround. Specifically: #3820 (comment) |
The problem continues to reproduce.
It is necessary to change |
Unless someone can definitively test our changes, we don't know what is necessary to do. Do you have a way to reproduce this issue consistently and can help us check if a fix does help? Or do you maybe know something we don't and can say for sure that it's the |
Same issue on version 1.7.3. |
We just started getting this problem after updating our coroutines dependency from 1.6.4 to 1.8.0-RC2. We currently only have this happening in our beta release but so far it looks like it is limited to Android 13 and 14. The crash originates in public final void makePending() {
Symbol symbol;
Symbol symbol2;
Symbol symbol3;
Symbol symbol4;
while (true) {
Object obj = this._state;
if (obj == null) {
return;
}
symbol = StateFlowKt.PENDING;
if (obj == symbol) {
return;
}
symbol2 = StateFlowKt.NONE;
boolean z16 = false;
if (obj == symbol2) {
AtomicReferenceFieldUpdater atomicReferenceFieldUpdater = _state$FU;
symbol3 = StateFlowKt.PENDING;
while (true) {
if (!atomicReferenceFieldUpdater.compareAndSet(this, obj, symbol3)) {
if (atomicReferenceFieldUpdater.get(this) != obj) {
break;
}
} else {
z16 = true;
break;
}
}
if (z16) {
return;
}
} else {
AtomicReferenceFieldUpdater atomicReferenceFieldUpdater2 = _state$FU;
symbol4 = StateFlowKt.NONE;
while (true) {
if (!atomicReferenceFieldUpdater2.compareAndSet(this, obj, symbol4)) {
if (atomicReferenceFieldUpdater2.get(this) != obj) {
break;
}
} else {
z16 = true;
break;
}
}
if (z16) {
int i9 = k.f270577;
((CancellableContinuationImpl) obj).resumeWith(c0.f270561);
return;
}
}
}
} after the update to public final void makePending() {
Symbol symbol;
Symbol symbol2;
Symbol symbol3;
Symbol symbol4;
AtomicReferenceFieldUpdater atomicReferenceFieldUpdater = _state$volatile$FU;
while (true) {
Object obj = atomicReferenceFieldUpdater.get(this);
if (obj == null) {
return;
}
symbol = StateFlowKt.PENDING;
if (obj == symbol) {
return;
}
symbol2 = StateFlowKt.NONE;
boolean z13 = false;
if (obj == symbol2) {
AtomicReferenceFieldUpdater atomicReferenceFieldUpdater2 = _state$volatile$FU;
symbol3 = StateFlowKt.PENDING;
while (true) {
if (!atomicReferenceFieldUpdater2.compareAndSet(this, obj, symbol3)) {
if (atomicReferenceFieldUpdater2.get(this) != obj) {
break;
}
} else {
z13 = true;
break;
}
}
if (z13) {
return;
}
} else {
AtomicReferenceFieldUpdater atomicReferenceFieldUpdater3 = _state$volatile$FU;
symbol4 = StateFlowKt.NONE;
while (true) {
if (!atomicReferenceFieldUpdater3.compareAndSet(this, obj, symbol4)) {
if (atomicReferenceFieldUpdater3.get(this) != obj) {
break;
}
} else {
z13 = true;
break;
}
}
if (z13) {
int i16 = k.f159498;
((CancellableContinuationImpl) obj).resumeWith(c0.f159482);
return;
}
}
}
} with the crash originating in this line: Note: Even though This is where it gets funky: This code calls @SuppressWarnings("unchecked")
public final V get(T obj) {
accessCheck(obj);
return (V)U.getObjectVolatile(obj, offset);
} with private final void accessCheck(T obj) {
if (!cclass.isInstance(obj))
throwAccessCheckException(obj);
}
static final /* synthetic */ AtomicReferenceFieldUpdater _state$FU = AtomicReferenceFieldUpdater.newUpdater(StateFlowSlot.class, Object.class, "_state"); and the constructor of this.cclass = (Modifier.isProtected(modifiers) &&
tclass.isAssignableFrom(caller) &&
!isSamePackage(tclass, caller))
? caller : tclass; so this on Android 13 the public boolean isInstance(Object obj) {
if (obj == null) {
return false;
}
return isAssignableFrom(obj.getClass());
} so this will get the into public boolean isAssignableFrom(Class<?> cls) {
if (this == cls) {
return true; // Can always assign to things of the same type.
} else if (this == Object.class) {
return !cls.isPrimitive(); // Can assign any reference to java.lang.Object.
} else if (isArray()) {
return cls.isArray() && componentType.isAssignableFrom(cls.componentType);
} else if (isInterface()) {
// Search iftable which has a flattened and uniqued list of interfaces.
Object[] iftable = cls.ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
if (iftable[i] == this) {
return true;
}
}
}
return false;
} else {
if (!cls.isInterface()) {
for (cls = cls.superClass; cls != null; cls = cls.superClass) {
if (cls == this) {
return true;
}
}
}
return false;
}
} And this is where the crash is in line Which means that the The public final Class<?> getClass() {
return shadow$_klass_;
} which I guess can be null, maybe a GC issue? Anyway, I will also file this with Google Android standard lib code examples from: https://android.googlesource.com/platform/libcore/+/refs/heads/android13-d1-release/ojluni/src/main/java/java/lang |
Issue in Google issue tracker: https://issuetracker.google.com/issues/325123736 |
Update: This is happening on Android 12, 13 and 14 for us and we support 9+ |
Just an FYI on the loop around |
Replace the specific place where ARFU gets misexecuted by specific Android toolchain Fixes #3820
We've merged a potential temporary workaround that is going to be included in the next release. Please note that the workaround is temporary, and we expect to rollback it once Google has identified and fixed the issue (which we assume it will taking its severity and priority: https://issuetracker.google.com/issues/325123736) |
So glad hear that,thank you so much! |
Thanks you so much for the invitation to me
…On Sat, 9 Mar 2024, 10:07 am mengrong.yang, ***@***.***> wrote:
We've merged a potential temporary workaround that is going to be included
in the next release.
Please note that the workaround is *temporary*, and we expect to rollback
it once Google has identified and fixed the issue (which we assume it will
taking its severity and priority:
https://issuetracker.google.com/issues/325123736)
So glad hear that,thank you so much!
—
Reply to this email directly, view it on GitHub
<#3820 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BFURIDYEZZ3TFA4KEVS66S3YXKKI5AVCNFSM6AAAAAA2SU43TWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSOBWG4ZTEMBVGA>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
We have a fork of 1.8.0 with the workaround from #4054 in prod now and have enough sessions that we can confirm that this issue is not happening anymore with the workaround! 🙏 for the fix(workaround! |
Replace the specific place where ARFU gets misexecuted by a specific Android toolchain Fixes Kotlin#3820
Given this answer in the issue tracker, it seems that Google considers your workaround valid, stable and definitive ^^ |
Thanks for pointing it out! |
Describe the bug
After upgrading from version 1.6.4 to 1.7.1 (we have since bumped to 1.7.2) we started seeing
NullPointerException
crashes when updating aStateFlow
value. I am not able to reproduce this locally, we are only seeing this through Firebase reports.This is happening on Android with
org.jetbrains.kotlinx:kotlinx-coroutines-android
. It's happening on many different devices and Android versions, so it isn't specific to one manufacturer/version.Provide a Reproducer
We have a lot of flows, and only one specific one is crashing. The only unique thing about the flow that is causing crashes is that it holds an
Enum
, but I don't know if that's causing it.The
StateFlow
is nullable, but the value set on it after initialization is never null. The code below isn't our production code, but is how our code looks likeThe text was updated successfully, but these errors were encountered: