From cad5197fbd7951c710146d8333f06a1e1b178211 Mon Sep 17 00:00:00 2001 From: Kevin B Kenny Date: Sat, 17 Mar 2007 22:31:40 +0000 Subject: * 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. --- ChangeLog | 8 +++++ tests/registry.test | 22 +++++++++++++- win/tclWinReg.c | 88 +++++++++++++++++++++++++++++++++++++++-------------- 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 + + * 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 * 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; } -- cgit v0.12