L fork of Tcl breaks Thread

After successful make:

$ ./L/bin/L 
% source tcl/tests/thread.test
Segmentation fault

Something in L’s fork of Tcl has broken threads.

Working of the imported “little” branch in Tcl’s
repository, I see this backtrace:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x2aaab2305700 (LWP 29246)]
0x000000000057d57c in TclLookupSimpleVar (interp=0x2aaab402d078, 
    varNamePtr=0x2aaab425bfc0, flags=1, create=0, errMsgPtr=0x2aaab23048b0, 
    indexPtr=0x2aaab23048bc)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclVar.c:845
845         if ((cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL)
Missing separate debuginfos, use: debuginfo-install glibc-2.17-106.el7_2.4.x86_64 libgcc-4.8.5-4.el7.x86_64 zlib-1.2.7-15.el7.x86_64
(gdb) print cxtNsPtr
$1 = (Namespace *) 0x0
(gdb) bt
#0  0x000000000057d57c in TclLookupSimpleVar (interp=0x2aaab402d078, 
    varNamePtr=0x2aaab425bfc0, flags=1, create=0, errMsgPtr=0x2aaab23048b0, 
    indexPtr=0x2aaab23048bc)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclVar.c:845
#1  0x000000000057d1d0 in TclObjLookupVarEx (interp=0x2aaab402d078, 
    part1Ptr=0x2aaab425bfc0, part2Ptr=0x0, flags=1, msg=0x0, createPart1=0, 
    createPart2=0, arrayPtrPtr=0x2aaab2304a40)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclVar.c:678
#2  0x000000000057ca9f in TclObjLookupVar (interp=0x2aaab402d078, 
    part1Ptr=0x2aaab425bfc0, part2=0x0, flags=1, msg=0x0, createPart1=0, 
    createPart2=0, arrayPtrPtr=0x2aaab2304a40)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclVar.c:488
#3  0x000000000057c960 in TclLookupVar (interp=0x2aaab402d078, 
    part1=0x638927 "L_fnsDeclared", part2=0x0, flags=1, msg=0x0, 
    createPart1=0, createPart2=0, arrayPtrPtr=0x2aaab2304a40)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclVar.c:405
#4  0x00000000005bad06 in compile_fnDecl (fun=0x2aaab41c8b40, 
    flags=(SCOPE_GLOBAL | DECL_FN | FN_PROTO_AND_BODY))
    at /local/tmp/dgp/fossil/tcllittle/generic/Lcompile.c:944
#5  0x00000000005b9f67 in ast_compile (ast=0x2aaab411cf80)
    at /local/tmp/dgp/fossil/tcllittle/generic/Lcompile.c:671
#6  0x00000000005b9975 in compile_script (scriptObj=0x2aaab4259c80, 
    nameObj=0x2aaab41de3f0)
    at /local/tmp/dgp/fossil/tcllittle/generic/Lcompile.c:501
#7  0x00000000005b9679 in Tcl_LObjCmd (clientData=0x0, interp=0x2aaab4268b90, 
    objc=3, objv=0x2aaab42b7ca0)
    at /local/tmp/dgp/fossil/tcllittle/generic/Lcompile.c:447
#8  0x00000000004168cd in Dispatch (data=0xd61b78, interp=0x2aaab4268b90, 
    result=0) at /local/tmp/dgp/fossil/tcllittle/generic/tclBasic.c:4387
#9  0x000000000041695b in TclNRRunCallbacks (interp=0x2aaab4268b90, result=0, 
    rootPtr=0x0) at /local/tmp/dgp/fossil/tcllittle/generic/tclBasic.c:4420
#10 0x0000000000416061 in Tcl_EvalObjv (interp=0x2aaab4268b90, objc=1, 
    objv=0x2aaab42b77c0, flags=2097168)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclBasic.c:4150
#11 0x0000000000418a54 in TclEvalEx (interp=0x2aaab4268b90, 
    script=0x625e48 "if {[namespace which -command tclInit] eq \"\"} {\n  proc tclInit {} {\n    global tcl_libPath tcl_library env tclDefaultLibrary\n    rename tclInit {}\n    if {[info exists tcl_library]} {\n\tset scripts {{s"..., 
    numBytes=2062, flags=0, line=70, clNextOuter=0x0, 
    outerScript=0x625e48 "if {[namespace which -command tclInit] eq \"\"} {\n  proc tclInit {} {\n    global tcl_libPath tcl_library env tclDefaultLibrary\n    rename tclInit {}\n    if {[info exists tcl_library]} {\n\tset scripts {{s"...)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclBasic.c:5306
#12 0x0000000000417cdf in Tcl_EvalEx (interp=0x2aaab4268b90, 
    script=0x625e48 "if {[namespace which -command tclInit] eq \"\"} {\n  proc tclInit {} {\n    global tcl_libPath tcl_library env tclDefaultLibrary\n    rename tclInit {}\n    if {[info exists tcl_library]} {\n\tset scripts {{s"..., 
    numBytes=-1, flags=0)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclBasic.c:4954
#13 0x00000000004195a9 in Tcl_Eval (interp=0x2aaab4268b90, 
    script=0x625e48 "if {[namespace which -command tclInit] eq \"\"} {\n  proc tclInit {} {\n    global tcl_libPath tcl_library env tclDefaultLibrary\n    rename tclInit {}\n    if {[info exists tcl_library]} {\n\tset scripts {{s"...)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclBasic.c:5900
#14 0x0000000000510ea5 in Tcl_Init (interp=0x2aaab4268b90)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclInterp.c:385
#15 0x00002aaab1ef3de2 in NewThread ()
   from /home/dgp/x86_64/linuxoldld/lib/thread2.7.3/libthread2.7.3.so
#16 0x00000000004e8658 in NewThreadProc (clientData=0xc67840)
    at /local/tmp/dgp/fossil/tcllittle/generic/tclEvent.c:1566

The root cause appears to be that somehow
an interp is created with iPtr->globalNsPtr == NULL.
Try to use that… CRASH!

Not certain, but it appears that the root cause of that may be a failure of L’s implementation to honor Tcl’s apartment model for threads.

Appears that L has a global variable named – wait for it – “L” of
type Linterp (see line 230 of Lcompile.h).

The Linterp struct contains a field of type (Tcl_Interp *) and it
appears that L code permits any thread at all to make use of
the interp stored there.

If L is constrained by design to be single-thread only, that
fact should be made more clear, and some guards enforcing
that would be a good idea too.

Cool, thanks for the feedback.
FYI, this forum uses markdown so I tweaked for the formatting of your stack trace so it is easier to read.

One of the other guys will need to respond to your issue.

It wasn’t a design choice, we just haven’t gotten there yet. Who in tcl land knows the most about the thread implementation?