argus 3.0.0 rc.28 memory leaks

Gabriel L. Somlo somlo at cmu.edu
Thu Aug 31 14:39:11 EDT 2006


Carter,

I've been running argus on a box with 1Gig of memory, and an
Endace card to capture several hundred Mbps from our core. Argus
becomes unresponsive in cca 20-30 minutes, because its memory
image grows to the point where it starts swapping, and I can't
get any more flow records from it beyond that point.

I bumped the memory to two Gigs, and now it takes longer but it still
maxes out eventually and argus has to be restarted.

I've started looking for possible memory leaks, and the attached patch
fixes the ones I found so far. I also fixed a couple of places where
the code allowed a null pointer to be de-referenced (didn't see those
being tickled in a real-life situation, but better safe than sorry :)

Please apply, and I'll try to find more once these changes are in :)

Thanks,
Gabriel
-------------- next part --------------
diff -NarU5 argus-3.0.0.rc.28.orig/argus/argus.c argus-3.0.0.rc.28/argus/argus.c
--- argus-3.0.0.rc.28.orig/argus/argus.c	2006-08-18 13:15:14.000000000 -0400
+++ argus-3.0.0.rc.28/argus/argus.c	2006-08-31 11:29:11.000000000 -0400
@@ -522,14 +522,16 @@
 
    ArgusDebug (1, "ArgusShutDown(%s)\n\n", ArgusSignalTable[sig]);
 #endif 
 
    if (!(ArgusShutDownStarted++)) {
+      clearArgusConfiguration(ArgusModel);
       ArgusCloseSource (ArgusSourceTask);
       ArgusCloseModeler(ArgusModel);
       ArgusCloseOutput(ArgusOutputTask);
       ArgusComplete ();
+      ArgusShutdownRecordAllocator();
 
    } else {
 #ifdef ARGUSDEBUG
    ArgusDebug (2, "ArgusShutDown() returning\n");
 #endif 
@@ -1022,12 +1024,19 @@
 
 
 void
 clearArgusWfile(void)
 {
+   if (ArgusOutputTask->ArgusWfileList != NULL) {
+      struct ArgusWfileStruct *wfile;
+      while ((wfile = (struct ArgusWfileStruct *) ArgusPopFrontList(ArgusOutputTask->ArgusWfileList, ARGUS_NOLOCK)) != NULL) {
+         if (wfile->filename != NULL) free(wfile->filename);
+         ArgusFree(wfile);
+      }
    ArgusDeleteList (ArgusOutputTask->ArgusWfileList);
    ArgusOutputTask->ArgusWfileList = NULL;
+   }
 }
 
 void
 setArgusWfile(char *file, char *filter)
 {
diff -NarU5 argus-3.0.0.rc.28.orig/argus/ArgusModeler.c argus-3.0.0.rc.28/argus/ArgusModeler.c
--- argus-3.0.0.rc.28.orig/argus/ArgusModeler.c	2006-08-28 22:31:58.000000000 -0400
+++ argus-3.0.0.rc.28/argus/ArgusModeler.c	2006-08-31 11:29:11.000000000 -0400
@@ -94,12 +94,14 @@
 /* align the ArgusThisFlow buffer */
 
    if ((retn->ArgusThisFlow = (struct ArgusSystemFlow *) ArgusCalloc (1, sizeof (struct ArgusSystemFlow) + 32)) == NULL)
       ArgusLog (LOG_ERR, "ArgusNewModeler () ArgusCalloc error %s\n", strerror(errno));
 
+/* ArgusCalloc already aligns on a 128-bit multiple -- GLS
    retn->ArgusThisFlow = (struct ArgusSystemFlow *) ((char *)retn->ArgusThisFlow + ((long)retn->ArgusThisFlow & 0x0F));
    retn->ArgusThisFlow = (struct ArgusSystemFlow *) ((char *)retn->ArgusThisFlow + 12);
+*/
 
    gettimeofday (tvp, 0L);
    retn->ArgusGlobalTime = *tvp;
    retn->ArgusThisLLC = &ArgusThisLLCBuffer;
  
@@ -143,10 +145,11 @@
    model->ArgusTCPTimeout  = ARGUS_TCPTIMEOUT;
    model->ArgusICMPTimeout = ARGUS_ICMPTIMEOUT;
    model->ArgusIGMPTimeout = ARGUS_IGMPTIMEOUT;
    model->ArgusFRAGTimeout = ARGUS_FRAGTIMEOUT;
 
+   /* FIXME: maybe we need an explicit ArgusInitRecordAllocator() method :) -- GLS */
    if ((retn = (struct ArgusRecordStruct *) ArgusMallocListRecord(sizeof(struct ArgusRecordStruct))) != NULL)
       ArgusFreeListRecord(retn);
 
 #ifdef ARGUSDEBUG
    ArgusDebug (1, "ArgusInitModeler() done\n");
@@ -168,14 +171,25 @@
          if (htbl->array)
             ArgusFree(htbl->array);
          ArgusFree(htbl);
       }
 
+      /* FIXME: we're shutting down, so why push another record onto the list ? -- GLS */
       if ((argus = ArgusGenerateListRecord (model, NULL, ARGUS_STOP)) != NULL) {
          model->ArgusTotalSends++;
          ArgusPushBackList (model->ArgusOutputList, (struct ArgusListRecord *) argus, ARGUS_LOCK);
       }
+
+      if (model->ArgusOutputList != NULL) {
+         while ((argus = (struct ArgusRecordStruct *) ArgusPopFrontList(model->ArgusOutputList, ARGUS_NOLOCK)) != NULL) {
+            ArgusFreeListRecord(argus);
+         }
+         ArgusDeleteList(model->ArgusOutputList);
+      }
+      ArgusFree(model->hstruct);
+      ArgusFree(model->ArgusThisFlow);
+      ArgusFree(model);
    }
 
 #ifdef ARGUSDEBUG
    ArgusDebug (1, "ArgusCloseModeler(0x%x)\n", model);
 #endif 
@@ -2463,12 +2477,12 @@
 ArgusCopyRecordStruct (struct ArgusRecordStruct *rec)
 {
    struct ArgusRecordStruct *retn = NULL;
    int i;
 
-   if ((retn = (struct ArgusRecordStruct *) ArgusMallocListRecord (sizeof(*retn))) != NULL) {
-      if (rec) {
+   if (rec) {
+      if ((retn = (struct ArgusRecordStruct *) ArgusMallocListRecord (sizeof(*retn))) != NULL) {
          bcopy ((char *)&rec->hdr, (char *)&retn->hdr, sizeof (rec->hdr));
          bcopy ((char *)&rec->canon, (char *)&retn->canon, sizeof (rec->canon));
 
          if ((retn->dsrindex = rec->dsrindex)) {
             for (i = 0; i < ARGUSMAXFLOWTYPE; i++) {
@@ -2510,16 +2524,16 @@
                   retn->dsrs[i] = NULL;
                   retn->dsrindex &= ~(0x01 << i);
                }
             }
          }
-      }
 
-      retn->hdr.type  = ARGUS_FAR;
-      retn->status    = rec->status;
-      retn->trans     = rec->trans;
-      retn->timeout   = rec->timeout;
+         retn->hdr.type  = ARGUS_FAR;
+         retn->status    = rec->status;
+         retn->trans     = rec->trans;
+         retn->timeout   = rec->timeout;
+      }
    }
 
 #ifdef ARGUSDEBUG
    ArgusDebug (8, "ArgusCopyRecordStruct (0x%x) done\n", rec);
 #endif 
diff -NarU5 argus-3.0.0.rc.28.orig/argus/ArgusOutput.c argus-3.0.0.rc.28/argus/ArgusOutput.c
--- argus-3.0.0.rc.28.orig/argus/ArgusOutput.c	2006-08-23 22:45:34.000000000 -0400
+++ argus-3.0.0.rc.28/argus/ArgusOutput.c	2006-08-31 11:29:11.000000000 -0400
@@ -136,10 +136,14 @@
 
             if (strcmp(wfile->filename, "/dev/null"))
                output->clients[ind].sock->filename = strdup(wfile->filename);
 
             output->clients[ind].ArgusClientStart++;
+
+            if (wfile->filename != NULL) free(wfile->filename);
+            if (wfile->filter != NULL) free(wfile->filter);
+            ArgusFree(wfile);
          }
       }
 
       ArgusDeleteList(ArgusWfileList);
    }
@@ -190,10 +194,14 @@
 #endif
       ArgusOutputProcess(output);
    }
 #endif /* ARGUS_THREADS */
 
+   ArgusFree(output->ArgusInitMar);
+   ArgusDeleteList(ArgusOutputTask->ArgusOutputList);
+   ArgusFree(output);
+
 #ifdef ARGUSDEBUG
    ArgusDebug (1, "ArgusCloseOutput() done\n");
 #endif
 }
 
diff -NarU5 argus-3.0.0.rc.28.orig/argus/ArgusSource.c argus-3.0.0.rc.28/argus/ArgusSource.c
--- argus-3.0.0.rc.28.orig/argus/ArgusSource.c	2006-08-28 23:14:45.000000000 -0400
+++ argus-3.0.0.rc.28/argus/ArgusSource.c	2006-08-31 14:25:21.000000000 -0400
@@ -198,20 +198,37 @@
 
    if (src) {
       if (src->ArgusInputFilter)
          ArgusFree (src->ArgusInputFilter);
 
-      if (src->ArgusDeviceList)
+      if (src->ArgusDeviceList != NULL) {
+         struct ArgusDeviceStruct *device;
+         while ((device = (struct ArgusDeviceStruct *) ArgusPopFrontList(src->ArgusDeviceList, ARGUS_NOLOCK)) != NULL) {
+           if (device->name != NULL) free(device->name);
+           ArgusFree(device);
+         }
          ArgusDeleteList(src->ArgusDeviceList);
+      }
 
       if (src->ArgusPcapOutFile)
          pcap_dump_close(src->ArgusPcapOutFile);
-   }
+
+      if (src->ArgusRfileList != NULL) {
+         struct ArgusRfileStruct *rfile;
+         while ((rfile = (struct ArgusRfileStruct *) ArgusPopFrontList(src->ArgusRfileList, ARGUS_NOLOCK)) != NULL) {
+           if (rfile->name != NULL) free(rfile->name);
+           ArgusFree(rfile);
+         }
+         ArgusDeleteList(src->ArgusRfileList);
+      }
 
 #ifdef ARGUSDEBUG
    ArgusDebug (1, "ArgusCloseSource(0x%x) deleting source\n", src);
 #endif
+      ArgusFree(src);
+   }
+
    return (0);
 }
 
 
 unsigned char
@@ -331,10 +348,15 @@
 
 void
 clearArgusDevice (struct ArgusSourceStruct *src)
 {
    if (src->ArgusDeviceList != NULL) {
+      struct ArgusDeviceStruct *device = NULL;
+      while ((device = (struct ArgusDeviceStruct *) ArgusPopFrontList(src->ArgusDeviceList, ARGUS_NOLOCK)) != NULL) {
+        if (device->name != NULL) free(device->name);
+        ArgusFree(device);
+      }
       ArgusDeleteList(src->ArgusDeviceList);
       src->ArgusDeviceList = NULL;
    }
 
 #ifdef ARGUSDEBUG
diff -NarU5 argus-3.0.0.rc.28.orig/argus/ArgusUtil.c argus-3.0.0.rc.28/argus/ArgusUtil.c
--- argus-3.0.0.rc.28.orig/argus/ArgusUtil.c	2006-08-23 22:36:06.000000000 -0400
+++ argus-3.0.0.rc.28/argus/ArgusUtil.c	2006-08-31 11:29:11.000000000 -0400
@@ -105,11 +105,12 @@
 void
 ArgusDeleteList (struct ArgusListStruct *list)
 {
    if (list) {
       while (list->start)
-         ArgusPopFrontList(list, ARGUS_LOCK);
+         /* FIXME: last-ditch effort, since list elements might contain further dynamically allocated data -- GLS */
+         ArgusFree(ArgusPopFrontList(list, ARGUS_LOCK));
 
       ArgusFree (list);
    }
 
 #ifdef ARGUSDEBUG
diff -NarU5 argus-3.0.0.rc.28.orig/common/argus_util.c argus-3.0.0.rc.28/common/argus_util.c
--- argus-3.0.0.rc.28.orig/common/argus_util.c	2006-08-18 13:14:48.000000000 -0400
+++ argus-3.0.0.rc.28/common/argus_util.c	2006-08-31 13:54:56.000000000 -0400
@@ -1033,13 +1033,14 @@
 
 int ArgusAllocTotal = 0;
 int ArgusAllocBytes = 0;
 int ArgusFreeTotal = 0;
 
+#if defined(ARGUSMEMDEBUG)
 struct ArgusMemoryList memory = {NULL, 0};
-
 #define ARGUS_ALLOC		0x45672381
+#endif
 
 void *     
 ArgusMalloc (int bytes) 
 {          
    void *retn = NULL; 
@@ -1052,11 +1053,11 @@
 #if defined(ARGUS_ALIGN_128)
       offset = 128;
 #endif
 
 #if defined(ARGUSMEMDEBUG)
-      if ((retn = (u_int *) malloc (bytes + sizeof(struct ArgusMemoryHeader) + offset)) != NULL) {
+      if ((retn = malloc (bytes + sizeof(struct ArgusMemoryHeader) + offset)) != NULL) {
          struct ArgusMemoryHeader *mem = (struct ArgusMemoryHeader *)retn;
          mem->tag = ARGUS_ALLOC;
          mem->len = bytes;
          mem->offset = offset;
 #if defined(__GNUC__)
@@ -1079,22 +1080,22 @@
          memory.count++;
          memory.total++;
          retn = (void *)(mem + 1);
       }
 #else
-      retn = (void *) malloc (bytes + offset);
+      retn = malloc (bytes + offset);
 #endif
 
-      if (retn != NULL) {
 #if defined(ARGUS_ALIGN_128)
+      if (retn != NULL) {
          unsigned short toff;
          toff = ((unsigned long)retn & (offset - 1));
          toff = offset - toff;
          retn = (void *)((char *)retn + toff);
          ((unsigned short *)retn)[-1] = toff;
-#endif
       }
+#endif
    }
 #ifdef ARGUSDEBUG
    ArgusDebug (6, "ArgusMalloc (%d) returning 0x%x\n", bytes, retn); 
 #endif
    return (retn); 
@@ -1102,25 +1103,26 @@
 
 void *
 ArgusCalloc (int nitems, int bytes)
 {
    void *retn = NULL;
+   int totbytes = nitems * bytes;
    int offset = 0;
 
    if (bytes) {
       ArgusAllocTotal++;
-      ArgusAllocBytes += bytes;
+      ArgusAllocBytes += totbytes;
 
 #if defined(ARGUS_ALIGN_128)
       offset = 128;
 #endif
 
 #if defined(ARGUSMEMDEBUG)
-      if ((retn = (u_int *) calloc (1, (nitems * bytes) + sizeof(struct ArgusMemoryHeader) + offset)) != NULL) {
-         struct ArgusMemoryHeader *mem = retn;
+      if ((retn = calloc (1, totbytes + sizeof(struct ArgusMemoryHeader) + offset)) != NULL) {
+         struct ArgusMemoryHeader *mem = (struct ArgusMemoryHeader *)retn;
          mem->tag = ARGUS_ALLOC;
-         mem->len = bytes;
+         mem->len = totbytes;
          mem->offset = offset;
 #if defined(__GNUC__)
          mem->frame[0] = __builtin_return_address(0);
          mem->frame[1] = __builtin_return_address(1);
          mem->frame[2] = __builtin_return_address(2);
@@ -1140,28 +1142,28 @@
          memory.total++;
          memory.count++;
          retn = (void *)(mem + 1);
       }
 #else
-      retn = calloc (1, (nitems * bytes) + offset);
+      retn = calloc (1, totbytes + offset);
 #endif
 
-      if (retn != NULL) {
 #if defined(ARGUS_ALIGN_128)
+      if (retn != NULL) {
          unsigned short toff;
          toff = ((unsigned long)retn & (offset - 1));
          toff = offset - toff;
          retn = (void *)((char *)retn + toff);
          ((unsigned short *)retn)[-1] = toff;
-#endif
       }
+#endif
    }
 
 #ifdef ARGUSDEBUG
    ArgusDebug (6, "ArgusCalloc (%d, %d) returning 0x%x\n", nitems, bytes, retn);
 #endif
-   return ((void *) retn);
+   return (retn);
 }
 
 
 void
 ArgusFree (void *buf)
@@ -1264,10 +1266,25 @@
    ArgusDebug (6, "ArgusMallocListRecord (%d) returning 0x%x\n", length, retn);
 #endif
    return (retn);
 }
 
+void ArgusShutdownRecordAllocator(void) {
+  struct ArgusMemoryHeader *crt, *rel;
+
+  if (ArgusMallocList != NULL) {
+    crt = ArgusMallocList->start;
+    while (crt != NULL) {
+      rel = crt;
+      crt = crt->nxt;
+      ArgusFree(rel);
+    }
+    ArgusFree(ArgusMallocList);
+    ArgusMallocList = NULL;
+  }
+}
+
 void
 ArgusFreeListRecord (void *buf)
 {
    struct ArgusMemoryHeader *mem = (struct ArgusMemoryHeader *)buf;
    struct ArgusRecordStruct *rec = buf;
@@ -1280,27 +1297,30 @@
    if (rec->dsrs[ARGUS_DSTUSERDATA_INDEX] != NULL) {
       ArgusFree(rec->dsrs[ARGUS_DSTUSERDATA_INDEX]);
       rec->dsrs[ARGUS_DSTUSERDATA_INDEX] = NULL;
    }
 
-   if ((ArgusMallocList == NULL) || (ArgusMallocList->count >= ARGUS_MEMORY_HI_THRESH)) {
+   if (ArgusMallocList == NULL)
       ArgusFree(rec);
-      ArgusMallocList->total--;
-
-   } else {
-      mem->nxt = NULL;
-      if (ArgusMallocList->end)
-         ArgusMallocList->end->nxt = mem;
+   else {
+      if (ArgusMallocList->count < ARGUS_MEMORY_HI_THRESH) {
+         mem->nxt = NULL;
+         if (ArgusMallocList->end != NULL)
+            ArgusMallocList->end->nxt = mem;
 
-      ArgusMallocList->end = mem;
+         ArgusMallocList->end = mem;
 
-      if (!(ArgusMallocList->start))
+        if (ArgusMallocList->start == NULL)
          ArgusMallocList->start = mem;
 
-      ArgusMallocList->count++;
+         ArgusMallocList->count++;
+      } else {
+        ArgusMallocList->total--;
+        ArgusFree(rec);
+      }
    }
-   
+
 #ifdef ARGUSDEBUG 
    ArgusDebug (6, "ArgusFreeListRecord (0x%x) returning\n", buf);
 #endif
    return;
 }


More information about the argus mailing list