Summary
The published 3.5.3+switch+vita export template aborts during shutdown on every clean exit. It is cosmetic, since the app has already exited and nothing is lost, but Horizon shows "The software was closed because an error occurred" every time, which looks broken.
It does not reproduce on a build made from the same source with a current toolchain. The fix looks like republishing the templates rather than a code change, which is why this is an issue and not a pull request.
Reproduction
Any project that calls get_tree().quit(). Minimal case: an empty scene, a label, and get_tree().quit() after five seconds. It happens on every exit, across reboots, and across two different host titles used for title takeover.
Evidence
Three builds, tested for a clean exit on a v1 Switch with Atmosphère:
| build |
source |
newlib |
quits cleanly |
published 3.5.3.stable template |
f4cf737d9c7 |
4.3.0.20230120 |
no, aborts every time |
| built locally |
f4cf737d9c7 (same source) |
4.6.0.20260123 |
yes |
| built locally |
5eccbcefabb |
4.6.0.20260123 |
yes |
The middle row is the point. The same source the published template was built from quits cleanly once compiled with a current toolchain. That rules out the thirteen commits between f4cf737d9c7 and 5eccbcefabb, none of which touch shutdown.
The published template names its own commit in its startup banner (v3.5.3.stable.custom_build.f4cf737d9), which is what made that comparison possible.
Where it faults
Atmosphère crash report, the same across five captures:
Process Name: hbloader
Type: Data Abort
PC: godot.switch.opt + 0x1f1ca74 -> ldr x19, [x0]
Stack: +0x19e11ec / +0x19e0324 / +0x19e12d4
The faulting loop walks parallel arrays of object pointers and destructor pointers, calling each and clearing the slot, and the deepest frame is process entry, so it runs after main returns. That is newlib's __call_exitprocs walking __cxa_atexit registrations. It is not the ELF's .fini_array, which has 46 entries rather than the 27 the disassembly showed.
So the crash is in the C library's own exit handler walker, and that library moved three years between the two builds.
Checking this yourself
Toolchain of any NRO, without building anything:
strings -a switch_release.nro | grep -o 'newlib-[0-9.]*' | sort -u
Rebuilding the published template's exact source:
git clone --branch main/3.5 https://github.com/Homebrodot/Godot.git
cd Godot && git checkout f4cf737d9c7
docker run --rm -v "$PWD":/godot -w /godot devkitpro/devkita64 bash -c '
apt-get update -qq && apt-get install -y -qq scons
scons -j8 platform=switch target=release tools=no'
Two things that were not obvious: scons is not in the image, and there is no pip either, so it has to come from apt. The image is multi-arch, so this runs natively on an Apple Silicon Mac too.
A rebuilt template
If it is useful in the meantime, there is a rebuilt template here: https://github.com/ferrolho/Godot/releases/tag/switch-template-3.5.3-rc1
It is a personal build, not an official one, and it also carries #25 and #26, so it is not a clean control. The unstripped ELF is attached alongside it so that crash reports from it can be turned into function names.
Caveat
This shows the abort no longer happens, not that the underlying defect is gone. A use-after-free in an exit handler can stop showing up purely because allocation layout shifted, and newlib 4.3 to 4.6 changes plenty of layout. Finding the actual faulting entry would need a live reproduction, and no current-toolchain build reproduces it. Worth knowing before treating it as closed.
Related
OS.get_datetime() returns all zeros on the published template. That one is fixed in source, by 3618ad0db1f [Switch] Implement OS time getters, which postdates the template. Same underlying situation: the published artefact is behind the branch. Two user-visible bugs, one action.
Suggested fix
Republish the export templates from a current toolchain.
Summary
The published
3.5.3+switch+vitaexport template aborts during shutdown on every clean exit. It is cosmetic, since the app has already exited and nothing is lost, but Horizon shows "The software was closed because an error occurred" every time, which looks broken.It does not reproduce on a build made from the same source with a current toolchain. The fix looks like republishing the templates rather than a code change, which is why this is an issue and not a pull request.
Reproduction
Any project that calls
get_tree().quit(). Minimal case: an empty scene, a label, andget_tree().quit()after five seconds. It happens on every exit, across reboots, and across two different host titles used for title takeover.Evidence
Three builds, tested for a clean exit on a v1 Switch with Atmosphère:
3.5.3.stabletemplatef4cf737d9c7f4cf737d9c7(same source)5eccbcefabbThe middle row is the point. The same source the published template was built from quits cleanly once compiled with a current toolchain. That rules out the thirteen commits between
f4cf737d9c7and5eccbcefabb, none of which touch shutdown.The published template names its own commit in its startup banner (
v3.5.3.stable.custom_build.f4cf737d9), which is what made that comparison possible.Where it faults
Atmosphère crash report, the same across five captures:
The faulting loop walks parallel arrays of object pointers and destructor pointers, calling each and clearing the slot, and the deepest frame is process entry, so it runs after
mainreturns. That is newlib's__call_exitprocswalking__cxa_atexitregistrations. It is not the ELF's.fini_array, which has 46 entries rather than the 27 the disassembly showed.So the crash is in the C library's own exit handler walker, and that library moved three years between the two builds.
Checking this yourself
Toolchain of any NRO, without building anything:
Rebuilding the published template's exact source:
Two things that were not obvious:
sconsis not in the image, and there is nopipeither, so it has to come fromapt. The image is multi-arch, so this runs natively on an Apple Silicon Mac too.A rebuilt template
If it is useful in the meantime, there is a rebuilt template here: https://github.com/ferrolho/Godot/releases/tag/switch-template-3.5.3-rc1
It is a personal build, not an official one, and it also carries #25 and #26, so it is not a clean control. The unstripped ELF is attached alongside it so that crash reports from it can be turned into function names.
Caveat
This shows the abort no longer happens, not that the underlying defect is gone. A use-after-free in an exit handler can stop showing up purely because allocation layout shifted, and newlib 4.3 to 4.6 changes plenty of layout. Finding the actual faulting entry would need a live reproduction, and no current-toolchain build reproduces it. Worth knowing before treating it as closed.
Related
OS.get_datetime()returns all zeros on the published template. That one is fixed in source, by3618ad0db1f [Switch] Implement OS time getters, which postdates the template. Same underlying situation: the published artefact is behind the branch. Two user-visible bugs, one action.Suggested fix
Republish the export templates from a current toolchain.