src/video/mir/SDL_mirwindow.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Jul 2014 10:33:32 -0700
changeset 8978 7753e4fd3d1d
parent 8753 497e72bba21b
child 9185 43f4122e1268
permissions -rw-r--r--
Fixed bug 2629 - Mac: crash when calling SDL_DestroyWindow with an active OpenGL context

Alex Szpakowski

Since this commit https://hg.libsdl.org/SDL/rev/1519c462cee6 , calling SDL_DestroyWindow will crash the program if the window has an active OpenGL context.

This is because the Cocoa_DestroyWindow code sets the window's driverdata to NULL and then calls [context setWindow:NULL], which tries to access the window's driverdata, resulting in a null pointer dereference.

I have attached a patch which fixes the issue by moving the line which sets the driverdata to NULL to after the lines which call functions that use the driverdata pointer.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /*
    23   Contributed by Brandon Schaefer, <brandon.schaefer@canonical.com>
    24 */
    25 
    26 #include "../../SDL_internal.h"
    27 
    28 #if SDL_VIDEO_DRIVER_MIR
    29 
    30 #include "../SDL_egl_c.h"
    31 #include "../SDL_sysvideo.h"
    32 
    33 #include "SDL_mirevents.h"
    34 #include "SDL_mirwindow.h"
    35 
    36 #include "SDL_mirdyn.h"
    37 
    38 int
    39 IsSurfaceValid(MIR_Window* mir_window)
    40 {
    41     if (!MIR_mir_surface_is_valid(mir_window->surface)) {
    42         const char* error = MIR_mir_surface_get_error_message(mir_window->surface);
    43         return SDL_SetError("Failed to created a mir surface: %s", error);
    44     }
    45 
    46     return 0;
    47 }
    48 
    49 MirPixelFormat
    50 FindValidPixelFormat(MIR_Data* mir_data)
    51 {
    52     unsigned int pf_size = 32;
    53     unsigned int valid_formats;
    54     unsigned int f;
    55 
    56     MirPixelFormat formats[pf_size];
    57     MIR_mir_connection_get_available_surface_formats(mir_data->connection, formats,
    58                                                  pf_size, &valid_formats);
    59 
    60     for (f = 0; f < valid_formats; f++) {
    61         MirPixelFormat cur_pf = formats[f];
    62 
    63         if (cur_pf == mir_pixel_format_abgr_8888 ||
    64             cur_pf == mir_pixel_format_xbgr_8888 ||
    65             cur_pf == mir_pixel_format_argb_8888 ||
    66             cur_pf == mir_pixel_format_xrgb_8888) {
    67 
    68             return cur_pf;
    69         }
    70     }
    71 
    72     return mir_pixel_format_invalid;
    73 }
    74 
    75 int
    76 MIR_CreateWindow(_THIS, SDL_Window* window)
    77 {
    78     MIR_Window* mir_window;
    79     MIR_Data* mir_data;
    80 
    81     MirSurfaceParameters surfaceparm =
    82     {
    83         .name = "MirSurface",
    84         .width = window->w,
    85         .height = window->h,
    86         .pixel_format = mir_pixel_format_invalid,
    87         .buffer_usage = mir_buffer_usage_hardware,
    88         .output_id = mir_display_output_id_invalid
    89     };
    90 
    91     MirEventDelegate delegate = {
    92         MIR_HandleInput,
    93         window
    94     };
    95 
    96     mir_window = SDL_calloc(1, sizeof(MIR_Window));
    97     if (!mir_window)
    98         return SDL_OutOfMemory();
    99 
   100     mir_data = _this->driverdata;
   101     window->driverdata = mir_window;
   102 
   103     if (mir_data->software)
   104         surfaceparm.buffer_usage = mir_buffer_usage_software;
   105 
   106     if (window->x == SDL_WINDOWPOS_UNDEFINED)
   107         window->x = 0;
   108 
   109     if (window->y == SDL_WINDOWPOS_UNDEFINED)
   110         window->y = 0;
   111 
   112     mir_window->mir_data = mir_data;
   113     mir_window->sdl_window = window;
   114 
   115     surfaceparm.pixel_format = FindValidPixelFormat(mir_data);
   116     if (surfaceparm.pixel_format == mir_pixel_format_invalid) {
   117         return SDL_SetError("Failed to find a valid pixel format.");
   118     }
   119 
   120     mir_window->surface = MIR_mir_connection_create_surface_sync(mir_data->connection, &surfaceparm);
   121     if (!MIR_mir_surface_is_valid(mir_window->surface)) {
   122         const char* error = MIR_mir_surface_get_error_message(mir_window->surface);
   123         return SDL_SetError("Failed to created a mir surface: %s", error);
   124     }
   125 
   126     if (window->flags & SDL_WINDOW_OPENGL) {
   127         EGLNativeWindowType egl_native_window =
   128                         (EGLNativeWindowType)MIR_mir_surface_get_egl_native_window(mir_window->surface);
   129 
   130         mir_window->egl_surface = SDL_EGL_CreateSurface(_this, egl_native_window);
   131 
   132         if (mir_window->egl_surface == EGL_NO_SURFACE) {
   133             return SDL_SetError("Failed to created a window surface %p",
   134                                 _this->egl_data->egl_display);
   135         }
   136     }
   137     else {
   138         mir_window->egl_surface = EGL_NO_SURFACE;
   139     }
   140 
   141     MIR_mir_surface_set_event_handler(mir_window->surface, &delegate);
   142 
   143     return 0;
   144 }
   145 
   146 void
   147 MIR_DestroyWindow(_THIS, SDL_Window* window)
   148 {
   149     MIR_Data* mir_data = _this->driverdata;
   150     MIR_Window* mir_window = window->driverdata;
   151 
   152     if (mir_data) {
   153         SDL_EGL_DestroySurface(_this, mir_window->egl_surface);
   154         MIR_mir_surface_release_sync(mir_window->surface);
   155 
   156         SDL_free(mir_window);
   157     }
   158     window->driverdata = NULL;
   159 }
   160 
   161 SDL_bool
   162 MIR_GetWindowWMInfo(_THIS, SDL_Window* window, SDL_SysWMinfo* info)
   163 {
   164     if (info->version.major == SDL_MAJOR_VERSION &&
   165         info->version.minor == SDL_MINOR_VERSION) {
   166         MIR_Window* mir_window = window->driverdata;
   167 
   168         info->subsystem = SDL_SYSWM_MIR;
   169         info->info.mir.connection = mir_window->mir_data->connection;
   170         info->info.mir.surface = mir_window->surface;
   171 
   172         return SDL_TRUE;
   173     }
   174 
   175     return SDL_FALSE;
   176 }
   177 
   178 void
   179 MIR_SetWindowFullscreen(_THIS, SDL_Window* window,
   180                         SDL_VideoDisplay* display,
   181                         SDL_bool fullscreen)
   182 {
   183     MIR_Window* mir_window = window->driverdata;
   184 
   185     if (IsSurfaceValid(mir_window) < 0)
   186         return;
   187 
   188     if (fullscreen) {
   189         MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_fullscreen);
   190     } else {
   191         MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_restored);
   192     }
   193 }
   194 
   195 void
   196 MIR_MaximizeWindow(_THIS, SDL_Window* window)
   197 {
   198     MIR_Window* mir_window = window->driverdata;
   199 
   200     if (IsSurfaceValid(mir_window) < 0)
   201         return;
   202 
   203     MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_maximized);
   204 }
   205 
   206 void
   207 MIR_MinimizeWindow(_THIS, SDL_Window* window)
   208 {
   209     MIR_Window* mir_window = window->driverdata;
   210 
   211     if (IsSurfaceValid(mir_window) < 0)
   212         return;
   213 
   214     MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_minimized);
   215 }
   216 
   217 void
   218 MIR_RestoreWindow(_THIS, SDL_Window * window)
   219 {
   220     MIR_Window* mir_window = window->driverdata;
   221 
   222     if (IsSurfaceValid(mir_window) < 0)
   223         return;
   224 
   225     MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_restored);
   226 }
   227 
   228 #endif /* SDL_VIDEO_DRIVER_MIR */
   229 
   230 /* vi: set ts=4 sw=4 expandtab: */