Tcl Source Code

View Ticket
Login
Ticket UUID: 28027d8bb7745fb053954276bb62aa4d6e340b16
Title: Per-interp Loaded library structures not cleaned up on interp exit.
Type: Bug Version:
Submitter: pooryorick Created on: 2021-05-15 09:44:07
Subsystem: - New Builtin Commands Assigned To: nobody
Priority: 5 Medium Severity: Important
Status: Open Last Modified: 2021-05-15 22:30:31
Resolution: Fixed Closed By: nobody
    Closed on:
Description:

At least through commit [7ffa017f9b76bf5d], The command,

make TESTFLAGS='-file unload.test -v t -match "unload-4.1"' valgrind >zzz2 2>&1

, produces a report indicating indirectly and directly-lost bytes as shown below. The cause is that when an interpreter is cleaned up, the list of loaded libraries is not currently cleaned up, and therefor storage that has been allocated is not deallocated.

unload.test
---- unload-4.1 start
--473305-- Reading syms from /path/to/src/unix/dltest/pkgua.so

Tests ended at Sat May 15 12:30:27 EEST 2021
all.tcl:	Total	27	Passed	1	Skipped	26	Failed	0
Sourced 1 Test Files.
--473305-- Discarding syms at 0x4abf060-0x4abfa88 in /path/to/src/unix/dltest/pkgua.so (have_dinfo 1)
--473305-- Discarding syms at 0x5830550-0x583617c in /usr/lib/libnss_files-2.33.so (have_dinfo 1)
==473305== 
==473305== HEAP SUMMARY:
==473305==     in use at exit: 64 bytes in 2 blocks
==473305==   total heap usage: 251,042 allocs, 251,040 frees, 33,292,046 bytes allocated
==473305== 
==473305== Searching for pointers to 2 not-freed blocks
==473305== Checked 151,504 bytes
==473305== 
==473305== 24 bytes in 1 blocks are indirectly lost in loss record 1 of 2
==473305==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==473305==    by 0x488C464: TclpAlloc (tclAlloc.c:699)
==473305==    by 0x48A89FE: Tcl_Alloc (tclCkalloc.c:1054)
==473305==    by 0x4ABF259: ???
==473305==    by 0x4ABF5D1: ???
==473305==    by 0x49D2FB4: Tcl_LoadObjCmd (tclLoad.c:463)
==473305==    by 0x4899194: Dispatch (tclBasic.c:4817)
==473305==    by 0x489921A: TclNRRunCallbacks (tclBasic.c:4857)
==473305==    by 0x4898ADC: Tcl_EvalObjv (tclBasic.c:4576)
==473305==    by 0x489B1AF: TclEvalEx (tclBasic.c:5728)
==473305==    by 0x49C60E8: Tcl_FSEvalFileEx (tclIOUtil.c:1782)
==473305==    by 0x49D4BFD: Tcl_MainEx (tclMain.c:399)
==473305==    by 0x10A3B4: main (tclAppInit.c:91)
==473305== 
==473305== 64 (40 direct, 24 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==473305==    at 0x483E77F: malloc (vg_replace_malloc.c:307)
==473305==    by 0x488C464: TclpAlloc (tclAlloc.c:699)
==473305==    by 0x48A89FE: Tcl_Alloc (tclCkalloc.c:1054)
==473305==    by 0x499C23D: CreateHashEntry (tclHash.c:351)
==473305==    by 0x4ABF239: ???
==473305==    by 0x4ABF5D1: ???
==473305==    by 0x49D2FB4: Tcl_LoadObjCmd (tclLoad.c:463)
==473305==    by 0x4899194: Dispatch (tclBasic.c:4817)
==473305==    by 0x489921A: TclNRRunCallbacks (tclBasic.c:4857)
==473305==    by 0x4898ADC: Tcl_EvalObjv (tclBasic.c:4576)
==473305==    by 0x489B1AF: TclEvalEx (tclBasic.c:5728)
==473305==    by 0x49C60E8: Tcl_FSEvalFileEx (tclIOUtil.c:1782)
==473305==    by 0x49D4BFD: Tcl_MainEx (tclMain.c:399)
==473305==    by 0x10A3B4: main (tclAppInit.c:91)
==473305== 
==473305== LEAK SUMMARY:
==473305==    definitely lost: 40 bytes in 1 blocks
==473305==    indirectly lost: 24 bytes in 1 blocks
==473305==      possibly lost: 0 bytes in 0 blocks
==473305==    still reachable: 0 bytes in 0 blocks
==473305==         suppressed: 0 bytes in 0 blocks
==473305== 
==473305== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

User Comments: pooryorick added on 2021-05-15 22:30:31:

Fixed in [a4de334c5f297a92]. In order to properly clean up, the loaded package, in this case pkgua.c, must be notified when a command is deleted so that it can adjust its books accordingly. A new callback, CommandDeleted, is provided to Tcl_CreateObjCommand, and it does the accounting so that the unload routine doesn't try to delete a command that has already been deleted.

Additionally, a new routine, UnloadLibrary, serves both Tcl_UnloadObjCmd and LoadCleanupProc, which takes care of cleanup when an interpreter is deleted. See [723d1eb93779e81b]. UnloadLibrary performs two distinct functions:

* remove the library from an interpreter

* unload the library from the process

It is valid to remove library from an interpreter without unloading the library from the process. Static libraries, for example, can not be unloaded from the process, but unloading them from an interpreter cleans up storage allocated to keep track of libraries loaded into interpreters. In order to completely clean up on interpreter deletion, it is necessary to deallocate this storage, even for a static library.

This new implementation also relies on a change made to tclBasic.c/DeleteInterpProc: When associated data is deleted, the corresponding Tcl_InterpDeleteProc is now called before the data is actually deleted instead of after. This allows the Tcl_InterpDeleteProc to use the associated data. See commit [ccfd61a7cf6bce85].