From fab036a94277cf8add9b3305fff923dd0f1eb97f Mon Sep 17 00:00:00 2001 From: Christian Ullrich Date: Tue, 26 Apr 2016 16:00:31 +0200 Subject: [PATCH] Fix the unload race as best we can. The fix is, unfortunately, to get rid of all caching. After fixing the load race in the previous commit, a situation was possible *) where a CRT is loaded, pgwin32_putenv() is called, and then later that CRT is unloaded again. The next call to pgwin32_putenv() would then attempt to use the cached function address and crash. *) It had been possible for untold years, but the probability was very low because the first call to pgwin32_putenv() occurs early in the process and used to finalize the list of CRTs the function will admit exist -- whatever is loaded at that point is likely to stay loaded. --- src/port/win32env.c | 84 ++++++++++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 52 deletions(-) diff --git a/src/port/win32env.c b/src/port/win32env.c index 20d3665..1e913fc 100644 --- a/src/port/win32env.c +++ b/src/port/win32env.c @@ -38,67 +38,47 @@ pgwin32_putenv(const char *envval) */ #ifdef _MSC_VER typedef int (_cdecl * PUTENVPROC) (const char *); - static struct + static char *modulenames[] = { - char *modulename; - HMODULE hmodule; - PUTENVPROC putenvFunc; - } rtmodules[] = - { - { "msvcrt", NULL, NULL }, - { "msvcrtd", NULL, NULL }, /* Visual Studio 6.0 / mingw */ - { "msvcr70", NULL, NULL }, - { "msvcr70d", NULL, NULL }, /* Visual Studio 2002 */ - { "msvcr71", NULL, NULL }, - { "msvcr71d", NULL, NULL }, /* Visual Studio 2003 */ - { "msvcr80", NULL, NULL }, - { "msvcr80d", NULL, NULL }, /* Visual Studio 2005 */ - { "msvcr90", NULL, NULL }, - { "msvcr90d", NULL, NULL }, /* Visual Studio 2008 */ - { "msvcr100", NULL, NULL }, - { "msvcr100d", NULL, NULL }, /* Visual Studio 2010 */ - { "msvcr110", NULL, NULL }, - { "msvcr110d", NULL, NULL }, /* Visual Studio 2012 */ - { "msvcr120", NULL, NULL }, - { "msvcr120d", NULL, NULL }, /* Visual Studio 2013 */ - { "ucrtbase", NULL, NULL }, - { "ucrtbased", NULL, NULL }, /* Visual Studio 2015+ */ - { NULL, 0, NULL } + "msvcrt", + "msvcrtd", /* Visual Studio 6.0 / mingw */ + "msvcr70", + "msvcr70d", /* Visual Studio 2002 */ + "msvcr71", + "msvcr71d", /* Visual Studio 2003 */ + "msvcr80", + "msvcr80d", /* Visual Studio 2005 */ + "msvcr90", + "msvcr90d", /* Visual Studio 2008 */ + "msvcr100", + "msvcr100d", /* Visual Studio 2010 */ + "msvcr110", + "msvcr110d", /* Visual Studio 2012 */ + "msvcr120", + "msvcr120d", /* Visual Studio 2013 */ + "ucrtbase", + "ucrtbased", /* Visual Studio 2015+ */ + NULL }; int i; - for (i = 0; rtmodules[i].modulename; i++) + /* + * Call the _putenv() function in all loaded CRTs. + * We cannot cache any information about loaded DLLs or + * export addresses in them because this can change at + * runtime. + */ + for (i = 0; modulenames[i]; i++) { - if (rtmodules[i].putenvFunc == NULL) + HMODULE hmodule = GetModuleHandle(modulenames[i]); + if (hmodule) { - if (rtmodules[i].hmodule == NULL) - { - /* Try to find this DLL */ - rtmodules[i].hmodule = GetModuleHandle(rtmodules[i].modulename); - if (rtmodules[i].hmodule == NULL) - { - continue; - } - else - { - rtmodules[i].putenvFunc = (PUTENVPROC) GetProcAddress(rtmodules[i].hmodule, "_putenv"); - if (rtmodules[i].putenvFunc == NULL) - { - continue; - } - } - } - else + PUTENVPROC putenvFunc = GetProcAddress(hmodule, "_putenv"); + if (putenvFunc) { - /* - * Module loaded, but we did not find the function last time. - * We're not going to find it this time either... - */ - continue; + putenvFunc(envval); } } - /* At this point, putenvFunc is set or we have exited the loop */ - rtmodules[i].putenvFunc(envval); } #endif /* _MSC_VER */ -- 2.8.1.windows.1