lexer: Fix buffer overread in journaling when source does not end in \n.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 29 Sep 2018 22:43:39 +0000 (15:43 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 29 Sep 2018 22:44:02 +0000 (15:44 -0700)
An earlier commit removed the requirement that a source file ends in \n,
but the lexer still made that assumption.  This is intended to fix the
problem.  (Probably, some new tests should be added.)

Thanks to John Darrington for reporting the problem.

Fixes: e0f9210e814d ("lexer: Add support for embedded \0 bytes and missing trailing new-line.")
src/language/lexer/lexer.c

index fb45465f1943aa1d2e811aecd8ef41fce5e2282e..98cf8ec298245dfc53caf68648be4169a4cf90b0 100644 (file)
@@ -1414,20 +1414,30 @@ lex_source_get__ (const struct lex_source *src_)
     }
   for (int i = 0; i < n_lines; i++)
     {
+      /* Beginning of line. */
       const char *line = &src->buffer[src->journal_pos - src->tail];
-      const char *newline = rawmemchr (line, '\n');
-      size_t line_len = newline - line;
-      if (line_len > 0 && line[line_len - 1] == '\r')
-        line_len--;
 
-      char *syntax = malloc (line_len + 2);
-      memcpy (syntax, line, line_len);
-      syntax[line_len] = '\n';
-      syntax[line_len + 1] = '\0';
+      /* Calculate line length, including \n or \r\n end-of-line if present. */
+      size_t max_len = state.line_pos - src->journal_pos;
+      const char *newline = memchr (line, '\n', max_len);
+      size_t line_len = newline ? newline - line + 1 : max_len;
+
+      /* Calculate line length excluding end-of-line. */
+      size_t copy_len = line_len;
+      if (copy_len > 0 && line[copy_len - 1] == '\n')
+        copy_len--;
+      if (copy_len > 0 && line[copy_len - 1] == '\r')
+        copy_len--;
+
+      /* Make a copy of the line with \n end-of-line and null terminator. */
+      char *syntax = xmalloc (copy_len + 2);
+      memcpy (syntax, line, copy_len);
+      syntax[copy_len] = '\n';
+      syntax[copy_len + 1] = '\0';
 
       text_item_submit (text_item_create_nocopy (TEXT_ITEM_SYNTAX, syntax));
 
-      src->journal_pos += newline - line + 1;
+      src->journal_pos += line_len;
     }
 
   token->token_len = state.seg_pos - src->seg_pos;