[Python-checkins] cpython (3.5): Issue #27932: Prevent memory leak in win32_ver().

steve.dower python-checkins at python.org
Sat Sep 17 20:30:23 EDT 2016


https://hg.python.org/cpython/rev/db4b254f5df4
changeset:   103906:db4b254f5df4
branch:      3.5
parent:      103900:13001cf82931
user:        Steve Dower <steve.dower at microsoft.com>
date:        Sat Sep 17 17:25:42 2016 -0700
summary:
  Issue #27932: Prevent memory leak in win32_ver().

files:
  Lib/platform.py    |  61 +---------------------------------
  Misc/NEWS          |   2 +
  Python/sysmodule.c |  37 ++++++++++++++++++++
  3 files changed, 40 insertions(+), 60 deletions(-)


diff --git a/Lib/platform.py b/Lib/platform.py
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -498,65 +498,6 @@
     (6, None): "post2012ServerR2",
 }
 
-def _get_real_winver(maj, min, build):
-    if maj < 6 or (maj == 6 and min < 2):
-        return maj, min, build
-
-    from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
-                        Structure, WinDLL)
-    from ctypes.wintypes import DWORD, HANDLE
-
-    class VS_FIXEDFILEINFO(Structure):
-        _fields_ = [
-            ("dwSignature", DWORD),
-            ("dwStrucVersion", DWORD),
-            ("dwFileVersionMS", DWORD),
-            ("dwFileVersionLS", DWORD),
-            ("dwProductVersionMS", DWORD),
-            ("dwProductVersionLS", DWORD),
-            ("dwFileFlagsMask", DWORD),
-            ("dwFileFlags", DWORD),
-            ("dwFileOS", DWORD),
-            ("dwFileType", DWORD),
-            ("dwFileSubtype", DWORD),
-            ("dwFileDateMS", DWORD),
-            ("dwFileDateLS", DWORD),
-        ]
-
-    kernel32 = WinDLL('kernel32')
-    version = WinDLL('version')
-
-    # We will immediately double the length up to MAX_PATH, but the
-    # path may be longer, so we retry until the returned string is
-    # shorter than our buffer.
-    name_len = actual_len = 130
-    while actual_len == name_len:
-        name_len *= 2
-        name = create_unicode_buffer(name_len)
-        actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
-                                                 name, len(name))
-        if not actual_len:
-            return maj, min, build
-
-    size = version.GetFileVersionInfoSizeW(name, None)
-    if not size:
-        return maj, min, build
-
-    ver_block = c_buffer(size)
-    if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
-        not ver_block):
-        return maj, min, build
-
-    pvi = POINTER(VS_FIXEDFILEINFO)()
-    if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
-        return maj, min, build
-
-    maj = pvi.contents.dwProductVersionMS >> 16
-    min = pvi.contents.dwProductVersionMS & 0xFFFF
-    build = pvi.contents.dwProductVersionLS >> 16
-
-    return maj, min, build
-
 def win32_ver(release='', version='', csd='', ptype=''):
     try:
         from sys import getwindowsversion
@@ -568,7 +509,7 @@
         from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
 
     winver = getwindowsversion()
-    maj, min, build = _get_real_winver(*winver[:3])
+    maj, min, build = winver._platform_version or winver[:3]
     version = '{0}.{1}.{2}'.format(maj, min, build)
 
     release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -71,6 +71,8 @@
 Library
 -------
 
+- Issue #27932: Prevent memory leak in win32_ver().
+
 - Fix UnboundLocalError in socket._sendfile_use_sendfile.
 
 - Issue #28075: Check for ERROR_ACCESS_DENIED in Windows implementation of
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -825,6 +825,7 @@
     {"service_pack_minor", "Service Pack minor version number"},
     {"suite_mask", "Bit mask identifying available product suites"},
     {"product_type", "System product type"},
+    {"_platform_version", "Diagnostic version number"},
     {0}
 };
 
@@ -849,6 +850,12 @@
     PyObject *version;
     int pos = 0;
     OSVERSIONINFOEX ver;
+    DWORD realMajor, realMinor, realBuild;
+    HANDLE hKernel32;
+    wchar_t kernel32_path[MAX_PATH];
+    LPVOID verblock;
+    DWORD verblock_size;
+
     ver.dwOSVersionInfoSize = sizeof(ver);
     if (!GetVersionEx((OSVERSIONINFO*) &ver))
         return PyErr_SetFromWindowsErr(0);
@@ -867,10 +874,40 @@
     PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask));
     PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType));
 
+    realMajor = ver.dwMajorVersion;
+    realMinor = ver.dwMinorVersion;
+    realBuild = ver.dwBuildNumber;
+
+    // GetVersion will lie if we are running in a compatibility mode.
+    // We need to read the version info from a system file resource
+    // to accurately identify the OS version. If we fail for any reason,
+    // just return whatever GetVersion said.
+    hKernel32 = GetModuleHandleW(L"kernel32.dll");
+    if (hKernel32 && GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH) &&
+        (verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL)) &&
+        (verblock = PyMem_RawMalloc(verblock_size))) {
+        VS_FIXEDFILEINFO *ffi;
+        UINT ffi_len;
+
+        if (GetFileVersionInfoW(kernel32_path, 0, verblock_size, verblock) &&
+            VerQueryValueW(verblock, L"", (LPVOID)&ffi, &ffi_len)) {
+            realMajor = HIWORD(ffi->dwProductVersionMS);
+            realMinor = LOWORD(ffi->dwProductVersionMS);
+            realBuild = HIWORD(ffi->dwProductVersionLS);
+        }
+        PyMem_RawFree(verblock);
+    }
+    PyStructSequence_SET_ITEM(version, pos++, PyTuple_Pack(3,
+        PyLong_FromLong(realMajor),
+        PyLong_FromLong(realMinor),
+        PyLong_FromLong(realBuild)
+    ));
+
     if (PyErr_Occurred()) {
         Py_DECREF(version);
         return NULL;
     }
+
     return version;
 }
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list