summaryrefslogtreecommitdiff
path: root/Python/sysmodule.c
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2016-09-17 17:27:48 -0700
committerSteve Dower <steve.dower@microsoft.com>2016-09-17 17:27:48 -0700
commitacffd14de543f9752af1ee29c36739c14b05767c (patch)
treedbfd090c97191c1c2c2c5baad80818789556f735 /Python/sysmodule.c
parent00b5fda8506040120d382ffa0c6b0238544fb727 (diff)
downloadcpython-acffd14de543f9752af1ee29c36739c14b05767c.tar.gz
Issue #27932: Prevent memory leak in win32_ver().
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r--Python/sysmodule.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index b7afe93ca5..5dd0d10834 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -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\
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\
-All elements are numbers, except service_pack which is a string. Platform\n\
-may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP/Vista/7,\n\
-3 for Windows CE. Product_type may be 1 for a workstation, 2 for a domain\n\
-controller, 3 for a server."
+All elements are numbers, except service_pack and platform_type which are\n\
+strings, and platform_version which is a 3-tuple. Platform is always 2.\n\
+Product_type may be 1 for a workstation, 2 for a domain controller, 3 for a\n\
+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};
@@ -912,6 +913,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}
};
@@ -936,6 +938,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);
@@ -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.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;
}