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

Segmentation fault in bitmap.cpp #150

Open
enumag opened this issue Jan 13, 2024 · 15 comments
Open

Segmentation fault in bitmap.cpp #150

enumag opened this issue Jan 13, 2024 · 15 comments

Comments

@enumag
Copy link

enumag commented Jan 13, 2024

I managed to get a gdb backtrace of the segfault.

#0  Bitmap::width (this=0x22d02ec0) at ../src/display/bitmap.cpp:864
#1  0x00007ff60526f06a in SpritePrivate::updateVisibility (this=0x1dd47130)
    at ../src/display/sprite.cpp:219
#2  0x00007ff60526f1ee in SpritePrivate::prepare (this=0x1dd47130) at ../src/display/sprite.cpp:317
#3  0x00007ff60531e2f6 in sigslot::detail::slot_pmf<void (SpritePrivate::*)(), SpritePrivate*>::call_slot (this=0x24395380) at ../src/util/sigslot/signal.hpp:927
#4  0x00007ff60531efd6 in sigslot::detail::slot_base<>::operator()<>() (this=0x24395380)
    at ../src/util/sigslot/signal.hpp:780
#5  0x00007ff60531ca8c in sigslot::signal_base<std::mutex>::operator()<>() (this=0xbad9c40)
    at ../src/util/sigslot/signal.hpp:1184
#6  0x00007ff605267325 in ScreenScene::composite (this=0x3aeb2f0)
    at ../src/display/graphics.cpp:508
#7  0x00007ff605275475 in GraphicsPrivate::redrawScreen (this=0x3aeb2c0)
    at ../src/display/graphics.cpp:1036
#8  0x00007ff60484278f in Graphics::update (this=0x3ae98d8, checkForShutdown=true)
    at ../src/display/graphics.cpp:1201
#9  0x00007ff60487673a in operator() (__closure=0x0) at ../binding/graphics-binding.cpp:47
#10 0x00007ff604876781 in _FUN () at ../binding/graphics-binding.cpp:50
#11 0x00007ffd47cfca98 in rb_nogvl () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#12 0x00007ffd47cfccf1 in rb_thread_call_without_gvl ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#13 0x00007ff6048767d1 in graphicsUpdate (argc=0, argv=0xf849c50, self=245178120)
    at ../binding/graphics-binding.cpp:45
#14 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#15 0x00007ffd47d48d6e in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#16 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#17 0x00007ffd47d56d32 in loop_i () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#18 0x00007ffd47b615fb in rb_vrescue2 () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#19 0x00007ffd47ea461b in rb_rescue2.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#20 0x00007ffd47d56ee8 in rb_f_loop.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#21 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#22 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#23 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#24 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#25 0x00007ffd47d5485d in rb_yield () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#26 0x00007ffd47aca01d in rb_ary_each () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#27 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#28 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#29 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#30 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#31 0x00007ffd47d56d32 in loop_i () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#32 0x00007ffd47b615fb in rb_vrescue2 () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#33 0x00007ffd47ea461b in rb_rescue2.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#34 0x00007ffd47d56ee8 in rb_f_loop.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#35 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#36 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#37 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#38 0x00007ffd47d5e85f in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#39 0x00007ffd47d5712e in rb_f_eval () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#40 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#41 0x00007ffd47d48d6e in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#42 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#43 0x00007ffd47d56d32 in loop_i () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#44 0x00007ffd47b615fb in rb_vrescue2 () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#45 0x00007ffd47ea461b in rb_rescue2.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#46 0x00007ffd47d56ee8 in rb_f_loop.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#47 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#48 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#49 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#50 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#51 0x00007ffd47d56d32 in loop_i () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#52 0x00007ffd47b615fb in rb_vrescue2 () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#53 0x00007ffd47ea461b in rb_rescue2.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#54 0x00007ffd47d56ee8 in rb_f_loop.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#55 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#56 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#57 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#58 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#59 0x00007ffd47d56d32 in loop_i () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#60 0x00007ffd47b615fb in rb_vrescue2 () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#61 0x00007ffd47ea461b in rb_rescue2.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#62 0x00007ffd47d56ee8 in rb_f_loop.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#63 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#64 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#65 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#66 0x00007ffd47d5e85f in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#67 0x00007ffd47d56d32 in loop_i () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#68 0x00007ffd47b615fb in rb_vrescue2 () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#69 0x00007ffd47ea461b in rb_rescue2.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#70 0x00007ffd47d56ee8 in rb_f_loop.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#71 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#72 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#73 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#74 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#75 0x00007ffd47d5712e in rb_f_eval () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#76 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#77 0x00007ffd47d48d6e in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#78 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#79 0x00007ffd47d5485d in rb_yield () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#80 0x00007ffd47aca01d in rb_ary_each () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#81 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#82 0x00007ffd47ea57f9 in vm_sendish.constprop ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#83 0x00007ffd47d4ab86 in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#84 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#85 0x00007ffd47d5712e in rb_f_eval () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#86 0x00007ffd47d415e9 in vm_call_cfunc_with_frame ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#87 0x00007ffd47d48d6e in vm_exec_core.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#88 0x00007ffd47d5e32b in rb_vm_exec () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#89 0x00007ffd47d5712e in rb_f_eval () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#90 0x00007ffd47d5114b in vm_call0_body.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#91 0x00007ffd47d533c7 in rb_funcallv_scope.lto_priv ()
   from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#92 0x00007ffd47d53b81 in rb_funcallv () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#93 0x00007ff60486a382 in evalHelper (arg=0xbaaf5b0) at ../binding/binding-mri.cpp:849
#94 0x00007ffd47b61984 in rb_protect () from C:\Projects\Reborn\Reborn\x64-msvcrt-ruby310.dll
#95 0x00007ff60486a3c9 in evalString (string=248084200, filename=248084160, state=0xbaaf80c)
    at ../binding/binding-mri.cpp:854
#96 0x00007ff60486ad3d in runRMXPScripts (btData=...) at ../binding/binding-mri.cpp:1024
#97 0x00007ff60486bcc9 in mriBindingExecute () at ../binding/binding-mri.cpp:1227
#98 0x00007ff604821c99 in rgssThreadFun (userdata=0x5fe880) at ../src/main.cpp:151
#99 0x00007ff604d447c7 in SDL_RunThread ()
#100 0x00007ff604d9401e in RunThreadViaBeginThreadEx ()
#101 0x00007ffdd62be634 in msvcrt!_beginthreadex () from C:\Windows\System32\msvcrt.dll
#102 0x00007ffdd62be70c in msvcrt!_endthreadex () from C:\Windows\System32\msvcrt.dll
#103 0x00007ffdd690257d in KERNEL32!BaseThreadInitThunk () from C:\Windows\System32\kernel32.dll
#104 0x00007ffdd798aa58 in ntdll!RtlUserThreadStart () from C:\Windows\SYSTEM32\ntdll.dll
#105 0x0000000000000000 in ?? ()
@Splendide-Imaginarius
Copy link

For reference, that's this line:

if (p->megaSurface) {

Might indicate that somehow p is null, though I don't see how that can happen.

@WaywardHeart
Copy link

WaywardHeart commented Jan 13, 2024

#145 should fix this.

Reiterating what's said in that PR, here's the exact sequence that happened:

  1. The sprite's bitmap was created before the sprite (Edit: Actually, I think deletion might happen in reverse order.)
  2. All references to the sprite and bitmap were discarded without disposing the sprite
  3. Ruby ran a minor GC run that asynchronously deleted the bitmap
  4. A call to Graphics.update was made before the sprite was garbage collected
  5. Memory values that used to belong to the bitmap were modified such that
  • bitmap->isDisposed() returned false
  • bitmap->p was non-null, but also something you don't want to try to access (I've seen 0x1 happen while I was trying to decide on a fix). I know it was probably non-null in this case because Sprite's prepare function currently has a call to bitmap->invalid(), because Struma ran into this same segfault and had the value be null consistently enough to create that as a workaround.

To fix this, #145 uses signals to set the bitmap pointers to null when they're disposed. Those pointers are only used internally by their respective classes, so setting them to null shouldn't cause any problems.

@enumag
Copy link
Author

enumag commented Jan 13, 2024

Wow that's a great analysis @WaywardHeart! Big thanks for fixing it. :) I'll cherry pick your commit into my fork since I need it soon-ish.

@WaywardHeart
Copy link

If you're interested in patching the game in question to keep the sprites from staying on screen longer than they should (or fps drops, if the game's making a lot of them), then you can use this script to find out where the sprites in question are created (although it'll also make those problems worse in the process by preventing garbage collection of them altogether). Ruby 1.9's garbage collector was a lot more aggressive than Ruby 3's, so sprites that would only linger for a few seconds in RGSS can stick around for a while in mkxp.

@enumag
Copy link
Author

enumag commented Jan 13, 2024

@WaywardHeart That script is for VX Ace with a link to a VX variant. Our game however is XP based so it wouldn't work.

@WaywardHeart
Copy link

Ah, yeah, I suppose there are a couple problems with each version that wouldn't let it work out of the box with XP.Here's a heavily modified script I just made that should work for you. It uses object ids and finalizers instead of storing the objects themselves, so it doesn't prevent garbage collection like the previous one does. You'll need to either activate debug mode or disable the check at the top of the script to use it, and it works fine as a preload script.

@enumag
Copy link
Author

enumag commented Jan 14, 2024

Okay I'm trying it. For now it throws this error. I might be able to debug and fix it tomorrow.
image

@WaywardHeart
Copy link

@enumag Oh, right. That method doesn't work on class instances. Sorry about that, it should be fixed now.

@enumag
Copy link
Author

enumag commented Jan 14, 2024

@WaywardHeart Yeah that works... but oh my it reports a ton of issues. 😳 How important is it to fix these? What impact does it have if these issues are not fixed?

@WaywardHeart
Copy link

Once the segfaults are fixed, then just some potential fps drops until the GC gets to them. It's probably not a big deal unless you're making and discarding a ton of them in a short period of time, and I think your stuff is mostly just text, so... it's probably fine? Also, I fixed a problem with the viewport.dispose overload if you downloaded it within the past... 20 minutes or so. I saw that Pokemon Flux has a lot too, so it might just be a problem with the Essentials core scripts rather than anything you've done.

@enumag
Copy link
Author

enumag commented Jan 14, 2024

I cherry picked your commit from #145 into my fork so we do have that fix applied in our game. Guess I don't need to worry about it too much then.

@WaywardHeart
Copy link

I think I saw #142's error logged in the console at one point, too. It got rescued, but it probably wouldn't hurt to pull in #149.

@enumag
Copy link
Author

enumag commented Jan 14, 2024

Oh yeah I noticed those "is recycled object" errors in our logs too. If #149 fixes that then awesome! Yoink! 🙇

@WaywardHeart
Copy link

I've given it a bit more thought, and I think what's going on is you're just hiding the text when you're done with it. While I personally don't think that's a good practice, we don't make draw calls for them so it's not harmful. Even the bitmaps attached to them are probably only in the double-digit kilobytes at the most. I'd say it's safe to ignore them.

@WaywardHeart
Copy link

Okay, I figured out what was going on. I was hooking the constructor (like the original script)... except mkxp doesn't generate the backend stuff until the initializer is called, and Essentials has some heavily used wrapper classes that never call it. Hook the initializer instead and the script reports almost nothing. Mystery solved!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants