Index: /trunk/docs/Changelog
===================================================================
--- /trunk/docs/Changelog	(revision 381)
+++ /trunk/docs/Changelog	(revision 382)
@@ -1,6 +1,8 @@
 3.0.1:
+	* fix a memory leak (reported by C. Westlake)
 	* fix an uninitialized variable in the suidcheck code (problem
 	  reports by T- Luettgert and Kai)
-	* fix a bug in the port check with --disable-ipv6 (reported by C. Westlake)
+	* fix a bug in the port check with --disable-ipv6 (reported 
+	  by C. Westlake)
 	* fix potential deadlock in sh_files.c (reported by S. Mirolo)
 	* change Makefile.in to stop on compile error rather than at link stage
Index: /trunk/include/sh_utils.h
===================================================================
--- /trunk/include/sh_utils.h	(revision 381)
+++ /trunk/include/sh_utils.h	(revision 382)
@@ -65,4 +65,6 @@
  */
 char * sh_util_strdup (const char * str) SH_GNUC_MALLOC;
+char * sh_util_strdup_track (const char * str, 
+			     char * file, int line) SH_GNUC_MALLOC;
 
 /* returns allocated memory
Index: /trunk/src/sh_fInotify.c
===================================================================
--- /trunk/src/sh_fInotify.c	(revision 381)
+++ /trunk/src/sh_fInotify.c	(revision 382)
@@ -167,10 +167,12 @@
 {
   ssize_t len = -1;
-  char *  buffer = SH_ALLOC(16384);
+  char *  buffer;
   static int count  = 0;
   static int count2 = 0;
 
   if (ShfInotifyActive == S_FALSE)
-    return SH_MOD_FAILED;
+    {
+      return SH_MOD_FAILED;
+    }
 
   if ( (sh.flag.inotify & SH_INOTIFY_DOSCAN) ||
@@ -178,6 +180,10 @@
     {
       if (0 != sh_fInotify_init_internal())
-	return SH_MOD_FAILED;
-    }
+	{
+	  return SH_MOD_FAILED;
+	}
+    }
+
+  buffer = SH_ALLOC(16384);
 
   /* Blocking read from inotify file descriptor.
@@ -203,5 +209,8 @@
 	{
 	  if (0 != sh_fInotify_init_internal())
-	   return SH_MOD_FAILED;
+	    {
+	      SH_FREE(buffer);
+	      return SH_MOD_FAILED;
+	    }
 	}
      }
@@ -230,4 +239,5 @@
     }
 
+  SH_FREE(buffer);
   return 0;
 }
@@ -371,4 +381,5 @@
 	    }
 	}
+      SH_FREE(filename);
     }
 
Index: /trunk/src/sh_inotify.c
===================================================================
--- /trunk/src/sh_inotify.c	(revision 381)
+++ /trunk/src/sh_inotify.c	(revision 382)
@@ -246,9 +246,10 @@
 }
 
-static sh_watch * sh_inotify_create_watch(const char * file, int nwatch, int flag)
+static sh_watch * sh_inotify_create_watch(const char * file, 
+					  int nwatch, int flag)
 {
   sh_watch * this = SH_ALLOC(sizeof(sh_watch));
 
-  this->file  = sh_util_strdup(file);
+  this->file  = sh_util_strdup_track(file, __FILE__, __LINE__);
   this->watch = nwatch;
   this->flag  = flag;
@@ -378,5 +379,5 @@
       *rdepth = this->watch->rdepth;
       *check_mask = this->watch->check_mask;
-      popret  = sh_util_strdup(this->watch->file);
+      popret  = sh_util_strdup_track(this->watch->file, __FILE__, __LINE__);
 
       watches->dormant_watches = this->next;
@@ -477,5 +478,6 @@
 int sh_inotify_add_watch_later(const char * filename, sh_watches * watches, 
 			       int * errnum,
-			       int class, unsigned long check_mask, int type, int rdepth)
+			       int class, unsigned long check_mask, int type, 
+			       int rdepth)
 {
   sh_watch   * item;
@@ -645,4 +647,5 @@
 	    {
 	      *errnum = ENOMEM;
+	      sh_inotify_free_watch(item);
 	      retval = -1;
 	      goto retpoint;
@@ -694,5 +697,5 @@
       *type       = item->type;
       *rdepth     = item->rdepth;
-      sret = sh_util_strdup(item->file);
+      sret = sh_util_strdup_track(item->file, __FILE__, __LINE__);
     }
   SH_MUTEX_UNLOCK(mutex_watches);
Index: /trunk/src/sh_utils.c
===================================================================
--- /trunk/src/sh_utils.c	(revision 381)
+++ /trunk/src/sh_utils.c	(revision 382)
@@ -329,14 +329,14 @@
       if        (0 == strncmp((char *) p, "user", 4)) {
 	out[rem] = 'u'; ++rem;
-	p += 3; state = 1;
+	p += 3;
       } else if (0 == strncmp((char *) p, "group", 5)) {
 	out[rem] = 'g'; ++rem;
-	p += 4; state = 1; 
+	p += 4; 
       } else if (0 == strncmp((char *) p, "mask", 4)) {
 	out[rem] = 'm'; ++rem;
-	p += 3; state = 1;
+	p += 3;
       } else if (0 == strncmp((char *) p, "other", 5)) {
 	out[rem] = 'o';
-	p += 4; state = 1; ++rem;
+	p += 4; ++rem;
       } else if (*p == '\0') {
 	if (rem > 0) { out[rem-1] = '\0'; }
@@ -366,5 +366,5 @@
   SH_VALIDATE_NE(len, 0);
 
-  if (sl_ok_adds (len, 1))
+  if (str && sl_ok_adds (len, 1))
     {
       p   = SH_ALLOC (len + 1);
@@ -387,9 +387,29 @@
   SH_VALIDATE_NE(str, NULL);
 
-  len = sl_strlen(str);
-  p   = SH_ALLOC (len + 1);
-  (void) memcpy (p, str, len+1);
-
+  if (str)
+    {
+      len = sl_strlen(str);
+      p   = SH_ALLOC (len + 1);
+      (void) memcpy (p, str, len+1);
+    }
   SL_RETURN( p, _("sh_util_strdup"));
+}
+
+char * sh_util_strdup_track (const char * str, char * file, int line) 
+{
+  char * p = NULL;
+  size_t len;
+
+  SL_ENTER(_("sh_util_strdup_track"));
+
+  SH_VALIDATE_NE(str, NULL);
+
+  if (str)
+    {
+      len = sl_strlen(str);
+      p   = SH_OALLOC (len + 1, file, line);
+      (void) memcpy (p, str, len+1);
+    }
+  SL_RETURN( p, _("sh_util_strdup_track"));
 }
 
@@ -407,13 +427,16 @@
   SH_VALIDATE_NE(ret, NULL);
 
-  for (c = *str; *c != '\0'; c++) {
-    for (d = delim; *d != '\0'; d++) {
-      if (*c == *d) {
-        *c = '\0';
-        *str = c + 1;
-        SL_RETURN(ret, _("sh_util_strsep"));
+  if (*str)
+    {
+      for (c = *str; *c != '\0'; c++) {
+	for (d = delim; *d != '\0'; d++) {
+	  if (*c == *d) {
+	    *c = '\0';
+	    *str = c + 1;
+	    SL_RETURN(ret, _("sh_util_strsep"));
+	  }
+	}
       }
     }
-  }
 
   /* If we get to here, there's no delimiters in the string */
@@ -1960,13 +1983,16 @@
 	}
 
-      c = strrchr(tmp2, '/');
-      if (c)
-	{
-	  retval = sh_util_strdup(++c);
-	  SH_FREE(tmp2);
-	}
-      else
-	{
-	  retval = tmp2;
+      if (tmp2) /* for llvm/clang analyzer */
+	{
+	  c = strrchr(tmp2, '/');
+	  if (c)
+	    {
+	      retval = sh_util_strdup(++c);
+	      SH_FREE(tmp2);
+	    }
+	  else
+	    {
+	      retval = tmp2;
+	    }
 	}
     }
