src/video/windx5/SDL_dx5yuv.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 12 Nov 2008 17:23:40 +0000
branchSDL-1.2
changeset 4158 96ce26f24b01
parent 1643 51038e80ae59
child 4159 a1b03ba2fcd0
permissions -rw-r--r--
Date: Sun, 7 Sep 2008 15:17:00 +0200
From: c2woody@gmx.net
Subject: [SDL] SDL 1.2 doube free/pointer zeroing missing

Hello,

this is about a crash/debug breakage for the current SDL 1.2
source tree (today's svn checkout, same problem in 1.2.13 and
before as far as relevant).
In some places memory is free()d but the associated pointer
is not zeroed, leading to for example double free()s.

For me this happened because SDL_StopEventThread() was executed
twice (during restart of the subsystems), once for the close
down in SDL_VideoQuit() and once at the startup, right at the
beginning of SDL_StartEventLoop(). Thus the code
SDL_DestroyMutex(SDL_EventQ.lock);
(see SDL_events.c) was called twice and executed the SDL_free(mutex);
twice as well, leading to a crash (msvc 64bit for which it was noticed).

I've tried to check all other occurrences of SDL_free and similar
code in msvc, see the attached patch (udiff against revision 4082).
Non-windows only codepaths have neither been checked nor touched.

Comments/ideas welcome.

Attached patch: NULLifies some pointers after they have been free()d.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* This is the DirectDraw implementation of YUV video overlays */
    25 
    26 #include "SDL_video.h"
    27 #include "SDL_dx5yuv_c.h"
    28 #include "../SDL_yuvfuncs.h"
    29 
    30 //#define USE_DIRECTX_OVERLAY
    31 
    32 /* The functions used to manipulate software video overlays */
    33 static struct private_yuvhwfuncs dx5_yuvfuncs = {
    34 	DX5_LockYUVOverlay,
    35 	DX5_UnlockYUVOverlay,
    36 	DX5_DisplayYUVOverlay,
    37 	DX5_FreeYUVOverlay
    38 };
    39 
    40 struct private_yuvhwdata {
    41 	LPDIRECTDRAWSURFACE3 surface;
    42 
    43 	/* These are just so we don't have to allocate them separately */
    44 	Uint16 pitches[3];
    45 	Uint8 *planes[3];
    46 };
    47 
    48 
    49 static LPDIRECTDRAWSURFACE3 CreateYUVSurface(_THIS,
    50                                          int width, int height, Uint32 format)
    51 {
    52 	HRESULT result;
    53 	LPDIRECTDRAWSURFACE  dd_surface1;
    54 	LPDIRECTDRAWSURFACE3 dd_surface3;
    55 	DDSURFACEDESC ddsd;
    56 
    57 	/* Set up the surface description */
    58 	SDL_memset(&ddsd, 0, sizeof(ddsd));
    59 	ddsd.dwSize = sizeof(ddsd);
    60 	ddsd.dwFlags = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT);
    61 	ddsd.dwWidth = width;
    62 	ddsd.dwHeight= height;
    63 #ifdef USE_DIRECTX_OVERLAY
    64 	ddsd.ddsCaps.dwCaps = (DDSCAPS_OVERLAY|DDSCAPS_VIDEOMEMORY);
    65 #else
    66 	ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN|DDSCAPS_VIDEOMEMORY);
    67 #endif
    68 	ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
    69 	ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
    70 	ddsd.ddpfPixelFormat.dwFourCC = format;
    71 
    72 	/* Create the DirectDraw video surface */
    73 	result = IDirectDraw2_CreateSurface(ddraw2, &ddsd, &dd_surface1, NULL); 
    74 	if ( result != DD_OK ) {
    75 		SetDDerror("DirectDraw2::CreateSurface", result);
    76 		return(NULL);
    77 	}
    78 	result = IDirectDrawSurface_QueryInterface(dd_surface1,
    79 			&IID_IDirectDrawSurface3, (LPVOID *)&dd_surface3);
    80 	IDirectDrawSurface_Release(dd_surface1);
    81 	if ( result != DD_OK ) {
    82 		SetDDerror("DirectDrawSurface::QueryInterface", result);
    83 		return(NULL);
    84 	}
    85 
    86 	/* Make sure the surface format was set properly */
    87 	SDL_memset(&ddsd, 0, sizeof(ddsd));
    88 	ddsd.dwSize = sizeof(ddsd);
    89 	result = IDirectDrawSurface3_Lock(dd_surface3, NULL,
    90 					  &ddsd, DDLOCK_NOSYSLOCK, NULL);
    91 	if ( result != DD_OK ) {
    92 		SetDDerror("DirectDrawSurface3::Lock", result);
    93 		IDirectDrawSurface_Release(dd_surface3);
    94 		return(NULL);
    95 	}
    96 	IDirectDrawSurface3_Unlock(dd_surface3, NULL);
    97 
    98 	if ( !(ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC) ||
    99 	      (ddsd.ddpfPixelFormat.dwFourCC != format) ) {
   100 		SDL_SetError("DDraw didn't use requested FourCC format");
   101 		IDirectDrawSurface_Release(dd_surface3);
   102 		return(NULL);
   103 	}
   104 
   105 	/* We're ready to go! */
   106 	return(dd_surface3);
   107 }
   108 
   109 #ifdef DEBUG_YUV
   110 static char *PrintFOURCC(Uint32 code)
   111 {
   112 	static char buf[5];
   113 
   114 	buf[3] = code >> 24;
   115 	buf[2] = (code >> 16) & 0xFF;
   116 	buf[1] = (code >> 8) & 0xFF;
   117 	buf[0] = (code & 0xFF);
   118 	return(buf);
   119 }
   120 #endif
   121 
   122 SDL_Overlay *DX5_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display)
   123 {
   124 	SDL_Overlay *overlay;
   125 	struct private_yuvhwdata *hwdata;
   126 
   127 #ifdef DEBUG_YUV
   128 	DWORD numcodes;
   129 	DWORD *codes;
   130 
   131 	printf("FOURCC format requested: 0x%x\n", PrintFOURCC(format));
   132 	IDirectDraw2_GetFourCCCodes(ddraw2, &numcodes, NULL);
   133 	if ( numcodes ) {
   134 		DWORD i;
   135 		codes = SDL_malloc(numcodes*sizeof(*codes));
   136 		if ( codes ) {
   137 			IDirectDraw2_GetFourCCCodes(ddraw2, &numcodes, codes);
   138 			for ( i=0; i<numcodes; ++i ) {
   139 				fprintf(stderr, "Code %d: 0x%x\n", i, PrintFOURCC(codes[i]));
   140 			}
   141 			SDL_free(codes);
   142 		}
   143 	} else {
   144 		fprintf(stderr, "No FOURCC codes supported\n");
   145 	}
   146 #endif
   147 
   148 	/* Create the overlay structure */
   149 	overlay = (SDL_Overlay *)SDL_malloc(sizeof *overlay);
   150 	if ( overlay == NULL ) {
   151 		SDL_OutOfMemory();
   152 		return(NULL);
   153 	}
   154 	SDL_memset(overlay, 0, (sizeof *overlay));
   155 
   156 	/* Fill in the basic members */
   157 	overlay->format = format;
   158 	overlay->w = width;
   159 	overlay->h = height;
   160 
   161 	/* Set up the YUV surface function structure */
   162 	overlay->hwfuncs = &dx5_yuvfuncs;
   163 
   164 	/* Create the pixel data and lookup tables */
   165 	hwdata = (struct private_yuvhwdata *)SDL_malloc(sizeof *hwdata);
   166 	overlay->hwdata = hwdata;
   167 	if ( hwdata == NULL ) {
   168 		SDL_OutOfMemory();
   169 		SDL_FreeYUVOverlay(overlay);
   170 		return(NULL);
   171 	}
   172 	hwdata->surface = CreateYUVSurface(this, width, height, format);
   173 	if ( hwdata->surface == NULL ) {
   174 		SDL_FreeYUVOverlay(overlay);
   175 		return(NULL);
   176 	}
   177 	overlay->hw_overlay = 1;
   178 
   179 	/* Set up the plane pointers */
   180 	overlay->pitches = hwdata->pitches;
   181 	overlay->pixels = hwdata->planes;
   182 	switch (format) {
   183 	    case SDL_YV12_OVERLAY:
   184 	    case SDL_IYUV_OVERLAY:
   185 		overlay->planes = 3;
   186 		break;
   187 	    default:
   188 		overlay->planes = 1;
   189 		break;
   190 	}
   191 
   192 	/* We're all done.. */
   193 	return(overlay);
   194 }
   195 
   196 int DX5_LockYUVOverlay(_THIS, SDL_Overlay *overlay)
   197 {
   198 	HRESULT result;
   199 	LPDIRECTDRAWSURFACE3 surface;
   200 	DDSURFACEDESC ddsd;
   201 
   202 	surface = overlay->hwdata->surface;
   203 	SDL_memset(&ddsd, 0, sizeof(ddsd));
   204 	ddsd.dwSize = sizeof(ddsd);
   205 	result = IDirectDrawSurface3_Lock(surface, NULL,
   206 					  &ddsd, DDLOCK_NOSYSLOCK, NULL);
   207 	if ( result == DDERR_SURFACELOST ) {
   208 		result = IDirectDrawSurface3_Restore(surface);
   209 		result = IDirectDrawSurface3_Lock(surface, NULL, &ddsd, 
   210 					(DDLOCK_NOSYSLOCK|DDLOCK_WAIT), NULL);
   211 	}
   212 	if ( result != DD_OK ) {
   213 		SetDDerror("DirectDrawSurface3::Lock", result);
   214 		return(-1);
   215 	}
   216 
   217 	/* Find the pitch and offset values for the overlay */
   218 #if defined(NONAMELESSUNION)
   219 	overlay->pitches[0] = (Uint16)ddsd.u1.lPitch;
   220 #else
   221 	overlay->pitches[0] = (Uint16)ddsd.lPitch;
   222 #endif
   223 	overlay->pixels[0] = (Uint8 *)ddsd.lpSurface;
   224 	switch (overlay->format) {
   225 	    case SDL_YV12_OVERLAY:
   226 	    case SDL_IYUV_OVERLAY:
   227 		/* Add the two extra planes */
   228 		overlay->pitches[1] = overlay->pitches[0] / 2;
   229 		overlay->pitches[2] = overlay->pitches[0] / 2;
   230 	        overlay->pixels[1] = overlay->pixels[0] +
   231 		                     overlay->pitches[0] * overlay->h;
   232 	        overlay->pixels[2] = overlay->pixels[1] +
   233 		                     overlay->pitches[1] * overlay->h / 2;
   234 	        break;
   235 	    default:
   236 		/* Only one plane, no worries */
   237 		break;
   238 	}
   239 	return(0);
   240 }
   241 
   242 void DX5_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay)
   243 {
   244 	LPDIRECTDRAWSURFACE3 surface;
   245 
   246 	surface = overlay->hwdata->surface;
   247 	IDirectDrawSurface3_Unlock(surface, NULL);
   248 }
   249 
   250 int DX5_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst)
   251 {
   252 	HRESULT result;
   253 	LPDIRECTDRAWSURFACE3 surface;
   254 	RECT srcrect, dstrect;
   255 
   256 	surface = overlay->hwdata->surface;
   257 	srcrect.top = src->y;
   258 	srcrect.bottom = srcrect.top+src->h;
   259 	srcrect.left = src->x;
   260 	srcrect.right = srcrect.left+src->w;
   261 	dstrect.top = SDL_bounds.top+dst->y;
   262 	dstrect.left = SDL_bounds.left+dst->x;
   263 	dstrect.bottom = dstrect.top+dst->h;
   264 	dstrect.right = dstrect.left+dst->w;
   265 #ifdef USE_DIRECTX_OVERLAY
   266 	result = IDirectDrawSurface3_UpdateOverlay(surface, &srcrect,
   267 				SDL_primary, &dstrect, DDOVER_SHOW, NULL);
   268 	if ( result != DD_OK ) {
   269 		SetDDerror("DirectDrawSurface3::UpdateOverlay", result);
   270 		return(-1);
   271 	}
   272 #else
   273 	result = IDirectDrawSurface3_Blt(SDL_primary, &dstrect, surface, &srcrect,
   274 							DDBLT_WAIT, NULL);
   275 	if ( result != DD_OK ) {
   276 		SetDDerror("DirectDrawSurface3::Blt", result);
   277 		return(-1);
   278 	}
   279 #endif
   280 	return(0);
   281 }
   282 
   283 void DX5_FreeYUVOverlay(_THIS, SDL_Overlay *overlay)
   284 {
   285 	struct private_yuvhwdata *hwdata;
   286 
   287 	hwdata = overlay->hwdata;
   288 	if ( hwdata ) {
   289 		if ( hwdata->surface ) {
   290 			IDirectDrawSurface_Release(hwdata->surface);
   291 		}
   292 		SDL_free(hwdata);
   293 		overlay->hwdata = NULL;
   294 	}
   295 }
   296