Skip to content

Commit

Permalink
Fix memory leak on unset of associative array (#64)
Browse files Browse the repository at this point in the history
Associative arrays weren't being properly freed from memory, which
was causing a memory leak.

This commit incorporates a patch and reproducer/regress test from:
https://www.mail-archive.com/ast-users@lists.research.att.com/msg01016.html

src/cmd/ksh93/sh/name.c:
- Properly free associative arrays from memory in nv_delete().

src/cmd/ksh93/tests/leaks.sh:
- Add regression test.
  • Loading branch information
JohnoKing committed Jul 9, 2020
1 parent bf79131 commit e70925c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 0 deletions.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -8,6 +8,8 @@ Any uppercase BUG_* names are modernish shell bug IDs.
- 'notty' is now written to the ksh auditing file instead of '(null)' if
the user's tty could not be determined.

- Unsetting an associative array no longer causes a memory leak to occur.

2020-07-05:

- In UTF-8 locales, fix corruption of the shell's internal string quoting
Expand Down
11 changes: 11 additions & 0 deletions src/cmd/ksh93/sh/name.c
Expand Up @@ -1298,7 +1298,18 @@ void nv_delete(Namval_t* np, Dt_t *root, int flags)
if(dtdelete(root,np))
{
if(!(flags&NV_NOFREE) && ((flags&NV_FUNCTION) || !nv_subsaved(np)))
{
Namarr_t *ap;
if(nv_isarray(np) && np->nvfun && (ap=nv_arrayptr(np)) && array_assoc(ap))
{
/* free associative array from memory */
while(nv_associative(np,0,NV_ANEXT))
nv_associative(np,0,NV_ADELETE);
nv_associative(np,0,NV_AFREE);
free((void*)np->nvfun);
}
free((void*)np);
}
}
#if 0
else
Expand Down
21 changes: 21 additions & 0 deletions src/cmd/ksh93/tests/leaks.sh
Expand Up @@ -101,4 +101,25 @@ done
after=$(getmem)
(( after > before )) && err_exit "memory leak with read -C when using <<< (leaked $((after - before)) $unit)"

# ======
# Unsetting an associative array shouldn't cause a memory leak
# See https://www.mail-archive.com/ast-users@lists.research.att.com/msg01016.html
typeset -A stuff
before=$(getmem)
for (( i=0; i<1000; i++ ))
do
unset stuff[xyz]
typeset -A stuff[xyz]
stuff[xyz][elem0]="data0"
stuff[xyz][elem1]="data1"
stuff[xyz][elem2]="data2"
stuff[xyz][elem3]="data3"
stuff[xyz][elem4]="data4"
done
unset stuff
after=$(getmem)
(( after > before )) && err_exit 'unset of associative array causes memory leak' \
"(leaked $((after - before)) $unit)"

# ======
exit $((Errors<125?Errors:125))

0 comments on commit e70925c

Please sign in to comment.