Bug 1325980 - Get full GFX DLL paths from UserModeDriverName as a fallback. r=kats
authorOriol <oriol-bugzilla@hotmail.com>
Sat, 01 Apr 2017 15:46:41 -0400
changeset 350866 f079689d79be7f51b9db0cc53a1ca4b8e7839a0d
parent 350865 56ef6e6757d478aff96101c335c0ed7a279987a6
child 350867 b7fab6a89c1d618d67e3a0b1f67e7c1bc09b9fd4
push id39961
push userarchaeopteryx@coole-files.de
push dateSun, 02 Apr 2017 16:54:14 +0000
treeherderautoland@6ba6c3b75587 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1325980
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1325980 - Get full GFX DLL paths from UserModeDriverName as a fallback. r=kats MozReview-Commit-ID: 1DFr2okgAdQ
widget/windows/GfxInfo.cpp
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -216,16 +216,49 @@ static nsresult GetKeyValue(const WCHAR*
       break;
     }
   }
   RegCloseKey(key);
 
   return retval;
 }
 
+static nsresult GetKeyValues(const WCHAR* keyLocation, const WCHAR* keyName, nsTArray<nsString>& destStrings)
+{
+  // First ask for the size of the value
+  DWORD size;
+  LONG rv = RegGetValueW(HKEY_LOCAL_MACHINE, keyLocation, keyName, RRF_RT_REG_MULTI_SZ, nullptr, nullptr, &size);
+  if (rv != ERROR_SUCCESS) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Create a buffer with the proper size and retrieve the value
+  WCHAR* wCharValue = new WCHAR[size / sizeof(WCHAR)];
+  rv = RegGetValueW(HKEY_LOCAL_MACHINE, keyLocation, keyName, RRF_RT_REG_MULTI_SZ, nullptr, (LPBYTE)wCharValue, &size);
+  if (rv != ERROR_SUCCESS) {
+    delete[] wCharValue;
+    return NS_ERROR_FAILURE;
+  }
+
+  // The value is a sequence of null-terminated strings, usually terminated by an empty string (\0).
+  // RegGetValue ensures that the value is properly terminated with a null character.
+  DWORD i = 0;
+  DWORD strLen = size / sizeof(WCHAR);
+  while (i < strLen) {
+    nsString value(wCharValue + i);
+    if (!value.IsEmpty()) {
+      destStrings.AppendElement(value);
+    }
+    i += value.Length() + 1;
+  }
+  delete[] wCharValue;
+
+  return NS_OK;
+}
+
 // The device ID is a string like PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD
 // this function is used to extract the id's out of it
 uint32_t
 ParseIDFromDeviceID(const nsAString &key, const char *prefix, int length)
 {
   nsAutoString id(key);
   ToUpperCase(id);
   int32_t start = id.Find(prefix);
@@ -571,43 +604,67 @@ GfxInfo::Init()
     nsAutoString dllFileName(is64bitApp ? u"igd10umd64" : u"igd10umd32");
     nsAutoString dllFileName2(is64bitApp ? u"igd10iumd64" : u"igd10iumd32");
 
     nsString dllVersion, dllVersion2;
     uint64_t dllNumericVersion = 0, dllNumericVersion2 = 0,
              driverNumericVersion = 0, knownSafeMismatchVersion = 0;
 
     // Only parse the DLL version for those found in the driver list
-    nsAutoString elligibleDLLs;
-    if (NS_SUCCEEDED(GetAdapterDriver(elligibleDLLs))) {
-      if (FindInReadable(dllFileName, elligibleDLLs)) {
+    nsAutoString eligibleDLLs;
+    if (NS_SUCCEEDED(GetAdapterDriver(eligibleDLLs))) {
+      if (FindInReadable(dllFileName, eligibleDLLs)) {
         dllFileName += NS_LITERAL_STRING(".dll");
         gfxWindowsPlatform::GetDLLVersion(dllFileName.get(), dllVersion);
         ParseDriverVersion(dllVersion, &dllNumericVersion);
       }
-      if (FindInReadable(dllFileName2, elligibleDLLs)) {
+      if (FindInReadable(dllFileName2, eligibleDLLs)) {
         dllFileName2 += NS_LITERAL_STRING(".dll");
         gfxWindowsPlatform::GetDLLVersion(dllFileName2.get(), dllVersion2);
         ParseDriverVersion(dllVersion2, &dllNumericVersion2);
       }
     }
 
+    // Sometimes the DLL is not in the System32 nor SysWOW64 directories. But UserModeDriverName
+    // (or UserModeDriverNameWow, if available) might provide the full path to the DLL in some
+    // DriverStore FileRepository.
+    if (dllNumericVersion == 0 && dllNumericVersion2 == 0) {
+      nsTArray<nsString> eligibleDLLpaths;
+      const WCHAR* keyLocation = mDeviceKey[mActiveGPUIndex].get();
+      GetKeyValues(keyLocation, L"UserModeDriverName", eligibleDLLpaths);
+      GetKeyValues(keyLocation, L"UserModeDriverNameWow", eligibleDLLpaths);
+      size_t length = eligibleDLLpaths.Length();
+      for (size_t i=0; i<length && dllNumericVersion == 0 && dllNumericVersion2 == 0; ++i) {
+        if (FindInReadable(dllFileName, eligibleDLLpaths[i])) {
+          gfxWindowsPlatform::GetDLLVersion(eligibleDLLpaths[i].get(), dllVersion);
+          ParseDriverVersion(dllVersion, &dllNumericVersion);
+        } else if (FindInReadable(dllFileName2, eligibleDLLpaths[i])) {
+          gfxWindowsPlatform::GetDLLVersion(eligibleDLLpaths[i].get(), dllVersion2);
+          ParseDriverVersion(dllVersion2, &dllNumericVersion2);
+        }
+      }
+    }
+
     ParseDriverVersion(mDriverVersion[mActiveGPUIndex], &driverNumericVersion);
     ParseDriverVersion(NS_LITERAL_STRING("9.17.10.0"), &knownSafeMismatchVersion);
 
     // If there's a driver version mismatch, consider this harmful only when
     // the driver version is less than knownSafeMismatchVersion.  See the
     // above comment about crashes with old mismatches.  If the GetDllVersion
     // call fails, we are not calling it a mismatch.
     if ((dllNumericVersion != 0 && dllNumericVersion != driverNumericVersion) ||
         (dllNumericVersion2 != 0 && dllNumericVersion2 != driverNumericVersion)) {
       if (driverNumericVersion < knownSafeMismatchVersion ||
           std::max(dllNumericVersion, dllNumericVersion2) < knownSafeMismatchVersion) {
         mHasDriverVersionMismatch = true;
-        gfxCriticalNoteOnce << "Mismatched driver versions between the registry " << NS_ConvertUTF16toUTF8(mDriverVersion[mActiveGPUIndex]).get() << " and DLL(s) " << NS_ConvertUTF16toUTF8(dllVersion).get() << ", " << NS_ConvertUTF16toUTF8(dllVersion2).get() << " reported.";
+        gfxCriticalNoteOnce << "Mismatched driver versions between the registry "
+                            << NS_ConvertUTF16toUTF8(mDriverVersion[mActiveGPUIndex]).get()
+                            << " and DLL(s) "
+                            << NS_ConvertUTF16toUTF8(dllVersion).get() << ", "
+                            << NS_ConvertUTF16toUTF8(dllVersion2).get() << " reported.";
       }
     } else if (dllNumericVersion == 0 && dllNumericVersion2 == 0) {
       // Leave it as an asserting error for now, to see if we can find
       // a system that exhibits this kind of a problem internally.
       gfxCriticalErrorOnce() << "Potential driver version mismatch ignored due to missing DLLs "
                              << NS_ConvertUTF16toUTF8(dllFileName).get() << " v="
                              << NS_ConvertUTF16toUTF8(dllVersion).get() << " and "
                              << NS_ConvertUTF16toUTF8(dllFileName2).get() << " v="