diff -r 25b485deb67a Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py Fri Jan 01 12:22:16 2016 -0600 +++ b/Lib/test/test_winreg.py Fri Jan 01 20:31:16 2016 -0600 @@ -64,7 +64,7 @@ def delete_tree(self, root, subkey): try: - hkey = OpenKey(root, subkey, KEY_ALL_ACCESS) + hkey = OpenKey(root, subkey, 0, KEY_ALL_ACCESS) except WindowsError: # subkey does not exist return @@ -367,6 +367,18 @@ finally: DeleteKey(HKEY_CURRENT_USER, test_key_name) + def test_read_string_containing_null(self): + # Test for issue 25778: REG_SZ should not contain null characters + try: + with CreateKey(HKEY_CURRENT_USER, test_key_name) as ck: + self.assertNotEqual(ck.handle, 0) + test_val = "A string\x00 with a null" + SetValueEx(ck, "test_name", 0, REG_SZ, test_val) + ret_val, ret_type = QueryValueEx(ck, "test_name") + self.assertEqual(ret_type, REG_SZ) + self.assertEqual(ret_val, u"A string") + finally: + DeleteKey(HKEY_CURRENT_USER, test_key_name) @unittest.skipUnless(REMOTE_NAME, "Skipping remote registry tests") diff -r 25b485deb67a PC/_winreg.c --- a/PC/_winreg.c Fri Jan 01 12:22:16 2016 -0600 +++ b/PC/_winreg.c Fri Jan 01 20:31:16 2016 -0600 @@ -789,9 +789,8 @@ } if (!PyString_Check(value)) return FALSE; - *retDataSize = 1 + strlen( - PyString_AS_STRING( - (PyStringObject *)value)); + *retDataSize = 1 + PyString_GET_SIZE( + (PyStringObject *)value); } *retDataBuf = (BYTE *)PyMem_NEW(DWORD, *retDataSize); if (*retDataBuf==NULL){ @@ -801,9 +800,9 @@ if (value == Py_None) strcpy((char *)*retDataBuf, ""); else - strcpy((char *)*retDataBuf, - PyString_AS_STRING( - (PyStringObject *)value)); + memcpy((char *)*retDataBuf, + PyString_AS_STRING((PyStringObject *)value), + *retDataSize); if (need_decref) Py_DECREF(value); break; @@ -929,16 +928,15 @@ break; case REG_SZ: case REG_EXPAND_SZ: - /* retDataBuf may or may not have a trailing NULL in - the buffer. */ - if (retDataSize && retDataBuf[retDataSize-1] == '\0') - --retDataSize; - if (retDataSize ==0) - retDataBuf = ""; - obData = PyUnicode_DecodeMBCS(retDataBuf, - retDataSize, - NULL); - break; + { + /* REG_SZ should be a NUL terminated string, but only by + * convention. The buffer may have been saved without a NUL + * or with embedded NULs. To be consistent with reg.exe and + * regedit.exe, consume only up to the first NUL. */ + size_t len = strnlen(retDataBuf, retDataSize); + obData = PyUnicode_DecodeMBCS(retDataBuf, len, NULL); + break; + } case REG_MULTI_SZ: if (retDataSize == 0) obData = PyList_New(0); @@ -1417,7 +1415,7 @@ if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) return NULL; - + rc = RegQueryValue(hKey, subKey, NULL, &retSize); if (rc == ERROR_MORE_DATA) retSize = 256;