Ticket UUID: | a3309d01dbb0f23c3cf717ace30d9663fa54735 | |||
Title: | Leak in array when unsetting keys from a proc | |||
Type: | Bug | Version: | 8.6.4 | |
Submitter: | bovine | Created on: | 2015-07-15 22:50:54 | |
Subsystem: | 07. Variables | Assigned To: | dgp | |
Priority: | 5 Medium | Severity: | Severe | |
Status: | Closed | Last Modified: | 2015-07-18 05:54:17 | |
Resolution: | Fixed | Closed By: | dgp | |
Closed on: | 2015-07-18 05:54:17 | |||
Description: |
I've discovered a memory leak in Tcl 8.6.4 on FreeBSD 9.1 and 10.1 with the following script. The leak does not occur under Tcl 8.5 https://gist.github.com/bovine/15c350d044325a93d5cb -- attached The issue seems to be specific to using lists that are built up using "lappend". If $foo is using a list that is directly "set" in a single operation, then the leak does not appear to occur. Additionally, the leak occurs when using "unset" to remove individual elements from myarray. If you "array unset myarray" entirely, then the memory seems to be properly freed. | |||
User Comments: |
dgp added on 2015-07-18 05:54:17:
Fix merged to trunk. dgp added on 2015-07-17 19:34:00: See branch bug-a3309d01db for conventional test that demos the leak. Branches off the checkin that bisecting determines is the cause of the leak. aspect added on 2015-07-16 03:22:29: The following patch seems to fix this issue without breaking existing tests. It's a bit brutish - a more sensitive patch would more closely compare this bytecoded INST_UNSET_ARRAY code with ArrayUnsetCmd(). Bug seems to have existed since 8.6.2, so I guess it's been in the bytecode all along. Index: generic/tclExecute.c ================================================================== --- generic/tclExecute.c +++ generic/tclExecute.c @@ -4178,11 +4178,11 @@ * No nasty traces and element exists, so we can proceed to * unset it. Might still not exist though... */ if (!TclIsVarUndefined(varPtr)) { - TclDecrRefCount(varPtr->value.objPtr); + TclPtrUnsetVar(interp, varPtr, arrayPtr, NULL, part2Ptr, flags, opnd); } else if (flags & TCL_LEAVE_ERR_MSG) { goto slowUnsetArray; } varPtr->value.objPtr = NULL; TRACE_APPEND(("OK\n")); aspect added on 2015-07-16 00:04:47: Just playing around with this on the script level, I've been able to simplify the test to the attached memleak-bovine.tcl + meminfo.tcl. Output shows allocated bytes increasing by ~900 each 5 iterations, and (total mallocs-total frees) increasing by 25 - this all after the array is "full" and elements are being deleted. Note this test doesn't require [lappend]. The dependency on [unset myarray($key)] is genuine -- using [array unset myarray $key] fails to exhibit the leak. Other variations: 1. moving the entire body of [doit] into the loop at global scope doesn't leak 2. moving the body of [doit] into the loop and wrapping it in a proc leaks 3. making myarray proc-local instead of global leaks aku added on 2015-07-15 23:10:10: gist extracted and attached. |