src/SDL_hints.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Wed, 29 Oct 2014 20:20:47 +0100
changeset 9201 21d9f9babb30
parent 8149 681eb46b8ac4
child 9202 01bb8e3ba14f
permissions -rw-r--r--
Fixed bug 2647 - Memory leak in SDL_AddHintCallback function - SDL_hints.c

Nitz

Variable entry going out of scope leaks the storage it points to, at:

/* Need to add a hint entry for this watcher */
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
if (!hint) {
return;
}

Patch is attached.
     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 #include "./SDL_internal.h"
    22 
    23 #include "SDL_hints.h"
    24 #include "SDL_error.h"
    25 
    26 
    27 /* Assuming there aren't many hints set and they aren't being queried in
    28    critical performance paths, we'll just use linked lists here.
    29  */
    30 typedef struct SDL_HintWatch {
    31     SDL_HintCallback callback;
    32     void *userdata;
    33     struct SDL_HintWatch *next;
    34 } SDL_HintWatch;
    35 
    36 typedef struct SDL_Hint {
    37     char *name;
    38     char *value;
    39     SDL_HintPriority priority;
    40     SDL_HintWatch *callbacks;
    41     struct SDL_Hint *next;
    42 } SDL_Hint;
    43 
    44 static SDL_Hint *SDL_hints;
    45 
    46 SDL_bool
    47 SDL_SetHintWithPriority(const char *name, const char *value,
    48                         SDL_HintPriority priority)
    49 {
    50     const char *env;
    51     SDL_Hint *hint;
    52     SDL_HintWatch *entry;
    53 
    54     if (!name || !value) {
    55         return SDL_FALSE;
    56     }
    57 
    58     env = SDL_getenv(name);
    59     if (env && priority < SDL_HINT_OVERRIDE) {
    60         return SDL_FALSE;
    61     }
    62 
    63     for (hint = SDL_hints; hint; hint = hint->next) {
    64         if (SDL_strcmp(name, hint->name) == 0) {
    65             if (priority < hint->priority) {
    66                 return SDL_FALSE;
    67             }
    68             if (!hint->value || !value || SDL_strcmp(hint->value, value) != 0) {
    69                 for (entry = hint->callbacks; entry; ) {
    70                     /* Save the next entry in case this one is deleted */
    71                     SDL_HintWatch *next = entry->next;
    72                     entry->callback(entry->userdata, name, hint->value, value);
    73                     entry = next;
    74                 }
    75                 SDL_free(hint->value);
    76                 hint->value = value ? SDL_strdup(value) : NULL;
    77             }
    78             hint->priority = priority;
    79             return SDL_TRUE;
    80         }
    81     }
    82 
    83     /* Couldn't find the hint, add a new one */
    84     hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
    85     if (!hint) {
    86         return SDL_FALSE;
    87     }
    88     hint->name = SDL_strdup(name);
    89     hint->value = value ? SDL_strdup(value) : NULL;
    90     hint->priority = priority;
    91     hint->callbacks = NULL;
    92     hint->next = SDL_hints;
    93     SDL_hints = hint;
    94     return SDL_TRUE;
    95 }
    96 
    97 SDL_bool
    98 SDL_SetHint(const char *name, const char *value)
    99 {
   100     return SDL_SetHintWithPriority(name, value, SDL_HINT_NORMAL);
   101 }
   102 
   103 const char *
   104 SDL_GetHint(const char *name)
   105 {
   106     const char *env;
   107     SDL_Hint *hint;
   108 
   109     env = SDL_getenv(name);
   110     for (hint = SDL_hints; hint; hint = hint->next) {
   111         if (SDL_strcmp(name, hint->name) == 0) {
   112             if (!env || hint->priority == SDL_HINT_OVERRIDE) {
   113                 return hint->value;
   114             }
   115             break;
   116         }
   117     }
   118     return env;
   119 }
   120 
   121 void
   122 SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
   123 {
   124     SDL_Hint *hint;
   125     SDL_HintWatch *entry;
   126     const char *value;
   127 
   128     if (!name || !*name) {
   129         SDL_InvalidParamError("name");
   130         return;
   131     }
   132     if (!callback) {
   133         SDL_InvalidParamError("callback");
   134         return;
   135     }
   136 
   137     SDL_DelHintCallback(name, callback, userdata);
   138 
   139     entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry));
   140     entry->callback = callback;
   141     entry->userdata = userdata;
   142 
   143     for (hint = SDL_hints; hint; hint = hint->next) {
   144         if (SDL_strcmp(name, hint->name) == 0) {
   145             break;
   146         }
   147     }
   148     if (!hint) {
   149         /* Need to add a hint entry for this watcher */
   150         hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
   151         if (!hint) {
   152             if(entry)
   153             {
   154               SDL_free(entry);
   155               entry = NULL;
   156             }
   157             return;
   158         }
   159         hint->name = SDL_strdup(name);
   160         hint->value = NULL;
   161         hint->priority = SDL_HINT_DEFAULT;
   162         hint->callbacks = NULL;
   163         hint->next = SDL_hints;
   164         SDL_hints = hint;
   165     }
   166 
   167     /* Add it to the callbacks for this hint */
   168     entry->next = hint->callbacks;
   169     hint->callbacks = entry;
   170 
   171     /* Now call it with the current value */
   172     value = SDL_GetHint(name);
   173     callback(userdata, name, value, value);
   174 }
   175 
   176 void
   177 SDL_DelHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
   178 {
   179     SDL_Hint *hint;
   180     SDL_HintWatch *entry, *prev;
   181 
   182     for (hint = SDL_hints; hint; hint = hint->next) {
   183         if (SDL_strcmp(name, hint->name) == 0) {
   184             prev = NULL;
   185             for (entry = hint->callbacks; entry; entry = entry->next) {
   186                 if (callback == entry->callback && userdata == entry->userdata) {
   187                     if (prev) {
   188                         prev->next = entry->next;
   189                     } else {
   190                         hint->callbacks = entry->next;
   191                     }
   192                     SDL_free(entry);
   193                     break;
   194                 }
   195                 prev = entry;
   196             }
   197             return;
   198         }
   199     }
   200 }
   201 
   202 void SDL_ClearHints(void)
   203 {
   204     SDL_Hint *hint;
   205     SDL_HintWatch *entry;
   206 
   207     while (SDL_hints) {
   208         hint = SDL_hints;
   209         SDL_hints = hint->next;
   210 
   211         SDL_free(hint->name);
   212         SDL_free(hint->value);
   213         for (entry = hint->callbacks; entry; ) {
   214             SDL_HintWatch *freeable = entry;
   215             entry = entry->next;
   216             SDL_free(freeable);
   217         }
   218         SDL_free(hint);
   219     }
   220 }
   221 
   222 /* vi: set ts=4 sw=4 expandtab: */