Skip to content

fix(libc): use the Annex K size limit and codes of the PS5 libc, as measured on a PS5 - #8965

Open
ionut27001 wants to merge 4 commits into
boykopovar:mainfrom
ionut27001:fix/libc-annexk-rsize-max
Open

ionut27001 wants to merge 4 commits into
boykopovar:mainfrom
ionut27001:fix/libc-annexk-rsize-max

Conversation

@ionut27001

@ionut27001 ionut27001 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

The Annex K size limit and violation codes of the PS5 libc, as measured in a payload process on a PS5 (firmware 12.70), differ from the ones the copy functions in core/libs/prx/libc/src/Strings.cpp used.

  • memcpy_s accepts a destination size up to 0x1fffffffffffffff and returns EINVAL (22) from 0x2000000000000000 up (L752-L766); wmemcpy_s has the same limit in elements (L772-L784). That is RSIZE_MAX = 2^61-1 for bytes and for wide elements. This libc used SIZE_MAX >> 1 for bytes and half of that for wide elements, and returned ERANGE (34) above it.
  • strcpy_s with a destination size of SIZE_MAX returns 22 and leaves the destination alone (L787); this libc returned 34.
  • strncpy_s with a count of SIZE_MAX, a destination size of 4 and a 6-character source returns 22 with dest[0] set to zero (L791); this libc returned 34. The code checks the count against RSIZE_MAX before whether the string fits; the measured call has a source that does not fit, so it does not show the case of a source that fits.

What changed: one RsizeMax of 2^61-1 for the byte and wide Annex K functions of Strings.cpp, EINVAL instead of ERANGE for a destination size above it, and the count check in strncpy_s (and so in strcpy_s, which now passes RSIZE_MAX as its count). memmove_s, wmemmove_s, strncat_s, wcsncpy_s and wcsncat_s take the same limit and the same EINVAL; strcat_s and wcscat_s follow through them. Those siblings were not measured, so that is an inference from the measured functions, and the debt entry says so. memset_s keeps its own limit.

Unchanged and matching the measurement: a count above the destination size returns 34 and zero-fills the destination (memcpy_s, L767); an overlapping source, a null destination and a null source return 22, with the destination zero-filled for the overlap and for a null source with a count of 4 (L768-L771); strcpy_s returns 34 with dest[0] set to zero when the source does not fit, 22 for a destination size of 0 and 22 with dest[0] set to zero for a null source (L785, L786, L788); strncpy_s returns 0 for a count of 3 into a destination size of 4 and 34 with dest[0] set to zero for a count of 4 (L789, L790).

fopen_s needed no change: the errno of the failed open, the null file pointer on failure and 22 for a null path, mode or file pointer are what L734-L746 show. The test pins them.

What is not done: the registered constraint handler is still not called for a violation. The measurement shows one call per violation for memcpy_s, wmemcpy_s, strcpy_s, strncpy_s and fopen_s with a counting handler installed, but not what the default handler does, so adding calls would change what a title sees. The debt entries for the Annex K functions and fopen_s are cut to that and to the unmeasured parts.

Relation to open pull requests:

Tested

  • Windows 11, MinGW-w64 GCC 15.2.0 (WinLibs), head 65c7c4a (main merged at 3fea2a9), the test now declaring the functions through prx/libc/include/Api.hpp (FileStream*, char16_t*, size_t) instead of local declarations: ctest --test-dir build -R "^(guest_libc_annexk_rsizemax|guest_strings|guest_wide_strings)$" ran twice: 3 of 3 passed both times.
  • Earlier, at head cd64f65 rebased onto main, ctest -R "guest_libc|guest_strings|guest_wide_strings|guest_string" ran twice: 8 of 8 passed both times.
  • With libc/src/Strings.cpp restored from the previous commit and rebuilt, guest_libc_annexk_rsizemax, guest_strings and guest_wide_strings fail (3 of 8); with the file restored they pass again.
  • The build had one failing target that this change does not touch: the AGC test agc_driver_image_array_window_past_layer_limit_tests does not compile with MinGW (alignas(65536)).
  • python tools/check_conventions.py --base origin/main passes at the head of this pull request.
  • No title and no homebrew was run. The measured values are from a payload process on one PS5 (firmware 12.70); a title process was not measured.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

@ionut27001

Copy link
Copy Markdown
Contributor Author

Probe lines the body refers to (p83, payload process on a PS5, firmware 12.70; log lines 734-791, quoted unchanged):

case fopen_s missing_read ret=2 errno_after=2 file_null=1 file_untouched=0 handler=0
case fopen_s existing_read ret=0 errno_after=0 file_null=0 file_untouched=0 handler=0
case fopen_s create_write ret=0 errno_after=0 file_null=0 file_untouched=0 handler=0
case fopen_s exclusive_on_existing_wx ret=17 errno_after=17 file_null=1 file_untouched=0 handler=0
case fopen_s exclusive_on_new_wx ret=0 errno_after=0 file_null=0 file_untouched=0 handler=0
case fopen_s invalid_mode_z ret=22 errno_after=22 file_null=1 file_untouched=0 handler=0
case fopen_s empty_mode ret=22 errno_after=22 file_null=1 file_untouched=0 handler=0
case fopen_s directory_read ret=0 errno_after=0 file_null=0 file_untouched=0 handler=0
case fopen_s directory_write ret=21 errno_after=21 file_null=1 file_untouched=0 handler=0
case fopen_s missing_read_plus ret=2 errno_after=2 file_null=1 file_untouched=0 handler=0
case fopen_s null_path ret=22 file_null=1 handler=1
case fopen_s null_mode ret=22 file_null=1 handler=1
case fopen_s null_file_pointer ret=22 handler=1
resolve sym=set_constraint_handler_s module=libSceLibcInternal.sprx exported=yes
resolve sym=memcpy_s module=libSceLibcInternal.sprx exported=yes
resolve sym=wmemcpy_s module=libSceLibcInternal.sprx exported=yes
resolve sym=strcpy_s module=libSceLibcInternal.sprx exported=yes
resolve sym=strncpy_s module=libSceLibcInternal.sprx exported=yes
case annexk memcpy_s destsz=0x40 n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x1000 n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x100000 n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x40000000 n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x7fffffff n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x80000000 n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0xffffffff n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x100000000 n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x10000000000 n=1 ret=0 copied=1 handler=0
case annexk memcpy_s destsz=0x4000000000000000 n=1 ret=22 copied=0 handler=1
case annexk memcpy_s destsz=0x7ffffffffffffffe n=1 ret=22 copied=0 handler=1
case annexk memcpy_s destsz=0x7fffffffffffffff n=1 ret=22 copied=0 handler=1
case annexk memcpy_s destsz=0x8000000000000000 n=1 ret=22 copied=0 handler=1
case annexk memcpy_s destsz=0xffffffffffffffff n=1 ret=22 copied=0 handler=1
case annexk memcpy_s largest_accepted_destsz=0x1fffffffffffffff first_refused_destsz=0x2000000000000000
case annexk memcpy_s n_above_destsz ret=34 dest_first8=000000005a5a5a5a handler=1
case annexk memcpy_s overlap ret=22 dest_first8=0000000000000000 handler=1
case annexk memcpy_s null_dest ret=22 handler=1
case annexk memcpy_s null_src n4 ret=22 dest_first8=0000000000000000 handler=1
case annexk memcpy_s null_src n0 ret=22 handler=1
case annexk wmemcpy_s destsz=0x20 n=1 ret=0 copied=1 handler=0
case annexk wmemcpy_s destsz=0x100000 n=1 ret=0 copied=1 handler=0
case annexk wmemcpy_s destsz=0x7fffffff n=1 ret=0 copied=1 handler=0
case annexk wmemcpy_s destsz=0x80000000 n=1 ret=0 copied=1 handler=0
case annexk wmemcpy_s destsz=0x100000000 n=1 ret=0 copied=1 handler=0
case annexk wmemcpy_s destsz=0x3ffffffffffffffe n=1 ret=22 copied=0 handler=1
case annexk wmemcpy_s destsz=0x3fffffffffffffff n=1 ret=22 copied=0 handler=1
case annexk wmemcpy_s destsz=0x4000000000000000 n=1 ret=22 copied=0 handler=1
case annexk wmemcpy_s destsz=0x7ffffffffffffffe n=1 ret=22 copied=0 handler=1
case annexk wmemcpy_s destsz=0x7fffffffffffffff n=1 ret=22 copied=0 handler=1
case annexk wmemcpy_s destsz=0x8000000000000000 n=1 ret=22 copied=0 handler=1
case annexk wmemcpy_s destsz=0xffffffffffffffff n=1 ret=22 copied=0 handler=1
case annexk wmemcpy_s largest_accepted_destsz=0x1fffffffffffffff first_refused_destsz=0x2000000000000000
case annexk strcpy_s destsz4_src6 ret=34 dest_first8=005a5a5a5a5a5a5a handler=1
case annexk strcpy_s destsz0 ret=22 dest_first4=5a5a5a5a handler=1
case annexk strcpy_s destsz_size_max ret=22 dest_first4=5a5a5a5a handler=1
case annexk strcpy_s null_src ret=22 dest_first4=005a5a5a handler=1
case annexk strncpy_s destsz4_n3 ret=0 dest_first8=616263005a5a5a5a handler=0
case annexk strncpy_s destsz4_n4 ret=34 dest_first8=005a5a5a5a5a5a5a handler=1
case annexk strncpy_s destsz4_n_trunc ret=22 dest_first8=005a5a5a5a5a5a5a handler=1

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

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.

Pull request Shared files not compared
PR 3965 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 5021 core/libs/prx/libc/CMakeLists.txt
core/libs/prx/libc/src/Strings.cpp
docs/dev/debt/libc.md
PR 5303 docs/dev/debt/libc.md
PR 6084 core/libs/prx/libc/CMakeLists.txt
PR 6819 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7081 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7386 docs/dev/debt/libc.md
PR 7447 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7645 core/libs/prx/libc/CMakeLists.txt
PR 7648 docs/dev/debt/libc.md
PR 7715 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7851 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 8150 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 8417 docs/dev/debt/libc.md
PR 9087 core/libs/tests/GuestStrings.cpp
docs/dev/debt/libc.md
PR 9340 docs/dev/debt/libc.md
PR 9371 docs/dev/debt/libc.md
PR 9447 docs/dev/debt/libc.md
PR 9466 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 9526 docs/dev/debt/libc.md
PR 9584 core/libs/prx/libc/CMakeLists.txt
PR 9677 docs/dev/debt/libc.md
PR 9761 docs/dev/debt/libc.md
PR 9773 core/libs/prx/libc/CMakeLists.txt
PR 9775 core/libs/prx/libc/CMakeLists.txt
PR 9798 core/libs/prx/libc/CMakeLists.txt
PR 9863 docs/dev/debt/libc.md
PR 9873 docs/dev/debt/libc.md
PR 9929 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 9935 docs/dev/debt/libc.md
PR 9964 docs/dev/debt/libc.md
PR 10002 docs/dev/debt/libc.md
PR 10007 docs/dev/debt/libc.md
PR 10113 docs/dev/debt/libc.md
PR 10158 docs/dev/debt/libc.md
PR 10165 docs/dev/debt/libc.md
PR 10200 docs/dev/debt/libc.md
PR 10226 docs/dev/debt/libc.md
PR 10234 docs/dev/debt/libc.md
PR 10245 docs/dev/debt/libc.md
PR 10250 docs/dev/debt/libc.md
PR 10253 docs/dev/debt/libc.md
PR 10265 docs/dev/debt/libc.md
PR 10274 docs/dev/debt/libc.md
PR 10315 docs/dev/debt/libc.md
PR 10321 docs/dev/debt/libc.md
PR 10325 docs/dev/debt/libc.md
PR 10328 docs/dev/debt/libc.md
PR 10345 docs/dev/debt/libc.md
PR 10349 docs/dev/debt/libc.md
PR 10397 docs/dev/debt/libc.md
PR 10405 docs/dev/debt/libc.md
PR 10506 docs/dev/debt/libc.md
PR 10510 docs/dev/debt/libc.md
PR 10512 docs/dev/debt/libc.md
PR 10565 docs/dev/debt/libc.md
PR 10569 docs/dev/debt/libc.md
PR 10749 docs/dev/debt/libc.md
PR 10780 docs/dev/debt/libc.md
PR 10987 docs/dev/debt/libc.md
PR 11109 docs/dev/debt/libc.md
PR 11172 docs/dev/debt/libc.md
PR 11260 docs/dev/debt/libc.md
PR 11262 docs/dev/debt/libc.md
PR 11266 docs/dev/debt/libc.md
PR 11332 docs/dev/debt/libc.md
PR 11621 docs/dev/debt/libc.md
PR 11624 core/libs/prx/libc/CMakeLists.txt
PR 11625 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 11628 core/libs/prx/libc/CMakeLists.txt
PR 11632 docs/dev/debt/libc.md
PR 11634 docs/dev/debt/libc.md
PR 11661 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 11664 core/libs/tests/GuestStrings.cpp
docs/dev/debt/libc.md
PR 11689 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 11698 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 11724 docs/dev/debt/libc.md
PR 11726 docs/dev/debt/libc.md
PR 11793 docs/dev/debt/libc.md
PR 11831 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 11848 docs/dev/debt/libc.md
PR 11895 docs/dev/debt/libc.md
PR 11907 docs/dev/debt/libc.md
PR 11947 core/libs/prx/libc/CMakeLists.txt
core/libs/tests/GuestStrings.cpp
docs/dev/debt/libc.md
PR 12053 docs/dev/debt/libc.md
PR 12057 docs/dev/debt/libc.md
PR 12071 core/libs/prx/libc/CMakeLists.txt
PR 12122 docs/dev/debt/libc.md
PR 12146 core/libs/prx/libc/CMakeLists.txt
PR 12149 docs/dev/debt/libc.md
PR 12184 docs/dev/debt/libc.md
PR 12271 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 12292 docs/dev/debt/libc.md
PR 12397 docs/dev/debt/libc.md
PR 12428 docs/dev/debt/libc.md
PR 12510 docs/dev/debt/libc.md
PR 12511 docs/dev/debt/libc.md
PR 12514 docs/dev/debt/libc.md
PR 12518 docs/dev/debt/libc.md
PR 12530 docs/dev/debt/libc.md
PR 12532 docs/dev/debt/libc.md
PR 12560 docs/dev/debt/libc.md
PR 12574 docs/dev/debt/libc.md
PR 12581 core/libs/prx/libc/src/Strings.cpp
PR 12592 docs/dev/debt/libc.md
PR 12593 docs/dev/debt/libc.md
PR 12594 core/libs/prx/libc/src/Strings.cpp
core/libs/tests/GuestStrings.cpp
docs/dev/debt/libc.md
PR 12595 docs/dev/debt/libc.md
PR 12598 docs/dev/debt/libc.md
PR 12605 docs/dev/debt/libc.md
PR 12622 core/libs/tests/GuestStrings.cpp
docs/dev/debt/libc.md
PR 12627 docs/dev/debt/libc.md
PR 12682 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 12688 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 12700 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 12704 docs/dev/debt/libc.md
PR 12717 core/libs/prx/libc/CMakeLists.txt
PR 12777 core/libs/prx/libc/CMakeLists.txt
PR 12841 docs/dev/debt/libc.md
PR 12849 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 12882 core/libs/prx/libc/CMakeLists.txt
PR 12883 core/libs/prx/libc/CMakeLists.txt
PR 12884 core/libs/prx/libc/CMakeLists.txt
PR 12885 core/libs/prx/libc/CMakeLists.txt
PR 12886 core/libs/prx/libc/CMakeLists.txt
PR 12887 core/libs/prx/libc/CMakeLists.txt
PR 12888 core/libs/prx/libc/CMakeLists.txt
PR 12889 core/libs/prx/libc/CMakeLists.txt
PR 12890 core/libs/prx/libc/CMakeLists.txt
PR 12920 docs/dev/debt/libc.md
PR 12947 docs/dev/debt/libc.md
PR 12965 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 13119 docs/dev/debt/libc.md
PR 13186 core/libs/tests/GuestStrings.cpp
docs/dev/debt/libc.md
PR 13303 core/libs/prx/libc/CMakeLists.txt
PR 13304 core/libs/prx/libc/CMakeLists.txt
PR 13305 core/libs/prx/libc/CMakeLists.txt
PR 13306 core/libs/prx/libc/CMakeLists.txt
PR 13307 core/libs/prx/libc/CMakeLists.txt
PR 13308 core/libs/prx/libc/CMakeLists.txt
PR 13310 core/libs/prx/libc/CMakeLists.txt
PR 13311 core/libs/prx/libc/CMakeLists.txt
PR 13312 core/libs/prx/libc/CMakeLists.txt
PR 13313 core/libs/prx/libc/CMakeLists.txt
PR 13314 core/libs/prx/libc/CMakeLists.txt
PR 13316 core/libs/prx/libc/CMakeLists.txt
PR 13317 core/libs/prx/libc/CMakeLists.txt
PR 13318 core/libs/prx/libc/CMakeLists.txt
PR 13319 core/libs/prx/libc/CMakeLists.txt
PR 13320 core/libs/prx/libc/CMakeLists.txt
PR 13378 core/libs/prx/libc/CMakeLists.txt
PR 13379 core/libs/prx/libc/CMakeLists.txt
PR 13380 core/libs/prx/libc/CMakeLists.txt
PR 13381 core/libs/prx/libc/CMakeLists.txt
PR 13382 core/libs/prx/libc/CMakeLists.txt
PR 13383 core/libs/prx/libc/CMakeLists.txt
PR 13385 core/libs/prx/libc/CMakeLists.txt
PR 13386 core/libs/prx/libc/CMakeLists.txt
PR 13387 core/libs/prx/libc/CMakeLists.txt
PR 13389 core/libs/prx/libc/CMakeLists.txt
PR 13390 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 13391 core/libs/prx/libc/CMakeLists.txt
PR 13392 core/libs/prx/libc/CMakeLists.txt
PR 13393 core/libs/prx/libc/CMakeLists.txt
PR 13394 core/libs/prx/libc/CMakeLists.txt
PR 13395 core/libs/prx/libc/CMakeLists.txt
PR 13449 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 13784 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 13793 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 13794 docs/dev/debt/libc.md
PR 13804 docs/dev/debt/libc.md
PR 13809 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 13828 docs/dev/debt/libc.md
PR 14020 docs/dev/debt/libc.md
PR 14085 docs/dev/debt/libc.md
PR 14212 docs/dev/debt/libc.md
PR 14235 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 14298 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 14326 docs/dev/debt/libc.md
PR 14385 core/libs/prx/libc/src/Strings.cpp
core/libs/tests/GuestStrings.cpp
core/libs/tests/GuestWideStrings.cpp
PR 14389 core/libs/prx/libc/src/Strings.cpp
core/libs/tests/GuestWideStrings.cpp
PR 14585 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 14588 docs/dev/debt/libc.md
PR 14595 docs/dev/debt/libc.md
PR 14610 docs/dev/debt/libc.md
PR 14619 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 14620 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 14623 core/libs/prx/libc/CMakeLists.txt
core/libs/prx/libc/src/Strings.cpp
docs/dev/debt/libc.md
PR 14799 core/libs/prx/libc/CMakeLists.txt
PR 14828 docs/dev/debt/libc.md
PR 14864 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 14878 docs/dev/debt/libc.md
PR 14915 docs/dev/debt/libc.md
PR 14955 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 15004 docs/dev/debt/libc.md
PR 15095 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 15098 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 15099 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 24, 2026

@harisibrar1 harisibrar1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked against main 522e32e and the 12.70 log in this PR, plus #10270's console gist (dcadb97109bb78711ff3f7ba1dc479ed, firmware 13.60):

  • The 2^61-1 limit and EINVAL for an oversized destsz match your log, #10270's psafestr2 boundary search, and the rsizeMax already in main's BoundsChecking.cpp:29. It still merges cleanly with main.
  • #10270 now changes the same twelve functions to the same limit and EINVAL, also calls the constraint handler and covers wcscpy_s, so the two will conflict throughout Strings.cpp, GuestStrings.cpp, GuestWideStrings.cpp and libc.md. Could you coordinate with @orezraey on which one lands? The fopen_s test and debt rewrite here look like the part #10270 doesn't cover.
  • Oversized counts: #10270's gist shows memcpy_s(d, 4, "abc", 1<<61) returning 22 with the destination zeroed (psafestr3 mcpy_count_big), while this branch returns 34 for that call (count > destsz). strncat_s(d="ab", 8, "c", 1<<61) returns 22 with d[0]=0 on the console (ncat_count_big), but 0 with "abc" here. psafestr3/4 show the same 22 for memmove_s, wcsncpy_s, wcsncat_s and wmemcpy_s, so the debt line saying those functions "accept one" would describe a known divergence. That run used a different firmware from yours, though.
  • wcscpy_s is on main now (SonyCrt.hpp:140, used by WideConversion.cpp:37 and libSceAmpr) with the old (SIZE_MAX >> 1) / 2 limit and ERANGE. With this PR, wcscpy_s(d, 0x2000000000000000, u"a") returns 0 while wcsncpy_s(d, 0x2000000000000000, u"a", 1) returns 22.
  • Small one: the body still describes #7841 as open, but it's merged as BoundsChecking.cpp.

Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@ionut27001 @harisibrar1 I checked the psafestr3/4 sources and raw logs, including the firmware and resolved-module lines. They show oversized memcpy_s counts returning 22 with the destination cleared, and oversized strncat_s counts returning 22 with dest[0] cleared. This branch instead returns 34 and success respectively. The older destination-size measurements do not establish a different result for these count cases. I’m changing this head to CHANGES rather than landing a known measured divergence and fixing it afterward.

I recommend using #10270 for the shared safe-copy/append implementation after its #9935 prerequisite, then rebasing this PR onto that result and retaining any distinct fopen_s tests/debt evidence. That also brings wcscpy_s and the constraint-handler paths into the same implementation. Please coordinate that split so the two overlapping implementations do not land independently. Neither a stale debt statement that oversized counts are accepted nor the current green tests settle these measured count results.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@ionut27001 The local declarations differ from main’s public headers: int fclose_nid_postfix(void*) at core/libs/tests/GuestLibcAnnexkRsizeMax.cpp:16 versus int fclose_nid_postfix(FileStream* stream) at core/libs/prx/libc/include/Api.hpp:221; int fopen_s_nid_postfix(void**, const char*, const char*) at core/libs/tests/GuestLibcAnnexkRsizeMax.cpp:15 versus int fopen_s_nid_postfix(FileStream** result, const char* filename, const char* mode) at core/libs/prx/libc/include/Api.hpp:220; int wmemcpy_s_nid_postfix(char16_t* dest, std::size_t destsz, const char16_t* src, std::size_t count) at core/libs/tests/GuestWideStrings.cpp:32 versus int wmemcpy_s_nid_postfix(char16_t* dest, size_t destsz, const char16_t* src, size_t count) at core/libs/prx/libc/include/Api.hpp:974. Main now requires each exported function to be declared once, in the library's public header (checked by the public_headers tests). Could you use main’s public signatures and types throughout the implementation and tests, or explain why the public declarations need to change?

@isnisk

isnisk commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Checked on Linux: Ubuntu 26.04 (WSL2), GCC 15.2.0, Release, this head (9eb6c97cb) merged onto main 3a2c51afd (clean merge).

  • With the change: guest_libc_annexk_rsizemax, guest_strings and guest_wide_strings pass, 3 rounds; no compiler warnings from the changed files.
  • Without it (main's Strings.cpp, the tests kept): all three abort 3 of 3 (guest_strings: Guest string check failed).
  • check_conventions.py --base origin/main passes.

Not checked: Windows, macOS, a title.

AI-assisted: yes (Claude Code).

@ionut27001

Copy link
Copy Markdown
Contributor Author

Agreed. I'll leave the shared safe-copy and append changes to #10270. Once #9935 and #10270 land, I'll rebase this PR onto them and keep only what is distinct:

  • the fopen_s cases from p83, with their debt evidence;
  • the matching test, using the public Api.hpp declarations instead of the local ones you pointed out.

If nothing distinct is left, I'll close it.

This was referenced Oct 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build docs libc needs rebase Conflicts with main, rebase needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants