diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | changes | 4 | ||||
-rw-r--r-- | generic/ttk/ttkTrace.c | 46 | ||||
-rw-r--r-- | tests/ttk/ttk.test | 10 | ||||
-rwxr-xr-x | win/configure | 58 | ||||
-rw-r--r-- | win/tcl.m4 | 15 |
6 files changed, 143 insertions, 1 deletions
@@ -1,3 +1,14 @@ +2011-06-17 Don Porter <dgp@users.sourceforge.net> + + * generic/ttk/ttkTrace.c: Workaround Bug 3062331. + * tests/ttk/ttk.test: + * changes: Updated + +2011-06-16 Jan Nijtmans <nijtmans@users.sf.net> + + * win/tcl.m4: Sync with win/tcl.m4 from Tcl + * win/configure: (regenerated) + 2011-06-10 Don Porter <dgp@users.sourceforge.net> * README: Correct some README bitrot. @@ -6778,4 +6778,6 @@ and -to (porter) 2011-06-10 (bug fix)[3175610] incomplete line item refresh (ferrieux) ---- Released 8.5.10, June 17, 2011 --- See ChangeLog for details --- +2011-06-17 (bug fix)[3062331] crash in unset traces (macdonald,porter) + +--- Released 8.5.10, June 22, 2011 --- See ChangeLog for details --- diff --git a/generic/ttk/ttkTrace.c b/generic/ttk/ttkTrace.c index 0128a1d..f171f3d 100644 --- a/generic/ttk/ttkTrace.c +++ b/generic/ttk/ttkTrace.c @@ -44,6 +44,16 @@ VarTraceProc( * If the variable is being unset, then re-establish the trace: */ if (flags & TCL_TRACE_DESTROYED) { + /* + * If a prior call to Ttk_UntraceVariable() left behind an + * indicator that we wanted this handler to be deleted (see below), + * cleanup the ClientData bits and exit. + */ + if (tracePtr->interp == NULL) { + Tcl_DecrRefCount(tracePtr->varnameObj); + ckfree((ClientData)tracePtr); + return NULL; + } Tcl_TraceVar(interp, name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, VarTraceProc, clientData); @@ -104,6 +114,42 @@ Ttk_TraceHandle *Ttk_TraceVariable( void Ttk_UntraceVariable(Ttk_TraceHandle *h) { if (h) { + ClientData cd = NULL; + + /* + * Workaround for Tcl Bug 3062331. The trace design problem is + * that when variable unset traces fire, Tcl documents that the + * traced variable has already been unset. It's already gone. + * So from within an unset trace, if you try to call + * Tcl_UntraceVar() on that variable, it will do nothing, because + * the variable by that name can no longer be found. It's gone. + * This means callers of Tcl_UntraceVar() that might be running + * in response to an unset trace have to handle the possibility + * that their Tcl_UntraceVar() call will do nothing. In this case, + * we have to support the possibility that Tcl_UntraceVar() will + * leave the trace in place, so we need to leave the ClientData + * untouched so when that trace does fire it will not crash. + */ + + /* + * Search the traces on the variable to see if the one we are tasked + * with removing is present. + */ + while ((cd = Tcl_VarTraceInfo(h->interp, Tcl_GetString(h->varnameObj), + 0, VarTraceProc, cd)) != NULL) { + if (cd == (ClientData) h) { + break; + } + } + /* + * If the trace we wish to delete is not visible, Tcl_UntraceVar + * will do nothing, so don't try to call it. Instead set an + * indicator in the Ttk_TraceHandle that we need to cleanup later. + */ + if (cd == NULL) { + h->interp = NULL; + return; + } Tcl_UntraceVar(h->interp, Tcl_GetString(h->varnameObj), TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, VarTraceProc, (ClientData)h); diff --git a/tests/ttk/ttk.test b/tests/ttk/ttk.test index ddfaf84..1eec180 100644 --- a/tests/ttk/ttk.test +++ b/tests/ttk/ttk.test @@ -555,6 +555,16 @@ test ttk-14.3 "-textvariable in nonexistant namespace" -body { } -returnCodes 1 -result {can't trace *: parent namespace doesn't exist} \ -match glob -cleanup { destroy .tw } +test ttk-15.1 {Bug 3062331} -setup { + destroy .b +} -body { + set Y {} + ttk::button .b -textvariable Y + trace variable Y u "destroy .b" + unset Y +} -cleanup { + destroy .b +} -result {} ## Test ensemble processing: # diff --git a/win/configure b/win/configure index 5911b66..b3a6294 100755 --- a/win/configure +++ b/win/configure @@ -3512,6 +3512,64 @@ echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6 echo "$as_me:$LINENO: result: Using 64-bit $MACHINE mode" >&5 echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6 ;; + *) + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #ifdef _WIN64 + #error 64-bit + #endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + tcl_win_64bit=no +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +tcl_win_64bit=yes + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$tcl_win_64bit" = "yes" ; then + do64bit=amd64 + MACHINE="AMD64" + echo "$as_me:$LINENO: result: Using 64-bit $MACHINE mode" >&5 +echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6 + fi + ;; esac else if test "${SHARED_BUILD}" = "0" ; then @@ -557,6 +557,21 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ MACHINE="IA64" AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) ;; + *) + AC_TRY_COMPILE([ + #ifdef _WIN64 + #error 64-bit + #endif + ], [], + tcl_win_64bit=no, + tcl_win_64bit=yes + ) + if test "$tcl_win_64bit" = "yes" ; then + do64bit=amd64 + MACHINE="AMD64" + AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) + fi + ;; esac else if test "${SHARED_BUILD}" = "0" ; then |