Files
AnyPS5/docs/dev/debt/libSceLibcInternal.md
T
xXPBSXxandClaude Sonnet 5.5 7535eb45fc fix(libSceLibcInternal): start fdopendir at the descriptor position and set FD_CLOEXEC
fdopendir listed the directory from its first entry whatever position the
descriptor had, and left FD_CLOEXEC unchanged. FreeBSD 11.4 fdopendir sets
FD_CLOEXEC on the descriptor and preserves the initial seek position (lib/libc/gen/opendir.c).
The Windows directory handle now skips the entries the descriptor already
consumed, the Linux handle duplicates the descriptor, and the test requires both.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 03:11:14 +02:00

7.4 KiB

libSceLibcInternal technical debt

Unknown function info

  • _sceLibcInternalThreadAtexit, _sceLibcInternalThreadDtors (libSceLibcInternal) - FreeBSD __cxa_thread_atexit semantics assumed; a null or non-image destructor and an allocation failure throw
  • _sceLibcInternalForceTlsDestructor (libSceLibcInternal) - behaviour follows sceLibcForceTlsDestructor(int) in a title's libc.prx (disassembly): the calling thread's destructors whose dso belongs to the module run newest first, only if the dso's module is loaded and the dso points to itself, in up to 4 passes. The return type is unknown (that function returns nothing), 0 is returned. The module of each dso is looked up when the destructors are forced, not when they are registered as libc.prx does

Functional

  • makecontext (libSceLibcInternal) follows FreeBSD 11's lib/libc/amd64/gen/makecontext.c: at most six arguments, a stack of at least MINSIGSTKSZ (2048) bytes, and exit(0) when the function returns with no uc_link. The console's version is not verified
  • makecontext (libSceLibcInternal) on Windows pins its stack writable until a later makecontext stack overlaps it, since nothing tells the library when the guest frees the stack
  • Thread exit destructors (libSceLibcInternal) run when a libkernel thread finishes; on the main or a host thread only _sceLibcInternalThreadDtors runs them, as exit does, else they are dropped
  • fdopendir (libSceLibcInternal) follows FreeBSD 11's fdopendir: it sets FD_CLOEXEC on the descriptor first, and the stream starts at the descriptor's current position instead of the first entry. On Windows the stream skips the entries the descriptor's cursor (lseek or getdirentries) has passed, which assumes that the descriptor and the stream list a directory in the same host order; on Linux the stream is opened on a duplicate of the descriptor, which shares its position. The Linux path is not run by the tests here. As in FreeBSD, a descriptor that is not open fails with EBADF, one that is not a directory with ENOTDIR (both leave it open, and FD_CLOEXEC stays set on the latter), and closedir closes it
  • fstatvfs (libSceLibcInternal) converts _fstatfs to the 88-byte struct statvfs as FreeBSD 9.2's sfs2svfs does (f_bsize from the transfer size, f_frsize from the block size, f_favail equal to f_ffree, f_fsid 0, ST_RDONLY and ST_NOSUID only). Differences: f_namemax is the statfs value, not fpathconf(_PC_NAME_MAX); negative f_bavail and f_ffree wrap to unsigned without EOVERFLOW, as the same-width copy in FreeBSD does; inode counts are 0 on Windows, inherited from _fstatfs; a null output returns EFAULT after the descriptor is validated, where FreeBSD would fault. Layout and conversion are unverified against the PS5 library (PS5MC imports fstatvfs but was not run)
  • posix_spawn and posix_spawnp (libSceLibcInternal) create no process. FreeBSD 11.4 returns the error the child's exec leaves (_posix_spawn_thr, do_posix_spawn), and posix_spawnp searches PATH, or _PATH_DEFPATH when it is unset, ending with ENOENT when no directory holds the program (_execvpe, execvPe). So when the program is not in the guest file system both return ENOENT and leave the process ID unwritten; when it is there they throw. PPSA99305 (Dusklight) reaches this when SDL looks for zenity to show a file dialog. The attributes and file actions are not applied, so one that would fail in the child is not reported, and whether the console's application sandbox lets the child be created at all (FreeBSD returns that error first) is unverified. The attribute and file action calls keep FreeBSD 11.4's objects. Null or uninitialized objects, which FreeBSD dereferences, throw.
  • getopt, getopt_long (libSceLibcInternal) follow FreeBSD 11 getopt.c and getopt_long.c with GNU_COMPATIBLE: getopt does not permute, getopt_long permutes unless POSIXLY_CORRECT is set in the guest environment or the option string starts with +, and the exported opterr, optind, optopt, optreset and optarg start at 1, 1, 0, 0 and null. Warnings go to the guest's current stderr prefixed with __progname, where FreeBSD's warnx keeps the stderr of its first call. A null getopt option string, a null argument vector or argument, a negative optind and an optind moved inside a pending permutation throw where FreeBSD faults. getopt_long_only is not exported. That the console's libSceLibcInternal uses this FreeBSD code is unverified
  • posix_spawnattr_getflags, getpgroup, getschedparam, getschedpolicy, getsigdefault, getsigmask, setpgroup, setschedparam, setschedpolicy and setsigmask (libSceLibcInternal) read and write the 0x30-byte attribute object at the offsets of the console's libSceLibcInternal.sprx (SDK 4.5x build of J03950001, 0x8D860 to 0x8D910: flags at 0, process group at 4, scheduling parameter at 8, policy at 0xC, default and masked signal sets at 0x10 and 0x20), which never fail there and return 0; the layout matched on a PS5 (firmware 13.60). Uninitialized attributes and null pointers, which the console dereferences, throw as the existing setters do
  • sys_siglist and sys_nsig (libSceLibcInternal) hold the 32 descriptions and the count of FreeBSD 11.4 siglist.c (NSIG 32, signal 0 to SIGUSR2); the console's table was not read
  • inet_aton, inet_addr, inet_ntoa and inet_ntoa_r (libSceLibcInternal) follow the FreeBSD code in the console's libSceLibcInternal.sprx (SDK 4.5x build of J03950001, 0x8ADE0 to 0x8B3D0) and matched it on a PS5 (firmware 13.60) for 20 inet_aton inputs; a null text, which the console dereferences, throws. inet_ntoa_r formats through libkernel's __inet_ntop, so a null buffer with room for the text throws and a null buffer that is too small sets ENOSPC, as __inet_ntop does for a null destination; the console's inet_ntoa_r was not measured with a null buffer