From 84d69b98f9ae5cfe704cef3af44ea42d0a549d73 Mon Sep 17 00:00:00 2001
From: Christian Ullrich <chris@chrullrich.net>
Date: Wed, 16 Nov 2016 16:55:45 +0100
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 d6391b0..25eed06 100644
--- a/src/port/win32env.c
+++ b/src/port/win32env.c
@@ -70,67 +70,47 @@ pgwin32_putenv(const char *envval)
 	 */
 #ifdef _MSC_VER
 	typedef int (_cdecl * PUTENVPROC) (const char *);
-	static struct
+	static const 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 and later */
-		{ NULL, NULL, 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 and later */
+		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 = (PUTENVPROC) 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.10.2.windows.1

