mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Serialize: Clear pointer maps and sets right after deleting their values
DoMap and DoSet cleared them, but only once the count had been read. A state truncated right there left the deleted pointers in place, to be freed again when the failed load reset the game. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
937c100af8
commit
7ad9a64cf4
2 files changed
+10
-6
No files matched your search
@@ -29,8 +29,6 @@ void DoMap(PointerWrap &p, M &x, typename M::mapped_type &default_val) {
|
||||
switch (p.mode) {
|
||||
case PointerWrap::MODE_READ:
|
||||
{
|
||||
// Clear before the guard below can bail out: for a map of pointers, our caller has
|
||||
// already deleted every value, so leaving them in place would be a use-after-free.
|
||||
x.clear();
|
||||
// Guard against an attacker-controlled count driving an enormous number of
|
||||
// loop iterations/allocations, same spirit as DoVector's guard.
|
||||
@@ -74,6 +72,8 @@ void Do(PointerWrap &p, std::map<K, T *> &x) {
|
||||
for (auto &iter : x) {
|
||||
delete iter.second;
|
||||
}
|
||||
// Right away: if reading the count fails, DoMap won't get as far as clearing.
|
||||
x.clear();
|
||||
}
|
||||
T *dv = nullptr;
|
||||
DoMap(p, x, dv);
|
||||
@@ -91,6 +91,8 @@ void Do(PointerWrap &p, std::unordered_map<K, T *> &x) {
|
||||
for (auto &iter : x) {
|
||||
delete iter.second;
|
||||
}
|
||||
// Right away: if reading the count fails, DoMap won't get as far as clearing.
|
||||
x.clear();
|
||||
}
|
||||
T *dv = nullptr;
|
||||
DoMap(p, x, dv);
|
||||
@@ -109,8 +111,6 @@ void DoMultimap(PointerWrap &p, M &x, typename M::mapped_type &default_val) {
|
||||
switch (p.mode) {
|
||||
case PointerWrap::MODE_READ:
|
||||
{
|
||||
// Clear before the guard below can bail out: for a map of pointers, our caller has
|
||||
// already deleted every value, so leaving them in place would be a use-after-free.
|
||||
x.clear();
|
||||
// Guard against an attacker-controlled count driving an enormous number of
|
||||
// loop iterations/allocations, same spirit as DoVector's guard.
|
||||
@@ -153,6 +153,8 @@ void Do(PointerWrap &p, std::multimap<K, T *> &x) {
|
||||
for (auto &iter : x) {
|
||||
delete iter.second;
|
||||
}
|
||||
// Right away: if reading the count fails, DoMap won't get as far as clearing.
|
||||
x.clear();
|
||||
}
|
||||
T *dv = nullptr;
|
||||
DoMultimap(p, x, dv);
|
||||
@@ -170,6 +172,8 @@ void Do(PointerWrap &p, std::unordered_multimap<K, T *> &x) {
|
||||
for (auto &iter : x) {
|
||||
delete iter.second;
|
||||
}
|
||||
// Right away: if reading the count fails, DoMap won't get as far as clearing.
|
||||
x.clear();
|
||||
}
|
||||
T *dv = nullptr;
|
||||
DoMultimap(p, x, dv);
|
||||
|
||||
@@ -29,8 +29,6 @@ void DoSet(PointerWrap &p, std::set<T> &x) {
|
||||
switch (p.mode) {
|
||||
case PointerWrap::MODE_READ:
|
||||
{
|
||||
// Clear before the guard below can bail out: for a set of pointers, our caller has
|
||||
// already deleted every element, so leaving them in place would be a use-after-free.
|
||||
x.clear();
|
||||
// Guard against an attacker-controlled count driving an enormous number of
|
||||
// loop iterations/allocations, same spirit as DoVector's guard.
|
||||
@@ -65,6 +63,8 @@ void Do(PointerWrap &p, std::set<T *> &x) {
|
||||
for (T *s : x) {
|
||||
delete s;
|
||||
}
|
||||
// Right away: if reading the count fails, DoSet won't get as far as clearing.
|
||||
x.clear();
|
||||
}
|
||||
DoSet(p, x);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user