File: PR306.patch

package info (click to toggle)
libsdl-perl 2.548-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,972 kB
  • sloc: perl: 13,985; ansic: 583; makefile: 35
file content (127 lines) | stat: -rw-r--r-- 3,686 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
From e9b907c08d9fcce4fccb3084ff38e65cb5c6828b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@debian.org>
Date: Tue, 18 Jul 2023 18:00:12 +0100
Subject: [PATCH] Distinguish between owned and borrowed references to a
 SDL_Surface

In many SDL APIs that return a SDL_Surface *, the surface is considered
to be owned by the caller, and must be freed by the caller.

However, SDL_SetVideoMode and presumably SDL_GetVideoSurface return
a pointer to SDL's internal video surface, which will be freed by SDL
if necessary, and must not be freed by library users.
Incorrectly freeing this surface can lead to a use-after-free crash,
manifesting as a test failure in t/core_video.t.

See also https://github.com/libsdl-org/sdl12-compat/issues/305

Resolves: https://github.com/PerlGameDev/SDL/issues/305
Signed-off-by: Simon McVittie <smcv@debian.org>

Bug-Debian: https://bugs.debian.org/1041211
Bug: https://github.com/PerlGameDev/SDL/issues/305
Origin: https://github.com/PerlGameDev/SDL/pull/306

---
 src/Core/Video.xs |  6 ++++--
 src/helper.h      |  7 ++++---
 typemap           | 23 +++++++++++++++++++++++
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/src/Core/Video.xs b/src/Core/Video.xs
index 8efa4b4a..e0d1a679 100644
--- a/src/Core/Video.xs
+++ b/src/Core/Video.xs
@@ -10,6 +10,8 @@
 
 #include <SDL.h>
 
+typedef SDL_Surface SDL_Surface_borrowed;
+
 void _uinta_free(Uint16* av, int len_from_av_len)
 {
 	if( av != NULL)
@@ -56,7 +58,7 @@ See: L<http:/*www.libsdl.org/cgi/docwiki.cgi/SDL_API#head-813f033ec44914f267f321
 
 =cut
 
-SDL_Surface *
+SDL_Surface_borrowed *
 video_get_video_surface()
 	PREINIT:
 		char* CLASS = "SDL::Surface";
@@ -125,7 +127,7 @@ video_video_mode_ok ( width, height, bpp, flags )
 		RETVAL
 
 
-SDL_Surface *
+SDL_Surface_borrowed *
 video_set_video_mode ( width, height, bpp, flags )
 	int width
 	int height
diff --git a/src/helper.h b/src/helper.h
index 1d2ee9a5..6b8e4ab5 100644
--- a/src/helper.h
+++ b/src/helper.h
@@ -58,12 +58,13 @@ void objDESTROY(SV *bag, void (* callback)(void *object))
         Uint32 *threadid = (Uint32*)(pointers[2]);
         
         if(PERL_GET_CONTEXT == pointers[1]
-        && *threadid == SDL_ThreadID())
+        && (threadid == NULL || *threadid == SDL_ThreadID()))
         {
             pointers[0] = NULL;
-            if(object)
+            if(object && threadid != NULL)
                 callback(object);
-            safefree(threadid);
+            if (threadid != NULL)
+                safefree(threadid);
             safefree(pointers);
         }
     }
diff --git a/typemap b/typemap
index c3ba997a..85a19265 100644
--- a/typemap
+++ b/typemap
@@ -34,6 +34,7 @@ SDL_UserEvent * 	O_OBJECT
 SDL_QuitEvent * 	O_OBJECT
 SDL_keysym *		O_OBJECT
 SDL_Surface *		O_OBJECT
+SDL_Surface_borrowed *	O_BORROWED
 SDL_SysWMmsg *		T_PTR
 SDL_CD *		O_OBJECT
 SDL_CDtrack *		O_OBJECT
@@ -122,6 +123,17 @@ O_OBJECT
         XSRETURN_UNDEF;
     }
 
+O_BORROWED
+    if ($var) {
+        void** pointers  = malloc(3 * sizeof(void*));
+        pointers[0]      = (void*)$var;
+        pointers[1]      = (void*)PERL_GET_CONTEXT;
+        pointers[2]      = NULL;
+        sv_setref_pv( $arg, CLASS, (void*)pointers );
+    } else {
+        XSRETURN_UNDEF;
+    }
+
 INPUT
 
 O_OBJECT_NPGC
@@ -136,3 +148,14 @@ O_OBJECT
     } else {
         XSRETURN_UNDEF;
     }
+
+O_BORROWED
+    /* Same as O_OBJECT */
+    if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
+        void** pointers = (void**)INT2PTR(void *, SvIV((SV *)SvRV( $arg )));
+        $var = ($type)(pointers[0]);
+    } else if ($arg == 0) {
+        XSRETURN(0);
+    } else {
+        XSRETURN_UNDEF;
+    }