Ticket UUID: | 467523 | |||
Title: | memory leak in [namespace eval foo {}] | |||
Type: | Bug | Version: | obsolete: 8.4a3 | |
Submitter: | rbrunner | Created on: | 2001-10-03 15:47:27 | |
Subsystem: | 47. Bytecode Compiler | Assigned To: | msofer | |
Priority: | 8 | Severity: | ||
Status: | Closed | Last Modified: | 2004-07-16 00:42:21 | |
Resolution: | Fixed | Closed By: | msofer | |
Closed on: | 2001-10-12 16:15:28 | |||
Description: |
The following code leaks (in every Tcl version): interp create foo foo eval { namespace eval bar {} } interp delete foo Note: interp create foo foo eval { namespace eval bar {\#} } interp delete foo does NOT leak. Unfortunately I didn't really track down the problem, but the call result = Tcl_EvalObjEx(interp, objv[3], 0); in generic/tclNamesp.c line 2955 (tcl8.4.a3), which is called with an empty string in objv[3] seems to cause the leak. Changing this code to if (strlen(Tcl_GetString(objv[3]))) result = Tcl_EvalObjEx(interp, objv[3], 0); else result = TCL_OK; fixes the symptoms, but certainly not the problem. (Sorry for not having a proper fix.) | |||
User Comments: |
msofer added on 2004-07-16 00:42:21:
Logged In: YES user_id=148712 This bug reappeared with the (faulty) fix of bug #983660 (in tcl8.5a2), and was fixed using a different strategy. The previous strategy was to have special code in TclReleaseLiteral to handle the self-references generated by empty scripts. The new approach avoids the self-reference altogether, by having empty scripts return an unshared literal. msofer added on 2001-10-12 23:15:29: File Added - 11886: leak.tests msofer added on 2001-10-12 23:15:28: Logged In: YES user_id=148712 Added tests in tests/compile.test - they are only effective if tcl was compiled with TCL_MEM_DEBUG msofer added on 2001-10-12 05:37:17: Logged In: YES user_id=148712 Patch committed to HEAD and core-8-3-1-branch msofer added on 2001-10-11 20:13:15: File Deleted - 11528: File Added - 11851: leak.patch msofer added on 2001-10-11 20:13:14: Logged In: YES user_id=148712 I do think I have a correct patch now - the special handling of self-referencing bytecodes in TclreleaseLiteral (tclLiteral.c) was being done too early (entryPtr->refCount == 2 at function entry) and removing two global table references in one go (setting entryPtr->refCount to 0) while decreasing the object's corresponding refCount by just one. My earlier patch corrected this by removing a reference to the object too - as Ronnie discovered, in some situations this caused the object to be accessed after it was removed. This patch restores "normal handling": each call to TclReleaseLiteral removes at most one reference in the global table, and the special code for self-referencing bytecodes is only used at the last pass. msofer added on 2001-10-10 00:03:01: Logged In: YES user_id=148712 Dump confirmed on linux; I am removing the patch from HEAD and core-8-3-1-branch rbrunner added on 2001-10-09 23:38:20: Logged In: YES user_id=205230 Here a complete log of what I'm doing. Note: running the code in an interactive tclsh works (no dump) and not changing the MEM_DEBUG_FLAGS in Makefile *ALSO* works (no dump). Let me know whether you need the tclConfig.sh or any other additional info ... > uname -a SunOS mlt 5.6 Generic_105181-26 sun4u sparc SUNW,Ultra-250 > tar xzf tcl8.4a3.tar.gz > cd tcl8.4a3/generic > # apply patch to tclLiteral.c (just copy 1.9 over 1.8) > cd ../unix ./configure > # change Makefile to memory debug #MEM_DEBUG_FLAGS = MEM_DEBUG_FLAGS = -DTCL_MEM_DEBUG > make > setenv LD_LIBRARY_PATH . > # write a mini script foo: vi foo #!./tclsh for {set a 0} {$a < 10} {incr a} { namespace eval bar {} namespace delete bar } > chmod +x foo > ./foo file = ./../generic/tclExecute.c, line = 663 Trying to increment refCount of previously disposed object. Abort (core dumped) > msofer added on 2001-10-09 23:02:53: Logged In: YES user_id=148712 Ronnie: Yes, the patch only adds one loc to tclLiteral.c I do not see any problems with that code in either 8.4a3, 8.4a4 or the 8-3-1-branch code - your script does not trigger a dump on my setup. Could you help me reproduce the dump? I'd need to know - configure and compile flags - how you are running the script: tclsh? tkcon? from a file? - anything else? Thanks rbrunner added on 2001-10-09 22:39:42: Logged In: YES user_id=205230 Miguel: did you only patch tclLiteral.c? Compiling with the latest version of this file (1.9, same as 1.8.2.1) tcl8.4a3 crashes running the following code: for {set a 0} {$a < 10} {incr a} { namespace eval bar {} namespace delete bar } my tclsh dumps core with file = ./../generic/tclExecute.c, line = 663 Trying to increment refCount of previously disposed object. Abort (core dumped) msofer added on 2001-10-06 08:05:05: Logged In: YES user_id=148712 Patch committed to HEAD and core-8-3-1-branch msofer added on 2001-10-06 07:02:03: File Added - 11620: leak.patch Logged In: YES user_id=148712 The attached leak.patch to generic/tclLiteral.c (TclReleaseLiteral) solves the issue. msofer added on 2001-10-05 20:37:05: Logged In: YES user_id=148712 The problem (I think) is that the object referred to by the literal "" in the slave interp is never freed, as it is self-referential: the bytecode pushes itself on the stack, so that the bytecode object always has refCount >=1 - it appears in its own local literal table. The code leaks 164 bytes: 24 for the object, 128 for its internal rep as a bytecode, 12 for the handle to the interpreter (it would be freed by CleanupByteCode when the object is freed). One possible solution I am exploring is to be more careful about sharing literals. The solution to this bug along this path could conceivably also fix [Bug 458361] in a roundabout way. rbrunner added on 2001-10-05 02:27:06: Logged In: YES user_id=205230 Some further observations: Any recursive call to Tcl_EvalObjEx with an empty string object to eval leaks: time {time {}} time {switch 1 1 {}} switch 1 1 {time {}} In addition I found out, that these calls leak, whenever the innermost empty code matches the Literal that is added in TclCompile.c line 1041 (tcl8.4a3): TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0) Setting this to TclRegisterLiteral(envPtr, " ", 2, /*onHeap*/ 0) makes time {time { }} leak. It seems that this equality increments the empty codes object's refCount (objPtr in Tcl_evalObjEx) to be too high -> it is not cleaned up properly. msofer added on 2001-10-04 02:12:50: Logged In: YES user_id=148712 No, that wasn't it ... msofer added on 2001-10-04 00:16:57: File Added - 11528: 467523.patch msofer added on 2001-10-04 00:16:55: Logged In: YES user_id=148712 I think the leak should occur at any evaluation of {}, ie, also for proc a {} {} a As I see it, the special handling of "bytecodes with empty source" in Tcl_EvalObjEx is at fault. I enclose a small patch that should correct this. Ronnie, Jeff: does this fix the bug? hobbs added on 2001-10-03 23:43:49: Logged In: YES user_id=72656 Confirmed in 8.3.3. |