allocator: 'die' routine is now given requested size
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 2 Jun 2011 08:15:18 +0000 (01:15 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 2 Jun 2011 08:15:18 +0000 (01:15 -0700)
* lib/allocator.h (struct allocator.die): New size arg.
* lib/careadlinkat.c (careadlinkat): Pass size to 'die' function.
If the actual problem is an ssize_t limitation, not a size_t or
malloc failure, fail with errno==ENAMETOOLONG instead of calling 'die'.

ChangeLog
lib/allocator.h
lib/careadlinkat.c

index 9c6f32f..561ff83 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2011-06-02  Paul Eggert  <eggert@cs.ucla.edu>
+
+       allocator: 'die' routine is now given requested size
+       * lib/allocator.h (struct allocator.die): New size arg.
+       * lib/careadlinkat.c (careadlinkat): Pass size to 'die' function.
+       If the actual problem is an ssize_t limitation, not a size_t or
+       malloc failure, fail with errno==ENAMETOOLONG instead of calling 'die'.
+
 2011-06-01  Eric Blake  <eblake@redhat.com>
 
        strerror: drop strerror_r dependency
index 953117d..b8de95c 100644 (file)
@@ -45,10 +45,11 @@ struct allocator
   /* Call FREE to free memory, like 'free'.  */
   void (*free) (void *);
 
-  /* If nonnull, call DIE if MALLOC or REALLOC fails.  DIE should not
-     return.  DIE can be used by code that detects memory overflow
-     while calculating sizes to be passed to MALLOC or REALLOC.  */
-  void (*die) (void);
+  /* If nonnull, call DIE (SIZE) if MALLOC (SIZE) or REALLOC (...,
+     SIZE) fails.  DIE should not return.  SIZE should equal SIZE_MAX
+     if size_t overflow was detected while calculating sizes to be
+     passed to MALLOC or REALLOC.  */
+  void (*die) (size_t);
 };
 
 /* An allocator using the stdlib functions and a null DIE function.  */
index e2909c7..6e4aa13 100644 (file)
@@ -135,6 +135,7 @@ careadlinkat (int fd, char const *filename,
           if (buf == stack_buf)
             {
               char *b = (char *) alloc->allocate (link_size);
+              buf_size = link_size;
               if (! b)
                 break;
               memcpy (b, buf, link_size);
@@ -158,6 +159,11 @@ careadlinkat (int fd, char const *filename,
         buf_size *= 2;
       else if (buf_size < buf_size_max)
         buf_size = buf_size_max;
+      else if (buf_size_max < SIZE_MAX)
+        {
+          errno = ENAMETOOLONG;
+          return NULL;
+        }
       else
         break;
       buf = (char *) alloc->allocate (buf_size);
@@ -165,7 +171,7 @@ careadlinkat (int fd, char const *filename,
   while (buf);
 
   if (alloc->die)
-    alloc->die ();
+    alloc->die (buf_size);
   errno = ENOMEM;
   return NULL;
 }