Merge branch 'jk/sq-dequote-on-bogus-input'
authorJunio C Hamano <gitster@pobox.com>
Tue, 27 Feb 2018 18:34:02 +0000 (10:34 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 27 Feb 2018 18:34:02 +0000 (10:34 -0800)
Code to unquote single-quoted string (used in the parser for
configuration files, etc.) did not diagnose bogus input correctly
and produced bogus results instead.

* jk/sq-dequote-on-bogus-input:
sq_dequote: fix extra consumption of source string

1  2 
quote.c
t/t1300-repo-config.sh
diff --combined quote.c
index 37d26868656fe8c8c65de41580ab5ae9e89981fc,5e44671d47627c717a209cd669b1362dcaf5a650..c95dd2cafbaa85c9c443a229134842bf06ce3200
+++ b/quote.c
@@@ -43,22 -43,6 +43,22 @@@ void sq_quote_buf(struct strbuf *dst, c
        free(to_free);
  }
  
 +void sq_quote_buf_pretty(struct strbuf *dst, const char *src)
 +{
 +      static const char ok_punct[] = "+,-./:=@_^";
 +      const char *p;
 +
 +      for (p = src; *p; p++) {
 +              if (!isalpha(*p) && !isdigit(*p) && !strchr(ok_punct, *p)) {
 +                      sq_quote_buf(dst, src);
 +                      return;
 +              }
 +      }
 +
 +      /* if we get here, we did not need quoting */
 +      strbuf_addstr(dst, src);
 +}
 +
  void sq_quotef(struct strbuf *dst, const char *fmt, ...)
  {
        struct strbuf src = STRBUF_INIT;
@@@ -72,7 -56,7 +72,7 @@@
        strbuf_release(&src);
  }
  
 -void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
 +void sq_quote_argv(struct strbuf *dst, const char **argv)
  {
        int i;
  
        for (i = 0; argv[i]; ++i) {
                strbuf_addch(dst, ' ');
                sq_quote_buf(dst, argv[i]);
 -              if (maxlen && dst->len > maxlen)
 -                      die("Too many or long arguments");
 +      }
 +}
 +
 +void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
 +{
 +      int i;
 +
 +      for (i = 0; argv[i]; i++) {
 +              strbuf_addch(dst, ' ');
 +              sq_quote_buf_pretty(dst, argv[i]);
        }
  }
  
@@@ -118,9 -94,15 +118,15 @@@ static char *sq_dequote_step(char *arg
                                *next = NULL;
                        return arg;
                case '\\':
-                       c = *++src;
-                       if (need_bs_quote(c) && *++src == '\'') {
-                               *dst++ = c;
+                       /*
+                        * Allow backslashed characters outside of
+                        * single-quotes only if they need escaping,
+                        * and only if we resume the single-quoted part
+                        * afterward.
+                        */
+                       if (need_bs_quote(src[1]) && src[2] == '\'') {
+                               *dst++ = src[1];
+                               src += 2;
                                continue;
                        }
                /* Fallthrough */
@@@ -455,7 -437,6 +461,7 @@@ void tcl_quote_buf(struct strbuf *sb, c
                case '{': case '}':
                case '$': case '\\': case '"':
                        strbuf_addch(sb, '\\');
 +                      /* fallthrough */
                default:
                        strbuf_addch(sb, c);
                        break;
diff --combined t/t1300-repo-config.sh
index cbeb9bebeea67c3654c279b2c12fed4825840d8f,0158d459c5326ea2a7e9c61400aa858da292273f..4f8e6f5fde3295cc91d2feb1fd85fa007e56016c
@@@ -901,36 -901,6 +901,36 @@@ test_expect_success 'get --path barfs o
        test_must_fail git config --get --path path.bool
  '
  
 +test_expect_success 'get --expiry-date' '
 +      rel="3.weeks.5.days.00:00" &&
 +      rel_out="$rel ->" &&
 +      cat >.git/config <<-\EOF &&
 +      [date]
 +      valid1 = "3.weeks.5.days 00:00"
 +      valid2 = "Fri Jun 4 15:46:55 2010"
 +      valid3 = "2017/11/11 11:11:11PM"
 +      valid4 = "2017/11/10 09:08:07 PM"
 +      valid5 = "never"
 +      invalid1 = "abc"
 +      EOF
 +      cat >expect <<-EOF &&
 +      $(test-date timestamp $rel)
 +      1275666415
 +      1510441871
 +      1510348087
 +      0
 +      EOF
 +      {
 +              echo "$rel_out $(git config --expiry-date date.valid1)"
 +              git config --expiry-date date.valid2 &&
 +              git config --expiry-date date.valid3 &&
 +              git config --expiry-date date.valid4 &&
 +              git config --expiry-date date.valid5
 +      } >actual &&
 +      test_cmp expect actual &&
 +      test_must_fail git config --expiry-date date.invalid1
 +'
 +
  cat > expect << EOF
  [quote]
        leading = " test"
@@@ -1206,6 -1176,29 +1206,29 @@@ test_expect_success 'git -c is not conf
        GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list
  '
  
+ sq="'"
+ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
+       cat >expect <<-\EOF &&
+       env.one one
+       env.two two
+       EOF
+       GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq} ${sq}env.two=two${sq}" \
+               git config --get-regexp "env.*" >actual &&
+       test_cmp expect actual &&
+       cat >expect <<-EOF &&
+       env.one one${sq}
+       env.two two
+       EOF
+       GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq}\\$sq$sq$sq ${sq}env.two=two${sq}" \
+               git config --get-regexp "env.*" >actual &&
+       test_cmp expect actual &&
+       test_must_fail env \
+               GIT_CONFIG_PARAMETERS="${sq}env.one=one${sq}\\$sq ${sq}env.two=two${sq}" \
+               git config --get-regexp "env.*"
+ '
  test_expect_success 'git config --edit works' '
        git config -f tmp test.value no &&
        echo test.value=yes >expect &&