Przeglądaj źródła

Tweak continuation-and-comment logic

I think there was a read-off-the-end-of-the-buffer bug that I fixed.
At least I added some good comments, I hope.
Nick Mathewson 15 lat temu
rodzic
commit
0a0cc4599f
2 zmienionych plików z 43 dodań i 5 usunięć
  1. 1 1
      changes/torrc_continuation
  2. 42 4
      src/common/util.c

+ 1 - 1
changes/torrc_continuation

@@ -2,5 +2,5 @@
     - Support line continuations in torrc.  If a line ends with a
     - Support line continuations in torrc.  If a line ends with a
       single backslash character, the newline is ignored, and the
       single backslash character, the newline is ignored, and the
       configuration value is treated as continuing on the next line.
       configuration value is treated as continuing on the next line.
-      Implements bug 1929.
+      Resolves bug 1929.
 
 

+ 42 - 4
src/common/util.c

@@ -2284,6 +2284,36 @@ unescape_string(const char *s, char **result, size_t *size_out)
 const char *
 const char *
 parse_config_line_from_str(const char *line, char **key_out, char **value_out)
 parse_config_line_from_str(const char *line, char **key_out, char **value_out)
 {
 {
+  /* I believe the file format here is supposed to be:
+     FILE = (EMPTYLINE | LINE)*
+
+     EMPTYLINE = SPACE* NL | COMMENT NL
+     SPACE = ' ' | '\r' | '\t'
+     COMMENT = '#' NOT-NL*
+     NOT-NL = Any character except '\n'
+     NL = '\n'
+
+     LINE = SPACE* KEY SPACE* VALUES NL
+     KEY = KEYCHAR+
+     KEYCHAR = Any character except ' ', '\r', '\n', '\t', '#', "\"
+
+     VALUES = QUOTEDVALUE | NORMALVALUE
+     QUOTEDVALUE = QUOTE QVITEM* QUOTE EOLSPACE?
+     QUOTE = '"'
+     QVCHAR = KEYCHAR | ESC ('n' | 't' | 'r' | '"' | ESC |'\'' | OCTAL | HEX)
+     ESC = "\\"
+     OCTAL = ODIGIT (ODIGIT ODIGIT?)?
+     HEX = ('x' | 'X') HEXDIGIT HEXDIGIT
+     ODIGIT = '0' .. '7'
+     HEXDIGIT = '0'..'9' | 'a' .. 'f' | 'A' .. 'F'
+     EOLSPACE = SPACE* COMMENT?
+
+     NORMALVALUE = (VALCHAR | ESC ESC_IGNORE | CONTINUATION)* EOLSPACE?
+     VALCHAR = Any character except ESC, '#', and '\n'
+     ESC_IGNORE = Any character except '#' or '\n'
+     CONTINUATION = ESC NL ( COMMENT NL )*
+   */
+
   const char *key, *val, *cp;
   const char *key, *val, *cp;
   int continuation = 0;
   int continuation = 0;
 
 
@@ -2323,7 +2353,7 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
   val = line;
   val = line;
 
 
   /* Find the end of the line. */
   /* Find the end of the line. */
-  if (*line == '\"') { // XXX No continuation here
+  if (*line == '\"') { // XXX No continuation handling is done here
     if (!(line = unescape_string(line, value_out, NULL)))
     if (!(line = unescape_string(line, value_out, NULL)))
        return NULL;
        return NULL;
     while (*line == ' ' || *line == '\t')
     while (*line == ' ' || *line == '\t')
@@ -2331,27 +2361,34 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
     if (*line && *line != '#' && *line != '\n')
     if (*line && *line != '#' && *line != '\n')
       return NULL;
       return NULL;
   } else {
   } else {
+    /* Look for the end of the line. */
     while (*line && *line != '\n' && (*line != '#' || continuation)) {
     while (*line && *line != '\n' && (*line != '#' || continuation)) {
       if (*line == '\\' && line[1] == '\n') {
       if (*line == '\\' && line[1] == '\n') {
         continuation = 1;
         continuation = 1;
-        ++line;
+        line += 2;
       } else if (*line == '#') {
       } else if (*line == '#') {
         do {
         do {
           ++line;
           ++line;
         } while (*line && *line != '\n');
         } while (*line && *line != '\n');
+        if (*line == '\n')
+          ++line;
+      } else {
+        ++line;
       }
       }
-      ++line;
     }
     }
+
     if (*line == '\n') {
     if (*line == '\n') {
       cp = line++;
       cp = line++;
     } else {
     } else {
       cp = line;
       cp = line;
     }
     }
+    /* Now back cp up to be the last nonspace character */
     while (cp>val && TOR_ISSPACE(*(cp-1)))
     while (cp>val && TOR_ISSPACE(*(cp-1)))
       --cp;
       --cp;
 
 
     tor_assert(cp >= val);
     tor_assert(cp >= val);
 
 
+    /* Now copy out and decode the value. */
     *value_out = tor_strndup(val, cp-val);
     *value_out = tor_strndup(val, cp-val);
     if (continuation) {
     if (continuation) {
       char *v_out, *v_in;
       char *v_out, *v_in;
@@ -2361,7 +2398,8 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
           do {
           do {
             ++v_in;
             ++v_in;
           } while (*v_in && *v_in != '\n');
           } while (*v_in && *v_in != '\n');
-          ++v_in;
+          if (*v_in == '\n')
+            ++v_in;
         } else if (v_in[0] == '\\' && v_in[1] == '\n') {
         } else if (v_in[0] == '\\' && v_in[1] == '\n') {
           v_in += 2;
           v_in += 2;
         } else {
         } else {