Posted to tcl by mr_calvin at Fri Oct 21 13:16:52 GMT 2016view pretty
# How-to run: `tclsh mem.tcl` # # Explanation: On shell exit, ::tcl namespace is not cleaned up, which # leaves Tcl_Objs referenced from within ::tcl with unbalanced # refcounts on exit. Their freeIntRepProcs are not executed. This # happens in interactive shells with the history (::history) feature # on, because it maintains the array ::tcl::history which, upon the # event Tcl_Objs shimmering from string to bytecode intreps, maintains # references beyond the point of shell exit (can be "fixed" by # deactivating the history by redefining the proc history to a NOOP, # or by calling ::history clear before exit). # # Example: The below example reproduces a variant of the issue in a # non-interactive shell (it is not a bytecode Tcl_Obj becoming # referenced from the ::tcl::HISTORY array, but a list). The refcount # bump in <<4b>> is not balanced (3->2) ... so, the freeIntRepProc of # 'new' Tcl_Obj is *never* (MethodFreeInternalRep) executed. set name "new" puts <<1>>[tcl::unsupported::representation $name]; # string(2) package req nx; puts <<2>>[tcl::unsupported::representation $name]; # string(2) set script [list ::nx::Object $name] puts <<3a>>[tcl::unsupported::representation $name]; # string(3) (+1 via list) puts <<3b>>[tcl::unsupported::representation $script]; # list(2) set ::tcl::HISTORY(1) $script ## FIX-1: the below would keep refcounts balanced on exit, because the global ns is cleared: # set ::tcl_HISTORY(1) $script puts <<4a>>[tcl::unsupported::representation $name]; # string(3) puts <<4b>>[tcl::unsupported::representation $script]; # list(3) (+1 via array) try $script; # $script is compiled (intrep -> bytecode), 'new' becomes nsfInstanceMethod intrep with NsfMethodContext puts <<5a>>[tcl::unsupported::representation $name]; # nsfInstanceMethod(3) puts <<5b>>[tcl::unsupported::representation $script]; # list(3) ## FIX-2: explicit deletes # unset ::tcl::HISTORY