retroarch: fix false IS_CORE_LOADED positives in static dummy builds

On static platforms, RARCH_PATH_CORE is populated at startup from the
salamander config (config_load_file_salamander), which records the
last-used core - including in HAVE_STATIC_DUMMY frontend builds that
link no libretro core at all. The corrective argv[0] overwrite in the
frontend's process_args runs only when the process receives arguments,
so it is skipped when the frontend is launched without argv (e.g. via
title override on Switch, as opposed to a forwarder).

RARCH_CTL_IS_CORE_LOADED then compares the requested core's basename
against this phantom path and reports the core as loaded. Both static
launch shortcuts in task_content.c trust that answer and load content
in-process into the dummy core instead of forking the real core NRO.
The history push records the entry with the phantom core_path, and the
runtime log attributes play time to it; the subsequent real launch of
the same content writes a second entry with the correct core, since
playlist_push keys entries on (path, core_path). Net user-visible
result: duplicate history entries with the wrong core assigned and
misattributed play time (reported against the Switch nightly in
libretro/RetroArch#19220).

A static dummy build can never have a real core loaded, so report
false unconditionally there. Core NRO builds are unaffected; their
already-loaded shortcut behaves as before.

Residual (out of scope): a core NRO cold-started without argv while
the salamander config names a different core can still misidentify
itself, since non-dummy builds have no reliable self-identity to
compare against without argv[0].
This commit is contained in:
libretroadmin authored and libretroadmin committed 2026-07-19 20:58:52 +02:00
1 parent 2c49a50252
commit e2790091c1
1 file changed
+17
+17
View File
@@ -8739,6 +8739,22 @@ bool retroarch_ctl(enum rarch_ctl_state state, void *data)
case RARCH_CTL_IS_DUMMY_CORE:
return runloop_st->current_core_type == CORE_TYPE_DUMMY;
case RARCH_CTL_IS_CORE_LOADED:
#ifdef HAVE_STATIC_DUMMY
/* A static dummy build links no libretro core, yet
* RARCH_PATH_CORE may still name one: on static
* platforms it is populated from the salamander
* config at startup, and the argv[0] overwrite in
* the frontend's process_args is skipped when the
* process is launched without arguments (e.g. via
* title override on Switch). Comparing names against
* that phantom path yields false positives, causing
* content to be loaded in-process into the dummy
* core instead of forking the real core, and history
* entries/runtime logs to be recorded against the
* wrong core. No core can ever be loaded in this
* process, so always report false. */
return false;
#else
{
const char *core_path = (const char*)data;
const char *core_file = path_basename_nocompression(core_path);
@@ -8755,6 +8771,7 @@ bool retroarch_ctl(enum rarch_ctl_state state, void *data)
}
}
return false;
#endif
#if defined(HAVE_RUNAHEAD) && (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
case RARCH_CTL_IS_SECOND_CORE_AVAILABLE:
return