[DynInst_API:] [PATCH dyninstAPI v2] Reallocate memory map buffer exponentially until there is enough space for the whole map.


Date: Mon, 14 Jul 2014 21:43:23 -0400
From: francis.deslauriers@xxxxxxxxxxxx
Subject: [DynInst_API:] [PATCH dyninstAPI v2] Reallocate memory map buffer exponentially until there is enough space for the whole map.
From: Francis Deslauriers <francis.deslauriers@xxxxxxxxxxxx>

Starting from the default size buffer, we try to read the memory map
without allocating new space. If we reach the end of the buffer before
the end of the file, we allocate a buffer twice as big and try again.
When we reach the MAX_MAP_SIZE we return an error to the calling
function.

Signed-off-by: Francis Deslauriers <francis.deslauriers@xxxxxxxxxxxx>
---
 dyninstAPI_RT/src/RTheap-linux.c | 95 +++++++++++++++++++++++++++++-----------
 1 file changed, 69 insertions(+), 26 deletions(-)

diff --git a/dyninstAPI_RT/src/RTheap-linux.c b/dyninstAPI_RT/src/RTheap-linux.c
index 97ebd55..215f5cd 100644
--- a/dyninstAPI_RT/src/RTheap-linux.c
+++ b/dyninstAPI_RT/src/RTheap-linux.c
@@ -43,6 +43,7 @@
 #include <sys/mman.h>                 /* mmap() */
 #include "RTheap.h"
 
+#define MAX_MAP_SIZE (1<<20)
 #if defined(MUTATEE64)
 
 int     DYNINSTheap_align = 4; /* heaps are word-aligned */
@@ -90,17 +91,21 @@ read it all in one call into this buffer.
 linux-2.4: reading /proc/PID/maps now returns after each line in the maps,
 so we must loop to get everything.
 */
-static char procAsciiMap[1<<15];
+
+// Static so we dont have to do the exponential backoff each time.
+static size_t mapSize = 1 << 15;
 
 int
 DYNINSTgetMemoryMap(unsigned *nump, dyninstmm_t **mapp)
 {
-   int fd;
+   int fd, done;
    ssize_t ret;
    size_t length;
    char *p;
    dyninstmm_t *ms;
    unsigned i, num;
+   char *procAsciiMap;
+
 
    /* 
       Here are two lines from 'cat /proc/self/maps' on Linux 2.2.  Each
@@ -112,44 +117,78 @@ DYNINSTgetMemoryMap(unsigned *nump, dyninstmm_t **mapp)
       0804a000-0804c000 rw-p 00001000 08:09 12089      /bin/cat
       0804c000-0804f000 rwxp 00000000 00:00 0
    */
-
-   fd = open("/proc/self/maps", O_RDONLY);
-   if (0 > fd) {
-      perror("open /proc");
-      return -1;
-   }
-   length = 0;
+   procAsciiMap = NULL;
+   done = 0;
    while (1)
    {
-      ret = read(fd, procAsciiMap + length, sizeof(procAsciiMap) - length);
-      if (0 == ret) break;
-      if (0 > ret) {
-	      close(fd);
-	      perror("read /proc");
-	      return -1;
-      }
-      length += ret;
-      if (length >= sizeof(procAsciiMap)) {
-	      close(fd);
-	      fprintf(stderr, "DYNINSTgetMemoryMap: memory map buffer overflow\n");
-	      return -1;
-      }
+       if(procAsciiMap == NULL) {
+           procAsciiMap = malloc(mapSize);
+           if (!procAsciiMap) {
+               fprintf(stderr, "DYNINSTgetMemoryMap: Out of memory\n");
+               goto end;
+           }
+       }
+       else
+       {
+           void *newMap = realloc(procAsciiMap, mapSize);
+           if (!newMap) {
+               fprintf(stderr, "DYNINSTgetMemoryMap: Out of memory\n");
+               goto freeBuffer;
+           }
+           procAsciiMap = newMap;
+       }
+       fd = open("/proc/self/maps", O_RDONLY);
+       if (0 > fd) {
+           perror("open /proc");
+           goto freeBuffer;
+       }
+       length = 0;
+       while (1)
+       {
+           ret = read(fd, procAsciiMap + length, mapSize - length);
+           length += ret;
+           if (0 == ret) {
+               done = 1;
+               break;
+           }
+           if (0 > ret) {
+               close(fd);
+               perror("read /proc");
+               goto freeBuffer;
+           }
+           /* Check if the buffer was to small and exponentially
+              increase its size */
+           if (length >= mapSize) {
+               close(fd);
+               mapSize = mapSize << 1;
+
+                  /* Return error if we reached the max size for
+                     the buffer*/
+                  if(mapSize > MAX_MAP_SIZE) {
+                      fprintf(stderr, "DYNINSTgetMemoryMap: memory map buffer \
+                                       is larger than the max size. max size=%d\n", MAX_MAP_SIZE);
+                      goto freeBuffer;
+                  }
+               break;
+           }
+       }
+       if(done) {
+           break;
+       }
    }
    procAsciiMap[length] = '\0'; /* Now string processing works */
 
-   close(fd);
-
    /* Count lines, which is the same as the number of segments.
       Newline characters separating lines are converted to nulls. */
    for (num = 0, p = strtok(procAsciiMap, "\n");
         p != NULL;
         num++, p = strtok(NULL, "\n"))
       ;
-     
+
    ms = (dyninstmm_t *) malloc(num * sizeof(dyninstmm_t));
    if (! ms) {
       fprintf(stderr, "DYNINSTgetMemoryMap: Out of memory\n");
-      return -1;
+      goto freeBuffer;
    }
 
    p = procAsciiMap;
@@ -176,9 +215,13 @@ DYNINSTgetMemoryMap(unsigned *nump, dyninstmm_t **mapp)
 
    *nump = num;
    *mapp = ms;
+   free(procAsciiMap);
    return 0;
  parseerr:
    free(ms);
    fprintf(stderr, "DYNINSTgetMemoryMap: /proc/self/maps parse error\n");
+ freeBuffer:
+   free(procAsciiMap);
+ end:
    return -1;
 }
-- 
1.8.3.2

[← Prev in Thread] Current Thread [Next in Thread→]