melonDS-emu / melonDS

DS emulator, sorta
https://melonds.kuribo64.net
GNU General Public License v3.0
3.15k stars 516 forks source link

Linux: crash on startup in DSi mode #1924

Open thesourcehim opened 8 months ago

thesourcehim commented 8 months ago

Can't start melonDS in linux in DSi mode:

[Thread debugging using libthread_db enabled]                                                                                                                                                                            
Using host libthread_db library "/lib64/libthread_db.so.1".                                                                                                                                          
melonDS 0.9.5                                                                                                                                                                                                            
https://melonds.kuribo64.net/
IPC: instance ID 3
[New Thread 0x7fffdfc106c0 (LWP 34226)]                                                                                                                                                                                  
[New Thread 0x7fffdd7956c0 (LWP 34228)]                                                                                                                                                                                  
[New Thread 0x7fffdcf946c0 (LWP 34229)]
[New Thread 0x7fffce1ff6c0 (LWP 34231)]                                                                                                                                                                                  
[New Thread 0x7fffcd9fe6c0 (LWP 34232)]
[New Thread 0x7fffcd1fd6c0 (LWP 34233)]
[Thread 0x7fffcd1fd6c0 (LWP 34233) exited]
[Thread 0x7fffce1ff6c0 (LWP 34231) exited]
[Thread 0x7fffcd9fe6c0 (LWP 34232) exited]
[New Thread 0x7fffcd9fe6c0 (LWP 34235)]
[New Thread 0x7fffce1ff6c0 (LWP 34236)]
[New Thread 0x7fffcd1fd6c0 (LWP 34237)]
[Thread 0x7fffcd1fd6c0 (LWP 34237) exited]
[Thread 0x7fffcd9fe6c0 (LWP 34235) exited]
[Thread 0x7fffce1ff6c0 (LWP 34236) exited]
[New Thread 0x7fffcd9fe6c0 (LWP 34239)]                                                                                                                                                                                  
[New Thread 0x7fffce1ff6c0 (LWP 34240)]
[New Thread 0x7fffcd1fd6c0 (LWP 34241)]
[New Thread 0x7fffc61ff6c0 (LWP 34242)]
[New Thread 0x7fffc59fe6c0 (LWP 34243)]
[New Thread 0x7fffc51fd6c0 (LWP 34244)]
[New Thread 0x7fffc49fc6c0 (LWP 34245)]
[New Thread 0x7fffaffff6c0 (LWP 34246)]
[New Thread 0x7fffc65ca6c0 (LWP 34248)]                                                                                                                                                                                  
Opened "/home/thesource/.config/melonDS/melonDS.ini" with FileMode 0x11 (effective mode "r")                                                                                                                             
Opened "/home/thesource/.config/melonDS/melonDS.4.ini" with FileMode 0x11 (effective mode "r")
warning: `/home/thesource/.cache/debuginfod_client/742112c0f740762bb4e2be1f09e8926e504838f8/debuginfo': can't read symbols:                                                                 
[New Thread 0x7fffacbff6c0 (LWP 34249)]                                                                                                                                                                                  
[New Thread 0x7fff9a3de6c0 (LWP 34253)]
[New Thread 0x7fff98bbc6c0 (LWP 34254)]
[Thread 0x7fff98bbc6c0 (LWP 34254) exited]
[Thread 0x7fff9a3de6c0 (LWP 34253) exited]
[New Thread 0x7fff9a3de6c0 (LWP 34255)]                                                                                                                                                                                  
[New Thread 0x7fff98bbc6c0 (LWP 34256)]
Opened "/home/thesource/.config/melonDS/melonDS.4.ini" with FileMode 0x12 (effective mode "w")                                                                                                                           
EGL Version: 1.5                                                                                                                                                                                                         
EGL Extensions: EGL_ANDROID_native_fence_sync EGL_EXT_buffer_age EGL_EXT_client_sync EGL_EXT_create_context_robustness EGL_EXT_image_dma_buf_import EGL_EXT_image_dma_buf_import_modifiers EGL_MESA_image_dma_buf_export EGL_EXT_output_base EGL_EXT_output_drm EGL_EXT_protected_content EGL_EXT_stream_consumer_egloutput EGL_EXT_stream_acquire_mode EGL_EXT_sync_reuse EGL_IMG_context_priority EGL_KHR_config_attribs EGL_KHR_create_context_no_error EGL_KHR_context_flush_control EGL_KHR_create_context EGL_KHR_fence_sync EGL_KHR_get_all_proc_addresses EGL_KHR_partial_update EGL_KHR_swap_buffers_with_damage EGL_KHR_no_config_context EGL_KHR_gl_colorspace EGL_KHR_gl_renderbuffer_image EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_3D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_image EGL_KHR_image_base EGL_KHR_reusable_sync EGL_KHR_stream EGL_KHR_stream_attrib EGL_KHR_stream_consumer_gltexture EGL_KHR_stream_cross_process_fd EGL_KHR_stream_fifo EGL_KHR_stream_producer_eglsurface EGL_KHR_surfaceless_context EGL_KHR_wait_sync EGL_NV_nvrm_fence_sync EGL_NV_quadruple_buffer EGL_NV_stream_consumer_eglimage EGL_NV_stream_cross_display EGL_NV_stream_cross_object EGL_NV_stream_cross_process EGL_NV_stream_cross_system EGL_NV_stream_dma EGL_NV_stream_flush EGL_NV_stream_metadata EGL_NV_stream_remote EGL_NV_stream_reset EGL_NV_stream_socket EGL_NV_stream_socket_inet EGL_NV_stream_socket_unix EGL_NV_stream_sync EGL_NV_stream_fifo_next EGL_NV_stream_fifo_synchronous EGL_NV_stream_consumer_gltexture_yuv EGL_NV_stream_attrib EGL_NV_stream_origin EGL_NV_system_time EGL_NV_output_drm_flip_event EGL_NV_triple_buffer EGL_NV_robustness_video_memory_purge EGL_EXT_present_opaque EGL_WL_bind_wayland_display EGL_WL_wayland_eglstream
Trying version 4.3 (Core)
Got version 4.3 (Core)
[New Thread 0x7fff8d3ff6c0 (LWP 34257)]
[New Thread 0x7fff8cbfe6c0 (LWP 34258)]
[New Thread 0x7fff83fff6c0 (LWP 34259)]
Created a OpenGL context
GL_VENDOR: NVIDIA Corporation
GL_RENDERER: NVIDIA GeForce RTX 3060 Laptop GPU/PCIe/SSE2
GL_VERSION: 4.3.0 NVIDIA 545.29.06
GL_SHADING_LANGUAGE_VERSION: 4.30 NVIDIA via Cg compiler
[New Thread 0x7fff837fe6c0 (LWP 34260)]

Thread 28 "EmuThread" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fff837fe6c0 (LWP 34260)]
std::__uniq_ptr_impl<melonDS::Renderer3D, std::default_delete<melonDS::Renderer3D> >::operator= (this=this@entry=0x5674148, __u=...) at /usr/include/c++/13/bits/unique_ptr.h:191
191             reset(__u.release());
Missing separate debuginfos, use: dnf debuginfo-install fdk-aac-2.0.2-6.fc39.x86_64 gstreamer1-1.22.8-1.fc39.x86_64 gstreamer1-plugins-bad-free-1.22.8-1.fc39.x86_64 gstreamer1-plugins-bad-free-libs-1.22.8-1.fc39.x86_64 gstreamer1-plugins-base-1.22.8-1.fc39.x86_64 gstreamer1-plugins-good-1.22.8-1.fc39.x86_64 xorg-x11-drv-nvidia-cuda-libs-545.29.06-1.fc39.x86_64 xorg-x11-drv-nvidia-libs-545.29.06-1.fc39.x86_64
(gdb) bt full
#0  std::__uniq_ptr_impl<melonDS::Renderer3D, std::default_delete<melonDS::Renderer3D> >::operator= (this=this@entry=0x5674148, __u=...) at /usr/include/c++/13/bits/unique_ptr.h:191
#1  0x00000000004ac58f in std::__uniq_ptr_data<melonDS::Renderer3D, std::default_delete<melonDS::Renderer3D>, true, true>::operator= (this=0x5674148) at /usr/include/c++/13/bits/unique_ptr.h:243
#2  std::unique_ptr<melonDS::Renderer3D, std::default_delete<melonDS::Renderer3D> >::operator= (this=0x5674148) at /usr/include/c++/13/bits/unique_ptr.h:414
#3  melonDS::GPU3D::SetCurrentRenderer (renderer=..., this=0x5674140) at /mnt/d/projects/git/melonDS/src/GPU3D.h:120
#4  melonDS::GPU::SetRenderer3D (this=0x55ce7a8, renderer=...) at /mnt/d/projects/git/melonDS/src/GPU.cpp:299
#5  0x00000000004335dd in EmuThread::run (this=0x7fffd4001d00) at /mnt/d/projects/git/melonDS/src/frontend/qt_sdl/main.cpp:553
        glrenderer = std::unique_ptr<melonDS::GLRenderer> = {get() = 0x0}
        mainScreenPos = {0, 0, 0}
        file = <optimized out>
        nframes = <optimized out>
        perfCountsSec = <optimized out>
        lastTime = <optimized out>
        frameLimitError = <optimized out>
        lastMeasureTime = <optimized out>
        winUpdateCount = <optimized out>
        winUpdateFreq = <optimized out>
        dsiVolumeLevel = <optimized out>
        melontitle = "p\333\177\203\377\177\000\000^\205N\366\377\177\000\000\020\321\377\377\377\177\000\000 \022\000\\\377\177\000\0000\f\000\\\377\177\000\000`\214X\366\377\177\000\000\020\321\377\377\377\177\000\0000\316\377\377\377\177\000\000\020\333\177\203\377\177\000\000\000)+\\\223\231\335\373\020\333\177\203\377\177\000\000p\v\000\\\377\177\000\000p\v\000\\"
#6  0x00007ffff62f5bbd in operator() (__closure=<optimized out>) at thread/qthread_unix.cpp:350
        thr = 0x7fffd4001d00
        data = 0x44f2210
        arg = <optimized out>
        arg = <optimized out>
        thr = <optimized out>
        data = <optimized out>
        locker = {val = <optimized out>}
#7  (anonymous namespace)::terminate_on_exception<QThreadPrivate::start(void*)::<lambda()> > (t=<optimized out>) at thread/qthread_unix.cpp:287
#8  QThreadPrivate::start (arg=0x7fffd4001d00) at thread/qthread_unix.cpp:310
        __clframe = {__cancel_routine = <optimized out>, __cancel_arg = 0x7fffd4001d00, __do_it = 1, __cancel_type = <optimized out>}
#9  0x00007ffff5cac897 in start_thread (arg=<optimized out>) at pthread_create.c:444
        ret = <optimized out>
        pd = <optimized out>
        out = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737317094816, 7425124597801438920, 140735399585472, -248, 1, 140737488342576, 7425124597814021832, 7425232994529857224}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
        not_first_call = <optimized out>
#10 0x00007ffff5d336fc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

MelonDS version: git4b4239d

System info:

Operating System: Fedora Linux 39
KDE Plasma Version: 5.27.10
KDE Frameworks Version: 5.111.0
Qt Version: 5.15.11
Kernel Version: 6.6.7-200.fc39.x86_64 (64-bit)
Graphics Platform: Wayland
Processors: 16 × Intel® Core™ i7-10870H CPU @ 2.20GHz
Memory: 15.4 ГиБ of RAM
Graphics Processor: Mesa Intel® UHD Graphics
Manufacturer: Dell Inc.
Product Name: Dell G15 5510

Config files: melonDS.ini.txt melonDS.4.ini.txt

RSDuck commented 8 months ago

do you use a release or did you build from newer source?

thesourcehim commented 8 months ago

Like I wrote in initial report: melonDS version: git4b4239d (it's currently the latest commit in git). Edit: not latest now.

thesourcehim commented 8 months ago

Release 0.9.5 does not crash, so I ran bisect:

bb42c8b6392e4e99634dc52137d2974781192482 is the first bad commit
commit bb42c8b6392e4e99634dc52137d2974781192482
Author: Jesse Talavera <jesse@jesse.tg>
Date:   Mon Dec 4 11:57:22 2023 -0500

    Refactor how save data (including SD cards) is initialized (#1898)

    * Remove `FATStorage::Open` and `FATStorage::Close`

    - That's what the constructor and destructor are for, respectively

    * Add `FATStorage::IsReadOnly`

    * Slight cleanup of `FATStorage`

    - Make it move-constructible and move-assignable
    - Represent the absence of a sync directory with `std::optional`, not an empty string
    - Add `FATStorageArgs` for later use

    * Refactor `CartHomebrew` to accept an optional `FATStorageArgs`

    - `CartHomebrew` uses it to load an SD card image
    - Not passing a `FATStorage` directly because we won't know if we need to load the card until we parse the ROM
    - Store the `FATStorage` inside a `std::optional` instead of a pointer
    - `CartHomebrew::Reset` no longer reloads the SD card; the frontend needs to set it with the `SetSDCard` method

    * Close `NANDImage::CurFile` when move-assigning

    - Whoops

    * Add `Args.h`

    - To construct a `NDS` or `DSi` with arguments
    - Mostly intended for system files

    * Fix incorrect `final` placement

    * Refactor how `DSi`'s NAND and SD card are set

    - Provide them via a `DSiArgs` argument in the constructor
    - Give `DSi_MMCStorage` ownership of the `NANDImage` or `FATStorage` as needed, and expose getters/setters
    - Replace `DSi_SDHost::Ports` with a `array<unique_ptr, 2>` to reduce the risk of leaks
    - Store `DSi_MMCStorage`'s disk images in a `std::variant`
    - The SD card and NAND image are no longer reset in `Reset()`; the frontend will need to do that itself

    * Add getters/setters on `DSi` itself for its storage media

    * Remove newly-unused `Platform::ConfigEntry`s

    * Use `DSi::SetNAND` in the frontend

    * Add `EmuThread::NeedToRecreateConsole`

    * Document `NDSArgs` and give its fields default values

    * Refactor how system files are loaded upon construction

    - Pass `NDSArgs&&` into `NDS`'s constructor
    - Use `std::array` for the emulator's BIOS images and the built-in FreeBIOS, to simplify copying and comparison
    - Initialize the BIOS, firmware, and SD cards from `NDSArgs` or `DSiArgs`
    - Add a new default constructor for `NDS` (not `DSi`) that initializes the DS with default system files
    - Embed `FirmwareMem::Firmware` directly instead of in a `unique_ptr`
    - `SPIHost` now takes a `Firmware&&` that it forwards to `FirmwareMem`
    - Add `Firmware` getters/setters plus `const` variants for `NDS`, `Firmware`, and `FirmwareMem`
    - Simplify installation of firmware

    * Initialize the DSi BIOS in the constructor

    - Change `DSi::ARM9iBIOS` and `ARM7iBIOS` to `std::array`

    * Update the frontend to reflect the core's changes

    * Remove `DSi_SDHost::CloseHandles`

    * Pass `nullopt` instead of the empty string when folder sync is off

    * Deduplicate ROM extraction logic

    - `LoadGBAROM` and `LoadROM` now delegate to `LoadROMData`
    - Also use `unique_ptr` instead of `new[]`

    * Oops, missed some `get()`'s

    * Move `NDS::IsLoadedARM9BIOSBuiltIn` to the header

    - So it's likelier to be inlined
    - Same for the ARM7 version

    * Remove `NDS::SetConsoleType`

    * Add `NDS::SetFirmware`

    * Move `GBACart::SetupSave` to be `protected`

    - It was only ever used inside the class

    * Rename `GBACart::LoadSave` to `SetSaveMemory`

    - Same for the cart slot

    * Declare `GBACartSlot` as a friend of `GBACart::CartCommon`

    * Revise `GBACartSlot`'s getters and setters

    - Rename `InsertROM` and `LoadROM` to `SetCart`
    - Add a `GetCart` method

    * Clean up getters and setters for NDS and GBA carts

    * Clean up how carts are inserted into the slots

    - Remove setters that operate directly on pointers, to simplify error-handling (use ParseROM instead)
    - Add overloads for all carts that accept a `const u8*` (to copy the ROM data) and a `unique_ptr<u8[]>` (to move the ROM data)
    - Store all ROM and RAM data in `unique_ptr`
    - Default-initialize all fields
    - Simplify constructors and destructors, inheriting where applicable

    * Refactor GBA save data insertion

    - Make `SetupSave` private and non-virtual and move its logic to be in `SetSaveMemory`
    - Add overloads for setting save data in the constructor
    - Update the SRAM completely in `SetSaveMemory`

    * Clean up `NDSCart::CartCommon::SetSaveMemory`

    - Move its declaration next to the other `SaveMemory` methods
    - Move its (empty) implementation to the header

    * Add some comments

    * Add Utils.cpp and Utils.h

    * Rename some functions in Utils for clarity

    * Add `GBACart::ParseROM` and `NDSCart::ParseROM` overloads that accept `unique_ptr<u8[]>`

    - The `u8*` overloads delegate to these new overloads
    - Also move `SetupSave` for both kinds of carts to be private non-virtual methods

    * Finalize the `NDSCart` refactor

    - Add `NDSCartArgs` to pass to `ParseROM`
    - Add SRAM arguments for all retail carts
    - Initialize SRAM inside the constructor
    - Delegate to other constructors where possible

    * Replace `ROMManager::NDSSave` and `GBASave` with `unique_ptr`

    * Make both cart slots return the previously-inserted cart in `EjectCart`

    - Primarily intended for reusing carts when resetting the console

    * Make `NDS::EjectCart` return the old cart

    * Initialize both cart slots with the provided ROM (if any)

    * Make `NDS::EjectGBACart` return the ejected cart

    * Clean up some comments in Args.h

    * Rename `ROMManager::LoadBIOS` to `BootToMenu`

    - Clarifies the intent

    * Add `ROMManager::LoadDLDISDCard`

    * Add a doc comment

    * Refactor how the `NDS` is created or updated

    - Rewrite `CreateConsole` to read from `Config` and load system files, but accept carts as arguments
    - Fail without creating an `NDS` if any required system file doesn't load
    - Add `UpdateConsole`, which delegates to `CreateConsole` if switching modes or starting the app
    - Use `std::variant` to indicate whether a cart should be removed, inserted, or reused
    - Load all system files (plus SD cards) in `UpdateConsole`
    - Eject the cart and reinsert it into the new console if applicable

    * Respect some more `Config` settings in the `Load*` functions

    * Remove `InstallNAND` in favor of `LoadNAND`

    * Fix some potential bugs in `LoadROMData`

    * Oops, forgot to delete the definition of `InstallNAND`

    * Add functions to get `FATStorageArgs`

    - Not the cards themselves, but to get the arguments you _would_ use to load the cards

    * Refactor `ROMManager::LoadROM`

    - Load the ROM and save data before trying to initialize the console

    * Clean up `ROMManager::Reset` and `BootToMenu`

    - Let `EmuThread::UpdateConsole` do the heavy lifting

    * Clean up `LoadGBAROM`

    * Remove some unused functions

    * Set the default DSi BIOS to be broken in `DSiArgs`

    * Respect `Config::DSiFullBIOSBoot` when loading DSi BIOS files

    * Remove some more unused functions

    * Remove redundant `virtual` specifiers

    * Refactor `NDSCart::CartCommon::Type()` to return a member instead of a constant

    - One less virtual dispatch
    - The cart type is read in `NDSCartSlot::DoSavestate`, which is a path downstream (due to rewinding)

    * Remove a hash that I computed for debugging purposes

    * Make `ByteSwap` `constexpr`

    * Remove an unused `#include`

    * Remove unnecessary functions from the NDS carts

    - Mostly overrides that added nothing

    * Default-initialize all NDSCart fields

    * Make `GBACart::Type()` not rely on virtual dispatch

    - `GBACartSlot::DoSavestate` calls it, and savestates can be a hot path downstream

    * Don't forget to reset the base class in `CartGameSolarSensor::Reset()`

    * Remove redundant `virtual` specifiers

    * Default-initialize some fields in `GBACart`

    * Fix ROMs not loading from archives in the frontend

    - Whoops

    * Change how the `Firmware` member is declared

    * Forgot an include in Utils.cpp

    * Rename `FirmwareMem::Firmware` to `FirmwareData` to fix a build error on Linux

    - One of these days I'll convince you people to let me use `camelCaseMemberNames`

    * Add `override` to places in `DSi_MMCStorage` that warrant it

    * Fix firmware saving on the frontend

    - Remove `GetConfigString` and `ConfigEntry::WifiSettingsPath` while I'm at it

    * Add a non-const `GetNAND()`

 src/Args.h                          |  100 ++
 src/CMakeLists.txt                  |    2 +
 src/DSi.cpp                         |   84 +-
 src/DSi.h                           |   22 +-
 src/DSi_AES.cpp                     |    2 +-
 src/DSi_NAND.cpp                    |    3 +
 src/DSi_NWifi.cpp                   |    6 +-
 src/DSi_SD.cpp                      |  202 ++--
 src/DSi_SD.h                        |   79 +-
 src/FATStorage.cpp                  |   90 +-
 src/FATStorage.h                    |   30 +-
 src/FreeBIOS.cpp                    |    4 +-
 src/FreeBIOS.h                      |    7 +-
 src/GBACart.cpp                     | 1796 +++++++++++++++++------------------
 src/GBACart.h                       |  546 ++++++-----
 src/NDS.cpp                         |   84 +-
 src/NDS.h                           |   63 +-
 src/NDSCart.cpp                     |  377 +++-----
 src/NDSCart.h                       |  230 +++--
 src/Platform.h                      |   17 -
 src/SPI.cpp                         |   94 +-
 src/SPI.h                           |   18 +-
 src/Utils.cpp                       |   66 ++
 src/Utils.h                         |   43 +
 src/Wifi.cpp                        |    6 +-
 src/frontend/qt_sdl/ArchiveUtil.cpp |    7 +-
 src/frontend/qt_sdl/ArchiveUtil.h   |    2 +-
 src/frontend/qt_sdl/Platform.cpp    |   28 -
 src/frontend/qt_sdl/ROMManager.cpp  |  647 ++++---------
 src/frontend/qt_sdl/ROMManager.h    |   19 +-
 src/frontend/qt_sdl/main.cpp        |  166 +++-
 src/frontend/qt_sdl/main.h          |   21 +-
 32 files changed, 2505 insertions(+), 2356 deletions(-)
 create mode 100644 src/Args.h
 create mode 100644 src/Utils.cpp
 create mode 100644 src/Utils.h
JesseTG commented 8 months ago

Oops. My bad. But if the crash came from setting the renderer, why is that commit the first bad one?

thesourcehim commented 8 months ago

Can't say, but there's no crash if console mode is set to ds.

thesourcehim commented 8 months ago

The place where app crash seems random, this what I get with commit 740489f

First launch: melonDS_crash1 Crashed in else block, both pointers that are passed are null

Second launch: melonDS_crash2 Crashed in SetCurrentRenderer, renderer is null

Heap corruption?

nadiaholmquist commented 8 months ago

This crash happens because after some refactoring it's possible for constructing an NDS object to fail, but the frontend code is not structured to handle that actually happening.

Make sure "use external BIOS/firmware" is on and your paths for them are all correct, that'll work around it for now.

thesourcehim commented 8 months ago

This crash happens because after some refactoring it's possible for constructing an NDS object to fail, but the frontend code is not structured to handle that actually happening.

Make sure "use external BIOS/firmware" is on and your paths for them are all correct, that'll work around it for now.

Hi, thanks for reply. Can you please clarify, should I enable DS (not DSi) external firmware? melonDS starts successfully in DS mode. It only crashes when DSi mode is enabled. DSi firmware, nand and their paths are correct, 0.9.5 release can boot them successfully.

nadiaholmquist commented 8 months ago

The option to use external firmware under the DS mode tab must be checked and the files there must also be valid for DSi mode to work.

thesourcehim commented 8 months ago

It works! Thank you! It seems that seetings made in DSi firmware boot mode are not saved though, every time I boot firmware everything is reset and I have to calibrate screen, set date etc. But that's different problem.