summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--changes4
-rw-r--r--generic/ttk/ttkTrace.c46
-rw-r--r--tests/ttk/ttk.test10
-rwxr-xr-xwin/configure58
-rw-r--r--win/tcl.m415
6 files changed, 143 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index c5b20b1..d865dae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/changes b/changes
index aad0c59..c5d1155 100644
--- a/changes
+++ b/changes
@@ -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
diff --git a/win/tcl.m4 b/win/tcl.m4
index be22fac..83a4ea3 100644
--- a/win/tcl.m4
+++ b/win/tcl.m4
@@ -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