Hi,

tail -r has two memory leaks when handling non-regular files. You can
easily see memory usage increasing with commands like

$ mknod pipe p
$ tail -r pipe pipe pipe > /dev/null

And then writing a large file into the pipe three times. top shows the
memory usage of tail increasing with each consecutive read.

The obvious memory leak is at the end of reverse(): the doubly linked
list (actually circular list) is never freed. To fix this, I break the
circle and iterate through it, freeing items until I hit NULL.

The less obvious one is in an error path. If tail fails to allocate an
item (tl) or space for its content (tl->l), it won't simply err() out
but tries to recover. Yet, it doesn't free tl if allocation of tl->l
failed.


Tobias

Index: reverse.c
===================================================================
RCS file: /cvs/src/usr.bin/tail/reverse.c,v
retrieving revision 1.19
diff -u -p -U4 -r1.19 reverse.c
--- reverse.c   27 Oct 2009 23:59:44 -0000      1.19
+++ reverse.c   26 Mar 2015 22:31:38 -0000
@@ -183,8 +183,10 @@ r_buf(FILE *fp)
                if (enomem || (tl = malloc(sizeof(BF))) == NULL ||
                    (tl->l = malloc(BSZ)) == NULL) {
                        if (!mark)
                                err(1, NULL);
+                       if (!enomem)
+                               free(tl);
                        tl = enomem ? tl->next : mark;
                        enomem += tl->len;
                } else if (mark) {
                        tl->next = mark;
@@ -258,6 +260,14 @@ r_buf(FILE *fp)
        }
        while ((tl = tl->next)->len) {
                WR(tl->l, tl->len);
                tl->len = 0;
+       }
+
+       tl->prev->next = NULL;
+       while (tl != NULL) {
+               tr = tl->next;
+               free(tl->l);
+               free(tl);
+               tl = tr;
        }
 }

Reply via email to