Skip to content
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

Fix ItemStack.EMPTY.getItem() rarely returning null due to threading #2826

Merged
merged 2 commits into from
Jan 20, 2023

Conversation

Technici4n
Copy link
Member

@Technici4n Technici4n requested a review from a team January 4, 2023 00:17
@Technici4n Technici4n added the bug Something isn't working label Jan 4, 2023
@modmuss50
Copy link
Member

Does this happen in vanilla?

@Technici4n
Copy link
Member Author

Unclear whether it happens in vanilla or not, but with mods it creates random crashes that don't point to the original modification. Transfer API is also guilty of calling .setCount(0) on empty stacks. You'd expect this to be a safe operation, and patching all the call sites is much uglier...
image

As for the performance impact: it seems like the whole injector gets inlined into updateEmptyState and the CI allocation is gone... Not too sure as I'm not used to reading hotspot output and had to do some "manual" disassembly, but it looks ok.

@shartte
Copy link
Contributor

shartte commented Jan 4, 2023

Unclear whether it happens in vanilla or not, but with mods it creates random crashes that don't point to the original modification. Transfer API is also guilty of calling .setCount(0) on empty stacks. You'd expect this to be a safe operation, and patching all the call sites is much uglier... image

As for the performance impact: it seems like the whole injector gets inlined into updateEmptyState and the CI allocation is gone... Not too sure as I'm not used to reading hotspot output and had to do some "manual" disassembly, but it looks ok.

How did you get the disassembly?

There is a tool that simplifies it greatly but I forgot the details (as usual :-P))

@Technici4n
Copy link
Member Author

I used -XX:+PrintAssembly which gave this:
image
No decompiler module to directly emit readable assembly, but I copy/pasted the instructions manually into https://defuse.ca/online-x86-assembler.htm. 😅

I also checked the inlining log (with -XX:+PrintInlining):
image
which suggests that the method got inlined.

FYI this is what I used to run the tests:
image
image

Not perfect, but seems OK at a glance.

@liach
Copy link
Contributor

liach commented Jan 4, 2023

Does this not hurt other items set to count 0 because they won't return null but a wrong value, which is less severe?

I personally recommend patching the instance field write/reads to local variables or mark the method synchronized for a more comprehensive solution.

@Technici4n
Copy link
Member Author

We could overwrite the method to this.empty = this.item == null || this.item == Items.AIR || this.count <= 0.

@Technici4n
Copy link
Member Author

Changed to an overwrite. Using a cancellable injector because of lithium's mixin: https://github.com/CaffeineMC/lithium-fabric/blob/1.19.x/dev/src/main/java/me/jellysquid/mods/lithium/mixin/item/ItemStackMixin.java that will conflict with any sort of @Overwrite.

@emilyploszaj
Copy link

Does this happen in vanilla?

For the bug I've reported to mojang, I was able to reproduce this bug in vanilla after several hours, you can see the crash log here. https://bugs.mojang.com/browse/MC-258939

@modmuss50
Copy link
Member

I was able to reproduce this bug in vanilla after several hours

Thats awesome! Thanks 👍

@Noaaan
Copy link

Noaaan commented Jan 12, 2023

Does this happen in vanilla?

For the bug I've reported to mojang, I was able to reproduce this bug in vanilla after several hours, you can see the crash log here. https://bugs.mojang.com/browse/MC-258939

Wow. We theorized and joked about this potentially being a vanilla bug. To have it confirmed is another story. Have hunted this issue for over 6 months, so finally putting it to rest is great.
Noaaan/MythicMetals#94

@emilyploszaj
Copy link

Wow. We theorized and joked about this potentially being a vanilla bug. To have it confirmed is another story. Have hunted this issue for over 6 months, so finally putting it to rest is great. Noaaan/MythicMetals#94

Tech told me he didn't think this was a vanilla bug so I had to prove him wrong

@modmuss50 modmuss50 merged commit c3530bb into FabricMC:1.19.3 Jan 20, 2023
modmuss50 pushed a commit that referenced this pull request Jan 20, 2023
…2826)

* Fix ItemStack.EMPTY.getItem() rarely returning null due to threading

* Overwrite instead

(cherry picked from commit c3530bb)
modmuss50 pushed a commit that referenced this pull request Jan 20, 2023
…2826)

* Fix ItemStack.EMPTY.getItem() rarely returning null due to threading

* Overwrite instead

(cherry picked from commit c3530bb)
(cherry picked from commit 693ffc0)
modmuss50 pushed a commit that referenced this pull request Mar 15, 2023
…2826)

* Fix ItemStack.EMPTY.getItem() rarely returning null due to threading

* Overwrite instead

(cherry picked from commit c3530bb)
(cherry picked from commit 693ffc0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants