From 1ec262be80f9439296918c20b55a5a6686af5347 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 17 Sep 2016 17:25:42 -0700 Subject: Issue #27932: Prevent memory leak in win32_ver(). --- 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 index e7eaa32..3e726a7 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -498,65 +498,6 @@ _WIN32_SERVER_RELEASES = { (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 @@ def win32_ver(release='', version='', csd='', ptype=''): 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 index 1cf1819..49879f5 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -71,6 +71,8 @@ Core and Builtins 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 index 8d7e05a..f688349 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -825,6 +825,7 @@ static PyStructSequence_Field windows_version_fields[] = { {"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 @@ sys_getwindowsversion(PyObject *self) 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 @@ sys_getwindowsversion(PyObject *self) 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; } -- cgit v0.12