]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tools: make parse_line() always terminate the args list
authorWilly Tarreau <w@1wt.eu>
Thu, 25 Jun 2020 05:35:42 +0000 (07:35 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 25 Jun 2020 07:43:27 +0000 (09:43 +0200)
parse_line() as added in commit c8d167bcf ("MINOR: tools: add a new
configurable line parse, parse_line()") presents an difficult usage
because it's up to the caller to determine the last written argument
based on what was passed to it. In practice the only way to safely
use it is for the caller to always pass nbarg-1 and make that last
entry point to the last arg + its strlen. This is annoying because
it makes it as painful to use as the infamous strncpy() while it has
all the information the caller needs.

This patch changes its behavior so that it guarantees that at least
one argument will point to the trailing zero at the end of the output
string, as long as there is at least one argument. The caller just
has to pass +1 to the arg count to make sure at least a last one is
empty.

src/cfgparse.c
src/tools.c

index 191698e2b649648def47d3bccecbaf7087561707..9f65d838941ecc6fed28812d873d1c87eddb8a9c 100644 (file)
@@ -1938,7 +1938,7 @@ next_line:
                        uint32_t err;
                        char *errptr;
 
-                       arg = MAX_LINE_ARGS;
+                       arg = MAX_LINE_ARGS + 1;
                        outlen = outlinesize;
                        err = parse_line(line, outline, &outlen, args, &arg,
                                         PARSE_OPT_ENV | PARSE_OPT_DQUOTE | PARSE_OPT_SQUOTE |
@@ -1977,7 +1977,7 @@ next_line:
                        }
 
                        if (err & PARSE_ERR_TOOMANY) {
-                               ha_alert("parsing [%s:%d]: too many words, truncating at word %d, position %ld: <%s>.\n",
+                               ha_alert("parsing [%s:%d]: too many words, truncating after word %d, position %ld: <%s>.\n",
                                         file, linenum, MAX_LINE_ARGS, (long)(args[MAX_LINE_ARGS-1] - outline + 1), args[MAX_LINE_ARGS-1]);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                fatal++;
index 10c973761ac90e685e01820698ecfe3411e2c0d7..964170065e5b646d8d6e58628a923798e0cfc66b 100644 (file)
@@ -4738,7 +4738,9 @@ void ha_generate_uuid(struct buffer *output)
  * extraneous ones are not emitted but <outlen> is updated so that the caller
  * knows how much to realloc. Similarly, <args> are not updated beyond <nbargs>
  * but the returned <nbargs> indicates how many were found. All trailing args
- * up to <nbargs> point to the trailing zero.
+ * up to <nbargs> point to the trailing zero, and as long as <nbargs> is > 0,
+ * it is guaranteed that at least one arg will point to the zero. It is safe
+ * to call it with a NULL <args> if <nbargs> is 0.
  *
  * <out> may overlap with <in> provided that it never goes further, in which
  * case the parser will accept to perform in-place parsing and unquoting/
@@ -4761,7 +4763,7 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
        char *brace = NULL;
        unsigned char hex1, hex2;
        size_t outmax = *outlen;
-       int argsmax = *nbargs;
+       int argsmax = *nbargs - 1;
        size_t outpos = 0;
        int squote = 0;
        int dquote = 0;
@@ -4771,7 +4773,10 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
        *nbargs = 0;
        *outlen = 0;
 
-       args[arg] = out;
+       /* argsmax may be -1 here, protecting args[] from any write */
+       if (arg < argsmax)
+               args[arg] = out;
+
        while (1) {
                if (*in >= '-' && *in != '\\') {
                        /* speedup: directly send all regular chars starting
@@ -4972,8 +4977,13 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
        *nbargs = arg;
        *outlen = outpos;
 
-       /* empty all trailing args by making them point to the trailing zero */
-       while (arg < argsmax)
+       /* empty all trailing args by making them point to the trailing zero,
+        * at least the last one in any case.
+        */
+       if (arg > argsmax)
+               arg = argsmax;
+
+       while (arg >= 0 && arg <= argsmax)
                args[arg++] = out + outpos - 1;
 
        return err;