Menu

#2050 Tcl_InitStubs crash/exception

obsolete: 8.4.0
closed
5
2002-11-27
2002-09-27
Anonymous
No

The error primarily involves the Tcl_InitStubs
function.

This is the scenario that causes the error:

1. Upon being loaded the component first calls
LoadLibrary for both the Tcl and Tk DLLs. Next,
some other initialization functions are called.
Finally, Tcl_InitStubs is called successfully.
Initialization is now complete.

2. Various Tcl/Tk calls are made without any
problems.

3. During component shutdown, Tcl_Finalize is
called followed by FreeLibrary on both the Tcl and
Tk DLLs.

4. Later, when the component is loaded again into
the same process (it's still running), it calls
LoadLibrary for both the Tcl and Tk DLLs [again]
and calls Tcl_InitStubs [again] as part of it's
initialization routine. An exception is immediately
thrown (unable to even step-into the code for
Tcl_InitStubs).

It is my impression that somehow the Tcl_InitStubs
function might be getting corrupted by
Tcl_Finalize.

If this behavior is by design, I apologize in advance
for this bug report.

JJM

Discussion

  • Jeffrey Hobbs

    Jeffrey Hobbs - 2002-10-01
    • assigned_to: nobody --> davygrvy
     
  • David Gravereaux

    Logged In: YES
    user_id=7549

    Tcl_Finalize() is normally used at the end of the application. I
    see what your doing and agree it should be looked at as
    unloading the DLL (but not the app) is a like completion.

    This should probably be an easy bug to fix once I get some
    free time to have a look.

     
  • David Gravereaux

    Logged In: YES
    user_id=7549

    Attached is a test console application that does what you
    describe, but I found no crashing happening.

    It could be possible that you're calling a Stubs redirected
    function after the unload (or between the loading) and that
    could be the cause. Have a look at the attachment and let
    me know if you have any follow-up concerns.

     
  • David Gravereaux

    • labels: --> 50. Embedding Support
    • status: open --> pending
     
  • David Gravereaux

    test case from bug description.

     
  • Nobody/Anonymous

    Logged In: NO

    When I stepped through the code (several times) to
    diagnose the problem, I noticed that the
    variable "tclStubsPtr" is never being reset to NULL.
    Additionally, it does not appear to ever be explicitly
    initialized to NULL.

    CONST char *
    Tcl_InitStubs (interp, version, exact)
    Tcl_Interp *interp;
    CONST char *version;
    int exact;
    {
    CONST char *actualVersion;
    TclStubs *tmp;

    if (!tclStubsPtr) {

    //*** NOTE: The first time through here, the tclStubsPtr
    is set to the one from the interp.
    //*** Since the tclStubsPtr is never explicitly reset (at
    least, not that I can find), this code is not executed the
    second time through.

    tclStubsPtr = HasStubSupport(interp);
    if (!tclStubsPtr) {
    return NULL;
    }
    }

    //*** I'm not sure what the "tmp" variable here is doing.
    //*** Upon close examination, I believe the cause of the
    crash is a bad address for Tcl_PkgRequireEx, as this is a
    macro defined to be "tclStubsPtr->tcl_PkgRequireEx".
    //*** Since the tclStubsPtr variable does not really exist
    in a known state after the first time around (or really, at
    all), by the time the second time roles around there is
    somehow total garbage in the tclStubsPtr that a simple
    call to HasStubSupport seems to fix. This is due to the
    fact that Tcl_CreateInterp actually sets up the internal
    stubs table inside the interp prior to Tcl_InitStubs ever
    being called, and I believe that Tcl_InitStubs should
    always rely on those values alone.

    actualVersion = Tcl_PkgRequireEx(interp, "Tcl",
    version, exact,
    (ClientData *) &tmp);
    if (actualVersion == NULL) {
    tclStubsPtr = NULL;
    return NULL;
    }

    if (tclStubsPtr->hooks) {
    tclPlatStubsPtr = tclStubsPtr->hooks-
    >tclPlatStubs;
    tclIntStubsPtr = tclStubsPtr->hooks-
    >tclIntStubs;
    tclIntPlatStubsPtr = tclStubsPtr->hooks-
    >tclIntPlatStubs;
    } else {
    tclPlatStubsPtr = NULL;
    tclIntStubsPtr = NULL;
    tclIntPlatStubsPtr = NULL;
    }

    return actualVersion;
    }

    JJM

     
  • David Gravereaux

    • status: pending --> open
     
  • David Gravereaux

    Logged In: YES
    user_id=7549

    Ahh! I agree with your detective work.

    As there isn't any linkage from Tcl to your
    extension/application when using Stubs, Tcl_Finalize can not
    take on responsibility to affect a global in the Stubs library
    used, so it looks like you should set it manually to NULL,
    now armed with the knowledge of how it works.

    void
    UnloadIt(Tcl_Interp *interp)
    {
    extern TclStubs *tclStubsPtr;

    Tcl_DeleteInterp(interp);
    Tcl_Finalize();
    FreeLibrary(hTclModule);
    tclStubsPtr = NULL;
    }

    I guess I was lucky in that Tcl had loaded into the same
    place for the test case I had made.

    Does this solve it for you?

     
  • Nobody/Anonymous

    Logged In: NO

    That works for me... Sounds like it's a doc fix... :)

     
  • David Gravereaux

    • status: open --> closed
     
  • David Gravereaux

    Logged In: YES
    user_id=7549

    I don't know if a doc fix is needed.. Seems like an edge case.

     
  • Jeffrey Hobbs

    Jeffrey Hobbs - 2002-12-04

    Logged In: YES
    user_id=72656

    The solution is to not do the tclStubsPtr check in
    tclStubLib.c Dave's work-around it also good, but you can
    make the tclStubLib.c change yourself if you compile
    yourself, since that part is statically loaded into your code. I
    plan on making that standard for future versions of Tcl.