CNA-BUG-154: A save container titled GamerServices shares its directory with the gamer-services store, so DeleteContainer("GamerServices") deletes local achievements and leaderboards

CNA snapshot 009d40f5  ·  Known Issues › Current bugs  ·  source links pinned to 009d40f5

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

The gamer-services store lives at <root>/GamerServices, where a StorageContainer titled GamerServices is also created, so deleting that title removes every persisted achievement and leaderboard entry.

Identifier
CNA-BUG-154
Category
Bug
Subsystem
Storage
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Severity
Low (a triage suggestion, not a project priority)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
StorageDevice::DeleteContainer(const std::string& titleName) and BeginOpenContainer/EndOpenContainer with the title GamerServices; the gamer-services local store under StorageDevice::GetStorageRootEXT()

Expected behaviour

A game's save containers and CNA's own gamer-services persistence are separate things: deleting a save title removes that title's saves, which is what DeleteContainer documents ("Removes the container directory tree for the given title name entirely").

Actual behaviour at TARGET

StoreRoot() in LocalGamerServicesStore.cpp is PathFromUtf8(StorageDevice::GetStorageRootEXT()) / "GamerServices", with achievements/ and leaderboards/ below it. A container titled GamerServices is created at <root>/GamerServices/AllPlayers (or PlayerN). DeleteContainer("GamerServices") passes the containment check, since the title is a non-root child of the root, and remove_alls <root>/GamerServices, achievements and leaderboards included. Opening such a container also puts the game's saves inside CNA's store directory. Nothing reserves the name.

Source locations

Evidence

Checked by reading LocalGamerServicesStore.cpp, StorageDevice.cpp and StorageContainer.cpp at 009d40f5; not executed. The storage internals page records the collision.

Focused reproduction

// Illustrative; not compiled or run for this entry.
StorageDevice::SetAppNameEXT("MyGame");
gamer->AwardAchievement("first_boss");        // <root>/GamerServices/achievements/...
device->DeleteContainer("GamerServices");     // removes <root>/GamerServices entirely
auto earned = gamer->GetAchievements();       // empty

Current tests

None: the storage fixture and the gamer-services fixture use different application names (CnaTestsContent002StorageDevice and CnaTestsGamerServices), so they never share a root.

Regression test

Award an achievement, call DeleteContainer("GamerServices"), and expect either a refusal or the achievement to survive. Moving the store below a reserved dot-directory (the isolated-storage coupling already uses .cna_isolated_storage) or rejecting the title would satisfy it.

Blast radius

Games whose save titles can be GamerServices (user-entered titles, or a title chosen by coincidence): one delete wipes local achievements and leaderboards. Every other title is unaffected.

Workaround

Do not use GamerServices as a container title, and filter it out of user-entered titles.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Known issues
Bug index