Skip to content

feat(libc): export the std::__sce_v2 _Locimp_ctor and _Locimp_dtor with facet reference counting - #16165

Merged
oneandonlydean merged 4 commits into
boykopovar:mainfrom
Danigamer05:feat/libc-sce-v2-locimp-ctor-dtor-20261105
Nov 6, 2026
Merged

oneandonlydean merged 4 commits into
boykopovar:mainfrom
Danigamer05:feat/libc-sce-v2-locimp-ctor-dtor-20261105

Conversation

@Danigamer05

@Danigamer05 Danigamer05 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

What

Builds on #16113: this branch contains its commit, so until it merges only the two commits after it are this PR's change.

Export the versioned std::__sce_v2 locale::_Locimp::_Locimp_ctor and _Locimp_dtor from libc, and make the versioned _Locimp family count facet references the way the console does.

Export NID Original address
_ZNSt8__sce_v26locale7_Locimp12_Locimp_ctorEPS1_RKS1_ XBQPgR5196I 0xF25E0
_ZNSt8__sce_v26locale7_Locimp12_Locimp_dtorEPS1_ L2pyahLSGFk 0xD1030

Changed exports: _ZNSt8__sce_v26locale7_Locimp11_New_LocimpERKS1_ (ynwqogpIbL0, 0xD0F60) and _ZNSt8__sce_v26locale7_Locimp14_Locimp_AddfacEPS1_PNS0_5facetEm (7KPYZ-jSAto, 0xF2680).

The behavior comes from the libc.prx bundled with PPSA03671 v01.001.005 (J03848509, SHA-256 483961e086b8a1fffa8138b3c0badf798987fb5f35ec908d828946408be2d8a6). As in the module:

  • _Locimp_ctor(self, source) builds only the facet vector. The caller has already copied the count. A zero count leaves the vector alone. Otherwise it calls malloc(count * 8), throws bad_alloc on null, and copies the facets from the last to the first, retaining each non-null one.
  • _Locimp_dtor(self) releases each non-null facet from the last to the first, calls deleteObject on the ones that reach zero, and frees the vector unless it is the classic one. It does not free the _Locimp.
  • _New_Locimp(const _Locimp&) allocates 0x30 bytes and sets the _Locimp vtable, one reference and a null vector. It copies the count, category, transparency and name pointer, then calls _Locimp_ctor. If that throws, it frees the object.
  • _Locimp_Addfac grows the vector with realloc to max(id + 1, 40) slots and clears the new ones. It retains the new facet, releases the one it replaces (deleting it at zero) and stores the new one.
  • The _Locimp objects built by _New_Locimp(const&), _New_Locimp(bool) and empty() get the module's _Locimp vtable. The last release returns the object, and deleteObject runs _Locimp_dtor and frees it. Before this PR they used the copy vtable and were never freed.

Before this PR, the versioned _New_Locimp(const&) and _Locimp_Addfac called the unversioned copy and insertion, which neither retain nor release. The unversioned functions are unchanged.

guest_sce_v2_locale passed facets with a null vtable to _Locimp_Addfac and read the copy after its last release. It now uses a counting facet and checks that the last release deletes the copy and its facet.

A new debt entry lists what still differs: the lock, null arguments, size overflow, the one-slot classic vector, and copies of locales built by unversioned calls. The versioned locale entry drops its sentence about the reused unversioned copy and insertion, and #16113's entry drops the one about the copy vtable.

Tested

Windows x86-64, WinLibs GCC 15.2.0, Release, BUILD_TESTING=ON, on top of #16113 (d18e1c71325, main d893997f1a6); the branch merges cleanly with main c4469b60daf. Exact tested commit: b24626696c2. It adds one commit to 4e7016e6926 that renames two internal helpers. The build, the tests, the side-by-side run and the conventions check ran on it; the negative control and the overlap checks below ran on 4e7016e6926.

Not tested: Linux, macOS, another SDK, a game, GPU or console. No game compatibility claim. No original module, extracted bytes, harness or log is committed or uploaded.

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: feat(libc): export the std::__sce_v2 locale::global, empty, classic and _Locinfo category calls #16113
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

🤖 Generated with Claude Code

Danigamer05 and others added 2 commits November 5, 2026 18:35
…nd _Locinfo category calls

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…th facet reference counting

The versioned _Locimp family now owns its facets the way the console's
libc.prx does: _Locimp_ctor retains every copied facet, _Locimp_dtor
releases them (deleting the ones that reach zero) and frees the vector,
_Locimp_Addfac retains the new facet and releases the one it replaces,
and _New_Locimp(const&) copies the fields and calls _Locimp_ctor. The
_Locimp objects built by the versioned calls get a vtable whose last
release runs _Locimp_dtor and frees the object.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JJenkx

JJenkx commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Windows check of head 4e7016e692, merged onto main b3189fd745 (da2e1b4a6f, clean merge).

Setup: Windows 11 Enterprise 22621, WinLibs GCC 15.2 UCRT, Release. The hosted Windows check does not run these tests on pull requests.

  • guest_sce_v2_locale passes in 3 of 3 runs, none skipped.

AI-assisted: yes.

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Progress report (151a2cb → 8c982c6)

📈 System libraries: 27.09% (+0.02%, +10 implemented functions)

✅ 10 implemented
Library Name
libc _ZNSt8__sce_v215_sceLibcLocinfoEPKc_nid_postfix
libc _ZNSt8__sce_v26locale16_SetgloballocaleEPv_nid_postfix
libc _ZNSt8__sce_v26locale5emptyEv_nid_postfix
libc _ZNSt8__sce_v26locale6globalERKS0__nid_postfix
libc _ZNSt8__sce_v26locale7_Locimp11_New_LocimpEb_nid_postfix
libc _ZNSt8__sce_v26locale7_Locimp12_Locimp_ctorEPS1_RKS1__nid_postfix
libc _ZNSt8__sce_v26locale7_Locimp12_Locimp_dtorEPS1__nid_postfix
libc _ZNSt8__sce_v26locale7classicEv_nid_postfix
libc _ZNSt8__sce_v28_Locinfo13_Locinfo_ctorEPS0_iPKc_nid_postfix
libc _ZNSt8__sce_v28_Locinfo16_Locinfo_AddcatsEPS0_iPKc_nid_postfix

Changed libraries (implemented exports)

Library Before After Change
libc 1629/1649 (98.79%) 1639/1659 (98.79%) +0.01%

The progress report counted DestroySceV2Locimp and DeleteSceV2Locimp as
implemented functions; the _nid_no_patch suffix excludes them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The last two checks compared against copy->base.vtable after deleteObject had freed the copy, so they read freed memory and failed once the allocator reused the first bytes.

Co-authored-by: Danigamer05 <96824289+Danigamer05@users.noreply.github.com>
@TechLevelZero

Copy link
Copy Markdown
Contributor

❌ AMD GPU test: failed

PR head 4e7016e merged onto main 813f46c · tested 2026-11-05 20:28 UTC · 46 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ❌ 3,978 passed · 18 failed (1 new: 1 not compared, 14 also fail on main, 3 unstable on main) · 71 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 4,067 of 4,097 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (1409 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.4 s, ⚠️ agc_driver_graphics_maps_fallback 113.9 s, ⚠️ agc_driver_graphics 112.0 s, ⚠️ public_headers 63.0 s, ⚠️ agc_graphics_profile_draw 60.2 s

Failing tests

This PR changes test files, so each failing test was also built and run on main with only the PR's test changes applied. ✅ there means the failure comes from the PR's other changes; ❌ means the test fails on main too, so this run does not show the PR caused it.

Test With this PR Same test on main 813f46c (main + this PR's test changes only)
guest_sce_v2_locimp_references ❌ failed not compared: test not defined on main with the PR's test changes
guest_sce_v2_locimp_references: Failed (also failed when re-run alone), assertion and diagnostics
ctest: Failed

2 failures
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_array_layer_target_cpu: failed in 2 of the last 10 main runs
agc_driver_job_manager_compute_capacity: failed in 9 of the last 10 main runs
agc_driver_two_sample_alpha_to_coverage_sample_mask_export: failed in 6 of the last 10 main runs
Failing on main too (14, not counted against this PR)
agc_driver_alpha_to_coverage_sample_mask_export
agc_driver_guest_memory_lifetime_direct
agc_driver_image_table
agc_driver_native_depth_bda_clear
agc_driver_native_depth_buffer_clear
agc_driver_native_depth_clears
agc_driver_native_multisample_depth
agc_driver_pipeline_journal
agc_driver_submit_progress
agc_graphics_profile_draw
agc_submit_progress
agc_submit_progress_no_timeline
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (1, not in the main baseline's validation pass)
guest_sce_v2_locimp_references
Validation IDs already present on main (4 IDs in 808 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (808 tests): agc_compute_pipeline_replay, agc_driver, agc_driver_address_draw_space_reuse, agc_driver_address_draw_space_reuse_held, agc_driver_address_draw_space_reuse_off, agc_driver_address_draw_space_reuse_transitions, agc_driver_address_draw_space_reuse_verify, agc_driver_address_passes, and 800 more
VUID-vkCmdCopyImage-srcImage-01548 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store_image_copy, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_plane_partially_unmapped_plane, agc_driver_depth_plane_unmapped_plane, and 3 more
VUID-vkCmdCopyImage-srcImage-01551 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store_image_copy, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_plane_partially_unmapped_plane, agc_driver_depth_plane_unmapped_plane, and 3 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
Skipped (71)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_copied_writer_label_order_drain: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_float16_unused_nan_payloads: skipped, the device has no native f16 conversions with RTE rounding and kept f16 denormals
agc_driver_gcn_display_present: skipped, no display: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
agc_driver_image_table_vouched_lookups: skipped, the device reports 4 of 4 host-imported pages written after a GPU read, so a watched imported table cannot be vouched for
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_recorded_draw_staging: skipped, the device does not keep host imports write-watched, so the target is never resident
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_unit_shadow: skipped, the device does not import watched host memory for unit shadows
agc_driver_unit_shadow_budget: skipped, the device does not import watched host memory for unit shadows
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_idle_publish_wait: skipped, the device reports 4 of 4 host-imported pages written after a GPU read, so a forced watch of the import reads its submissions as CPU stores
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_shadowed_key_stores: skipped, the device imports no watched host memory under a unit shadow
agc_small_tiled_shadow_label: skipped, host imports are unavailable: the test block is not imported and watched
agc_storage_clear_hand_over: skipped, the device imports no watched host memory for the clear-key hand-over
agc_storage_pending_key_refresh: skipped, refreshes over a pending key store are not testable here
agc_unit_shadow: skipped, the device does not import watched host memory for unit shadows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_net_ctl_disconnected: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_device_capability: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_host_resolution_disabled: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROL
Reproduce
git fetch origin 4e7016e6926d6cb2d41de9956b004d9e4308ecf1 813f46cd685f49aafa9ccac7ca7d65b9179b4974
git checkout 813f46cd685f49aafa9ccac7ca7d65b9179b4974 && git merge --no-ff 4e7016e6926d6cb2d41de9956b004d9e4308ecf1
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1
# the failing tests, on this merge and on main:
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(guest_sce_v2_locimp_references)$' --parallel 1 -V

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Hi @Danigamer05, the new locimp-references test failed on Linux: the last two checks (_New_Locimp(bool) and empty() use the owning vtable) read copy->base.vtable after deleteObject had already freed copy, so they compared against freed memory. I pushed a small fix-up that saves the vtable pointer before the free; with it all three guest_sce_v2_loc* tests pass here. No change to the library code.

@Danigamer05

Copy link
Copy Markdown
Contributor Author

Thanks for the fix-up, I also carried it into #16178.

@oneandonlydean
oneandonlydean merged commit 65ad958 into boykopovar:main Nov 6, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants