diff options
-rw-r--r-- | lib/allocator.h | 12 | ||||
-rw-r--r-- | lib/careadlinkat.c | 34 |
2 files changed, 25 insertions, 21 deletions
diff --git a/lib/allocator.h b/lib/allocator.h index 54cc5ff66f0..4ac863b224c 100644 --- a/lib/allocator.h +++ b/lib/allocator.h @@ -21,8 +21,15 @@ #include <stddef.h> +/* An object describing a memory allocator family. */ + struct allocator { + /* Do not use GCC attributes such as __attribute__ ((malloc)) with + the function types pointed at by these members, because these + attributes do not work with pointers to functions. See + <http://lists.gnu.org/archive/html/bug-gnulib/2011-04/msg00007.html>. */ + /* Call MALLOC to allocate memory, like 'malloc'. On failure MALLOC should return NULL, though not necessarily set errno. When given a zero size it may return NULL even if successful. */ @@ -37,8 +44,9 @@ 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. */ + /* 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); }; diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c index 828c0508db7..15ffe24c0f4 100644 --- a/lib/careadlinkat.c +++ b/lib/careadlinkat.c @@ -57,6 +57,11 @@ careadlinkatcwd (int fd, char const *filename, char *buffer, } #endif +/* A standard allocator. For now, only careadlinkat needs this, but + perhaps it should be moved to the allocator module. */ +static struct allocator const standard_allocator = + { malloc, realloc, free, NULL }; + /* Assuming the current directory is FD, get the symbolic link value of FILENAME as a null-terminated string and put it into a buffer. If FD is AT_FDCWD, FILENAME is interpreted relative to the current @@ -88,17 +93,8 @@ careadlinkat (int fd, char const *filename, SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX; char stack_buf[1024]; - void *(*pmalloc) (size_t) = malloc; - void *(*prealloc) (void *, size_t) = realloc; - void (*pfree) (void *) = free; - void (*pdie) (void) = NULL; - if (alloc) - { - pmalloc = alloc->malloc; - prealloc = alloc->realloc; - pfree = alloc->free; - pdie = alloc->die; - } + if (! alloc) + alloc = &standard_allocator; if (! buffer_size) { @@ -127,7 +123,7 @@ careadlinkat (int fd, char const *filename, { if (buf != buffer) { - pfree (buf); + alloc->free (buf); errno = readlinkat_errno; } return NULL; @@ -142,16 +138,16 @@ careadlinkat (int fd, char const *filename, if (buf == stack_buf) { - char *b = (char *) pmalloc (link_size); + char *b = (char *) alloc->malloc (link_size); if (! b) break; memcpy (b, buf, link_size); buf = b; } - else if (link_size < buf_size && buf != buffer && prealloc) + else if (link_size < buf_size && buf != buffer && alloc->realloc) { /* Shrink BUF before returning it. */ - char *b = (char *) prealloc (buf, link_size); + char *b = (char *) alloc->realloc (buf, link_size); if (b) buf = b; } @@ -160,7 +156,7 @@ careadlinkat (int fd, char const *filename, } if (buf != buffer) - pfree (buf); + alloc->free (buf); if (buf_size <= buf_size_max / 2) buf_size *= 2; @@ -168,12 +164,12 @@ careadlinkat (int fd, char const *filename, buf_size = buf_size_max; else break; - buf = (char *) pmalloc (buf_size); + buf = (char *) alloc->malloc (buf_size); } while (buf); - if (pdie) - pdie (); + if (alloc->die) + alloc->die (); errno = ENOMEM; return NULL; } |