Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 74f4af7

Browse files
committed
Issue #27932: Prevent memory leak in win32_ver().
1 parent 1374053 commit 74f4af7

5 files changed

Lines changed: 57 additions & 81 deletions

File tree

Doc/library/sys.rst

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -552,26 +552,15 @@ always available.
552552
Return a named tuple describing the Windows version
553553
currently running. The named elements are *major*, *minor*,
554554
*build*, *platform*, *service_pack*, *service_pack_minor*,
555-
*service_pack_major*, *suite_mask*, and *product_type*.
556-
*service_pack* contains a string while all other values are
555+
*service_pack_major*, *suite_mask*, *product_type* and
556+
*platform_version*. *service_pack* contains a string,
557+
*platform_version* a 3-tuple and all other values are
557558
integers. The components can also be accessed by name, so
558559
``sys.getwindowsversion()[0]`` is equivalent to
559560
``sys.getwindowsversion().major``. For compatibility with prior
560561
versions, only the first 5 elements are retrievable by indexing.
561562

562-
*platform* may be one of the following values:
563-
564-
+-----------------------------------------+-------------------------+
565-
| Constant | Platform |
566-
+=========================================+=========================+
567-
| :const:`0 (VER_PLATFORM_WIN32s)` | Win32s on Windows 3.1 |
568-
+-----------------------------------------+-------------------------+
569-
| :const:`1 (VER_PLATFORM_WIN32_WINDOWS)` | Windows 95/98/ME |
570-
+-----------------------------------------+-------------------------+
571-
| :const:`2 (VER_PLATFORM_WIN32_NT)` | Windows NT/2000/XP/x64 |
572-
+-----------------------------------------+-------------------------+
573-
| :const:`3 (VER_PLATFORM_WIN32_CE)` | Windows CE |
574-
+-----------------------------------------+-------------------------+
563+
*platform* will be :const:`2 (VER_PLATFORM_WIN32_NT)`.
575564

576565
*product_type* may be one of the following values:
577566

@@ -587,17 +576,23 @@ always available.
587576
| | a domain controller. |
588577
+---------------------------------------+---------------------------------+
589578

590-
591579
This function wraps the Win32 :c:func:`GetVersionEx` function; see the
592580
Microsoft documentation on :c:func:`OSVERSIONINFOEX` for more information
593581
about these fields.
594582

583+
*platform_version* returns the accurate major version, minor version and
584+
build number of the current operating system, rather than the version that
585+
is being emulated for the process. It is intended for use in logging rather
586+
than for feature detection.
587+
595588
Availability: Windows.
596589

597590
.. versionchanged:: 3.2
598591
Changed to a named tuple and added *service_pack_minor*,
599592
*service_pack_major*, *suite_mask*, and *product_type*.
600593

594+
.. versionchanged:: 3.6
595+
Added *platform_version*
601596

602597
.. function:: get_coroutine_wrapper()
603598

Lib/platform.py

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

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

569510
winver = getwindowsversion()
570-
maj, min, build = _get_real_winver(*winver[:3])
511+
maj, min, build = winver.platform_version or winver[:3]
571512
version = '{0}.{1}.{2}'.format(maj, min, build)
572513

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

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Core and Builtins
2929
Library
3030
-------
3131

32+
- Issue #27932: Prevent memory leak in win32_ver().
33+
3234
- Fix UnboundLocalError in socket._sendfile_use_sendfile.
3335

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

PCbuild/pythoncore.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
<PreprocessorDefinitions>_USRDLL;Py_BUILD_CORE;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
7070
</ClCompile>
7171
<Link>
72-
<AdditionalDependencies>shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
72+
<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
7373
<BaseAddress>0x1e000000</BaseAddress>
7474
</Link>
7575
</ItemDefinitionGroup>

Python/sysmodule.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -894,10 +894,11 @@ Return information about the running version of Windows as a named tuple.\n\
894894
The members are named: major, minor, build, platform, service_pack,\n\
895895
service_pack_major, service_pack_minor, suite_mask, and product_type. For\n\
896896
backward compatibility, only the first 5 items are available by indexing.\n\
897-
All elements are numbers, except service_pack which is a string. Platform\n\
898-
may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP/Vista/7,\n\
899-
3 for Windows CE. Product_type may be 1 for a workstation, 2 for a domain\n\
900-
controller, 3 for a server."
897+
All elements are numbers, except service_pack and platform_type which are\n\
898+
strings, and platform_version which is a 3-tuple. Platform is always 2.\n\
899+
Product_type may be 1 for a workstation, 2 for a domain controller, 3 for a\n\
900+
server. Platform_version is a 3-tuple containing a version number that is\n\
901+
intended for identifying the OS rather than feature detection."
901902
);
902903

903904
static PyTypeObject WindowsVersionType = {0, 0, 0, 0, 0, 0};
@@ -912,6 +913,7 @@ static PyStructSequence_Field windows_version_fields[] = {
912913
{"service_pack_minor", "Service Pack minor version number"},
913914
{"suite_mask", "Bit mask identifying available product suites"},
914915
{"product_type", "System product type"},
916+
{"platform_version", "Diagnostic version number"},
915917
{0}
916918
};
917919

@@ -936,6 +938,12 @@ sys_getwindowsversion(PyObject *self)
936938
PyObject *version;
937939
int pos = 0;
938940
OSVERSIONINFOEX ver;
941+
DWORD realMajor, realMinor, realBuild;
942+
HANDLE hKernel32;
943+
wchar_t kernel32_path[MAX_PATH];
944+
LPVOID verblock;
945+
DWORD verblock_size;
946+
939947
ver.dwOSVersionInfoSize = sizeof(ver);
940948
if (!GetVersionEx((OSVERSIONINFO*) &ver))
941949
return PyErr_SetFromWindowsErr(0);
@@ -954,10 +962,40 @@ sys_getwindowsversion(PyObject *self)
954962
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask));
955963
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType));
956964

965+
realMajor = ver.dwMajorVersion;
966+
realMinor = ver.dwMinorVersion;
967+
realBuild = ver.dwBuildNumber;
968+
969+
// GetVersion will lie if we are running in a compatibility mode.
970+
// We need to read the version info from a system file resource
971+
// to accurately identify the OS version. If we fail for any reason,
972+
// just return whatever GetVersion said.
973+
hKernel32 = GetModuleHandleW(L"kernel32.dll");
974+
if (hKernel32 && GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH) &&
975+
(verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL)) &&
976+
(verblock = PyMem_RawMalloc(verblock_size))) {
977+
VS_FIXEDFILEINFO *ffi;
978+
UINT ffi_len;
979+
980+
if (GetFileVersionInfoW(kernel32_path, 0, verblock_size, verblock) &&
981+
VerQueryValueW(verblock, L"", (LPVOID)&ffi, &ffi_len)) {
982+
realMajor = HIWORD(ffi->dwProductVersionMS);
983+
realMinor = LOWORD(ffi->dwProductVersionMS);
984+
realBuild = HIWORD(ffi->dwProductVersionLS);
985+
}
986+
PyMem_RawFree(verblock);
987+
}
988+
PyStructSequence_SET_ITEM(version, pos++, PyTuple_Pack(3,
989+
PyLong_FromLong(realMajor),
990+
PyLong_FromLong(realMinor),
991+
PyLong_FromLong(realBuild)
992+
));
993+
957994
if (PyErr_Occurred()) {
958995
Py_DECREF(version);
959996
return NULL;
960997
}
998+
961999
return version;
9621000
}
9631001

0 commit comments

Comments
 (0)