Bah.  When I originally wrote this patch, I used a test program and not
the (much) larger (by at least an order of magnitude) program I'm
normally working on.  As such, I didn't discover this bug until I tried
to run my larger program against an SDL_Perl with the patch I provided. 
The patch attached to this email supersedes the patch I sent in the
email with message-id <[EMAIL PROTECTED]>.

The only change between the previous patch I sent and this one is that
the FreeSurface function won't try to operate on NULL pointers.  I
didn't know perl is in the habit of passing NULLs to this function for
some odd reason and both perl's Safefree (which I finally tracked down
to being really Perl_mfree) and SDL_FreeSurface are no-ops if NULL
pointers are passed.

There is still a possible bug if SDL_FreeSurface detects that the
refcount for the surface is greater than one (and then doesn't actually
free the surface) and the surface was created with pre-allocated pixel
memory, which the FreeSurface function will then free.  After this,
hijinks will ensue if the surface is then used again.  But a cursory
examination of the libSDL source to determine where the refcount of a
surface in could be greater than one was fruitless, so I'm forgetting
about this as a possible problem.  It would be cool, had one really felt
the need to fix this, if SDL_FreeSurface returned something other than
void so you could determine if it actually did some free'ing or not
(rather than having to peek at the refcount field in the SDL_Surface
structure), but I digress.

diff -Naur SDL_Perl-2.1.0/src/SDL.xs SDL_Perl-2.1.0-memleak/src/SDL.xs
--- SDL_Perl-2.1.0/src/SDL.xs	2004-03-25 01:41:23.000000000 -0600
+++ SDL_Perl-2.1.0-memleak/src/SDL.xs	2004-07-05 03:06:45.856441242 -0500
@@ -745,7 +745,11 @@
 	Uint32 Bmask
 	Uint32 Amask
 	CODE:
-		RETVAL = SDL_CreateRGBSurfaceFrom ( pixels, width, height,
+		Uint8* newpixels;
+		Uint32 size = pitch * height;
+		New(0, newpixels, size, Uint8);
+		Copy(pixels, newpixels, size, Uint8);
+		RETVAL = SDL_CreateRGBSurfaceFrom ( newpixels, width, height,
 				depth, pitch, Rmask, Gmask, Bmask, Amask );
 	OUTPUT:	
 		RETVAL
@@ -767,10 +771,9 @@
 	SDL_Surface *surface
 	CODE:
 		Uint8* pixels;
-		Uint32 size = surface->pitch * surface->format->BytesPerPixel*
-				surface->h;
-		pixels = (Uint8*)safemalloc(size);
-		memcpy(pixels,surface->pixels,size);
+		Uint32 size = surface->pitch * surface->h;
+		New(0, pixels, size, Uint8);
+		Copy(surface->pixels, pixels, size, Uint8);
 		RETVAL = SDL_CreateRGBSurfaceFrom(pixels,surface->w,surface->h,
 			surface->format->BitsPerPixel, surface->pitch,
 			surface->format->Rmask, surface->format->Gmask,
@@ -782,7 +785,13 @@
 FreeSurface ( surface )
 	SDL_Surface *surface
 	CODE:
-		SDL_FreeSurface(surface);
+		if (surface) {
+			Uint8* pixels = surface->pixels;
+			Uint32 flags = surface->flags;
+			SDL_FreeSurface(surface);
+			if (flags & SDL_PREALLOC)
+				Safefree(pixels);
+		}
 	
 Uint32
 SurfaceFlags ( surface )

Reply via email to