summaryrefslogtreecommitdiff
path: root/lib/careadlinkat.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/careadlinkat.c')
-rw-r--r--lib/careadlinkat.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c
index 197ce8de77f..1aa04363dac 100644
--- a/lib/careadlinkat.c
+++ b/lib/careadlinkat.c
@@ -1,7 +1,7 @@
/* Read symbolic links into a buffer without size limitation, relative to fd.
- Copyright (C) 2001, 2003-2004, 2007, 2009-2020 Free Software
- Foundation, Inc.
+ Copyright (C) 2001, 2003-2004, 2007, 2009-2020 Free Software Foundation,
+ Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -72,23 +72,38 @@ careadlinkat (int fd, char const *filename,
SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
char stack_buf[1024];
+#if (defined GCC_LINT || defined lint) && _GL_GNUC_PREREQ (10, 1)
+ /* Pacify preadlinkat without creating a pointer to the stack
+ that a broken gcc -Wreturn-local-addr would cry wolf about. See:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95044
+ This workaround differs from the mainline code, but
+ no other way to pacify GCC 10.1.0 is known; even an explicit
+ #pragma does not pacify GCC. When the GCC bug is fixed this
+ workaround should be limited to the broken GCC versions. */
+# define WORK_AROUND_GCC_BUG_95044
+#endif
+
if (! alloc)
alloc = &stdlib_allocator;
- if (! buffer_size)
+ if (!buffer)
{
+#ifdef WORK_AROUND_GCC_BUG_95044
+ buffer = alloc->allocate (sizeof stack_buf);
+#else
/* Allocate the initial buffer on the stack. This way, in the
common case of a symlink of small size, we get away with a
single small malloc() instead of a big malloc() followed by a
shrinking realloc(). */
buffer = stack_buf;
+#endif
buffer_size = sizeof stack_buf;
}
buf = buffer;
buf_size = buffer_size;
- do
+ while (buf)
{
/* Attempt to read the link into the current buffer. */
ssize_t link_length = preadlinkat (fd, filename, buf, buf_size);
@@ -117,19 +132,19 @@ careadlinkat (int fd, char const *filename,
if (buf == stack_buf)
{
- char *b = (char *) alloc->allocate (link_size);
+ char *b = alloc->allocate (link_size);
buf_size = link_size;
if (! b)
break;
- memcpy (b, buf, link_size);
- buf = b;
+ return memcpy (b, buf, link_size);
}
- else if (link_size < buf_size && buf != buffer && alloc->reallocate)
+
+ if (link_size < buf_size && buf != buffer && alloc->reallocate)
{
/* Shrink BUF before returning it. */
- char *b = (char *) alloc->reallocate (buf, link_size);
+ char *b = alloc->reallocate (buf, link_size);
if (b)
- buf = b;
+ return b;
}
return buf;
@@ -138,8 +153,8 @@ careadlinkat (int fd, char const *filename,
if (buf != buffer)
alloc->free (buf);
- if (buf_size <= buf_size_max / 2)
- buf_size *= 2;
+ if (buf_size < buf_size_max / 2)
+ buf_size = 2 * buf_size + 1;
else if (buf_size < buf_size_max)
buf_size = buf_size_max;
else if (buf_size_max < SIZE_MAX)
@@ -149,9 +164,8 @@ careadlinkat (int fd, char const *filename,
}
else
break;
- buf = (char *) alloc->allocate (buf_size);
+ buf = alloc->allocate (buf_size);
}
- while (buf);
if (alloc->die)
alloc->die (buf_size);