On Mon, Aug 03, 2009 at 04:03:27PM +0200, Werner Fink wrote:
> On Thu, Jul 09, 2009 at 03:51:27PM +0200, Werner Fink wrote:
> > Hi,
> > 
> > I've just to report a memory leak caused by a shell function which
> > uses an echo as last line in the shell function.
> > 
> > -----------------------------------------------------------------------
> > #!/usr/bin/ksh
> > 
> > PATH=/bin:/usr/bin:/usr/sbin:/sbin
> > 
> > # Description:  Get the interval to sample information
> > # Output:       interval seconds
> > getSampleInterval()
> > {
> >     # Example for this arithmetic, suppose the next time is 45 second
> >     # If current second is in [35, 40], such as 38, 
> >     #   the interval should be 10 - 38 % 10 + 5 = 7
> >     # If current second is in [41, 45], such as 42,
> >     #   the interval should be 10 - 42 % 10 - 5 = 3
> >     # If the current second is 45, the interval should be 10 - 45 % 10 - 5 
> > = 0
> > 
> >     typeset -ilu _currSec=$(date +%S)
> >     typeset -ilu _interval
> > 
> >     ((_interval=10-(_currSec%10)))
> > 
> >     if ((_interval >= 5))
> >     then 
> >     ((_interval=_interval-5))
> >     else
> >     ((_interval=_interval+5))
> >     fi
> > 
> >     echo $_interval    
> > }
> > 
> > typeset -ilu times=0
> > typeset -ilu interval
> > 
> > while [ 1 -eq 1 ]
> > do
> >     # First, get the interval to check
> >     interval=$(getSampleInterval)
> >     sleep $interval
> > 
> >     ((times++))
> > 
> >     state=$(egrep '^VmData|^VmRSS|^VmSize' </proc/$$/status)
> >     [ "$state" != "$oldstate" ] && echo $state
> >     oldstate="$state"
> > done
> > -----------------------------------------------------------------------
> 
> Found the following three problems:
> 
> in src/cmd/ksh93/sh/xec.c in function sh_funct() in the first line
> 
>                 nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE);
> 
> the allocated Namfun_t of the builtin node SH_FUNNAMENOD is set
> but never freed in src/cmd/ksh93/sh/subshell.c in function nv_restore().
> 
> The same for src/cmd/ksh93/bltins/misc.c in function b_dot_cmd()
> in the first line
> 
>         nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
> 
> the allocated Namfun_t of the builtin node SH_PATHNAMENOD is set
> but never freed in src/cmd/ksh93/sh/subshell.c in function nv_restore().
> 
> At last but not least in src/cmd/ksh93/sh/xec.c in function init_level()
> the struct Level is allocated as Namfun_t of the builtin node
> SH_LEVELNOD but also never freed in nv_restore().
> 
> In src/cmd/ksh93/sh/subshell.c in function nv_restore() the
> allocated Namfun_t will be overwritten in the line
> 
>                 mp->nvfun = np->nvfun;
> 
> moreover it seems that at least for the nodes SH_FUNNAMENOD and
> SH_PATHNAMENOD the cached values will be cloned by allocation
> further memory for the already allocated Namfun_t for every
> cycle of the loop.
> 
> How this can be avoided?

I'm using the attached workaround which is a workaround only.
This because the reason of two of the three leaks are located
in the layers below nv_clone() used in sh_assignok() for
SH_PATHNAMENOD and SH_FUNNAMENOD.  The leak of the SH_LEVELNOD
seems to located also below nv_clone() in combination with
the _nv_unset() found in nv_restore().

       Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr
--- src/cmd/ksh93/bltins/misc.c
+++ src/cmd/ksh93/bltins/misc.c	2009-08-04 11:59:27.525901725 +0000
@@ -276,7 +276,11 @@ int    b_dot_cmd(register int n,char *ar
 	shp->st.cmdname = argv[0];
 	if(np)
 		shp->st.filename = np->nvalue.rp->fname;
+	if (SH_PATHNAMENOD->nvfun)
+		SH_PATHNAMENOD->nvfun->nofree |= 4;
 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
+	if (SH_PATHNAMENOD->nvfun)
+		SH_PATHNAMENOD->nvfun->nofree &= ~4;
 	shp->posix_fun = 0;
 	if(np || argv[1])
 		argsave = sh_argnew(shp,argv,&saveargfor);
--- src/cmd/ksh93/sh/subshell.c
+++ src/cmd/ksh93/sh/subshell.c	2009-08-04 11:57:31.829902225 +0000
@@ -252,7 +252,7 @@ Namval_t *sh_assignok(register Namval_t
 	Dt_t			*dp;
 	Namval_t		*mpnext;
 	Namarr_t		*ap;
-	int			save;
+	int			save, leak;
 	/* don't bother with this */
 	if(!sp->shpwd || (nv_isnull(np) && !add))
 		return(np);
@@ -309,7 +309,18 @@ Namval_t *sh_assignok(register Namval_t
 	save = shp->subshell;
 	shp->subshell = 0;
 	mp->nvname = np->nvname;
+	leak = 0;
+	if (np->nvfun && np->nvfun->nofree&4)
+	{
+		leak = 1;
+		np->nvfun->nofree &= ~4;
+	}
 	nv_clone(np,mp,(add?(nv_isnull(np)?0:NV_NOFREE)|NV_ARRAY:NV_MOVE));
+	if (leak && mp->nvfun && np->nvfun != mp->nvfun)
+	{
+    		free((void*)mp->nvfun);
+		mp->nvfun = np->nvfun;
+	}
 	shp->subshell = save;
 	return(np);
 }
--- src/cmd/ksh93/sh/xec.c
+++ src/cmd/ksh93/sh/xec.c	2009-08-04 11:58:31.033901866 +0000
@@ -339,6 +339,7 @@ struct Level
 	Namfun_t	hdr;
 	short		maxlevel;
 };
+struct Level *leaklp;
 
 /*
  * this is for a debugger but it hasn't been tested yet
@@ -352,7 +353,11 @@ static void put_level(Namval_t* np,const
 	int16_t level, oldlevel = (int16_t)nv_getnum(np);
 	nv_putv(np,val,flags,fp);
 	if(!val)
+	{
+		if (np == SH_LEVELNOD)
+			leaklp = (struct Level*)(SH_LEVELNOD->nvfun);
 		return;
+	}
 	level = nv_getnum(np);
 	if(level<0 || level > lp->maxlevel)
 	{
@@ -374,7 +379,22 @@ static const Namdisc_t level_disc = {  s
 
 static struct Level *init_level(int level)
 {
-	struct Level *lp = newof(NiL,struct Level,1,0);
+	struct Level *lp;
+	if (!leaklp)
+		lp = newof(NiL,struct Level,1,0);
+	else
+	{
+		if (leaklp->hdr.disc)
+		{
+			leaklp->hdr.disc = NIL(const Namdisc_t*);
+			lp = leaklp;
+		}
+		else
+		{
+			free((void*)leaklp);
+			lp = newof(NiL,struct Level,1,0);
+		}
+	}
 	lp->maxlevel = level;
 	_nv_unset(SH_LEVELNOD,0);
 	nv_onattr(SH_LEVELNOD,NV_INT16|NV_NOFREE);
@@ -2689,7 +2709,11 @@ static void sh_funct(Shell_t *shp,Namval
 		save = argv[-1];
 		argv[-1] = 0;
 		shp->st.funname = nv_name(np);
+		if (SH_FUNNAMENOD->nvfun)
+			SH_FUNNAMENOD->nvfun->nofree |= 4;
 		nv_putval(SH_FUNNAMENOD, nv_name(np),NV_NOFREE);
+		if (SH_FUNNAMENOD->nvfun)
+			SH_FUNNAMENOD->nvfun->nofree &= ~4;
 		opt_info.index = opt_info.offset = 0;
 		error_info.errors = 0;
 		shp->st.loopcnt = 0;
_______________________________________________
ast-developers mailing list
[email protected]
https://mailman.research.att.com/mailman/listinfo/ast-developers

Reply via email to