Merge pull request #10 from KhronosGroup/master

added checks for high integrity for Windows secure_getenv
diff --git a/README.md b/README.md
index ee8499a..099f3a6 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,11 @@
 By default, the OpenCL ICD Loader will look for OpenCL Headers in the `inc` directory.
 
 By default, the OpenCL ICD Loader on Windows requires the Windows Driver Kit (WDK).
+To build OpenCL ICD Loader with WDK support -
+* Install recent Windows WDK currently at https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk
+
+* Establish environment variable WDK to include directory. Ex: set WDK=C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0
+
 An OpenCL ICD Loader may be built without the Windows Driver Kit using the CMake variable `OPENCL_ICD_LOADER_REQUIRE_WDK`, however this option should be used with caution since it may prevent the OpenCL ICD Loader from enumerating some OpenCL implementations.
 This dependency may be removed in the future.
 
diff --git a/loader/linux/icd_linux.c b/loader/linux/icd_linux.c
index f6ae790..809f095 100644
--- a/loader/linux/icd_linux.c
+++ b/loader/linux/icd_linux.c
@@ -172,4 +172,3 @@
 {
     dlclose(library);
 }
-
diff --git a/loader/windows/icd_windows.c b/loader/windows/icd_windows.c
index 9c87817..f1609e8 100644
--- a/loader/windows/icd_windows.c
+++ b/loader/windows/icd_windows.c
@@ -23,8 +23,77 @@
 #include <windows.h>
 #include <winreg.h>
 
+#include <initguid.h>
+#include <dxgi.h>
+typedef HRESULT (WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID, void **);
+
 static INIT_ONCE initialized = INIT_ONCE_STATIC_INIT;
 
+typedef struct WinAdapter
+{
+    char * szName;
+    LUID luid;
+} WinAdapter;
+
+const LUID ZeroLuid = { 0, 0 };
+
+static WinAdapter* pWinAdapterBegin = NULL;
+static WinAdapter* pWinAdapterEnd = NULL;
+static WinAdapter* pWinAdapterCapacity = NULL;
+
+BOOL adapterAdd(const char* szName, LUID luid)
+{
+    BOOL result = TRUE; 
+    if (pWinAdapterEnd == pWinAdapterCapacity)
+    {
+        size_t oldCapacity = pWinAdapterCapacity - pWinAdapterBegin;
+        size_t newCapacity = oldCapacity;
+        if (0 == newCapacity)
+        {
+            newCapacity = 1;
+        }
+	else if(newCapacity < UINT_MAX/2)
+	{
+            newCapacity *= 2;
+	}
+
+        WinAdapter* pNewBegin = malloc(newCapacity * sizeof(*pWinAdapterBegin));
+        if (!pNewBegin)
+	    result = FALSE;
+	else
+        {
+            if (pWinAdapterBegin)
+            {
+                memcpy(pNewBegin, pWinAdapterBegin, oldCapacity * sizeof(*pWinAdapterBegin));
+                free(pWinAdapterBegin);
+            }
+            pWinAdapterCapacity = pNewBegin + newCapacity;
+            pWinAdapterEnd = pNewBegin + oldCapacity;
+            pWinAdapterBegin = pNewBegin;
+        }
+    }
+    if (pWinAdapterEnd != pWinAdapterCapacity)
+    {
+        size_t nameLen = (strlen(szName) + 1)*sizeof(szName[0]);
+        pWinAdapterEnd->szName = malloc(nameLen);
+	if (!pWinAdapterEnd->szName)
+	    result = FALSE;
+	else 
+	{
+            memcpy(pWinAdapterEnd->szName, szName, nameLen);
+            pWinAdapterEnd->luid = luid;
+            ++pWinAdapterEnd;
+        }
+    }
+    return result;
+}
+
+void adapterFree(WinAdapter *pWinAdapter)
+{
+    free(pWinAdapter->szName);
+    pWinAdapter->szName = NULL;
+}
+
 /*
  * 
  * Vendor enumeration functions
@@ -36,6 +105,7 @@
 BOOL CALLBACK khrIcdOsVendorsEnumerate(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
 {
     LONG result;
+    BOOL status = FALSE;
     const char* platformsName = "SOFTWARE\\Khronos\\OpenCL\\Vendors";
     HKEY platformsKey = NULL;
     DWORD dwIndex;
@@ -103,19 +173,63 @@
                 KHR_ICD_TRACE("Value not zero, skipping\n");
                 continue;
             }
-
             // add the library
-            khrIcdVendorAdd(cszLibraryName);
-        }
-
-        result = RegCloseKey(platformsKey);
-        if (ERROR_SUCCESS != result)
-        {
-            KHR_ICD_TRACE("Failed to close platforms key %s, ignoring\n", platformsName);
+            status |= adapterAdd(cszLibraryName, ZeroLuid);
         }
     }
 
-    return TRUE;
+    // Add adapters according to DXGI's preference order
+    HMODULE hDXGI = LoadLibrary("dxgi.dll");
+    if (hDXGI)
+    {
+        IDXGIFactory* pFactory = NULL;
+        PFN_CREATE_DXGI_FACTORY pCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGI, "CreateDXGIFactory");
+	if (pCreateDXGIFactory)
+	{
+            HRESULT hr = pCreateDXGIFactory(&IID_IDXGIFactory, &pFactory);
+            if (SUCCEEDED(hr))
+            {
+                UINT i = 0;
+                IDXGIAdapter* pAdapter = NULL;
+                while (SUCCEEDED(pFactory->lpVtbl->EnumAdapters(pFactory, i++, &pAdapter)))
+                {
+                    DXGI_ADAPTER_DESC AdapterDesc;
+                    if (SUCCEEDED(pAdapter->lpVtbl->GetDesc(pAdapter, &AdapterDesc)))
+                    {
+                        for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
+                        {
+                            if (iterAdapter->luid.LowPart == AdapterDesc.AdapterLuid.LowPart
+                                && iterAdapter->luid.HighPart == AdapterDesc.AdapterLuid.HighPart)
+                            {
+                                khrIcdVendorAdd(iterAdapter->szName);
+                                break;
+                            }
+			}
+                    }
+
+                    pAdapter->lpVtbl->Release(pAdapter);
+                }
+                pFactory->lpVtbl->Release(pFactory);
+            }
+            FreeLibrary(hDXGI);
+	}
+    }
+
+    // Go through the list again, putting any remaining adapters at the end of the list in an undefined order
+    for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
+    {
+        khrIcdVendorAdd(iterAdapter->szName);
+        adapterFree(iterAdapter);
+    }
+
+    free(pWinAdapterBegin);	
+
+    result = RegCloseKey(platformsKey);
+    if (ERROR_SUCCESS != result)
+    {
+        KHR_ICD_TRACE("Failed to close platforms key %s, ignoring\n", platformsName);
+    }
+    return status;
 }
 
 // go through the list of vendors only once
@@ -151,4 +265,3 @@
 {
     FreeLibrary( (HMODULE)library);
 }
-
diff --git a/loader/windows/icd_windows_dxgk.c b/loader/windows/icd_windows_dxgk.c
index 8cc3fb9..c55cbf7 100644
--- a/loader/windows/icd_windows_dxgk.c
+++ b/loader/windows/icd_windows_dxgk.c
@@ -35,18 +35,23 @@
 bool khrIcdOsVendorsEnumerateDXGK(void)
 {
     bool ret = false;
+    int result = 0;
 #if defined(OPENCL_ICD_LOADER_REQUIRE_WDK)
 #if defined(DXGKDDI_INTERFACE_VERSION_WDDM2_4) && (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM2_4)
+    // Get handle to GDI Runtime
+    HMODULE h = LoadLibrary("gdi32.dll");
+    if (h == NULL)
+        return ret;
+
+    if(GetProcAddress((HMODULE)h, "D3DKMTSubmitPresentBltToHwQueue")) // OS Version check
     {
         D3DKMT_ADAPTERINFO* pAdapterInfo = NULL;
         D3DKMT_ENUMADAPTERS2 EnumAdapters;
         NTSTATUS Status = STATUS_SUCCESS;
 
-        // Get handle to GDI Runtime
-        HMODULE h = LoadLibrary("gdi32.dll");
-        KHR_ICD_ASSERT(h != NULL);
-
         char cszLibraryName[MAX_PATH] = { 0 };
+        EnumAdapters.NumAdapters = 0;
+        EnumAdapters.pAdapters = NULL;
         PFND3DKMT_ENUMADAPTERS2 pEnumAdapters2 = (PFND3DKMT_ENUMADAPTERS2)GetProcAddress((HMODULE)h, "D3DKMTEnumAdapters2");
         if (!pEnumAdapters2)
         {
@@ -83,47 +88,50 @@
             KHR_ICD_TRACE("D3DKMT_ENUMADAPTERS2 status != SUCCESS\n");
             goto out;
         }
+        const char* cszOpenCLRegKeyName = getOpenCLRegKeyName();
+        const int szOpenCLRegKeyName = (int)(strlen(cszOpenCLRegKeyName) + 1)*sizeof(cszOpenCLRegKeyName[0]);
         for (UINT AdapterIndex = 0; AdapterIndex < EnumAdapters.NumAdapters; AdapterIndex++)
         {
-            D3DDDI_QUERYREGISTRY_INFO QueryArgs = {0};
-            D3DDDI_QUERYREGISTRY_INFO* pQueryArgs = &QueryArgs;
+            D3DDDI_QUERYREGISTRY_INFO queryArgs = {0};
+            D3DDDI_QUERYREGISTRY_INFO* pQueryArgs = &queryArgs;
             D3DDDI_QUERYREGISTRY_INFO* pQueryBuffer = NULL;
-            QueryArgs.QueryType = D3DDDI_QUERYREGISTRY_ADAPTERKEY;
-            QueryArgs.QueryFlags.TranslatePath = TRUE;
-            QueryArgs.ValueType = REG_SZ;
-#ifdef _WIN64
-            wcscpy_s(QueryArgs.ValueName, ARRAYSIZE(L"OpenCLDriverName"), L"OpenCLDriverName");
-#else
-            // There is no WOW prefix for 32bit Windows hence make a specific check
-            BOOL is_wow64;
-            if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)
-            {
-                wcscpy_s(QueryArgs.ValueName, ARRAYSIZE(L"OpenCLDriverNameWow"), L"OpenCLDriverNameWow");
-            }
-            else
-            {
-                wcscpy_s(QueryArgs.ValueName, ARRAYSIZE(L"OpenCLDriverName"), L"OpenCLDriverName");
-            }
-#endif
-            D3DKMT_QUERYADAPTERINFO QueryAdapterInfo = {0};
-            QueryAdapterInfo.hAdapter = pAdapterInfo[AdapterIndex].hAdapter;
-            QueryAdapterInfo.Type = KMTQAITYPE_QUERYREGISTRY;
-            QueryAdapterInfo.pPrivateDriverData = &QueryArgs;
-            QueryAdapterInfo.PrivateDriverDataSize = sizeof(QueryArgs);
-            Status = D3DKMTQueryAdapterInfo(&QueryAdapterInfo);
+            queryArgs.QueryType = D3DDDI_QUERYREGISTRY_ADAPTERKEY;
+            queryArgs.QueryFlags.TranslatePath = TRUE;
+            queryArgs.ValueType = REG_SZ;
+            result = MultiByteToWideChar(
+                CP_ACP,
+                0,
+                cszOpenCLRegKeyName,
+                szOpenCLRegKeyName,
+                queryArgs.ValueName,
+                ARRAYSIZE(queryArgs.ValueName));
+	    if (!result)
+	    {
+                KHR_ICD_TRACE("MultiByteToWideChar status != SUCCESS\n");
+                continue;
+	    }
+            D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {0};
+            queryAdapterInfo.hAdapter = pAdapterInfo[AdapterIndex].hAdapter;
+            queryAdapterInfo.Type = KMTQAITYPE_QUERYREGISTRY;
+            queryAdapterInfo.pPrivateDriverData = &queryArgs;
+            queryAdapterInfo.PrivateDriverDataSize = sizeof(queryArgs);
+            Status = D3DKMTQueryAdapterInfo(&queryAdapterInfo);
             if (!NT_SUCCESS(Status))
             {
-                KHR_ICD_TRACE("D3DKMT_QUERYADAPTERINFO status != SUCCESS\n");
-                goto out;
+                // Continue trying to get as much info on each adapter as possible.
+                // It's too late to return FALSE and claim WDDM2_4 enumeration is not available here.
+                continue;
             }
             if (NT_SUCCESS(Status) && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW)
             {
-                ULONG QueryBufferSize = sizeof(D3DDDI_QUERYREGISTRY_INFO) + QueryArgs.OutputValueSize;
-                pQueryBuffer = (D3DDDI_QUERYREGISTRY_INFO*)malloc(QueryBufferSize);
-                memcpy(pQueryBuffer, &QueryArgs, sizeof(D3DDDI_QUERYREGISTRY_INFO));
-                QueryAdapterInfo.pPrivateDriverData = pQueryBuffer;
-                QueryAdapterInfo.PrivateDriverDataSize = QueryBufferSize;
-                Status = D3DKMTQueryAdapterInfo(&QueryAdapterInfo);
+                ULONG queryBufferSize = sizeof(D3DDDI_QUERYREGISTRY_INFO) + queryArgs.OutputValueSize;
+                pQueryBuffer = (D3DDDI_QUERYREGISTRY_INFO*)malloc(queryBufferSize);
+                if (pQueryBuffer == NULL)
+		    continue;
+                memcpy(pQueryBuffer, &queryArgs, sizeof(D3DDDI_QUERYREGISTRY_INFO));
+                queryAdapterInfo.pPrivateDriverData = pQueryBuffer;
+                queryAdapterInfo.PrivateDriverDataSize = queryBufferSize;
+                Status = D3DKMTQueryAdapterInfo(&queryAdapterInfo);
                 pQueryArgs = pQueryBuffer;
             }
             if (NT_SUCCESS(Status) && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
@@ -133,7 +141,7 @@
                 {
                     size_t len = wcstombs(cszLibraryName, pWchar, sizeof(cszLibraryName));
                     KHR_ICD_ASSERT(len == (sizeof(cszLibraryName) - 1));
-                    khrIcdVendorAdd(cszLibraryName);
+                    ret |= adapterAdd(cszLibraryName, pAdapterInfo[AdapterIndex].AdapterLuid);
                 }
             }
             else if (Status == STATUS_INVALID_PARAMETER && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_FAIL)
@@ -143,11 +151,12 @@
             }
             free(pQueryBuffer);
         }
-        ret = true;
 out:
       free(pAdapterInfo);
-      FreeLibrary(h);
     }
+
+    FreeLibrary(h);
+
 #endif
 #endif
     return ret;
diff --git a/loader/windows/icd_windows_hkr.c b/loader/windows/icd_windows_hkr.c
index 3387181..a323312 100644
--- a/loader/windows/icd_windows_hkr.c
+++ b/loader/windows/icd_windows_hkr.c
@@ -19,6 +19,7 @@
 #include "icd.h"
 #include "icd_windows_hkr.h"
 #include <windows.h>
+#include "icd_windows_dxgk.h"
 #include <cfgmgr32.h>
 #include <assert.h>
 #include <stdbool.h>
@@ -51,7 +52,7 @@
 #endif
 
 // Do not free the memory returned by this function.
-static const char* GetOpenCLRegKeyName(void)
+const char* getOpenCLRegKeyName(void)
 {
 #ifdef _WIN64
     return OPENCL_REG_SUB_KEY;
@@ -96,7 +97,7 @@
     {
         result = RegQueryValueExA(
             hkey,
-            GetOpenCLRegKeyName(),
+            getOpenCLRegKeyName(),
             NULL,
             &dwLibraryNameType,
             NULL,
@@ -117,7 +118,7 @@
 
         result = RegQueryValueExA(
             hkey,
-            GetOpenCLRegKeyName(),
+            getOpenCLRegKeyName(),
             NULL,
             &dwLibraryNameType,
             (LPBYTE)cszOclPath,
@@ -136,9 +137,7 @@
 
         KHR_ICD_TRACE("    Path: %s\n", cszOclPath);
 
-        khrIcdVendorAdd(cszOclPath);
-
-        bRet = true;
+        bRet |= adapterAdd(cszOclPath, ZeroLuid);
     }
 
 out:
diff --git a/loader/windows/icd_windows_hkr.h b/loader/windows/icd_windows_hkr.h
index 698fe5a..039da05 100644
--- a/loader/windows/icd_windows_hkr.h
+++ b/loader/windows/icd_windows_hkr.h
@@ -17,5 +17,13 @@
  */
 
 #include <stdbool.h>
+#include <windows.h>
 
 bool khrIcdOsVendorsEnumerateHKR(void);
+
+extern const LUID ZeroLuid;
+
+BOOL adapterAdd(const char* szName, LUID luid);
+
+// Do not free the memory returned by this function.
+const char* getOpenCLRegKeyName(void);