Tk Source Code

View Ticket
Login
Ticket UUID: 805cffb017fde5baeb09ef1b8f4fccb980008cbb
Title: segfault via Tk_ConfigureWidget
Type: Bug Version: 8.5.111-8.6.4
Submitter: aspect Created on: 2015-06-30 15:12:29
Subsystem: 23. Option Parsing Assigned To: jan.nijtmans
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2015-07-07 15:28:17
Resolution: Fixed Closed By: jan.nijtmans
    Closed on: 2015-07-07 15:28:17
Description:
  package require Tk
  catch {canvas .c -bg #001 -width x}
  canvas .d

causes a crash on the above versions (and core-8.5-branch) on Linux and Windows.
Note sure about OSX.  8.6 seems to be unaffected.

Removing either of the options from the first call avoids the crash.  As does re-ordering
them, or specifying "-background" instead of "-bg", or replacing canvas with scrollbar.

The crash comes from the call to Tk_SetBackgroundFromBorder in ConfigureCanvas, which sees
NULL in canvasPtr->bgBorder when the 2nd canvas (.d) is being constructed.

The common element seems to be Tk_ConfigureWidget():  best hypothesis at this stage is:

* the first call to Tk_ConfigureWidget() with a bad -width leaves something related to
the previous option (-bg) in an inconsistent state
* the second call trips over this and returns TCL_OK, but NULL is in bgBorder illegally

See chat log from 2015-06-30T12:41:15Z for initial report and much discussion.
User Comments: jan.nijtmans added on 2015-07-07 15:28:17:
Thanks for the patch! I was able to reproduce it (in Tk 8.6.4 too!), patch appears to work fine and looks good to me.

anonymous added on 2015-07-03 14:53:38:
Possible fix verified withTk 8.6.4 on AndroWish on ARM and plain SDL based Tk 8.6.4 on Linux x86_64:

--- old/generic/tkOldConfig.c    2014-08-26 06:41:06.248988059 +0200
+++ new/generic/tkOldConfig.c    2015-07-03 16:22:01.029610301 +0200
@@ -113,6 +113,10 @@
 
     staticSpecs = GetCachedSpecs(interp, specs);
 
+    for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) {
+       specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
+    }
+
     /*
      * Pass one: scan through all of the arguments, processing those that
      * match entries in the specs.
@@ -167,7 +171,6 @@
            if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED)
                    || (specPtr->argvName == NULL)
                    || (specPtr->type == TK_CONFIG_SYNONYM)) {
-               specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
                continue;
            }
            if (((specPtr->specFlags & needFlags) != needFlags)
@@ -1126,7 +1129,6 @@
                    specPtr->defValue = Tk_GetUid(specPtr->defValue);
                }
            }
-           specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
        }
     } else {
        cachedSpecs = Tcl_GetHashValue(entryPtr);

aspect added on 2015-07-01 00:32:02:
scoofy has summarised key info from the chat at
http://morpheus.spectralhead.com/txt/wish-segfault.tcl.txt

Some of my intelligence above was gathered with the following patch applied:

Index: generic/tkCanvas.c
==================================================================
--- generic/tkCanvas.c
+++ generic/tkCanvas.c
@@ -488,10 +488,12 @@
            |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
            |LeaveWindowMask|PointerMotionMask|VirtualEventMask,
            CanvasBindProc, (ClientData) canvasPtr);
     Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,
            CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING);
+printf("Calling ConfigureCanvas(%p, %p, %d, %p)\n", interp, canvasPtr, argc, argv);
+printf("bgBorder = %p\n", canvasPtr->bgBorder);
     if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
        goto error;
     }
 
     Tcl_SetResult(interp, Tk_PathName(canvasPtr->tkwin), TCL_STATIC);
@@ -1885,21 +1887,32 @@
 {
     XGCValues gcValues;
     GC newGC;
     Tk_State old_canvas_state=canvasPtr->canvas_state;
 
+    printf("Entering Tk_ConfigureWidget(%p, %p, %p, %d, %p, %p, %x)\n",
+           interp, canvasPtr->tkwin, configSpecs,
+           objc, (CONST char **) objv, (char *) canvasPtr,
+           flags);
+    int i;
+    for(i=0; i < objc; ++i) {
+       printf("objv[%d] = '%s'\n", i, Tcl_GetString(objv[i]));
+    }
     if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
            objc, (CONST char **) objv, (char *) canvasPtr,
            flags|TK_CONFIG_OBJS) != TCL_OK) {
+    printf("configure returned ERROR: %p\n", canvasPtr);
        return TCL_ERROR;
     }
+    printf("configure returned .. okay?: %p\n", canvasPtr);
 
     /*
      * A few options need special processing, such as setting the background
      * from a 3-D border and creating a GC for copying bits to the screen.
      */
 
+    printf("About to call SetBackgroundFromBorder(%p, %p)\n", canvasPtr->tkwin, canvasPtr->bgBorder);
     Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
 
     if (canvasPtr->highlightWidth < 0) {
        canvasPtr->highlightWidth = 0;
     }

aspect added on 2015-06-30 15:14:22:
The bad option after -bg doesn't have to be -width:

% catch {scrollbar .c -bg #001 -potato}
% scrollbar .d
Segmentation Fault