summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2002-03-22 07:03:30 +0000
committerUlrich Drepper <drepper@redhat.com>2002-03-22 07:03:30 +0000
commit0472723ab8f686b0a64d3d37690a044a73e2ad94 (patch)
tree07b32aaa266e590ac338fb44de40acb39fed6d24
parent3181d9d11f2a1d9eb94518a6d0ba9fd89ebcab7d (diff)
downloadglibc-0472723ab8f686b0a64d3d37690a044a73e2ad94.tar.gz
glibc-0472723ab8f686b0a64d3d37690a044a73e2ad94.tar.xz
glibc-0472723ab8f686b0a64d3d37690a044a73e2ad94.zip
(addgrbyname): Improve buffer allocate with alloca. Use realloc if too large. (addgrbyid): Likewise.
-rw-r--r--nscd/grpcache.c86
1 files changed, 77 insertions, 9 deletions
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index 05ba40ed7c..a7895ad486 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -1,5 +1,5 @@
 /* Cache handling for group lookup.
-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <error.h>
 #include <grp.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -28,6 +29,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <libintl.h>
+#include <stackinfo.h>
 
 #include "nscd.h"
 #include "dbg_log.h"
@@ -204,11 +206,12 @@ addgrbyname (struct database *db, int fd, request_header *req,
      look again in the table whether the dataset is now available.  We
      simply insert it.  It does not matter if it is in there twice.  The
      pruning function only will look at the timestamp.  */
-  int buflen = 256;
+  int buflen = 1024;
   char *buffer = alloca (buflen);
   struct group resultbuf;
   struct group *grp;
   uid_t oldeuid = 0;
+  bool use_malloc = false;
 
   if (debug_level > 0)
     dbg_log (_("Haven't found \"%s\" in group cache!"), (char *)key);
@@ -222,15 +225,47 @@ addgrbyname (struct database *db, int fd, request_header *req,
   while (__getgrnam_r (key, &resultbuf, buffer, buflen, &grp) != 0
 	 && errno == ERANGE)
     {
+      char *old_buffer = buffer;
       errno = 0;
-      buflen += 256;
-      buffer = alloca (buflen);
+      buflen += 1024;
+
+      if (__builtin_expect (buflen > 32768, 0))
+	{
+	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
+	  if (buffer == NULL)
+	    {
+	      /* We ran out of memory.  We cannot do anything but
+		 sending a negative response.  In reality this should
+		 never happen.  */
+	      grp = NULL;
+	      buffer = old_buffer;
+	      break;
+	    }
+	  use_malloc = true;
+	}
+      else
+	{
+	  buffer = alloca (buflen);
+#if _STACK_GROWS_DOWN
+	  if (buffer + buflen == old_buffer)
+	    buflen = 2 * buflen - 1024;
+#elif _STACK_GROWS_UP
+	  if (old_buffer + buflen - 1024 == buffer)
+	    {
+	      buffer = old_buffer;
+	      buflen = 2 * buflen - 1024;
+	    }
+#endif
+	}
     }
 
   if (secure[grpdb])
     seteuid (oldeuid);
 
   cache_addgr (db, fd, req, key, grp, uid);
+
+  if (use_malloc)
+    free (buffer);
 }
 
 
@@ -242,14 +277,15 @@ addgrbygid (struct database *db, int fd, request_header *req,
      look again in the table whether the dataset is now available.  We
      simply insert it.  It does not matter if it is in there twice.  The
      pruning function only will look at the timestamp.  */
-  int buflen = 256;
+  int buflen = 1024;
   char *buffer = alloca (buflen);
   struct group resultbuf;
   struct group *grp;
   uid_t oldeuid = 0;
   char *ep;
-  gid_t gid = strtoul ((char *)key, &ep, 10); 
-  
+  gid_t gid = strtoul ((char *)key, &ep, 10);
+  bool use_malloc = false;
+
   if (*(char*)key == '\0' || *ep != '\0')  /* invalid numeric gid */
     {
       if (debug_level > 0)
@@ -271,13 +307,45 @@ addgrbygid (struct database *db, int fd, request_header *req,
   while (__getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0
 	 && errno == ERANGE)
     {
+      char *old_buffer = buffer;
       errno = 0;
-      buflen += 256;
-      buffer = alloca (buflen);
+      buflen += 1024;
+
+      if (__builtin_expect (buflen > 32768, 0))
+	{
+	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
+	  if (buffer == NULL)
+	    {
+	      /* We ran out of memory.  We cannot do anything but
+		 sending a negative response.  In reality this should
+		 never happen.  */
+	      grp = NULL;
+	      buffer = old_buffer;
+	      break;
+	    }
+	  use_malloc = true;
+	}
+      else
+	{
+	  buffer = alloca (buflen);
+#if _STACK_GROWS_DOWN
+	  if (buffer + buflen == old_buffer)
+	    buflen = 2 * buflen - 1024;
+#elif _STACK_GROWS_UP
+	  if (old_buffer + buflen - 1024 == buffer)
+	    {
+	      buffer = old_buffer;
+	      buflen = 2 * buflen - 1024;
+	    }
+#endif
+	}
     }
 
   if (secure[grpdb])
     seteuid (oldeuid);
 
   cache_addgr (db, fd, req, key, grp, uid);
+
+  if (use_malloc)
+    free (buffer);
 }