Hello,

There is a bug in path_alias() function that may cause a memory leak while 
creating subshells.

Reproducer script :
> cat subshell-leak.sh 
#!/bin/ksh93

while true
do
      PATH=.
for DIR in /usr/bin /usr/sbin  \
           /bin /usr/local/bin
do
    if [ -d ${DIR} ]
    then
        PATH=${PATH}:${DIR}
        true
    fi
done

        time=$(date +%T)

        prev=${page}
        page=$(cat /proc/$$/stat|awk '{print $24}')

done

Running above script with valgrind shows this report :

==12108== HEAP SUMMARY:
==12108==     in use at exit: 291,164 bytes in 270 blocks
==12108==   total heap usage: 5,171 allocs, 4,901 frees, 18,409,728 bytes 
allocated
==12108== 
==12108== LEAK SUMMARY:
==12108==    definitely lost: 7,663 bytes in 79 blocks
==12108==    indirectly lost: 0 bytes in 0 blocks
==12108==      possibly lost: 5,392 bytes in 3 blocks
==12108==    still reachable: 278,109 bytes in 188 blocks
==12108==         suppressed: 0 bytes in 0 blocks
==12108== Rerun with --leak-check=full to see details of leaked memory
==12108== 
==12108== For counts of detected and suppressed errors, rerun with: -v
==12108== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)


ksh maintains value of $PATH as a linked list. When a subshell is forked, ksh 
duplicates $PATH by increasing refcount for every element in linked list by 
calling path_dup() and path_alias() functions. However when the subshell exits 
this refcount is not decreased. Next time when $PATH is reset to a new value, 
ksh calls path_delete() function to delete linked list which stored older path. 
But path_delete() function does not free elements whose refcount is greater 
than 1 and leaves a memory leak in the shell.

Attached patch fixes this issue.

-- 
--
Siteshwar Vashisht
diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c
index d723987..9965bf5 100644
--- a/src/cmd/ksh93/sh/path.c
+++ b/src/cmd/ksh93/sh/path.c
@@ -1791,8 +1791,12 @@ void path_alias(register Namval_t *np,register Pathcomp_t *pp)
 	{
 		struct stat statb;
 		char *sp;
+		Pathcomp_t *old = 0;
 		nv_offattr(np,NV_NOPRINT);
 		nv_stack(np,&talias_init);
+		old = (Pathcomp_t*)np->nvalue.cp;
+		if (old && (--old->refcount <= 0))
+			free((void*)old);
 		np->nvalue.cp = (char*)pp;
 		pp->refcount++;
 		nv_setattr(np,NV_TAGGED|NV_NOFREE);
-- 
2.9.3

_______________________________________________
ast-developers mailing list
[email protected]
http://lists.research.att.com/mailman/listinfo/ast-developers

Reply via email to