Issue #27932: Prevent memory leak in win32_ver().
This commit is contained in:
commit
5f9c3926cc
|
@ -552,26 +552,15 @@ always available.
|
||||||
Return a named tuple describing the Windows version
|
Return a named tuple describing the Windows version
|
||||||
currently running. The named elements are *major*, *minor*,
|
currently running. The named elements are *major*, *minor*,
|
||||||
*build*, *platform*, *service_pack*, *service_pack_minor*,
|
*build*, *platform*, *service_pack*, *service_pack_minor*,
|
||||||
*service_pack_major*, *suite_mask*, and *product_type*.
|
*service_pack_major*, *suite_mask*, *product_type* and
|
||||||
*service_pack* contains a string while all other values are
|
*platform_version*. *service_pack* contains a string,
|
||||||
|
*platform_version* a 3-tuple and all other values are
|
||||||
integers. The components can also be accessed by name, so
|
integers. The components can also be accessed by name, so
|
||||||
``sys.getwindowsversion()[0]`` is equivalent to
|
``sys.getwindowsversion()[0]`` is equivalent to
|
||||||
``sys.getwindowsversion().major``. For compatibility with prior
|
``sys.getwindowsversion().major``. For compatibility with prior
|
||||||
versions, only the first 5 elements are retrievable by indexing.
|
versions, only the first 5 elements are retrievable by indexing.
|
||||||
|
|
||||||
*platform* may be one of the following values:
|
*platform* will be :const:`2 (VER_PLATFORM_WIN32_NT)`.
|
||||||
|
|
||||||
+-----------------------------------------+-------------------------+
|
|
||||||
| Constant | Platform |
|
|
||||||
+=========================================+=========================+
|
|
||||||
| :const:`0 (VER_PLATFORM_WIN32s)` | Win32s on Windows 3.1 |
|
|
||||||
+-----------------------------------------+-------------------------+
|
|
||||||
| :const:`1 (VER_PLATFORM_WIN32_WINDOWS)` | Windows 95/98/ME |
|
|
||||||
+-----------------------------------------+-------------------------+
|
|
||||||
| :const:`2 (VER_PLATFORM_WIN32_NT)` | Windows NT/2000/XP/x64 |
|
|
||||||
+-----------------------------------------+-------------------------+
|
|
||||||
| :const:`3 (VER_PLATFORM_WIN32_CE)` | Windows CE |
|
|
||||||
+-----------------------------------------+-------------------------+
|
|
||||||
|
|
||||||
*product_type* may be one of the following values:
|
*product_type* may be one of the following values:
|
||||||
|
|
||||||
|
@ -587,17 +576,23 @@ always available.
|
||||||
| | a domain controller. |
|
| | a domain controller. |
|
||||||
+---------------------------------------+---------------------------------+
|
+---------------------------------------+---------------------------------+
|
||||||
|
|
||||||
|
|
||||||
This function wraps the Win32 :c:func:`GetVersionEx` function; see the
|
This function wraps the Win32 :c:func:`GetVersionEx` function; see the
|
||||||
Microsoft documentation on :c:func:`OSVERSIONINFOEX` for more information
|
Microsoft documentation on :c:func:`OSVERSIONINFOEX` for more information
|
||||||
about these fields.
|
about these fields.
|
||||||
|
|
||||||
|
*platform_version* returns the accurate major version, minor version and
|
||||||
|
build number of the current operating system, rather than the version that
|
||||||
|
is being emulated for the process. It is intended for use in logging rather
|
||||||
|
than for feature detection.
|
||||||
|
|
||||||
Availability: Windows.
|
Availability: Windows.
|
||||||
|
|
||||||
.. versionchanged:: 3.2
|
.. versionchanged:: 3.2
|
||||||
Changed to a named tuple and added *service_pack_minor*,
|
Changed to a named tuple and added *service_pack_minor*,
|
||||||
*service_pack_major*, *suite_mask*, and *product_type*.
|
*service_pack_major*, *suite_mask*, and *product_type*.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.6
|
||||||
|
Added *platform_version*
|
||||||
|
|
||||||
.. function:: get_coroutine_wrapper()
|
.. function:: get_coroutine_wrapper()
|
||||||
|
|
||||||
|
|
|
@ -497,65 +497,6 @@ _WIN32_SERVER_RELEASES = {
|
||||||
(6, None): "post2012ServerR2",
|
(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=''):
|
def win32_ver(release='', version='', csd='', ptype=''):
|
||||||
try:
|
try:
|
||||||
from sys import getwindowsversion
|
from sys import getwindowsversion
|
||||||
|
@ -567,7 +508,7 @@ def win32_ver(release='', version='', csd='', ptype=''):
|
||||||
from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
|
from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
|
||||||
|
|
||||||
winver = getwindowsversion()
|
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)
|
version = '{0}.{1}.{2}'.format(maj, min, build)
|
||||||
|
|
||||||
release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
|
release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
|
||||||
|
|
|
@ -35,6 +35,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #27932: Prevent memory leak in win32_ver().
|
||||||
|
|
||||||
- Fix UnboundLocalError in socket._sendfile_use_sendfile.
|
- Fix UnboundLocalError in socket._sendfile_use_sendfile.
|
||||||
|
|
||||||
- Issue #28075: Check for ERROR_ACCESS_DENIED in Windows implementation of
|
- Issue #28075: Check for ERROR_ACCESS_DENIED in Windows implementation of
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
<PreprocessorDefinitions>_USRDLL;Py_BUILD_CORE;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_USRDLL;Py_BUILD_CORE;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>version.lib;shlwapi.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<BaseAddress>0x1e000000</BaseAddress>
|
<BaseAddress>0x1e000000</BaseAddress>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
|
|
@ -894,10 +894,11 @@ Return information about the running version of Windows as a named tuple.\n\
|
||||||
The members are named: major, minor, build, platform, service_pack,\n\
|
The members are named: major, minor, build, platform, service_pack,\n\
|
||||||
service_pack_major, service_pack_minor, suite_mask, and product_type. For\n\
|
service_pack_major, service_pack_minor, suite_mask, and product_type. For\n\
|
||||||
backward compatibility, only the first 5 items are available by indexing.\n\
|
backward compatibility, only the first 5 items are available by indexing.\n\
|
||||||
All elements are numbers, except service_pack which is a string. Platform\n\
|
All elements are numbers, except service_pack and platform_type which are\n\
|
||||||
may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP/Vista/7,\n\
|
strings, and platform_version which is a 3-tuple. Platform is always 2.\n\
|
||||||
3 for Windows CE. Product_type may be 1 for a workstation, 2 for a domain\n\
|
Product_type may be 1 for a workstation, 2 for a domain controller, 3 for a\n\
|
||||||
controller, 3 for a server."
|
server. Platform_version is a 3-tuple containing a version number that is\n\
|
||||||
|
intended for identifying the OS rather than feature detection."
|
||||||
);
|
);
|
||||||
|
|
||||||
static PyTypeObject WindowsVersionType = {0, 0, 0, 0, 0, 0};
|
static PyTypeObject WindowsVersionType = {0, 0, 0, 0, 0, 0};
|
||||||
|
@ -912,6 +913,7 @@ static PyStructSequence_Field windows_version_fields[] = {
|
||||||
{"service_pack_minor", "Service Pack minor version number"},
|
{"service_pack_minor", "Service Pack minor version number"},
|
||||||
{"suite_mask", "Bit mask identifying available product suites"},
|
{"suite_mask", "Bit mask identifying available product suites"},
|
||||||
{"product_type", "System product type"},
|
{"product_type", "System product type"},
|
||||||
|
{"platform_version", "Diagnostic version number"},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -936,6 +938,12 @@ sys_getwindowsversion(PyObject *self)
|
||||||
PyObject *version;
|
PyObject *version;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
OSVERSIONINFOEX ver;
|
OSVERSIONINFOEX ver;
|
||||||
|
DWORD realMajor, realMinor, realBuild;
|
||||||
|
HANDLE hKernel32;
|
||||||
|
wchar_t kernel32_path[MAX_PATH];
|
||||||
|
LPVOID verblock;
|
||||||
|
DWORD verblock_size;
|
||||||
|
|
||||||
ver.dwOSVersionInfoSize = sizeof(ver);
|
ver.dwOSVersionInfoSize = sizeof(ver);
|
||||||
if (!GetVersionEx((OSVERSIONINFO*) &ver))
|
if (!GetVersionEx((OSVERSIONINFO*) &ver))
|
||||||
return PyErr_SetFromWindowsErr(0);
|
return PyErr_SetFromWindowsErr(0);
|
||||||
|
@ -954,10 +962,40 @@ sys_getwindowsversion(PyObject *self)
|
||||||
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask));
|
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask));
|
||||||
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType));
|
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()) {
|
if (PyErr_Occurred()) {
|
||||||
Py_DECREF(version);
|
Py_DECREF(version);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue