zsh-workers
 help / color / mirror / code / Atom feed
* [PATCH] compsys maps anonymous memory and never frees it
       [not found]     ` <080904072526.ZM12341@torch.brasslantern.com>
@ 2008-09-07  8:23       ` "xRaich[o]²x"
  2008-09-07  9:25         ` Andrey Borzenkov
  2008-09-07 11:04         ` Andrey Borzenkov
  0 siblings, 2 replies; 4+ messages in thread
From: "xRaich[o]²x" @ 2008-09-07  8:23 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote:
> On Sep 4,  1:04am, =?ISO-8859-1?Q?Bj=F6rn_Herzig?= wrote:
> }
> } I looked at the problem a little closer. Zsh does not call mmap to
> } allocate them and they dont get allocated when completion happens but
> } when the next command gets issued.
>
> If this is true, then this is something happening down in the library
> or kernel implementation of fork() and is out of zsh's control.
>
> Did you build zsh yourself?  Can you check config.h for USE_MMAP ?
> If USE_MMAP is defined then anytime zsh parses a command it will have
> called mmap() to allocate zsh-heap space.  You can try reconfiguring
> with --enable-zsh-mem and then check the pmap behavior again.
>
> } So in my example the new maps got added to the process' address space
> } when i executed pmap, but the same happens with any other programm.
> } Builtins however are an exception. So things start to go wrong when it
> } comes to forking.
>
> If you run pmap from another shell window rather than executing it
> from within the shell whose map you're examining, does the behavior
> change at all?
>
> My only guess goes something like this:
>
> Zsh has mapped memory for the heap during parsing etc.  Those pages
> have had data written and therefore are marked "dirty".  When fork()
> is called, those pages become shared address space with the child
> process.  Zsh munmap()s them later but they aren't returned to the
> system because the child process is still using them.
>
> I'm not really happy with any of these explanations yet.
>
>   

Ok, i found it.... after wandering around in a few deadends and getting 
some stuff wrong... but well.

i did the following change to mem.c

mod_export void
old_heaps(Heap old)
{
    Heap h, n;

    queue_signals();
    for (h = heaps; h; h = n) {
    n = h->next;
    DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
#ifdef USE_MMAP
    //munmap((void *) h, sizeof(*h));
    munmap((void *) h, h->size);
#else
    //zfree(h, sizeof(*h));
    zfree(h, h->size);
#endif
    }
    heaps = old;
    fheap = NULL;
    unqueue_signals();
}

this might open up a can of worms. i don't know where this is going to 
blow up, but i'm pretty sure it will. but well... it seems to work.
old_heaps tried to unmap a 16384 bytes big segment by calling 
munmap(...,sizeof(h*)) which is 16 and left the rest in memory (which 
explains why the segments wasn't added explicitly).

Here is the dtrace script that finally caught the bug, if someone is 
interested:

#!/usr/sbin/dtrace -s

BEGIN
{
    printf("\nTarget is : %d\nSegement is %X\n",$target, $1);
}

syscall::mmap64:return
/arg1 == $1 && pid == $target/
{
    printf("mmap returns: %x",arg1);
    self->triggered = 1;
}

pid$target:zsh:dupstring:return
/self->triggered == 1/
{
    printf("Dupstring: %s",copyinstr(arg1));
    self->triggered = 0;
}

syscall::mmap64:entry
/pid == $target/
{
    printf("mmap size: %d",arg1);
}

syscall::munmap:entry
/arg0 == $1 && pid == $target/
{
    printf("munmap size: %d\n",arg1);
    ustack();
    self->munmapping = 1;
}

syscall::munmap:return
/self->munmapping/
{
    printf("Result of munmapping the segment in question was: %d",arg1);
    self->munmapping = 0;
}

fbt::as_removeseg:entry
/execname == "zsh" && ((struct seg*)arg1)->s_base == (caddr_t)$1/
{
    printf("\nGot removed");
    ustack(50);
    stack();
    exit(0);
}

fbt::as_addseg:entry
/execname == "zsh" && ((struct seg*)arg1)->s_base == (caddr_t)$1/
{
    printf("\nGot added");
    ustack();
    stack();
}

Regards,
Björn


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] compsys maps anonymous memory and never frees it
  2008-09-07  8:23       ` [PATCH] compsys maps anonymous memory and never frees it "xRaich[o]²x"
@ 2008-09-07  9:25         ` Andrey Borzenkov
  2008-09-07 11:04         ` Andrey Borzenkov
  1 sibling, 0 replies; 4+ messages in thread
From: Andrey Borzenkov @ 2008-09-07  9:25 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 3168 bytes --]

On Sunday 07 September 2008, xRaich[o]²x wrote:
> 
> Bart Schaefer wrote:
> > On Sep 4,  1:04am, =?ISO-8859-1?Q?Bj=F6rn_Herzig?= wrote:
> > }
> > } I looked at the problem a little closer. Zsh does not call mmap to
> > } allocate them and they dont get allocated when completion happens but
> > } when the next command gets issued.
> >
> > If this is true, then this is something happening down in the library
> > or kernel implementation of fork() and is out of zsh's control.
> >
> > Did you build zsh yourself?  Can you check config.h for USE_MMAP ?
> > If USE_MMAP is defined then anytime zsh parses a command it will have
> > called mmap() to allocate zsh-heap space.  You can try reconfiguring
> > with --enable-zsh-mem and then check the pmap behavior again.
> >
> > } So in my example the new maps got added to the process' address space
> > } when i executed pmap, but the same happens with any other programm.
> > } Builtins however are an exception. So things start to go wrong when it
> > } comes to forking.
> >
> > If you run pmap from another shell window rather than executing it
> > from within the shell whose map you're examining, does the behavior
> > change at all?
> >
> > My only guess goes something like this:
> >
> > Zsh has mapped memory for the heap during parsing etc.  Those pages
> > have had data written and therefore are marked "dirty".  When fork()
> > is called, those pages become shared address space with the child
> > process.  Zsh munmap()s them later but they aren't returned to the
> > system because the child process is still using them.
> >
> > I'm not really happy with any of these explanations yet.
> >
> >   
> 
> Ok, i found it.... after wandering around in a few deadends and getting 
> some stuff wrong... but well.
> 
> i did the following change to mem.c
> 
> mod_export void
> old_heaps(Heap old)
> {
>     Heap h, n;
> 
>     queue_signals();
>     for (h = heaps; h; h = n) {
>     n = h->next;
>     DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
> #ifdef USE_MMAP
>     //munmap((void *) h, sizeof(*h));
>     munmap((void *) h, h->size);

Good catch (it was obvious bug)

> #else
>     //zfree(h, sizeof(*h));
>     zfree(h, h->size);

In most other places we are using zfree(h, HEAPSIZE); there is no guarantee
heap is actually of size HEAPSIZE, but that does not matter (second argument
is used only with enable-zsh-mem and serves as plausibility check only).

Here is patch in proper format. It is using HEAPSIZE for consistency:

Index: Src/mem.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/mem.c,v
retrieving revision 1.16
diff -u -p -r1.16 mem.c
--- Src/mem.c   17 May 2008 17:55:38 -0000      1.16
+++ Src/mem.c   7 Sep 2008 09:23:32 -0000
@@ -153,9 +153,9 @@ old_heaps(Heap old)
        n = h->next;
        DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
 #ifdef USE_MMAP
-       munmap((void *) h, sizeof(*h));
+       munmap((void *) h, h->size);
 #else
-       zfree(h, sizeof(*h));
+       zfree(h, HEAPSIZE);
 #endif
     }
     heaps = old;

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] compsys maps anonymous memory and never frees it
  2008-09-07  8:23       ` [PATCH] compsys maps anonymous memory and never frees it "xRaich[o]²x"
  2008-09-07  9:25         ` Andrey Borzenkov
@ 2008-09-07 11:04         ` Andrey Borzenkov
  2008-09-08 21:19           ` "xRaich[o]²x"
  1 sibling, 1 reply; 4+ messages in thread
From: Andrey Borzenkov @ 2008-09-07 11:04 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 2026 bytes --]

On Sunday 07 September 2008, xRaich[o]²x wrote:
> 
> Bart Schaefer wrote:
> > On Sep 4,  1:04am, =?ISO-8859-1?Q?Bj=F6rn_Herzig?= wrote:
> > }
> > } I looked at the problem a little closer. Zsh does not call mmap to
> > } allocate them and they dont get allocated when completion happens but
> > } when the next command gets issued.
> >

I was able to more or less reproduce it on Linux; but now after your patch
I get what looks like memory leak. Here are heaps after several memory
intensive completions:

Address   Kbytes     RSS    Anon  Locked Mode   Mapping
08048000     608       -       -       - r-x--  zsh
080e0000      16       -       -       - rw---  zsh
080e4000      92       -       -       - rw---    [ anon ]
09d6a000     672       -       -       - rw---    [ anon ]

[...]

Address   Kbytes     RSS    Anon  Locked Mode   Mapping
08048000     608       -       -       - r-x--  zsh
080e0000      16       -       -       - rw---  zsh
080e4000      92       -       -       - rw---    [ anon ]
09d6a000    5340       -       -       - rw---    [ anon ]
b6a68000   15464       -       -       - rw---    [ anon ]


Compare this with version without patch:

Address   Kbytes     RSS    Anon  Locked Mode   Mapping
08048000     528       -       -       - r-x--  zsh
080cc000      16       -       -       - rw---  zsh
080d0000      88       -       -       - rw---    [ anon ]
099df000     744       -       -       - rw---    [ anon ]

[...]

Address   Kbytes     RSS    Anon  Locked Mode   Mapping
08048000     528       -       -       - r-x--  zsh
080cc000      16       -       -       - rw---  zsh
080d0000      88       -       -       - rw---    [ anon ]
099df000    5520       -       -       - rw---    [ anon ]
b6adb000   15464       -       -       - rw---    [ anon ]
b7a05000      12       -       -       - rw---    [ anon ]
b7b46000     108       -       -       - rw---    [ anon ]

So it looks like we still have some memory leak somewhere. 

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] compsys maps anonymous memory and never frees it
  2008-09-07 11:04         ` Andrey Borzenkov
@ 2008-09-08 21:19           ` "xRaich[o]²x"
  0 siblings, 0 replies; 4+ messages in thread
From: "xRaich[o]²x" @ 2008-09-08 21:19 UTC (permalink / raw)
  To: zsh-workers

Andrey Borzenkov wrote:
> On Sunday 07 September 2008, xRaich[o]²x wrote:
>   
>> Bart Schaefer wrote:
>>     
>>> On Sep 4,  1:04am, =?ISO-8859-1?Q?Bj=F6rn_Herzig?= wrote:
>>> }
>>> } I looked at the problem a little closer. Zsh does not call mmap to
>>> } allocate them and they dont get allocated when completion happens but
>>> } when the next command gets issued.
>>>
>>>       
>
> I was able to more or less reproduce it on Linux; but now after your patch
> I get what looks like memory leak. Here are heaps after several memory
> intensive completions:
>
> Address   Kbytes     RSS    Anon  Locked Mode   Mapping
> 08048000     608       -       -       - r-x--  zsh
> 080e0000      16       -       -       - rw---  zsh
> 080e4000      92       -       -       - rw---    [ anon ]
> 09d6a000     672       -       -       - rw---    [ anon ]
>
> [...]
>
> Address   Kbytes     RSS    Anon  Locked Mode   Mapping
> 08048000     608       -       -       - r-x--  zsh
> 080e0000      16       -       -       - rw---  zsh
> 080e4000      92       -       -       - rw---    [ anon ]
> 09d6a000    5340       -       -       - rw---    [ anon ]
> b6a68000   15464       -       -       - rw---    [ anon ]
>
>
> Compare this with version without patch:
>
> Address   Kbytes     RSS    Anon  Locked Mode   Mapping
> 08048000     528       -       -       - r-x--  zsh
> 080cc000      16       -       -       - rw---  zsh
> 080d0000      88       -       -       - rw---    [ anon ]
> 099df000     744       -       -       - rw---    [ anon ]
>
> [...]
>
> Address   Kbytes     RSS    Anon  Locked Mode   Mapping
> 08048000     528       -       -       - r-x--  zsh
> 080cc000      16       -       -       - rw---  zsh
> 080d0000      88       -       -       - rw---    [ anon ]
> 099df000    5520       -       -       - rw---    [ anon ]
> b6adb000   15464       -       -       - rw---    [ anon ]
> b7a05000      12       -       -       - rw---    [ anon ]
> b7b46000     108       -       -       - rw---    [ anon ]
>
> So it looks like we still have some memory leak somewhere. 
>   
Are you sure that those segments aren't those dlopen allocates when 
loading modules? they are actually created by the operating system and 
needed.

What i find a bit disturbing is that whenever loading modules one 
segment gets unmapped by munmap with two times its size. I think the 
operating system will catch that but maybe this is possible to fix 
somehow. i wrote a little dtrace script that keeps track of every mapped 
segment and checks if they get munmapped with the correct size. 
Everything except the mentioned munmap seems to work after the patch.

Regards,
Björn


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-09-08 21:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <48BDF1EC.4050204@gmail.com>
     [not found] ` <080902200652.ZM9887@torch.brasslantern.com>
     [not found]   ` <682f90440809031604j5e349af2q8d40f24fc429dcc3@mail.gmail.com>
     [not found]     ` <080904072526.ZM12341@torch.brasslantern.com>
2008-09-07  8:23       ` [PATCH] compsys maps anonymous memory and never frees it "xRaich[o]²x"
2008-09-07  9:25         ` Andrey Borzenkov
2008-09-07 11:04         ` Andrey Borzenkov
2008-09-08 21:19           ` "xRaich[o]²x"

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).