summaryrefslogtreecommitdiff
path: root/lib/canonicalize.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/canonicalize.c')
-rw-r--r--lib/canonicalize.c91
1 files changed, 37 insertions, 54 deletions
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index e331e3ff1b..3342f70140 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -162,28 +162,18 @@ seen_triple (Hash_table **ht, char const *filename, struct stat const *st)
return false;
}
+/* Scratch buffers used by canonicalize_filename_mode_stk and managed
+ by __realpath. */
+struct realpath_bufs
+{
+ struct scratch_buffer rname;
+ struct scratch_buffer extra;
+ struct scratch_buffer link;
+};
-/* Act like canonicalize_filename_mode (see below), with an additional argument
- rname_buf that can be used as temporary storage.
-
- If GCC_LINT is defined, do not inline this function with GCC 10.1
- and later, to avoid creating a pointer to the stack that GCC
- -Wreturn-local-addr incorrectly complains about. See:
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644
- Although the noinline attribute can hurt performance a bit, no better way
- to pacify GCC 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. */
-#if _GL_GNUC_PREREQ (10, 1)
-# if defined GCC_LINT || defined lint
-__attribute__ ((__noinline__))
-# elif __OPTIMIZE__ && !__NO_INLINE__
-# define GCC_BOGUS_WRETURN_LOCAL_ADDR
-# endif
-#endif
static char *
canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
- struct scratch_buffer *rname_buf)
+ struct realpath_bufs *bufs)
{
char *dest;
char const *start;
@@ -211,12 +201,7 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
return NULL;
}
- struct scratch_buffer extra_buffer, link_buffer;
- scratch_buffer_init (&extra_buffer);
- scratch_buffer_init (&link_buffer);
- scratch_buffer_init (rname_buf);
- char *rname_on_stack = rname_buf->data;
- char *rname = rname_on_stack;
+ char *rname = bufs->rname.data;
bool end_in_extra_buffer = false;
bool failed = true;
@@ -226,12 +211,12 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
if (!IS_ABSOLUTE_FILE_NAME (name))
{
- while (!getcwd (rname, rname_buf->length))
+ while (!getcwd (bufs->rname.data, bufs->rname.length))
{
switch (errno)
{
case ERANGE:
- if (scratch_buffer_grow (rname_buf))
+ if (scratch_buffer_grow (&bufs->rname))
break;
FALLTHROUGH;
case ENOMEM:
@@ -241,7 +226,7 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
dest = rname;
goto error;
}
- rname = rname_buf->data;
+ rname = bufs->rname.data;
}
dest = rawmemchr (rname, '\0');
start = name;
@@ -265,7 +250,7 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
for (i = 2; name[i] != '\0' && !ISSLASH (name[i]); )
i++;
if (name[i] != '\0' /* implies ISSLASH (name[i]) */
- && i + 1 < rname_buf->length)
+ && i + 1 < bufs->rname.length)
{
prefix_len = i;
memcpy (dest, name + 2, i - 2 + 1);
@@ -275,7 +260,7 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
{
/* Either name = '\\server'; this is an invalid file name.
Or name = '\\server\...' and server is more than
- rname_buf->length - 4 bytes long. In either
+ bufs->rname.length - 4 bytes long. In either
case, stop the UNC processing. */
}
}
@@ -320,13 +305,13 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
if (!ISSLASH (dest[-1]))
*dest++ = '/';
- while (rname + rname_buf->length - dest
+ while (rname + bufs->rname.length - dest
< startlen + sizeof dir_suffix)
{
idx_t dest_offset = dest - rname;
- if (!scratch_buffer_grow_preserve (rname_buf))
+ if (!scratch_buffer_grow_preserve (&bufs->rname))
xalloc_die ();
- rname = rname_buf->data;
+ rname = bufs->rname.data;
dest = rname + dest_offset;
}
@@ -339,12 +324,12 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
{
while (true)
{
- buf = link_buffer.data;
- idx_t bufsize = link_buffer.length;
+ buf = bufs->link.data;
+ idx_t bufsize = bufs->link.length;
n = readlink (rname, buf, bufsize - 1);
if (n < bufsize - 1)
break;
- if (!scratch_buffer_grow (&link_buffer))
+ if (!scratch_buffer_grow (&bufs->link))
xalloc_die ();
}
}
@@ -383,18 +368,18 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
buf[n] = '\0';
- char *extra_buf = extra_buffer.data;
+ char *extra_buf = bufs->extra.data;
idx_t end_idx IF_LINT (= 0);
if (end_in_extra_buffer)
end_idx = end - extra_buf;
size_t len = strlen (end);
if (INT_ADD_OVERFLOW (len, n))
xalloc_die ();
- while (extra_buffer.length <= len + n)
+ while (bufs->extra.length <= len + n)
{
- if (!scratch_buffer_grow_preserve (&extra_buffer))
+ if (!scratch_buffer_grow_preserve (&bufs->extra))
xalloc_die ();
- extra_buf = extra_buffer.data;
+ extra_buf = bufs->extra.data;
}
if (end_in_extra_buffer)
end = extra_buf + end_idx;
@@ -453,20 +438,15 @@ canonicalize_filename_mode_stk (const char *name, canonicalize_mode_t can_mode,
error:
if (ht)
hash_free (ht);
- scratch_buffer_free (&extra_buffer);
- scratch_buffer_free (&link_buffer);
if (failed)
- {
- scratch_buffer_free (rname_buf);
- return NULL;
- }
+ return NULL;
*dest++ = '\0';
- char *result = scratch_buffer_dupfree (rname_buf, dest - rname);
+ char *result = malloc (dest - rname);
if (!result)
xalloc_die ();
- return result;
+ return memcpy (result, rname, dest - rname);
}
/* Return the canonical absolute name of file NAME, while treating
@@ -479,10 +459,13 @@ error:
char *
canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
{
- #ifdef GCC_BOGUS_WRETURN_LOCAL_ADDR
- #warning "GCC might issue a bogus -Wreturn-local-addr warning here."
- #warning "See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93644>."
- #endif
- struct scratch_buffer rname_buffer;
- return canonicalize_filename_mode_stk (name, can_mode, &rname_buffer);
+ struct realpath_bufs bufs;
+ scratch_buffer_init (&bufs.rname);
+ scratch_buffer_init (&bufs.extra);
+ scratch_buffer_init (&bufs.link);
+ char *result = canonicalize_filename_mode_stk (name, can_mode, &bufs);
+ scratch_buffer_free (&bufs.link);
+ scratch_buffer_free (&bufs.extra);
+ scratch_buffer_free (&bufs.rname);
+ return result;
}