Itk - the [incr Tk] extension

View Ticket
Login
Ticket Hash: 9ca6444fcd84ba5a051bfeba2a423664b6d2ed78
Title: iwidgets dateentry dumps core if used twice
Status: Closed Type: Code_Defect
Severity: Critical Priority: Immediate
Subsystem: Resolution: Fixed
Last Modified: 2016-03-01 15:56:29
Version Found In: iwidgets 4.0.1
User Comments:
dagnygren added on 2015-04-23 16:53:11:
Get a stright core dump when using a dateentry widget twice in the same window.

Example code borrowed from demos:
=============================
package require Iwidgets 4.0

proc returnCmd {} {
  puts [.de get]
}

iwidgets::dateentry .de -labeltext "Start Date:" -command returnCmd
pack .de -fill x -expand yes -padx 10 -pady 10

iwidgets::dateentry .de0 -labeltext "End Date:"
pack .de0
============================
Core dump stack trace:
(gdb) bt
#0  0x0000001c0000000c in ?? ()
#1  0x00007fffedd70715 in Itcl_EvalMemberCode (interp=0x619e80, imPtr=0x8a2820, contextIoPtr=0xb2a970, objc=1, objv=0x61ee08)
    at ./generic/itclMethod.c:1277
#2  0x00007fffedd7122e in NRExecMethod (clientData=0x8a2820, interp=0x619e80, objc=1, objv=0x61ee08)
    at ./generic/itclMethod.c:1649
#3  0x00007ffff7648b72 in Dispatch (data=0xc4da48, interp=0x619e80, result=0)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:4359
#4  0x00007ffff7648bfb in TclNRRunCallbacks (interp=0x619e80, result=0, rootPtr=0xc4da70)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:4392
#5  0x00007ffff764e645 in Tcl_NRCallObjProc (interp=0x619e80, objProc=0x7fffedd710c9 <NRExecMethod>, clientData=0x8a2820, objc=1, 
    objv=0x61ee08) at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:8077
#6  0x00007fffedd7128a in Itcl_ExecMethod (clientData=0x8a2820, interp=0x619e80, objc=1, objv=0x61ee08)
    at ./generic/itclMethod.c:1662
#7  0x00007ffff7648b72 in Dispatch (data=0xc4e618, interp=0x619e80, result=0)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:4359
#8  0x00007ffff7648bfb in TclNRRunCallbacks (interp=0x619e80, result=0, rootPtr=0xc4e9d0)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:4392
#9  0x00007ffff764b730 in TclEvalObjEx (interp=0x619e80, objPtr=0xa56220, flags=0, invoker=0x0, word=0)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:5960
#10 0x00007ffff764b6c4 in Tcl_EvalObjEx (interp=0x619e80, objPtr=0xa56220, flags=0)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:5941
#11 0x00007fffedb34bc1 in Itk_ConfigClassOption () from /usr/local/lib/itk4.0.1/libitk4.0.1.so
#12 0x00007fffedb335be in ?? () from /usr/local/lib/itk4.0.1/libitk4.0.1.so
#13 0x00007ffff7648b72 in Dispatch (data=0xab6068, interp=0x619e80, result=0)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:4359
#14 0x00007ffff7648bfb in TclNRRunCallbacks (interp=0x619e80, result=0, rootPtr=0xa53850)
    at /usr/local/src/languages/tcl/tcl8.6.4/generic/tclBasic.c:4392
#15 0x00007fffedd3e26c in Itcl_NRRunCallbacks (interp=0x619e80, rootPtr=0xa53850) at ./generic/itcl2TclOO.c:28
#16 0x00007fffedd7acb9 in ItclObjectCmd (clientData=0x9ea490, interp=0x619e80, oPtr=0xb4ad10, clsPtr=0x0, objc=3, objv=0x61eb30)
    at ./generic/itclObject.c:3095
#17 0x00007fffedd7050b in CallItclObjectCmd (data=0xab5a08, interp=0x619e80, result=0) at ./generic/itclMethod.c:1172
============================
Versions:
tcl 8.6.4
tk 8.6.4
itk 4.0.1
iwidgets 4.0.1

dagnygren added on 2015-04-25 11:24:45:
Found the reason:
Both dateentry and timeentry tries to rewrite itself
for getting the default Icon (In dateentry iwidgets::Dateentry::_getDefaultIcon).

The code is:
    itcl::body ::iwidgets::Dateentry::_getDefaultIcon {} {
        return $_defaultIcon
    }


within the method itself.
Never really liked selfmodifying code and just changed the logic
to check if the icon name is empty and only executing the finding code
if so, otherwise it will return the old value.

Somebody with iwidgets knowledge might want to enter this in the code as I con't even know whom to address...


But the interpreter should still NOT crash....

dgp added on 2015-05-01 16:57:25:
The submitted demo does not segfault for me when
I make use of the current trunk of Itcl and Itk
and the iwidgets found here:

http://core.tcl.tk/iwidgets/index

which calls itself "iwidgets 4.1"

I take it this is not the same scenario where
you see the crash.

If the Itcl trunk can still be made to crash, I
am interested.  Please tell me where to find the
iwidgets 4.0.1 you used in your testing.  Thanks.

dagnygren added on 2015-05-01 17:23:36:
I got iwidgets from:
http://sourceforge.net/projects/incrtcl/files/%5BIncr%20Widgets%5D/4.0.1/

But thanks for pointing to the 4.1 version.

dgp added on 2015-05-06 16:24:53:
The 2002 release housed @ sourceforge calling itself "Iwidgets 4.0.1"
as downloaded is completlely incompatible with the current systems
for building and installing Tcl packages.  Its `make install` target
seeks to use an "installFile.tcl" script that was apparently retired 
in 2002.

If you can fill in the gaps of the actual steps you followed to take
those sources, make them available for use by Tcl, and then prompt
a segfault, that would be helpful.

dgp added on 2015-05-06 16:38:36:
I managed to adapt the Makefile to use the modern tclconfig/install-sh
program instead, and then `make install` produces what I must assume
is the intended installation of "Iwidgets 4.0.1".  At least before
I installed, there was no such package to be found, and after I
installed, [package require Iwidgets] succeeded and reported 4.0.1
as the loaded version.

dgp added on 2015-05-06 16:39:09:
Having done that, however, a `make test` attempt is 
a festival of failure.

dgp added on 2015-05-06 16:43:40:
The good news is that having Iwidgets 4.0.1 installed,
I can attempt the submitted bug demo.

Right away, things are not as reported.  The Iwidget 4.0.1
sources have explicit dependency command:

package require Itk 3.2

Following [package] version satisfaction rules, this seeks
out the latest Itk 3.* installed, and will not make use of
Itk 4.  That works as expected, and I find that I am testing
Iwidgets 4.0.1 partnered with packages that call themselves:

% set itcl::patchLevel
3.4.2
% set itk::patchLevel
3.4.1

Continuing the demo script, there is no crash.

dgp added on 2015-05-06 16:52:59:
So then I hacked out the requirements arguments
so that Iwidgets 4.0.1 would drag in the latest
Itk and Itcl it could find:

% package require Iwidgets
4.0.1
% set itcl::patchLevel
4.0.3
% set itk::patchLevel
4.0.1
% proc returnCmd {} {
  puts [.de get]
}
% iwidgets::dateentry .de -labeltext "Start Date:" -command returnCmd
.de
% pack .de -fill x -expand yes -padx 10 -pady 10
% iwidgets::dateentry .de0 -labeltext "End Date:"
Segmentation fault

Reproduced!

dgp added on 2015-05-06 17:26:24:
When I enable debugging symbols in everything to get more info,
the segfault goes away, and in its place I get an error with
-errorinfo:


class "iwidgets::Dateentry" already exists
    while executing
"itcl::class iwidgets::Dateentry {
    inherit iwidgets::Datefield

    constructor {args} {
        eval Datefield::constructor $args
    } {}

    itk_optio..."
    (file "/home/dgp/x86_64/linuxoldld/lib/iwidgets/scripts/dateentry.itk" line 59)
    invoked from within
"source /home/dgp/x86_64/linuxoldld/lib/iwidgets/scripts/dateentry.itk"
    (in namespace eval "::" script line 1)
    invoked from within
"namespace eval :: $auto_index($name)"
    (procedure "::auto_load" line 13)
    invoked from within
"::auto_load ::iwidgets::Dateentry::_getDefaultIcon"
    (while autoloading code for "::iwidgets::Dateentry::_getDefaultIcon")
    invoked from within
"_getDefaultIcon"
    (while configuring option "-icon" for widget "::.de0")
    invoked from within
"::itcl::builtin::Archetype itk_initialize {*}$args"
    (object "::.de0" method "::itk::Archetype::itk_initialize" body line 2)
    invoked from within
"itk_initialize -labeltext {End Date:}"
    ("eval" body line 1)
    invoked from within
"eval itk_initialize $args"
    while constructing object "::.de0" in ::iwidgets::Dateentry::constructor (body line 16)
    invoked from within
"::iwidgets::Dateentry .de0 -labeltext {End Date:}"
    ("uplevel" body line 1)
    invoked from within
"uplevel ::iwidgets::Dateentry $pathName $args"
    (procedure "iwidgets::dateentry" line 2)
    invoked from within
"iwidgets::dateentry .de0 -labeltext "End Date:""

The mysteries would be 1) Why a repeated auto-load attempt?
and 2) Where did the segfault go?

dagnygren added on 2015-05-06 18:55:04:
Nice to see that it was not only me :-)

1. I also wondered about this. My not so much informed suspicion is that the redefine in the first invocation makes the function somehow different in name and thus itcl is trying to autoload again ??
2. This points to a stack or heap overrun somewhere. Debug reorders the variables on stack/heap and the overrun does not cause a core dump. But there is definitely a fault in the code somewhere...

dgp added on 2015-05-06 19:07:25:
You likely already know this, but indeed removing
the overwriting [itcl::body] makes the problem go away.

dgp added on 2015-05-06 19:25:18:
An important clue seems to be that Itcl itself
makes calls to [::auto_load] -- calls that don't
pass through [::unknown].

As an aside, this is a sticking point for any
plans to phase out the auto-loader commands.

dgp added on 2015-05-07 16:44:14:
The error is in the preservation logic governing the lifecycle
of the ItclMemberCode struct in Itcl.  When the code is changed
in mid-operation, the preserves and releases are not properly
balanced and as a consequence an imPtr->codePtr that is still
being used gets freed.

In the right circumstances, that freed memory is allocated to
other things, overwritten, and total chaos ensues.

dgp added on 2015-05-07 16:52:31:
In particular, the routine ItclCheckCallMethod() takes care to
preserve the value of imPtr->codePtr in the pre-method setup code.

Later, the routine ItclAfterCallMethod() take care to release
the value of imPtr->codePtr in the post-method teardown code.

The problem is that there's nothing in place to make sure
the value of imPtr->codePtr hasn't changed on us during the
method evaluation.  Then the balance is wrong and it's a mess.

dgp added on 2015-05-07 20:31:17:
See branch bug-9ca6444fcd in the Itcl repos
for a first attempt at a patch for this.

Really don't like it, but really don't like
what it's building on either.  Seems to work.

dgp added on 2016-03-01 15:56:29:
With the Itcl 4.0.4 and Itk 4.0.2 releases, I no longer
reproduce this.  I will close the branch with the candidate
fix, since other changes seem to have corrected the problem.
Please add a comment here if you do not confirm this.