cellSaveData: Fix FixedDelete crash and sort the save list before cutting it #19896

Open
digant73 opened 10:31pm on October 20, 2026 wants to merge 199 Ξ” into rpcs3/rpcs3 master from
cellsavedata-fixed-delete

Pull Request Overview

  • Opened on October 20, 2026
  • Status Open
  • Commit count 6 with first commit October 20, 2026

Total Delta

199 Total Diff Delta

Open Days

Open 18 weekdays

Test Delta

0 Diff Delta in Test Files
Breakdown by Phase

How long has this pull request spent in each phase of its lifecycle?

Data pending calculation for pull request

Author avatar

cellSaveData: Fix FixedDelete crash and sort the save list before cutting it

Analysis, hwtest and fixes made by Opus 5.5. Tested by me.

(confirmed by me) Fixes #18883
(supersedes) Closes #18916

Bugs
1. FixedDelete crash (#18883). RAGE deletes a save with cellSaveDataUserFixedDelete, dirNamePrefix = "" and NOCONFIRM. An empty prefix listed nothing for a delete, so the dirName chosen by funcFixed was not found and delete_save() read save_entries[-1]. Any FixedDelete of a dirName missing from the list crashed the same way.
2. Confirmation for an unlisted save. With option NONE, a save that is not in the list got "Do you want to save this data?".
3. List cut before sorting. The list was cut to dirListMax while scanning, so with more matching saves than dirListMax the game got an arbitrary subset.
4. Save sizes. Two values disagreed with the console and with funcStat:
- funcDone sizeKB: counted every file of the save, PARAM.SFO included, and left out the 35 KB that funcStat adds for the system files.
- Size shown in the list and confirmation dialogs: had the same problem, and was also divided by 1000.

For the test save (one 16-byte file) this gave 4 KB in funcDone and 3 KB in the dialogs, against 36 KB in funcStat.

Fixes (verified with a PSL1GHT test run on a PS3 and on RPCS3)
- An empty prefix lists all saves for FixedDelete too.
- A dirName that is not on disk returns CELL_SAVEDATA_ERROR_NODATA, before the confirmation and without calling funcDone.
- A dirName that is on disk but not in the list is deleted.
- With option NONE, the confirmation for an unlisted save shows its title, subtitle, date and size, as for a listed save.
- All matching saves are sorted first, then the first dirListMax are kept. Size and icon are read only for the kept entries.
- funcDone and the dialogs now compute the size as funcStat does: game files rounded up to 1 KB each, plus 35 KB, shown in KB of 1024 bytes.

Hwtest comparison

FIXED_DELETE_HWTEST.zip

β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ Case β”‚ Call / prefix / β”‚ PS3 β”‚ Upstream β”‚ This β”‚
β”‚ β”‚ dirName / option β”‚ β”‚ β”‚ PR β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C1 β”‚ Fixed, FDT, FDT-A, β”‚ deleted, CELL_OK β”‚ same β”‚ same β”‚
β”‚ β”‚ NOCONFIRM β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C2 β”‚ Fixed, "", FDT-A, β”‚ all saves listed, β”‚ empty list, crash β”‚ same β”‚
β”‚ β”‚ NOCONFIRM β”‚ deleted, CELL_OK β”‚ β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C3 β”‚ UserFixed, "", FDT-A, β”‚ as C2 β”‚ crash β”‚ same β”‚
β”‚ β”‚ NOCONFIRM β”‚ β”‚ β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C4 β”‚ Fixed, FDT, missing β”‚ ERROR_NODATA, no β”‚ crash β”‚ same β”‚
β”‚ β”‚ β”‚ funcDone β”‚ β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C5 β”‚ Fixed, "", missing β”‚ ERROR_NODATA β”‚ crash β”‚ same β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C6 β”‚ Fixed, NOMATCH, FDT-B β”‚ empty list, FDT-B β”‚ crash β”‚ same β”‚
β”‚ β”‚ on disk, NOCONFIRM β”‚ deleted, CELL_OK β”‚ β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C7 β”‚ Fixed, * β”‚ ERROR_PARAM, no β”‚ same β”‚ same β”‚
β”‚ β”‚ β”‚ funcFixed β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C8 β”‚ Fixed, "", FDT-A, β”‚ confirmation with save β”‚ crash β”‚ same β”‚
β”‚ β”‚ NONE β”‚ info, deleted β”‚ β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C9 β”‚ Fixed, FDT, missing, β”‚ ERROR_NODATA, no β”‚ confirmation, β”‚ same β”‚
β”‚ β”‚ NONE β”‚ confirmation β”‚ crash β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Fixed, NOMATCH, FDT-B β”‚ confirmation with β”‚ "save this β”‚ same β”‚
β”‚ C10 β”‚ on disk, NONE β”‚ FDT-B's info, deleted, β”‚ data?", crash β”‚ as PS3 β”‚
β”‚ β”‚ β”‚ CELL_OK β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ L1 β”‚ MODIFIEDTIME desc, β”‚ C A B D E F G β”‚ same β”‚ same β”‚
β”‚ β”‚ max 64 β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ L2 β”‚ MODIFIEDTIME desc, β”‚ C A B β”‚ directory-order β”‚ same β”‚
β”‚ β”‚ max 3 β”‚ β”‚ subset β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ L3 β”‚ SUBTITLE asc, max 64 β”‚ E D A G C B F β”‚ same β”‚ same β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ L4 β”‚ SUBTITLE asc, max 2 β”‚ E D β”‚ directory-order β”‚ same β”‚
β”‚ β”‚ β”‚ β”‚ subset β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ L5 β”‚ SUBTITLE desc, max 2 β”‚ F B β”‚ directory-order β”‚ same β”‚
β”‚ β”‚ β”‚ β”‚ subset β”‚ as PS3 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ S1 β”‚ funcStat sizeKB / β”‚ 36 / 35 β”‚ same β”‚ same β”‚
β”‚ β”‚ sysSizeKB β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ S1 β”‚ funcDone sizeKB β”‚ 36 β”‚ 4 β”‚ 36 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ S1 β”‚ size in confirmation β”‚ 36 KB β”‚ 3 KB β”‚ 36 KB β”‚
β”‚ β”‚ dialog β”‚ β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜

How the results were obtained:
- Upstream was run only up to C2, where it crashes. Its other results are read from the code, not from a run.
- The dialog sizes were read off the screen, not from the test log.

Not changed: the PS3 also shows "Deleting... / Delete completed / No saved data" notices, even with NOCONFIRM.

In game: RAGE (BLES01378) deletes a save from its menu without crashing. That in-game test was run before the size changes.

This work implements [BLJM60994] RAGE [About Save data issue] (open)

Quick summary

If you deleting save data in the game menu causes RPCS3 to crash.

Details

No response

Attach a log file

RPCS3_BLJM60994_RAGE_Crash_log.zip

Attach capture files for visual issues

Boot with default. https://github.com/user-attachments/assets/31d0ca62-0550-480b-8c36-8c03180d26c6

System configuration

RPCS3 0.0.41-19456-2ce45bd9 Alpha Windows11 Ryzen7 5800X RAM 48GB RADEON RX 9060XT

Other details

No response

No comments have been left on this PR.