From 201670ec0a3324fd959acf6dadda51bd8041b3f8 Mon Sep 17 00:00:00 2001
From: David Gow <[EMAIL REDACTED]>
Date: Wed, 9 Mar 2022 21:29:50 +0800
Subject: [PATCH] Handle SDL12_Surface::refcount in SDL_FreeSurface
SDL_Surface has a refcount field, and surfaces shouldn't be destroyed
until it's zero.
Confusingly, in sdl12-compat, there are two refcount fields: one for the
SDL 1.2 surface, and one for the SDL 2.0 surface used to implement it.
There are two ways this could be implemented:
1) Keep the SDL12_Surface and SDL20_Surface refcounts synchronised
across every call into SDL2.
2) Completely separate the refcounts.
This implements option 2: the SDL12_Surface's refcount is set to 1 when
created, not to be equal to the SDL2 surface's refcount. We then
decrement this and free it as required.
This is safe for two reasons:
- As long as the 1.2 surface's refcount is > 0, there must be at least
one reference to the 2.0 surface.
- It turns out nothing in SDL 2 is actually using the SDL 2 surface
refcount.
This makes "frogatto"[1] not crash on startup with a double-free of
SDL_Surfaces, as it makes heavy use of the SDL 1.2 refcount field[2].
[1]: https://frogatto.com/download/
[2]: https://github.com/frogatto/frogatto/blob/1.2_stable/src/surface.hpp
---
src/SDL12_compat.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index 733ece6..3677856 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -4325,6 +4325,9 @@ DECLSPEC void SDLCALL
SDL_FreeSurface(SDL12_Surface *surface12)
{
if (surface12 && (surface12 != VideoSurface12)) {
+ surface12->refcount--;
+ if (surface12->refcount)
+ return;
SDL20_FreeSurface(surface12->surface20);
if (surface12->format) {
SDL20_free(surface12->format->palette);