From e70925ce1033790b95e7c48af78a4134ac22dd2e Mon Sep 17 00:00:00 2001 From: Johnothan King Date: Wed, 8 Jul 2020 17:09:40 -0700 Subject: [PATCH] Fix memory leak on unset of associative array (#64) 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. --- NEWS | 2 ++ src/cmd/ksh93/sh/name.c | 11 +++++++++++ src/cmd/ksh93/tests/leaks.sh | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/NEWS b/NEWS index fe6b22f7e012..d9a8030a3150 100644 --- a/NEWS +++ b/NEWS @@ -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 diff --git a/src/cmd/ksh93/sh/name.c b/src/cmd/ksh93/sh/name.c index 3451d5b79f50..27ee99344be1 100644 --- a/src/cmd/ksh93/sh/name.c +++ b/src/cmd/ksh93/sh/name.c @@ -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 diff --git a/src/cmd/ksh93/tests/leaks.sh b/src/cmd/ksh93/tests/leaks.sh index f4b06f4f359d..2fd0aacf3aa3 100755 --- a/src/cmd/ksh93/tests/leaks.sh +++ b/src/cmd/ksh93/tests/leaks.sh @@ -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))