summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--tests/registry.test22
-rw-r--r--win/tclWinReg.c88
3 files changed, 94 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 0c9de6e..0b24e79 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-03-17 Kevin Kenny <kennykb@acm.org>
+
+ * win/tclWinReg.c (GetKeyNames): Size the buffer for enumerating
+ key names correctly, so that Unicode names exceeding 127 chars
+ can be retrieved without crashing. [Bug 1682211]
+ * tests/registry.test (registry-4.9): Added test case for the
+ above bug.
+
2007-03-15 Mo DeJong <mdejong@users.sourceforge.net>
* generic/tclIOUtil.c (Tcl_Stat): Reimplement workaround
diff --git a/tests/registry.test b/tests/registry.test
index 28027d5..742a8e5 100644
--- a/tests/registry.test
+++ b/tests/registry.test
@@ -10,7 +10,7 @@
# Copyright (c) 1997 by Sun Microsystems, Inc. All rights reserved.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
-# RCS: @(#) $Id: registry.test,v 1.19 2006/03/21 11:12:29 dkf Exp $
+# RCS: @(#) $Id: registry.test,v 1.20 2007/03/17 22:31:41 kennykb Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest 2
@@ -249,6 +249,20 @@ test registry-4.8 {GetKeyNames: Unicode} {win reg nt} {
registry delete HKEY_CLASSES_ROOT\\TclFoobar
set result
} "baz\u30b7bar blat"
+test registry-4.9 {GetKeyNames: very long key [Bug 1682211]} {*}{
+ -constraints {win && reg}
+ -setup {
+ registry set HKEY_CLASSES_ROOT\\TclFoobar\\a
+ registry set HKEY_CLASSES_ROOT\\TclFoobar\\b[string repeat x 254]
+ registry set HKEY_CLASSES_ROOT\\TclFoobar\\c
+ }
+ -body {
+ lsort [registry keys HKEY_CLASSES_ROOT\\TclFoobar]
+ }
+ -cleanup {
+ registry delete HKEY_CLASSES_ROOT\\TclFoobar
+ }} \
+ -result [list a b[string repeat x 254] c]
test registry-5.1 {GetType} {win reg english} {
registry delete HKEY_CLASSES_ROOT\\TclFoobar
@@ -600,3 +614,9 @@ test registry-12.5 {BroadcastValue} {win reg} {
# cleanup
::tcltest::cleanupTests
return
+
+# Local Variables:
+# mode: tcl
+# tcl-indent-level: 4
+# fill-column: 78
+# End:
diff --git a/win/tclWinReg.c b/win/tclWinReg.c
index f1d7e30..ca61554 100644
--- a/win/tclWinReg.c
+++ b/win/tclWinReg.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinReg.c,v 1.37 2006/04/05 16:52:56 dgp Exp $
+ * RCS: @(#) $Id: tclWinReg.c,v 1.38 2007/03/17 22:31:41 kennykb Exp $
*/
#include "tclInt.h"
@@ -589,21 +589,17 @@ GetKeyNames(
Tcl_Obj *keyNameObj, /* Key to enumerate. */
Tcl_Obj *patternObj) /* Optional match pattern. */
{
- HKEY key;
- DWORD index;
- char buffer[MAX_PATH+1], *pattern, *name;
- Tcl_Obj *resultPtr;
- int result = TCL_OK;
- Tcl_DString ds;
-
- /*
- * Attempt to open the key for enumeration.
- */
-
- if (OpenKey(interp, keyNameObj, KEY_ENUMERATE_SUB_KEYS, 0,
- &key) != TCL_OK) {
- return TCL_ERROR;
- }
+ char *pattern; /* Pattern being matched against subkeys */
+ HKEY key; /* Handle to the key being examined */
+ DWORD subKeyCount; /* Number of subkeys to list */
+ DWORD maxSubKeyLen; /* Maximum string length of any subkey */
+ char *buffer; /* Buffer to hold the subkey name */
+ DWORD bufSize; /* Size of the buffer */
+ DWORD index; /* Position of the current subkey */
+ char *name; /* Subkey name */
+ Tcl_Obj *resultPtr; /* List of subkeys being accumulated */
+ int result = TCL_OK; /* Return value from this command */
+ Tcl_DString ds; /* Buffer to translate subkey name to UTF-8 */
if (patternObj) {
pattern = Tcl_GetString(patternObj);
@@ -611,15 +607,58 @@ GetKeyNames(
pattern = NULL;
}
- /*
- * Enumerate over the subkeys until we get an error, indicating the end of
- * the list.
+ /* Attempt to open the key for enumeration. */
+
+ if (OpenKey(interp, keyNameObj,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ 0, &key) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Determine how big a buffer is needed for enumerating subkeys, and
+ * how many subkeys there are
*/
+ result = (*regWinProcs->regQueryInfoKeyProc)
+ (key, NULL, NULL, NULL, &subKeyCount, &maxSubKeyLen, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ if (result != ERROR_SUCCESS) {
+ Tcl_SetObjResult(interp, Tcl_NewObj());
+ Tcl_AppendResult(interp, "unable to query key \"",
+ Tcl_GetString(keyNameObj), "\": ", NULL);
+ AppendSystemError(interp, result);
+ RegCloseKey(key);
+ return TCL_ERROR;
+ }
+ if (regWinProcs->useWide) {
+ buffer = ckalloc((maxSubKeyLen+1) * sizeof(WCHAR));
+ } else {
+ buffer = ckalloc(maxSubKeyLen+1);
+ }
+
+ /* Enumerate the subkeys */
+
resultPtr = Tcl_NewObj();
- for (index = 0; (*regWinProcs->regEnumKeyProc)(key, index, buffer,
- MAX_PATH+1) == ERROR_SUCCESS; index++) {
- Tcl_WinTCharToUtf((TCHAR *) buffer, -1, &ds);
+ for (index = 0; index < subKeyCount; ++index) {
+ bufSize = maxSubKeyLen+1;
+ result = (*regWinProcs->regEnumKeyExProc)
+ (key, index, buffer, &bufSize, NULL, NULL, NULL, NULL);
+ if (result != ERROR_SUCCESS) {
+ Tcl_SetObjResult(interp, Tcl_NewObj());
+ Tcl_AppendResult(interp,
+ "unable to enumerate subkeys of \"",
+ Tcl_GetString(keyNameObj),
+ "\": ", NULL);
+ AppendSystemError(interp, result);
+ result = TCL_ERROR;
+ break;
+ }
+ if (regWinProcs->useWide) {
+ Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize * sizeof(WCHAR), &ds);
+ } else {
+ Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize, &ds);
+ }
name = Tcl_DStringValue(&ds);
if (pattern && !Tcl_StringMatch(name, pattern)) {
Tcl_DStringFree(&ds);
@@ -632,8 +671,11 @@ GetKeyNames(
break;
}
}
- Tcl_SetObjResult(interp, resultPtr);
+ if (result == TCL_OK) {
+ Tcl_SetObjResult(interp, resultPtr);
+ }
+ ckfree(buffer);
RegCloseKey(key);
return result;
}