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