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

Segfault during demo #371

Closed
lanodan opened this issue Sep 9, 2023 · 4 comments
Closed

Segfault during demo #371

lanodan opened this issue Sep 9, 2023 · 4 comments
Labels

Comments

@lanodan
Copy link

lanodan commented Sep 9, 2023

Information

  • OS: Gentoo Linux (clang + glibc)
  • Taisei version: 1.4

How to reproduce

  • Page in the intro
  • Let it idle for the demo to run
  • Fight happens
  • Transitions to white
  • Crash

Backtraces

First coredump:

(lldb) bt
* thread #1, name = 'taisei', stop reason = signal SIGSEGV
  * frame #0: 0x00005603b8174d5f taisei`process_projectiles(projlist=0x00005603b8391650, collision=true) at projectile.c:553:18
    frame #1: 0x00005603b8178cf2 taisei`COTASKTHUNK_stage_comain [inlined] COTASK_stage_comain(_cotask_args=<unavailable>) at stage.c:1034:3
    frame #2: 0x00005603b8178a0f taisei`COTASKTHUNK_stage_comain(arg=<unavailable>, arg_size=<unavailable>) at stage.c:1014:1
    frame #3: 0x00005603b818ae50 taisei`cotask_entry(varg=0x00007ffd32b71920) at cotask.c:371:9
    frame #4: 0x00005603b828842b taisei`koishi_entry(co=0x00005603bae8dde0) at fiber.h:68:17
    frame #5: 0x00005603b8288413 taisei`co_entry(tf=<unavailable>) at fcontext.c:50:2
    frame #6: 0x00005603b82884df taisei`make_fcontext at make_x86_64_sysv_elf_gas.S:71
(lldb) v -A
(ProjectileList *) projlist = 0x00005603b8391650
(bool) collision = true
(ProjCollisionResult) col = {
  type = PCOL_NONE
  fatal = false
  location = 0 + 0.0078125i
  damage = (amount = -0.00300286338, type = 0xb8387140)
  entity = NULL
}
(bool) stage_cleared = <no location, value may have been optimized out>

(Projectile *) proj = 0xc024000000000000
(Projectile *) next = <variable not available>

(bool) destroy = <variable not available>

From launching it in lldb:

Process 22653 stopped
* thread #1, name = 'taisei', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
    frame #0: 0x00007ffff72a45ce libc.so.6`__libc_free + 30
libc.so.6`__libc_free:
->  0x7ffff72a45ce <+30>: movq   -0x8(%rdi), %rax
    0x7ffff72a45d2 <+34>: movl   %fs:(%rbx), %ebp
    0x7ffff72a45d5 <+37>: testb  $0x2, %al
    0x7ffff72a45d7 <+39>: jne    0x7ffff72a4630            ; <+128>
(lldb) bt
* thread #1, name = 'taisei', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
  * frame #0: 0x00007ffff72a45ce libc.so.6`__libc_free + 30
    frame #1: 0x000055555557883c taisei`_dynarray_free_data(sizeof_element=16, darr=0x00005555564f8098) at dynarray.c:24:2
    frame #2: 0x00005555555b095f taisei`coevent_cancel(evt=<unavailable>) at coevent.c:130:3 [artificial]
    frame #3: 0x00005555555b0995 taisei`_coevent_array_action(num=3, events=0x00005555564f8080, func=(taisei`coevent_cancel at coevent.c:111)) at coevent.c:138:3
    frame #4: 0x000055555559ad31 taisei`process_projectiles [inlined] delete_projectile(projlist=0x00005555557b7650, p=0x00005555564f7f60, col=0x0000000000000000) at projectile.c:315:2
    frame #5: 0x000055555559acef taisei`process_projectiles(projlist=0x00005555557b7650, collision=true) at projectile.c:554:4
    frame #6: 0x000055555559ecf2 taisei`COTASKTHUNK_stage_comain [inlined] COTASK_stage_comain(_cotask_args=<unavailable>) at stage.c:1034:3
    frame #7: 0x000055555559ea0f taisei`COTASKTHUNK_stage_comain(arg=<unavailable>, arg_size=<unavailable>) at stage.c:1014:1
    frame #8: 0x00005555555b0e50 taisei`cotask_entry(varg=0x00007fffffffd0b0) at cotask.c:371:9
    frame #9: 0x00005555556ae42b taisei`koishi_entry(co=0x000055555630cc40) at fiber.h:68:17
    frame #10: 0x00005555556ae413 taisei`co_entry(tf=<unavailable>) at fcontext.c:50:2
    frame #11: 0x00005555556ae4df taisei`make_fcontext at make_x86_64_sysv_elf_gas.S:71

Second coredump got while recording display to get more context

(lldb) bt
* thread #1, name = 'taisei', stop reason = signal SIGSEGV
  * frame #0: 0x00007f4860ae95ce libc.so.6`__libc_free + 30
    frame #1: 0x000055c11eaa883c taisei`_dynarray_free_data(sizeof_element=16, darr=0x000055c120d8b6a8) at dynarray.c:24:2
    frame #2: 0x000055c11eae095f taisei`coevent_cancel(evt=<unavailable>) at coevent.c:130:3 [artificial]
    frame #3: 0x000055c11eae0995 taisei`_coevent_array_action(num=3, events=0x000055c120d8b690, func=(taisei`coevent_cancel at coevent.c:111)) at coevent.c:138:3
    frame #4: 0x000055c11eacad31 taisei`process_projectiles [inlined] delete_projectile(projlist=0x000055c11ece7650, p=0x000055c120d8b570, col=0x0000000000000000) at projectile.c:315:2
    frame #5: 0x000055c11eacacef taisei`process_projectiles(projlist=0x000055c11ece7650, collision=true) at projectile.c:554:4
    frame #6: 0x000055c11eacecf2 taisei`COTASKTHUNK_stage_comain [inlined] COTASK_stage_comain(_cotask_args=<unavailable>) at stage.c:1034:3
    frame #7: 0x000055c11eacea0f taisei`COTASKTHUNK_stage_comain(arg=<unavailable>, arg_size=<unavailable>) at stage.c:1014:1
    frame #8: 0x000055c11eae0e50 taisei`cotask_entry(varg=0x00007ffd6a640670) at cotask.c:371:9
    frame #9: 0x000055c11ebde42b taisei`koishi_entry(co=0x000055c120a39430) at fiber.h:68:17
    frame #10: 0x000055c11ebde413 taisei`co_entry(tf=<unavailable>) at fcontext.c:50:2
    frame #11: 0x000055c11ebde4df taisei`make_fcontext at make_x86_64_sysv_elf_gas.S:71
(lldb) v -A
(lldb) f 4
frame #4: 0x000055c11eacad31 taisei`process_projectiles [inlined] delete_projectile(projlist=0x000055c11ece7650, p=0x000055c120d8b570, col=0x0000000000000000) at projectile.c:315:2
(lldb) v -A
(ProjectileList *) projlist = 0x000055c11ece7650
(Projectile *) p = 0x000055c120d8b570
(ProjCollisionResult *) col = NULL
(lldb) f 5
frame #5: 0x000055c11eacacef taisei`process_projectiles(projlist=0x000055c11ece7650, collision=true) at projectile.c:554:4
(lldb) v -A
(ProjectileList *) projlist = 0x000055c11ece7650
(bool) collision = true
(ProjCollisionResult) col = {
  type = PCOL_NONE
  fatal = false
  location = 212.382 + 271.824i
  damage = (amount = 0, type = DMG_ENEMY_SHOT)
  entity = NULL
}
(bool) stage_cleared = <no location, value may have been optimized out>

(Projectile *) proj = 0x000055c120d8b570
(Projectile *) next = 0xc024000000000000
(bool) destroy = <variable not available>

Building taisei with LLVM/clang scan-build utility also reports 42 bugs found, including some memory errors and logic errors (majority of bugs found being unused code due to dead assignments).

@lanodan
Copy link
Author

lanodan commented Sep 9, 2023

Interestingly after playing some run and updating the settings (enabling "shoot by default", toggling it back changes nothing), I can no longer reproduce…

@Akaricchi
Copy link
Member

Maybe try it with a clean userdir (TAISEI_STORAGE_PATH=/tmp/foo) to see if that reproduces it again?

If you do manage to reproduce it, try building with ASan (meson configure -Db_sanitize=address) and running without a debugger. Usually that produces more useful information for memory management bugs.

@Akaricchi Akaricchi added the crash label Sep 9, 2023
@Akaricchi
Copy link
Member

Confirmed consistently reproducible with a clean userdir.

@Akaricchi
Copy link
Member

Found the problem. It was a bad interaction between the intro and the demoplayer system, hence why it stopped occurring for you once you had your progress file saved — the intro stopped playing on subsequent runs. See the commit message for details.

Thanks for the report. I'll land the fix in v1.4.x and master branches in a few minutes.

Akaricchi added a commit that referenced this issue Sep 10, 2023
This fixes a nasty interaction between the intro sequence and the
demoplayer introduced in 3ff6204. The cutscene tries to suspend the
demoplayer for its duration and then resume it later. When the
suspension counter hits 0, the demoplayer event handlers are installed
globally. And then AFTER that happens, the demoplayer is actually
initialized, resetting the suspension counter and installing the event
handlers AGAIN. When the demoplayer is then suspended (e.g. by starting
the actual demo playback), only one set of those handlers is removed,
which has the effect of the demoplayer remaining active even in-game.
Eventually, it tries to play a demo while a game is already running,
at which point all hell breaks loose.

Fix this by making suspend and resume no-ops until the demoplayer has
been properly initialized.

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

No branches or pull requests

2 participants