Repository navigation
fix(libkernel): fail sce path calls with ENAMETOOLONG for a path of 1024 bytes or more - #14874
Conversation
…024 bytes or more
|
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.
|
BunnyFl
left a comment
There was a problem hiding this comment.
Reviewed at 2de34f87bf, merged locally into main 66e1f7f993 (clean merge; GitHub reports it mergeable). Windows 11 Pro 10.0.26300, WinLibs GCC 15.2.0, Release, Ninja.
The bug is as described. CopyGuestPath_nid_no_patch returns guest errnos: 14 for a null or unreadable source, 12 for an allocation failure and 63 for no NUL within 1024 bytes (CopyGuestString_nid_no_patch(source, 1024, ...)). Both SceErrorFromErrno mappers take host errnos:
Stdio.cpppasses 1 to 34 through and maps the hostENAMETOOLONG(38 on MinGW, 36 on Linux), so guest 63 falls through toGUEST_EIO.Open.cpppasses 1 to 34 through and sends anything else toFilesystemErroras a hoststd::generic_categorycode.
SceKernelError(e) is 0x80020000 | e, so 12 and 14 give the same results as before, and 63 now gives SCE_KERNEL_ERROR_ENAMETOOLONG, as sceKernelOpen already does.
What I ran
ctest -R '^guest_path_name_length$' --repeat until-fail:3: passes, 3 of 3.- Negative control:
main'sOpen.cppandStdio.cppwith this PR's test: fails withthe sce path calls must fail a path of exactly 1024 bytes with SCE_KERNEL_ERROR_ENAMETOOLONG: sceKernelStat returned 0x80020005. python tools/check_conventions.py --base upstream/main: passes.
Looks good.
AI-assisted: yes (Claude Code)
What
On e0caf13 (line numbers below refer to it) a guest path with no NUL in its first 1024 bytes makes
sceKernelStat,sceKernelUnlink,sceKernelMkdir,sceKernelRmdir,sceKernelChmod,sceKernelTruncateandsceKernelUtimesreturnSCE_KERNEL_ERROR_EIO(0x80020005) on Windows (run) and, by the same mapping, on Linux (not run).CopyGuestPath_nid_no_patchreturns the guest errno 63 (ENAMETOOLONG) for such a path (core/libs/prx/libc/src/General.cpp:570and574), but these seven callers pass it toSceErrorFromErrno(core/libs/prx/libkernel/File/src/Open.cpp:461and482;core/libs/prx/libkernel/File/src/Stdio.cpp:1349,1646,1690,1730and1768), which maps host errnos: values 1 to 34 pass through, and 63 is not host ENAMETOOLONG on MinGW (38) or Linux (36), soStdio.cpp:509andFilesystemErrorbehindOpen.cpp:185turn it into EIO. Only on macOS, where host ENAMETOOLONG is 63, does the mapping give the right code (derived from the code, not run). FreeBSD'snameicopies the path withcopyinstr(..., MAXPATHLEN, ...)and fails with ENAMETOOLONG when no NUL fits in 1024 bytes (sys/kern/vfs_lookup.c), and the repository already returnsSceKernelError(error)for the same copy failure insceKernelOpen(Open.cpp:300) andsceKernelCheckReachability(Stdio.cpp:1162); the POSIX wrappers already set errno 63 for these paths, ascore/libs/tests/GuestPathNameLength.cppchecks forstat. The seven call sites came in with 2c5fcf6, which usedSceKernelErroronly insceKernelOpenandsceKernelCheckReachability.CopyGuestPath_nid_no_patchfails, the seven calls returnSceKernelError(error), assceKernelOpendoes, so a path of 1024 bytes or more without a NUL givesSCE_KERNEL_ERROR_ENAMETOOLONG(0x8002003F). EFAULT (14) and ENOMEM (12) from the copy keep their values, because both mappers already passed 1 to 34 through. BothSceErrorFromErrnomappers stay unchanged: they map host errnos, and host 63 is ENOSR on Linux. Valid paths never reach this branch.guest_path_name_lengthchecks that all seven calls return 0x8002003F for the existing path of exactly 1024 bytes and for the path of 1100 bytes.pr_overlap.py --branchfinds no shared lines with the open pull requests it can compare and cannot compare 16 that also changeOpen.cpporStdio.cppbut do not merge withmain(feat(aot): consolidate native ARM64 compiler, runtime and consumers #5021, feat(libkernel): support SEEK_DATA and SEEK_HOLE in lseek #6936, feat(libkernel): report open, read and close notes on watched files #7121, feat(libc): support archive-backed stdio reads #7447, feat(libkernel): implement the named ksem semaphores #9293, feat(libkernel_sys): implement POSIX message queues #9297, feat(libkernel_sys): implement kmq_notify registration #9302, fix(libkernel): report lookup errors when creating through a trailing slash #10319, feat(libc): implement fcloseall with tracked stream lifetimes #11831, fix(libkernel): preserve DOS device names and trailing dots or spaces on Windows #12560, feat(libkernel): cancel blocked POSIX reads with owned operations #12682, fix(libkernel): preserve blocking sockets over nonblocking native transport #12688, feat(libkernel): cancel blocked POSIX writes with partial progress #12700, fix(libkernel): unlink a dangling Windows directory link #12820, test(libkernel): unlink a dangling Windows junction #12835 and feat(libkernel): support deferred cancellation in POSIX accept #12965). Checked by hand: a trial merge of this branch with each of them conflicts in exactly the files thatmainwith it already conflicts in, so this change adds no conflict.Tested
Windows 11, WinLibs GCC 15.2.0, full configuration (Ninja, Release,
BUILD_TESTING=ON; built targets:guest_path_name_length_testswithlibkernel, and the related test targets below), on 2de34f8 (based on e0caf13;mainat 5bae1a4 changed none of these files and merges cleanly):Open.cppandStdio.cppof e0caf13,cmake --build build --target guest_path_name_length_testsandbuild/tests/guest_path_name_length_tests.exeabort withthe sce path calls must fail a path of exactly 1024 bytes with SCE_KERNEL_ERROR_ENAMETOOLONG: sceKernelStat returned 0x80020005. The helper stops at the first wrong result; the other six calls go through the sameSceErrorFromErrnomapping.ctest --test-dir build -R '^guest_path_name_length$' --output-on-failurepassed (0.04 s), and the executable run directly exits 0.ctest --test-dir build -R '^(guest_path_name_length|guest_filesystem|guest_filesystem_error|guest_file_timestamps|guest_truncate|guest_truncate_extend|guest_rename_dot|guest_directory)$' --output-on-failure: 8 of 8 passed.python tools/check_conventions.py --base e0caf13600 --head HEADwith this title and description passed.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)