Tcl Source Code

View Ticket
Login
Ticket UUID: 2874678
Title: dict incr leaks
Type: Bug Version: obsolete: 8.5.7
Submitter: wastl-nagel Created on: 2009-10-08 12:35:15
Subsystem: 15. Dict Object Assigned To: dkf
Priority: 9 Immediate Severity:
Status: Closed Last Modified: 2009-10-08 21:44:12
Resolution: Fixed Closed By: dkf
    Closed on: 2009-10-08 14:44:12
Description:
If a dict is created and filled via "dict incr" with a bigger set of keys it seems to leak. If the dict is destroyed (unset or overwritten) a lot of memory still keeps allocated. 

The following code consumes approx. 500MB memory on my machine (Linux, 64-bit):

set chars {a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9}

for {set i 0} {$i < 1000} {incr i} {
append prefix [lindex $chars [expr int([tcl::mathfunc::rand]*62)]]
set dictionary [dict create]
foreach char $chars {
foreach c $chars {
dict incr dictionary $prefix$char$c $i
}
}
}

I've tested Tcl 8.5.2 (OpenSuSE 11.0, x86_64), 8.5.7, 8.6b1 (both built from source), 
all three leak, cf. attached valgrind log files for same code but only 100 cycles.

For 8.5.2 TclBN_mp_init_size according to valgrind seems to be reason.

% uname -mrvs
Linux 2.6.25.20-0.5-default #1 SMP 2009-08-14 01:48:11 +0200 x86_64
User Comments: dkf added on 2009-10-08 21:44:12:

allow_comments - 1

dkf added on 2009-10-08 21:44:11:
Fixed in HEAD and 8.5 (the patch was slightly wrong, but helped narrow down what needed to be done a lot; thanks!)

dkf added on 2009-10-08 21:24:57:
The following test seems to be exact:

test dict-19.3 {dict: testing for leaks - Bug 2874678} -setup {
    proc memtest script {
set end [lindex [split [memory info] \n] 3 3]
for {set i 0} {$i < 5} {incr i} {
    uplevel 1 $script
    set tmp $end
    set end [lindex [split [memory info] \n] 3 3]
}
expr {$end - $tmp}
    }
} -constraints memory -body {
    set d aDictVar; # Force interpreted [dict incr]
    memtest {
dict incr $d aKey 0
unset $d
    }
} -cleanup {
    unset d
    rename memtest {}
} -result 0

dkf added on 2009-10-08 21:22:24:
And requires an explicit increment to do so.

dkf added on 2009-10-08 21:21:09:
Leaks 8 words per *interpreted* [dict incr] that creates a dictionary entry.

wastl-nagel added on 2009-10-08 20:26:03:
May the patch below fix the problem?

--- ./generic/tclDictObj.c~     2009-01-06 17:07:17.000000000 +0100
+++ ./generic/tclDictObj.c      2009-10-08 15:00:29.000000000 +0200
@@ -2148,6 +2148,7 @@
            mp_int increment;

            code = Tcl_GetBignumFromObj(interp, objv[3], &increment);
+            mp_clear(&increment);
            if (code != TCL_OK) {
                Tcl_AddErrorInfo(interp, "\n    (reading increment)");
            } else {

wastl-nagel added on 2009-10-08 19:35:20:

File Added - 345735: valgrind_tcl_dict.zip

Attachments: