This pull request's diff hasn't been prepared yet. Log in with GitHub to have us prepare it for review.

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
Reviewing
63 fewer changed lines
(38% less) vs GitHub
This saves about 66.5 hours per year vs conventional diff tools
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

digant73 authored
of work between October 20 and October 21
Diff Delta:
199
About 34 Diff Delta/hour
Classified as:  Bug Fix, Feature Add, General

digant73's Description of Work #18883 [BLJM60994] RAGE [About Save data issue]

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.

1 total changed file
Loading changes...
End of PR:
All files reviewed β€” nice work, champ! πŸ’ͺ