Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Oct 2014 10:08:53 +1000
From:      Paul Koch <paul.koch@akips.com>
To:        freebsd-stable@FreeBSD.org
Subject:   Suspected kernel memory leak with mmap/sha1 ?
Message-ID:  <20141030100853.65a62326@akips.com>

next in thread | raw e-mail | index | archive | help
Hi,

We have been trying to track down an odd problem with what appears
to be a kernel memory leak, but are at a complete loss of what is
going on.  We have a cut down test program that reproduces the problem.

 FreeBSD shed62.akips.com 10.1-RC3 FreeBSD 10.1-RC3 #0 r273491:
 Thu Oct 23 05:08:22 UTC 2014
 root@shed31.akips.com:/usr/obj/usr/src/sys/GENERIC  amd64


Basically our app mmap's large data files (eg. 250M) which contain blocks
of compressed data.  Our uncompress runs the data through SHA1 before
uncompressing it.  What we see is active memory being consumed, but can't
figure out what is consuming it as our process size stays constant.
When our process exits, active memory stays high and is never freed. If
enough memory leaks, then the machine starts swapping and game over for
our application.

We've tried it on both ufs and zfs with the same results.  Interestingly
if you umount the zfs file system the active memory immediately disappears.
Without the SHA1_xxx it runs fine.

It's almost like a denial of service problem.


To show the problem, run top and watch active memory.

Compile the test program below 

 cc -o leaktest -O2 leaktest.c
 find /usr -type f | xargs ./leaktest
 
For some reason, active memory skyrockets, especially when it encounters
large files.  Running the program does not reproduce the problem 100% of
the time, but close to it.

Any suggestions ??


-----------------------------------------------

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sha.h>

#define BUFSIZE (1 * 1024 * 1024)

#define TMIN(a,b) ({            \
      typeof (a) _a = (a);      \
      typeof (b) _b = (b);      \
      _a < _b ? _a : _b;        \
})

int
main (int argc, char **argv)
{
   int     i, j,
           fd = -1,
           open_flags = O_RDONLY,
           prot_flags = PROT_READ,
           mmap_flags = 0;
   char   *filename,
          *data = NULL,
          *buf = NULL,
          *p;
   size_t  len,
           rlen;
   struct stat s;
   u_char   md[20];
   SHA_CTX  SD;


   if ((buf = malloc ((size_t) BUFSIZE)) == NULL) {
      fprintf (stderr, "malloc: %s\n", strerror (errno));
      goto END;
   }

   for (i = 1; i < argc; i++) {
      filename = argv[i];
      
      if (stat (filename, &s) != 0)
         fprintf (stderr, "stat: %s %s\n", filename, strerror (errno));

      else if ((fd = open (filename, open_flags)) == -1)
         fprintf (stderr, "open: %s %s\n", filename, strerror (errno));

      else if ((data = mmap (NULL, (size_t) s.st_size, prot_flags, 
                mmap_flags, fd, (off_t) 0)) == MAP_FAILED) {
         fprintf (stderr, "mmap: %s %s\n", filename, strerror (errno));
         close (fd);
         fd = -1;
      }

      else {
         printf ("%s: %zd bytes\n", filename, s.st_size);

         p = data;
         len = s.st_size;

         while (len > 0) {
            rlen = TMIN (BUFSIZE, len);

            /* Copy BUFSIZE lumps into buf and modify it so the compiler 
             * doesn't optimise it out
             */
            memcpy (buf, p, rlen);
            for (j = 0; j < BUFSIZE; j += 1024)
               buf[j]++;

            SHA1_Init (&SD);
            SHA1_Update (&SD, p, rlen);
            SHA1_Final (md, &SD);

            p += rlen;
            len -= rlen;
         }

         if (munmap (data, (size_t) s.st_size) == -1) {
            fprintf (stderr, "munmap: %s %s\n", filename, strerror (errno));
            goto END;
         }
         if (close (fd) == -1) {
            fprintf (stderr, "close: %s %s\n", filename, strerror (errno));
            goto END;
         }
      }
   }

END:
   free (buf);

   exit (0);
}


-- 
Paul Koch | Founder, CEO
AKIPS Network Monitor
http://www.akips.com
Brisbane, Australia




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20141030100853.65a62326>