Skip to content

Commit 1ec262b

Browse files
committed
Issue python#27932: Prevent memory leak in win32_ver().
1 parent 1c75c18 commit 1ec262b

3 files changed

Lines changed: 40 additions & 60 deletions

File tree

‎Lib/platform.py‎

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -498,65 +498,6 @@ def _syscmd_ver(system='', release='', version='',
498498
(6, None): "post2012ServerR2",
499499
}
500500

501-
def _get_real_winver(maj, min, build):
502-
if maj < 6 or (maj == 6 and min < 2):
503-
return maj, min, build
504-
505-
from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
506-
Structure, WinDLL)
507-
from ctypes.wintypes import DWORD, HANDLE
508-
509-
class VS_FIXEDFILEINFO(Structure):
510-
_fields_ = [
511-
("dwSignature", DWORD),
512-
("dwStrucVersion", DWORD),
513-
("dwFileVersionMS", DWORD),
514-
("dwFileVersionLS", DWORD),
515-
("dwProductVersionMS", DWORD),
516-
("dwProductVersionLS", DWORD),
517-
("dwFileFlagsMask", DWORD),
518-
("dwFileFlags", DWORD),
519-
("dwFileOS", DWORD),
520-
("dwFileType", DWORD),
521-
("dwFileSubtype", DWORD),
522-
("dwFileDateMS", DWORD),
523-
("dwFileDateLS", DWORD),
524-
]
525-
526-
kernel32 = WinDLL('kernel32')
527-
version = WinDLL('version')
528-
529-
# We will immediately double the length up to MAX_PATH, but the
530-
# path may be longer, so we retry until the returned string is
531-
# shorter than our buffer.
532-
name_len = actual_len = 130
533-
while actual_len == name_len:
534-
name_len *= 2
535-
name = create_unicode_buffer(name_len)
536-
actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
537-
name, len(name))
538-
if not actual_len:
539-
return maj, min, build
540-
541-
size = version.GetFileVersionInfoSizeW(name, None)
542-
if not size:
543-
return maj, min, build
544-
545-
ver_block = c_buffer(size)
546-
if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
547-
not ver_block):
548-
return maj, min, build
549-
550-
pvi = POINTER(VS_FIXEDFILEINFO)()
551-
if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
552-
return maj, min, build
553-
554-
maj = pvi.contents.dwProductVersionMS >> 16
555-
min = pvi.contents.dwProductVersionMS & 0xFFFF
556-
build = pvi.contents.dwProductVersionLS >> 16
557-
558-
return maj, min, build
559-
560501
def win32_ver(release='', version='', csd='', ptype=''):
561502
try:
562503
from sys import getwindowsversion
@@ -568,7 +509,7 @@ def win32_ver(release='', version='', csd='', ptype=''):
568509
from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
569510

570511
winver = getwindowsversion()
571-
maj, min, build = _get_real_winver(*winver[:3])
512+
maj, min, build = winver._platform_version or winver[:3]
572513
version = '{0}.{1}.{2}'.format(maj, min, build)
573514

574515
release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or

‎Misc/NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ Core and Builtins
7171
Library
7272
-------
7373

74+
- Issue #27932: Prevent memory leak in win32_ver().
75+
7476
- Fix UnboundLocalError in socket._sendfile_use_sendfile.
7577

7678
- Issue #28075: Check for ERROR_ACCESS_DENIED in Windows implementation of

‎Python/sysmodule.c‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ static PyStructSequence_Field windows_version_fields[] = {
825825
{"service_pack_minor", "Service Pack minor version number"},
826826
{"suite_mask", "Bit mask identifying available product suites"},
827827
{"product_type", "System product type"},
828+
{"_platform_version", "Diagnostic version number"},
828829
{0}
829830
};
830831

@@ -849,6 +850,12 @@ sys_getwindowsversion(PyObject *self)
849850
PyObject *version;
850851
int pos = 0;
851852
OSVERSIONINFOEX ver;
853+
DWORD realMajor, realMinor, realBuild;
854+
HANDLE hKernel32;
855+
wchar_t kernel32_path[MAX_PATH];
856+
LPVOID verblock;
857+
DWORD verblock_size;
858+
852859
ver.dwOSVersionInfoSize = sizeof(ver);
853860
if (!GetVersionEx((OSVERSIONINFO*) &ver))
854861
return PyErr_SetFromWindowsErr(0);
@@ -867,10 +874,40 @@ sys_getwindowsversion(PyObject *self)
867874
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask));
868875
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType));
869876

877+
realMajor = ver.dwMajorVersion;
878+
realMinor = ver.dwMinorVersion;
879+
realBuild = ver.dwBuildNumber;
880+
881+
// GetVersion will lie if we are running in a compatibility mode.
882+
// We need to read the version info from a system file resource
883+
// to accurately identify the OS version. If we fail for any reason,
884+
// just return whatever GetVersion said.
885+
hKernel32 = GetModuleHandleW(L"kernel32.dll");
886+
if (hKernel32 && GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH) &&
887+
(verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL)) &&
888+
(verblock = PyMem_RawMalloc(verblock_size))) {
889+
VS_FIXEDFILEINFO *ffi;
890+
UINT ffi_len;
891+
892+
if (GetFileVersionInfoW(kernel32_path, 0, verblock_size, verblock) &&
893+
VerQueryValueW(verblock, L"", (LPVOID)&ffi, &ffi_len)) {
894+
realMajor = HIWORD(ffi->dwProductVersionMS);
895+
realMinor = LOWORD(ffi->dwProductVersionMS);
896+
realBuild = HIWORD(ffi->dwProductVersionLS);
897+
}
898+
PyMem_RawFree(verblock);
899+
}
900+
PyStructSequence_SET_ITEM(version, pos++, PyTuple_Pack(3,
901+
PyLong_FromLong(realMajor),
902+
PyLong_FromLong(realMinor),
903+
PyLong_FromLong(realBuild)
904+
));
905+
870906
if (PyErr_Occurred()) {
871907
Py_DECREF(version);
872908
return NULL;
873909
}
910+
874911
return version;
875912
}
876913

0 commit comments

Comments
 (0)