diff options
author | Brian Curtin <brian.curtin@gmail.com> | 2010-05-26 18:09:32 (GMT) |
---|---|---|
committer | Brian Curtin <brian.curtin@gmail.com> | 2010-05-26 18:09:32 (GMT) |
commit | 9c9d878b3a65c33a13ebb96221db8578841126f3 (patch) | |
tree | 0ce814e563a7781652ed6474411f9dac79c1a021 | |
parent | f6da42fd5af0954d6d8a4f1cde08a56aca17fafd (diff) | |
download | cpython-9c9d878b3a65c33a13ebb96221db8578841126f3.zip cpython-9c9d878b3a65c33a13ebb96221db8578841126f3.tar.gz cpython-9c9d878b3a65c33a13ebb96221db8578841126f3.tar.bz2 |
Merged revisions 81547 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/py3k
........
r81547 | brian.curtin | 2010-05-26 12:43:50 -0500 (Wed, 26 May 2010) | 6 lines
Fix #2810 - handle the case where some registry calls return
ERROR_MORE_DATA, requiring another call to get the remaining data.
Patch by Daniel Stutzbach
........
-rw-r--r-- | Lib/test/test_winreg.py | 54 | ||||
-rw-r--r-- | Misc/NEWS | 6 | ||||
-rw-r--r-- | PC/winreg.c | 119 |
3 files changed, 151 insertions, 28 deletions
diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index fd28852..37ec2bc 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -5,6 +5,7 @@ import os, sys import unittest from test import support +threading = support.import_module("threading") # Do this first so test will be skipped if module doesn't exist support.import_module('winreg') @@ -185,6 +186,59 @@ class WinregTests(unittest.TestCase): self.assertEqual(type(r), str) self.assertEqual(r, os.environ["windir"] + "\\test") + def test_changing_value(self): + # Issue2810: A race condition in 2.6 and 3.1 may cause + # EnumValue or QueryValue to throw "WindowsError: More data is + # available" + done = False + + class VeryActiveThread(threading.Thread): + def run(self): + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: + use_short = True + long_string = 'x'*2000 + while not done: + s = 'x' if use_short else long_string + use_short = not use_short + SetValue(key, 'changing_value', REG_SZ, s) + + thread = VeryActiveThread() + thread.start() + try: + with CreateKey(HKEY_CURRENT_USER, + test_key_name+'\\changing_value') as key: + for _ in range(1000): + num_subkeys, num_values, t = QueryInfoKey(key) + for i in range(num_values): + name = EnumValue(key, i) + QueryValue(key, name[0]) + finally: + done = True + thread.join() + DeleteKey(HKEY_CURRENT_USER, test_key_name+'\\changing_value') + DeleteKey(HKEY_CURRENT_USER, test_key_name) + + def test_long_key(self): + # Issue2810, in 2.6 and 3.1 when the key name was exactly 256 + # characters, EnumKey threw "WindowsError: More data is + # available" + name = 'x'*256 + try: + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: + SetValue(key, name, REG_SZ, 'x') + num_subkeys, num_values, t = QueryInfoKey(key) + EnumKey(key, 0) + finally: + DeleteKey(HKEY_CURRENT_USER, '\\'.join((test_key_name, name))) + DeleteKey(HKEY_CURRENT_USER, test_key_name) + + def test_dynamic_key(self): + # Issue2810, when the value is dynamically generated, these + # throw "WindowsError: More data is available" in 2.6 and 3.1 + EnumValue(HKEY_PERFORMANCE_DATA, 0) + QueryValueEx(HKEY_PERFORMANCE_DATA, "") + + def test_main(): support.run_unittest(WinregTests) @@ -211,6 +211,12 @@ Library - Issue #6716/2: Backslash-replace error output in compilall. +Extension Modules +----------------- + +- Issue #2810: Fix cases where the Windows registry API returns + ERROR_MORE_DATA, requiring a re-try in order to get the complete result. + Build ----- diff --git a/PC/winreg.c b/PC/winreg.c index e6d113d..c321d9f 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -1003,7 +1003,14 @@ PyEnumKey(PyObject *self, PyObject *args) int index; long rc; PyObject *retStr; - wchar_t tmpbuf[256]; /* max key name length is 255 */ + + /* The Windows docs claim that the max key name length is 255 + * characters, plus a terminating nul character. However, + * empirical testing demonstrates that it is possible to + * create a 256 character key that is missing the terminating + * nul. RegEnumKeyEx requires a 257 character buffer to + * retrieve such a key name. */ + wchar_t tmpbuf[257]; DWORD len = sizeof(tmpbuf); /* includes NULL terminator */ if (!PyArg_ParseTuple(args, "Oi:EnumKey", &obKey, &index)) @@ -1030,8 +1037,8 @@ PyEnumValue(PyObject *self, PyObject *args) long rc; wchar_t *retValueBuf; BYTE *retDataBuf; - DWORD retValueSize; - DWORD retDataSize; + DWORD retValueSize, bufValueSize; + DWORD retDataSize, bufDataSize; DWORD typ; PyObject *obData; PyObject *retVal; @@ -1049,6 +1056,8 @@ PyEnumValue(PyObject *self, PyObject *args) "RegQueryInfoKey"); ++retValueSize; /* include null terminators */ ++retDataSize; + bufDataSize = retDataSize; + bufValueSize = retValueSize; retValueBuf = (wchar_t *)PyMem_Malloc(sizeof(wchar_t) * retValueSize); if (retValueBuf == NULL) return PyErr_NoMemory(); @@ -1058,16 +1067,33 @@ PyEnumValue(PyObject *self, PyObject *args) return PyErr_NoMemory(); } - Py_BEGIN_ALLOW_THREADS - rc = RegEnumValueW(hKey, - index, - retValueBuf, - &retValueSize, - NULL, - &typ, - retDataBuf, - &retDataSize); - Py_END_ALLOW_THREADS + while (1) { + wchar_t *tmp; + Py_BEGIN_ALLOW_THREADS + rc = RegEnumValueW(hKey, + index, + retValueBuf, + &retValueSize, + NULL, + &typ, + (BYTE *)retDataBuf, + &retDataSize); + Py_END_ALLOW_THREADS + + if (rc != ERROR_MORE_DATA) + break; + + bufDataSize *= 2; + tmp = (char *)PyMem_Realloc(retDataBuf, bufDataSize); + if (tmp == NULL) { + PyErr_NoMemory(); + retVal = NULL; + goto fail; + } + retDataBuf = tmp; + retDataSize = bufDataSize; + retValueSize = bufValueSize; + } if (rc != ERROR_SUCCESS) { retVal = PyErr_SetFromWindowsErrWithFunction(rc, @@ -1224,23 +1250,44 @@ PyQueryValue(PyObject *self, PyObject *args) long rc; PyObject *retStr; wchar_t *retBuf; - long bufSize = 0; + DWORD bufSize = 0; + DWORD retSize = 0; + wchar_t *tmp; if (!PyArg_ParseTuple(args, "OZ:QueryValue", &obKey, &subKey)) return NULL; if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) return NULL; - if ((rc = RegQueryValueW(hKey, subKey, NULL, &bufSize)) - != ERROR_SUCCESS) + + rc = RegQueryValueW(hKey, subKey, NULL, &retSize); + if (rc == ERROR_MORE_DATA) + retSize = 256; + else if (rc != ERROR_SUCCESS) return PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryValue"); - retBuf = (wchar_t *)PyMem_Malloc(bufSize); + + bufSize = retSize; + retBuf = (wchar_t *) PyMem_Malloc(bufSize); if (retBuf == NULL) return PyErr_NoMemory(); - if ((rc = RegQueryValueW(hKey, subKey, retBuf, &bufSize)) - != ERROR_SUCCESS) { + while (1) { + retSize = bufSize; + rc = RegQueryValueW(hKey, subKey, retBuf, &retSize); + if (rc != ERROR_MORE_DATA) + break; + + bufSize *= 2; + tmp = (wchar_t *) PyMem_Realloc(retBuf, bufSize); + if (tmp == NULL) { + PyMem_Free(retBuf); + return PyErr_NoMemory(); + } + retBuf = tmp; + } + + if (rc != ERROR_SUCCESS) { PyMem_Free(retBuf); return PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryValue"); @@ -1259,8 +1306,8 @@ PyQueryValueEx(PyObject *self, PyObject *args) wchar_t *valueName; long rc; - BYTE *retBuf; - DWORD bufSize = 0; + BYTE *retBuf, *tmp; + DWORD bufSize = 0, retSize; DWORD typ; PyObject *obData; PyObject *result; @@ -1270,18 +1317,34 @@ PyQueryValueEx(PyObject *self, PyObject *args) if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) return NULL; - if ((rc = RegQueryValueExW(hKey, valueName, - NULL, NULL, NULL, - &bufSize)) - != ERROR_SUCCESS) + + rc = RegQueryValueExW(hKey, valueName, NULL, NULL, NULL, &bufSize); + if (rc == ERROR_MORE_DATA) + bufSize = 256; + else if (rc != ERROR_SUCCESS) return PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryValueEx"); retBuf = (BYTE *)PyMem_Malloc(bufSize); if (retBuf == NULL) return PyErr_NoMemory(); - if ((rc = RegQueryValueExW(hKey, valueName, NULL, - &typ, retBuf, &bufSize)) - != ERROR_SUCCESS) { + + while (1) { + retSize = bufSize; + rc = RegQueryValueExW(hKey, valueName, NULL, &typ, + (BYTE *)retBuf, &retSize); + if (rc != ERROR_MORE_DATA) + break; + + bufSize *= 2; + tmp = (char *) PyMem_Realloc(retBuf, bufSize); + if (tmp == NULL) { + PyMem_Free(retBuf); + return PyErr_NoMemory(); + } + retBuf = tmp; + } + + if (rc != ERROR_SUCCESS) { PyMem_Free(retBuf); return PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryValueEx"); |