Repository navigation
fix(libSceSystemService): give LoadExec's next executable the host standard error - #5699
Conversation
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
A title where this shows: VLC for PS5 (PPSA85300). Its
Not checked on Windows. AI-assisted: yes |
adriadam10
left a comment
There was a problem hiding this comment.
Checked on current main merged with this head. Two problems:
core/libs/prx/libSceSystemService/Export.cpp:186: the descriptor 2 restore only runs inStartHostExecutable(execv). A call whose argument list has a first entry (RetroArch's{"", NULL}, any list) goes throughReplaceinLoadExec.cpp:160(fexecve) before that, so the next image still inherits the title's redirect. The restore needs to happen on that path too, after the shutdown andfflush.core/libs/tests/GuestSystemServiceLoadExecStandardError.cpp:25,43: the test passes{"--after-load-exec"}, which is now the whole guestargv(argc == 1, no program name in front). The re-executed image never seesargc == 2, forks again and loops, printing the host CPU line over and over until killed. Check the new image withargc == 1andargv[0]equal to the marker, and keep a second case with a null list for theexecvpath, so both paths are pinned.
Once both paths restore it, the debt line in docs/dev/debt/libSceSystemService.md should also say that fexecve closes every descriptor above 2 while descriptor 2 gets the kept host one.
|
A second title, on the other LoadExec path: RetroArch (PPSA99169). Its picker passes an argument list ( Linux, RTX 4070 Ti, NVIDIA 595.99, GCC 13.3, Release, a pad sequence that picks the RetroArch frontend, 60 s runs:
if (const int host = HostStandardError_nid_no_patch(); host >= 0 && ::dup2(host, 2) != 2) {
throw std::system_error(errno, std::generic_category(), "LoadExec: giving the host standard error back to descriptor 2");
}I didn't look at the Windows AI-assisted: yes |
|
Cross-validation on Windows 11 Pro 26220, NVIDIA RTX 4070 (596.21), MinGW GCC 15.2, PR head 7a4688c merged on main 8dc92ae with #6237 a03e023: This is a Windows no-regression check only. The PPSA85300 (VLC 0.3.1). Relinked with
On Windows the relaunched image's own output already reaches the console without this PR. The console log of each run has the start-up block twice ( The test suite on main + #6237 + this PR ( From reading current Side observation, not investigated: in all four runs the relaunched VLC appended to the same No Windows concerns. Written with Claude Code assistance. |
…andard error A guest dup2 onto descriptor 2 keeps a close-on-exec duplicate of the host's standard error (boykopovar#4792), so the runtime's own output stays on the console while the title's stderr goes where the title pointed it. The duplicate did not survive LoadExec's execv, and the next executable started with descriptor 2 still on the title's redirect: its runtime output, terminate report included, went there. RetroArch (PPSA99169) points stderr at app0/trace.txt and then starts its picker. The picker's [gpu] and sceKernelDebugOutText lines landed in trace.txt, and its abort on an unconverted es-de.bin showed up nowhere; the message was found only in the core dump. Before execv, the kept descriptor now goes back onto descriptor 2.
…d title
A forked child with stderr on a pipe moves the guest's descriptor 2 to a
second pipe with dup2, then starts itself again through
sceSystemServiceLoadExec("/app0/eboot.bin"). What the new image writes
to stderr must reach the first pipe and nothing the second. It fails
with the previous execv, where the text goes to the guest's pipe.
…adExec's fexecve A LoadExec with an argument list replaces the process through Replace (fexecve), which runs before StartHostExecutable, so the next image still wrote to the title's redirect. Descriptor 2 now gets the kept host descriptor there too, after the shutdown and the flush and before close_range closes it.
…aths The re-executed image is told apart by an environment variable. With an argument list (fexecve) it sees argc 1 and the marker as argv[0]; with a null list (execv) it sees only its path.
7a4688c to
6473318
Compare
|
@adriadam10 thanks, both points were right. Rebased onto
Linux, GCC 16.2.1, Release:
@milescoviello the restore is now in Could you take another look and merge if it's fine now? |
|
RetroArch (PPSA99169) on the new head: this fixes it. Linux (Ubuntu 24.04, GCC 13.3, Release, RTX 4070 Ti, NVIDIA 595.99), the same pad sequence that picks the RetroArch frontend, 60 s runs:
With the PR, the third image (the frontend, started through Not checked: Windows, since AI-assisted: yes |
|
Rerun on Windows 11 Pro 26220 (RTX 4070 596.21, MinGW GCC 15.2): head
Not checked: the Linux paths, and the PPSA85300 / PPSA99169 title runs on this head. Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
|
@screamm thanks, that answers it: on Windows both launch paths already pass the host standard error on, so the AI-assisted: yes (Claude Code) |
|
@adriadam10 a reminder on this one when you have time. Head
The PR description now covers both paths. I can't request a review myself (no write access), so this comment is the request. Could you take another look? |
adriadam10
left a comment
There was a problem hiding this comment.
Re-checked on current main merged with this head. Both points are fixed: Replace restores descriptor 2 before the close_range calls (LoadExec.cpp:157), and the test pins both the fexecve path (argc == 1, argv[0] is the marker) and the execv path. The new test passes, fails without the source changes, and the rest of the libSceSystemService ctest scope is green. The debt entry matches the code; merging.
What
#4792 keeps the host's standard error on Linux when a guest redirects descriptor 2: the first redirect keeps a duplicate, the host
stderrand the terminate report write to it, and the guest's stream follows its redirect. The duplicate does not survivesceSystemServiceLoadExec: it is close-on-exec forexecv, andReplacecloses every descriptor above 2 beforefexecve. The next executable starts with descriptor 2 still on the title's redirect and keeps that as its "host" standard error, so its runtime output, the terminate report included, goes into the title's file, or into a pipe whose reader is gone (SIGPIPE).LoadExec.cppReplace(argument list,fexecve): descriptor 2 gets the kept host descriptor after the guest shutdown andfflush, before theclose_rangecalls.Export.cppStartHostExecutable(null list,execv): the same restore right beforeexecv.guest_system_load_exec_standard_errortest (Linux): a forked child with stderr on a pipe moves the guest's descriptor 2 to a second pipe withdup2, then starts itself again throughsceSystemServiceLoadExec("/app0/eboot.bin", ...), once with{"--after-load-exec", NULL}(fexecve, the new image must seeargc == 1andargv[0]equal to the marker) and once with a null list (execv,argc == 1). The new image is recognised by an environment variable. What it writes to stderr must reach the first pipe and nothing the second.Titles.
fexecve): onmainthe third image dies with SIGPIPE 8 s in when AnyPS5 writes[memory] configured flexible memoryto the kept copy of the picker's pipe. With this PR it runs to the limit (@milescoviello, 3 of 3).execv): together with fix(libSceSystemService): park guest threads during LoadExec's shutdown as exit does #6237, the second image's output reaches the log again (@milescoviello, 2 of 2).Windows is not changed: both launch paths there use
CreateProcessWand already pass the host standard error handle on (#4640; checked by @screamm).Tested
Linux (Bazzite 44, GCC 16.2.1, Ninja, Release,
-DBUILD_TESTING=ON), head6473318a6onmain92e50418f:guest_system_load_exec_standard_errorpasses 3 of 3. With onlyLoadExec.cppfrommainit aborts, and with onlyExport.cppfrommainit aborts too, so each path is pinned.loadexec_arguments,guest_system_relaunch,guest_nested_exitand theguest_system_exitset pass.tools/check_conventions.py --base upstream/mainpasses.ctest836 of 836 pass; no Windows code changes.Checklist
main; no other open PR implements the same functions.mdfiles or images added to the repository