Commit Graph
73 Commits
Author SHA1 Message Date
Adrià bff0289787 Merge pull request #13529 from Oscar45397/test/libc-fgets-size-one
test(libc): check fgets with a size of 1 stores only the null character
2026-10-31 01:57:57 +01:00
AdriàandClaude Sonnet 5.5 18260015cc test(libc): open the fgets size-one stream with TemporaryFile::Open
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-31 01:22:47 +01:00
Oscar45397andClaude Opus 5.5 549585910a test(libc): check fgets with a size of 1 stores only the null character
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 01:22:39 +01:00
Adrià 20199a1182 test(libc): use TemporaryFile for getchar and putchar streams 2026-10-31 00:59:51 +01:00
Oscar45397andClaude Opus 5.5 943fead34a test(libc): cover getchar and putchar
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 00:59:47 +01:00
AdriàandClaude Sonnet 5.5 f0620bafae fix(tests): open GuestStandardStreams scratch streams under a Unicode TEMP
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-30 18:21:00 +01:00
bunbeans2-archandClaude Opus 5.5 6878d1be40 fix(tests): open scratch streams under a Unicode TEMP on Windows
On Windows, std::tmpfile() returns NULL with errno 22 when %TEMP%
contains a character outside the ANSI code page, where GetTempPathA
returns '?' in its place. Fifteen tests that capture output through it
aborted. TemporaryFile::Open() opens a unique delete-on-close file under
temp_directory_path() with _wfopen; other hosts keep std::tmpfile().

Part of #13083

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 18:21:00 +01:00
Adrià 4db29f8fbc Merge pull request #12991 from Oscar45397/test/libc-getc-putc
test(libc): cover getc and putc
2026-10-30 10:20:39 +01:00
Oscar45397andClaude Opus 5.5 335cce6bef test(libc): cover getc and putc
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 20:03:31 +01:00
Oscar45397andClaude Opus 5.5 96704fa920 test(libc): check ungetc of EOF fails and a push-back clears end of file
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 20:00:48 +01:00
Adrià df53927b7b Merge pull request #10929 from Aspct3434/claude/modest-curie-705h76
fix(libc): read characters outside the BMP as surrogate pairs in fgetwc
2026-10-29 13:49:54 +01:00
Oscar45397andClaude Opus 5.5 1dd153cf22 test(libc): define the setvbuf mode check outside the Windows-only block
CheckSetvbufInvalidMode sat inside the #ifdef _WIN32 block of
CheckStandardStreamDeleteSharing while main calls it on every platform,
so the Linux build failed. It uses nothing Windows-specific: move it
above the block so the check also runs on Linux.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 22:04:44 +01:00
Oscar45397andClaude Opus 5.5 e4e4985106 test(libc): check setvbuf rejects an invalid buffering mode
GuestStandardStreams used setvbuf only with valid modes.
CheckSetvbufInvalidMode requires modes 3, -1 and INT_MAX to return EOF,
as FreeBSD's setvbuf does for any mode other than _IOFBF, _IOLBF and
_IONBF (C11 7.21.5.6: nonzero for an invalid mode). A rejected call with
a buffer must not adopt it: a character written afterwards stays out of
that buffer and the stream still writes and reads back normally.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 22:04:44 +01:00
Claude 84aec8b0ac fix(libc): read characters outside the BMP as surrogate pairs in fgetwc
fputws and wprintf write a UTF-16 surrogate pair as one four-byte
UTF-8 sequence, but fgetwc decoded that sequence into a single code
point above 0xFFFF, which is not a 16-bit guest wchar_t value, and
fgetws stored it truncated: fputws(u"A\U0001F600\n") read back as
A, U+F600, newline.

fgetwc now returns the high surrogate and keeps the low one in the
stream for the next read, so fgetws stores the pair, also when the
buffer fills between the two halves. A successful seek discards it,
as FreeBSD's fseeko resets the stream's mbstate. Sequences that
decode to an overlong form or above U+10FFFF, and lead bytes F8 to
FF, fail with EILSEQ instead of returning made-up characters; the
three-byte surrogates that fputwc writes for a single unit are still
read back as that unit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QegaHM5QeCynUQ2ZLWHE4b
2026-10-28 14:43:48 +01:00
Dean 4c6fcfcb5c Merge pull request #9763 from rooklz/fix/libc-freopen-closed-stream
fix(libc): reopen a closed stream in freopen instead of aborting
2026-10-28 13:48:50 +13:00
Dean 77f68f314b Merge pull request #11560 from Ragbie/fix/write-after-read-update-stream
fix(libc): set up streams for writing after a read as FreeBSD does on Windows
2026-10-27 21:27:48 +13:00
Rookie 4c28647f0a fix(libc): answer EBADF to a null filename on a closed stream as the console does 2026-10-27 08:11:28 +00:00
Rookie 9618254977 fix(libc): reopen a closed stream in freopen instead of aborting 2026-10-27 08:11:28 +00:00
Dean f8c0779c48 Merge pull request #10782 from MarcZX10/marc/fix-perror-closed-stderr
fix(libc): let perror skip a closed standard error
2026-10-27 10:32:10 +13:00
Dean fd0da73ec5 Merge pull request #10781 from MarcZX10/marc/fix-printf-s-closed-stdout
fix(libc): fail printf_s on a closed standard output with EBADF
2026-10-27 09:04:40 +13:00
Evrim Cicek a7b52084ec fix(libc): set up streams for writing after a read as FreeBSD does on Windows
On Windows the UCRT drops a write that directly follows a read on an r+,
w+ or a+ stream: fputc and fprintf report success, fwrite returns 0 and
fputs returns EOF, all without the error indicator, and the file is left
unchanged, also after an fflush. On a stream open only for reading, fputc
after a read reports success as well.

Writes now first do what FreeBSD 11.4's __swsetup does: a stream open only
for reading fails with EBADF and sets the error indicator, and an update
stream that is reading drops its read buffer and ungetc data, clears end
of file and writes at the descriptor's offset. This covers fwrite, fputs,
fputc, putc_unlocked, fprintf, fprintf_s, fputwc, fputws, fwprintf,
fwprintf_s, puts and wprintf, and printf, vprintf and printf_s, which
write to standard output through PrintWindows and now return -1 there
instead of throwing.

Linux is unchanged: glibc writes at the stream position, which the libc
technical debt now records.
2026-10-26 21:53:56 +03:00
orezraeyandClaude Opus 5.5 3dac7eb76c fix(libc): check the fdopen mode before the descriptor and skip the access check as measured on a PS5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 17:01:01 -03:00
MarcZX10 2562a7d9d1 test(libc): cover printf_s on a closed standard output 2026-10-25 07:56:20 +00:00
MarcZX10 df44b2aa59 test(libc): cover perror on a closed standard error 2026-10-25 07:56:12 +00:00
MarcZX10 c2efce8ab7 test(libc): cover the wide calls on a closed stream 2026-10-25 06:30:05 +00:00
boykopovar f38d29fd08 refactor(sdk): add canonical headers for remaining libraries 2026-10-24 23:17:42 +03:00
Dean 5669dff560 Merge pull request #9596 from JJenkx/windows/fgetws-console-contract
fix(libc): follow the console fgetws for short buffers and read errors
2026-10-24 15:22:31 +13:00
Queuze 6d31de8561 chore: sync contribution #8873 with main 2026-10-23 20:02:20 -03:00
JJenkxandClaude Opus 5.5 ea6aa0a809 fix(libc): follow the console fgetws for short buffers and read errors
The fgetws in the libc.prx that titles ship (the same 133 bytes in the
copies of PPSA13934, PPSA07923 and PPSA05916, read from disassembly)
differs from this one in two cases:

- A size below 2 returns null at once, without writing the buffer,
  errno or the stream (cmp $0x2,%esi; jge, else the null result). Here a
  size of 1 stored a NUL and returned the buffer, and a size of 0 or less
  set the stream error and errno 22.
- When fgetwc returns -1 after characters were stored, the console
  null-terminates and returns the buffer; it returns null only when
  nothing was stored, and never checks ferror. Here a read error after
  some characters returned null.

The rest already matches: each fgetwc result is stored as its low 16 bits
(mov %ax,(%rbx)), and the newline test compares all 32 bits. A null buffer
or stream, which the console dereferences, keeps failing with errno 22.

guest_standard_streams now expects the console results for sizes 1, 0
and -1 and for an invalid byte after a stored character; its fgetwc error
indicator check is unchanged. The libc debt entry cites the reading and
what it leaves unverified.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 16:19:24 -04:00
Queuze a2e07a5eb5 test(libc): check host stdout after freopen 2026-10-21 06:18:20 -03:00
hypermist 04dc63a353 Merge remote-tracking branch 'upstream/main' into fix/libc-utf8-multibyte
# Conflicts:
#	core/libs/prx/libc/src/Multibyte.cpp
2026-10-21 16:20:33 +13:00
Dean 6c12024f7d Merge pull request #8741 from Queuse/fix/libc-freopen-share-delete
fix(libc): share delete on standard stream reopen
2026-10-21 14:47:29 +13:00
Queuze 3916eeaf6f fix(libc): share delete on standard stream reopen 2026-10-20 20:07:16 -03:00
p3nicillin dde6b34d37 feat(libc): implement unlocked stream status queries 2026-10-20 23:41:22 +01:00
hypermistandClaude Opus 5.5 906f18f609 fix(libc): convert multibyte text as UTF-8 like the console's C locale
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RbLgECLQ2bpDM7oe2urGZK
2026-10-21 02:51:59 +13:00
babyhuey 2d8d3b9dc1 fix(libc): keep the host standard stream when a guest freopen of it fails 2026-10-18 09:12:17 -04:00
T3cm0andClaude Opus 5.5 22c584acd3 feat(libc): implement clearerr_unlocked, fileno_unlocked and fgetln
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-17 16:17:27 -05:00
Adrià 21ca964f3f Merge pull request #5632 from babyhuey/fix/libc-closed-stream-writes
fix(libc): fail stream calls on a stream that a failed freopen closed
2026-10-15 17:03:43 +02:00
Nawasfadili 6509ec274a feat(libc): implement wide and unlocked stream I/O 2026-10-14 14:24:37 +00:00
babyhuey 292752ff5a fix(libc): fail stream calls on a stream that a failed freopen closed 2026-10-14 02:20:06 -04:00
Dean 6546a33944 Merge pull request #4728 from Ondra97/codex/fix-fdopen-access-mode
fix(libc): reject incompatible fdopen access modes on Windows
2026-10-14 19:06:55 +13:00
Ondra97 f2120a6458 fix(libc): reject incompatible fdopen access modes on Windows 2026-10-13 05:30:05 +02:00
David 7aabb9005c fix(libc): fail fseek and ftell on a pipe with ESPIPE on Windows 2026-10-13 02:38:01 +00:00
David dbbd6d582c fix(libc): append through a descriptor opened by fdopen in an append mode on Windows 2026-10-12 20:09:54 +00:00
Dean b701bc5d8d Merge pull request #4372 from milescoviello/fix/fflush-read-stream
fix(libc): leave a stream that is reading untouched in fflush on Linux
2026-10-13 07:22:17 +13:00
Dean 655cba83d5 Merge pull request #4358 from milescoviello/fix/scanf-binary-prefix
fix(libc): read %i without the C23 binary prefix in the scanf family on Linux
2026-10-13 07:19:26 +13:00
Dean b538b28d8b Merge pull request #4354 from milescoviello/fix/fopen-append-position
fix(libc): start append-mode streams at the end of the file
2026-10-13 07:18:50 +13:00
Dean d58ba1010e Merge pull request #4232 from MarcZX100/codex/carry-fdopen-modes-4022
fix(libc): accept FreeBSD fdopen modes
2026-10-13 01:30:04 +13:00
milescovielloandClaude Opus 5.5 89bc9d1082 fix(libc): read %i without the C23 binary prefix in the scanf family on Linux
On Linux sscanf, vsscanf, fscanf and sscanf_s hand their conversions to
glibc. Since glibc 2.38, code built as GNU C++ calls the C23 entry
points (__isoc23_vsscanf, __isoc23_vfscanf, __isoc23_sscanf), whose %i
reads a 0b/0B binary prefix. On main,
sscanf("0b101 x", "%i%n%7s", &value, &end, rest) stores value 5 and
end 5 and leaves "x" for the %s; " -0B11" gives -3. TechnicalDebt
records this.

FreeBSD's %i knows only the 0 and 0x prefixes. FreeBSD 11.4
lib/libc/stdio/vfscanf.c, parseint, lines 345-353 and 371-380:

	case '0':
		if (base == 0) {
			base = 8;
			flags |= PFXOK;
		}
	...
	/* letters ok iff hex */
	case 'A': case 'B': case 'C':
	case 'D': case 'E': case 'F':
	case 'a': case 'b': case 'c':
	case 'd': case 'e': case 'f':
		/* no need to fix base here */
		if (base <= 10)
			break;	/* not legal here */

so "0b101" stores 0, consumes the "0" and leaves "b101", as C17 does
and as the strtol family here already does.

With glibc the scanf family now calls __isoc99_vsscanf and
__isoc99_vfscanf, the entry points GNU C++ used before glibc 2.38
(exported since 2.7), which read %i without the binary prefix. Other
hosts keep std::vsscanf and std::vfscanf. The TechnicalDebt entry is
removed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 08:38:06 +00:00
milescovielloandClaude Opus 5.5 1337bd7e45 fix(libc): leave a stream that is reading untouched in fflush on Linux
fflush() passed every stream to glibc's fflush(). For a stream that is
reading, glibc seeks the descriptor back and drops the read buffer, and
with a pushed-back character it gets the position wrong: after fgetc()
returned 'a' from "abcdef\n" and ungetc('Z'), fflush() returned 0 and
the next fread() returned "bcdef\n\n". The pushed-back 'Z' was lost and
the last byte came back twice.

FreeBSD's fflush() writes out only a stream that is writing and leaves
every other stream as it is, lib/libc/stdio/fflush.c:

	if ((fp->_flags & (__SWR | __SRW)) == 0)
		retval = 0;
	else
		retval = __sflush(fp);

and __sflush():

	t = fp->_flags;
	if ((t & __SWR) == 0)
		return (0);

fflush() on Linux now returns 0 without calling the host for a stream
whose last operation was not a write (__fwriting() is 0). fflush(NULL)
and streams that are writing are unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 08:00:21 +00:00