aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarmen Stoppels <me@harmenstoppels.nl>2024-06-24 16:00:14 +0100
committerNick Clifton <nickc@redhat.com>2024-06-24 16:00:14 +0100
commit3af54857cd2b63412fb4517aa2a9ecd360f6426c (patch)
tree6bce416afbef0ae4d1f1f2bfc0239eacade68b09
parente13c4e58907998631962b8d79f7bcf562e461541 (diff)
downloadbinutils-master.zip
binutils-master.tar.gz
binutils-master.tar.bz2
libdep plugin: fix bugs in parser and drop escapingHEADmaster
PR ld/31906 * libdep_plugin.c (str2vec): Fix bug where null byte was not copied on memmove during quote handling and escaping, causing repeat of the last character in the last argument. Fix buffer overflow in **res when arguments were separated by `\t` instead of ` `. Remove handling of the escape character `\`, as it made it impossible to specify paths containing `\` -- the implementation merely dropped `\`, and was affected by the memmove bug, so this should not be breaking; just single and double quotes are sufficient to deal with white space and quote characters, there is no need for escaping. Handle syntax errors on unterminated quotes. Make the parser linear time instead of quadratic.
-rw-r--r--ld/libdep_plugin.c174
1 files changed, 80 insertions, 94 deletions
diff --git a/ld/libdep_plugin.c b/ld/libdep_plugin.c
index 414f3cf..9cd3d77 100644
--- a/ld/libdep_plugin.c
+++ b/ld/libdep_plugin.c
@@ -132,88 +132,68 @@ get_libdeps (int fd)
return rc;
}
-/* Turn a string into an argvec. */
-static char **
-str2vec (char *in)
+/* Parse arguments in-place as contiguous C-strings
+ and return the number of arguments. */
+
+static int
+parse_libdep (char *str)
{
- char **res;
- char *s, *first, *end;
- char *sq, *dq;
- int i;
-
- end = in + strlen (in);
- s = in;
- while (isspace ((unsigned char) *s)) s++;
- first = s;
-
- i = 1;
- while ((s = strchr (s, ' ')))
- {
- s++;
- i++;
- }
- res = (char **)malloc ((i+1) * sizeof (char *));
- if (!res)
- return res;
-
- i = 0;
- sq = NULL;
- dq = NULL;
- res[0] = first;
- for (s = first; *s; s++)
+ char *src, *dst;
+ char quote;
+ int narg;
+
+ src = dst = str;
+
+ for (; isspace ((unsigned char) *src); ++src)
+ ;
+
+ if (*src == '\0')
+ return 0;
+
+ narg = 1;
+ quote = 0;
+
+ while (*src)
{
- if (*s == '\\')
- {
- memmove (s, s+1, end-s-1);
- end--;
- }
- if (isspace ((unsigned char) *s))
+ if (*src == '\'' || *src == '\"')
{
- if (sq || dq)
- continue;
- *s++ = '\0';
- while (isspace ((unsigned char) *s)) s++;
- if (*s)
- res[++i] = s;
- }
- if (*s == '\'' && !dq)
- {
- if (sq)
+ if (!quote)
+ quote = *src++;
+ else if (*src == quote)
{
- memmove (sq, sq+1, s-sq-1);
- memmove (s-2, s+1, end-s-1);
- end -= 2;
- s--;
- sq = NULL;
+ ++src;
+ quote = 0;
}
else
- {
- sq = s;
- }
+ *dst++ = *src++;
}
- if (*s == '"' && !sq)
+ else if (!quote && isspace ((unsigned char) *src))
{
- if (dq)
- {
- memmove (dq, dq+1, s-dq-1);
- memmove (s-2, s+1, end-s-1);
- end -= 2;
- s--;
- dq = NULL;
- }
- else
- {
- dq = s;
- }
+ ++narg;
+ ++src;
+ *dst++ = '\0';
+ for (; isspace ((unsigned char) *src); ++src);
}
+ else
+ *dst++ = *src++;
}
- res[++i] = NULL;
- return res;
+
+ *dst = '\0';
+
+ if (quote)
+ {
+ TV_MESSAGE (LDPL_WARNING,
+ "libdep syntax error: unterminated quoted string");
+ return 0;
+ }
+
+ return narg;
}
static char *prevfile;
/* Standard plugin API registerable hook. */
+
static enum ld_plugin_status
onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
{
@@ -237,8 +217,8 @@ onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
return LDPS_ERR;
/* This hook only gets called on actual object files.
- * We have to examine the archive ourselves, to find
- * our LIBDEPS member. */
+ We have to examine the archive ourselves, to find
+ our LIBDEPS member. */
rv = get_libdeps (file->fd);
if (rv == LDPS_ERR)
return rv;
@@ -256,51 +236,51 @@ onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
}
/* Standard plugin API registerable hook. */
+
static enum ld_plugin_status
onall_symbols_read (void)
{
linerec *lr;
- char **vec;
+ int nargs;
+ char const *arg;
enum ld_plugin_status rv = LDPS_OK;
while ((lr = line_head))
{
line_head = lr->next;
- vec = str2vec (lr->line);
- if (vec)
+ nargs = parse_libdep (lr->line);
+ arg = lr->line;
+
+ int i;
+ for (i = 0; i < nargs; i++, arg = strchr (arg, '\0') + 1)
{
- int i;
- for (i = 0; vec[i]; i++)
+ if (arg[0] != '-')
{
- if (vec[i][0] != '-')
- {
- TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
- vec[i]);
- fflush (NULL);
- continue;
- }
- if (vec[i][1] == 'l')
- rv = tv_add_input_library (vec[i]+2);
- else if (vec[i][1] == 'L')
- rv = tv_set_extra_library_path (vec[i]+2);
- else
- {
- TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
- vec[i]);
- fflush (NULL);
- }
- if (rv != LDPS_OK)
- break;
+ TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s", arg);
+ fflush (NULL);
+ continue;
}
- free (vec);
+ if (arg[1] == 'l')
+ rv = tv_add_input_library (arg + 2);
+ else if (arg[1] == 'L')
+ rv = tv_set_extra_library_path (arg + 2);
+ else
+ {
+ TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s", arg);
+ fflush (NULL);
+ }
+ if (rv != LDPS_OK)
+ break;
}
free (lr);
}
+
line_tail = NULL;
return rv;
}
/* Standard plugin API registerable hook. */
+
static enum ld_plugin_status
oncleanup (void)
{
@@ -309,20 +289,25 @@ oncleanup (void)
free (prevfile);
prevfile = NULL;
}
+
if (line_head)
{
linerec *lr;
+
while ((lr = line_head))
{
line_head = lr->next;
free (lr);
}
+
line_tail = NULL;
}
+
return LDPS_OK;
}
/* Standard plugin API entry point. */
+
enum ld_plugin_status
onload (struct ld_plugin_tv *tv)
{
@@ -351,6 +336,7 @@ onload (struct ld_plugin_tv *tv)
(*tv_register_all_symbols_read) (onall_symbols_read);
(*tv_register_cleanup) (oncleanup);
}
+
fflush (NULL);
return LDPS_OK;
}