kevinlawler / kona

Open-source implementation of the K programming language
ISC License
1.36k stars 138 forks source link

Memory leak using the ```\l file``` command #627

Closed tavmem closed 1 year ago

tavmem commented 2 years ago

As Bakul reported in #615:

Try this simple test:
file1.k:

foo:(("abc";))

Run k under valgrind. Just load file1 and exit and check for leaks.

file2.k:

foo:(("abc"
))

Run k under valgrind. Just load file2 and exit. and check for leaks.
They create identical objects but in the second case there is a leak!
tavmem commented 2 years ago
- valgrind --leak-check=full ./k
==71409== Memcheck, a memory error detector
==71409== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==71409== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==71409== Command: ./k
==71409== 
kona      \ for help. \\ to exit.

  \l file2
  \\
==71409== 
==71409== HEAP SUMMARY:
==71409==     in use at exit: 206 bytes in 13 blocks
==71409==   total heap usage: 81 allocs, 68 frees, 34,501 bytes allocated
==71409== 
==71409== 13 bytes in 1 blocks are definitely lost in loss record 4 of 11
==71409==    at 0x484586F: malloc (vg_replace_malloc.c:381)
==71409==    by 0x425BA8: alloc (km.c:45)
==71409==    by 0x429AA4: strdupn (ks.c:11)
==71409==    by 0x40B8A7: getdelim_ (getline.c:43)
==71409==    by 0x40B8A7: getline_ (getline.c:33)
==71409==    by 0x41A2B9: line (kc.c:228)
==71409==    by 0x41C1AD: lines (kc.c:223)
==71409==    by 0x40AE23: load (c.c:84)
==71409==    by 0x41A3CF: line (kc.c:274)
==71409==    by 0x41C5C0: attend (kc.c:432)
==71409==    by 0x4037B2: main (main.c:8)
tavmem commented 1 year ago

I realized that I closed this issue without documenting how I determined what the problem was.

lines(kc.c)
line(kc.c)    fln: 1    a: 0x7ffcd97bf908    *a: (null)
getline_(getline.c)    *n: 0    s: 0x7ffcd97bf8b0    *s: (null)
getdelim_(getline.c)    *n: 0    s: 0x7ffcd97bf8b0    *s: (null)
strdupn    s: 0x9e3a30    k: 11    strlen(s): 11    s[strlen(s)-1]: 10    s: foo:("abc"
alloc: 12
z(getdelim_)    strlen(z): 11    &z: 0x7ffcd97bf830    z: foo:("abc"
*n(getdelim_res): 11    strlen(*s): 11    s: 0x7ffcd97bf8b0    *s: foo:("abc"
z(getline_res): 11
call-appender-from-line(kc.c)    *n: 0    *a: (null)    &s: 0x7ffcd97bf8b0    c: 11    s: foo:("abc"
appender(getline.c)
complete(p.c)
alloc: 1
push(km.c)    call-appender-from-push
appender(getline.c)
c(line-res): 11

line(kc.c)    fln: 0    a: 0x7ffcd97bf908    *a: foo:("abc"
getline_(getline.c)    *n: 0    s: 0x7ffcd97bf8b0    *s: (null)
getdelim_(getline.c)    *n: 0    s: 0x7ffcd97bf8b0    *s: (null)
strdupn    s: 0x9e3a30    k: 2    strlen(s): 2    s[strlen(s)-1]: 10    s: )
alloc: 3
z(getdelim_)    strlen(z): 2    &z: 0x7ffcd97bf830    z: )
*n(getdelim_res): 2    strlen(*s): 2    s: 0x7ffcd97bf8b0    *s: )
z(getline_res): 2
call-appender-from-line(kc.c)    *n: 11    *a: foo:("abc"
    &s: 0x7ffcd97bf8b0    c: 2    s: )
appender(getline.c)
complete(p.c)

I tracked the contents of key variables in the functions used by valgrind. Note that in the first execution of "line" the string "s" has content. In the second execution of "line" the string "s" (with the same pointer address) is null.