Merge branch 'jc/mailinfo-cleanup-fix'
authorJunio C Hamano <gitster@pobox.com>
Tue, 13 Feb 2018 21:39:14 +0000 (13:39 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 13 Feb 2018 21:39:14 +0000 (13:39 -0800)
Corner case bugfix.

* jc/mailinfo-cleanup-fix:
mailinfo: avoid segfault when can't open files

1  2 
mailinfo.c
diff --combined mailinfo.c
index a89db22ab0c8ef50ae31d5811de5fc48d09224a2,36ec927b9ef9e41c08ba5934b450980002b98aca..d04142ccc76067e83f1839b6315b292268e90c58
@@@ -1,5 -1,4 +1,5 @@@
  #include "cache.h"
 +#include "config.h"
  #include "utf8.h"
  #include "strbuf.h"
  #include "mailinfo.h"
@@@ -58,17 -57,17 +58,17 @@@ static void parse_bogus_from(struct mai
  static const char *unquote_comment(struct strbuf *outbuf, const char *in)
  {
        int c;
 -      int take_next_litterally = 0;
 +      int take_next_literally = 0;
  
        strbuf_addch(outbuf, '(');
  
        while ((c = *in++) != 0) {
 -              if (take_next_litterally == 1) {
 -                      take_next_litterally = 0;
 +              if (take_next_literally == 1) {
 +                      take_next_literally = 0;
                } else {
                        switch (c) {
                        case '\\':
 -                              take_next_litterally = 1;
 +                              take_next_literally = 1;
                                continue;
                        case '(':
                                in = unquote_comment(outbuf, in);
  static const char *unquote_quoted_string(struct strbuf *outbuf, const char *in)
  {
        int c;
 -      int take_next_litterally = 0;
 +      int take_next_literally = 0;
  
        while ((c = *in++) != 0) {
 -              if (take_next_litterally == 1) {
 -                      take_next_litterally = 0;
 +              if (take_next_literally == 1) {
 +                      take_next_literally = 0;
                } else {
                        switch (c) {
                        case '\\':
 -                              take_next_litterally = 1;
 +                              take_next_literally = 1;
                                continue;
                        case '"':
                                return in;
@@@ -149,14 -148,16 +149,14 @@@ static void handle_from(struct mailinf
        at = strchr(f.buf, '@');
        if (!at) {
                parse_bogus_from(mi, from);
 -              return;
 +              goto out;
        }
  
        /*
         * If we already have one email, don't take any confusing lines
         */
 -      if (mi->email.len && strchr(at + 1, '@')) {
 -              strbuf_release(&f);
 -              return;
 -      }
 +      if (mi->email.len && strchr(at + 1, '@'))
 +              goto out;
  
        /* Pick up the string around '@', possibly delimited with <>
         * pair; that is the email part.
        }
  
        get_sane_name(&mi->name, &f, &mi->email);
 +out:
        strbuf_release(&f);
  }
  
@@@ -367,16 -367,11 +367,16 @@@ static struct strbuf *decode_q_segment(
  
        while ((c = *in++) != 0) {
                if (c == '=') {
 -                      int d = *in++;
 +                      int ch, d = *in;
                        if (d == '\n' || !d)
                                break; /* drop trailing newline */
 -                      strbuf_addch(out, (hexval(d) << 4) | hexval(*in++));
 -                      continue;
 +                      ch = hex2chr(in);
 +                      if (ch >= 0) {
 +                              strbuf_addch(out, ch);
 +                              in += 2;
 +                              continue;
 +                      }
 +                      /* garbage -- fall through */
                }
                if (rfc2047 && c == '_') /* rfc2047 4.2 (2) */
                        c = 0x20;
@@@ -762,13 -757,8 +762,13 @@@ static int handle_commit_msg(struct mai
        assert(!mi->filter_stage);
  
        if (mi->header_stage) {
 -              if (!line->len || (line->len == 1 && line->buf[0] == '\n'))
 +              if (!line->len || (line->len == 1 && line->buf[0] == '\n')) {
 +                      if (mi->inbody_header_accum.len) {
 +                              flush_inbody_header_accum(mi);
 +                              mi->header_stage = 0;
 +                      }
                        return 0;
 +              }
        }
  
        if (mi->use_inbody_headers && mi->header_stage) {
@@@ -827,7 -817,6 +827,7 @@@ static void handle_filter(struct mailin
                if (!handle_commit_msg(mi, line))
                        break;
                mi->filter_stage++;
 +              /* fallthrough */
        case 1:
                handle_patch(mi, line);
                break;
@@@ -888,10 -877,7 +888,10 @@@ static int read_one_header_line(struct 
        for (;;) {
                int peek;
  
 -              peek = fgetc(in); ungetc(peek, in);
 +              peek = fgetc(in);
 +              if (peek == EOF)
 +                      break;
 +              ungetc(peek, in);
                if (peek != ' ' && peek != '\t')
                        break;
                if (strbuf_getline_lf(&continuation, in))
@@@ -925,7 -911,8 +925,7 @@@ again
                /* we hit an end boundary */
                /* pop the current boundary off the stack */
                strbuf_release(*(mi->content_top));
 -              free(*(mi->content_top));
 -              *(mi->content_top) = NULL;
 +              FREE_AND_NULL(*(mi->content_top));
  
                /* technically won't happen as is_multipart_boundary()
                   will fail first.  But just in case..
                        error("Detected mismatched boundaries, can't recover");
                        mi->input_error = -1;
                        mi->content_top = mi->content;
 +                      strbuf_release(&newline);
                        return 0;
                }
                handle_filter(mi, &newline);
@@@ -1108,10 -1094,6 +1108,10 @@@ int mailinfo(struct mailinfo *mi, cons
  
        do {
                peek = fgetc(mi->input);
 +              if (peek == EOF) {
 +                      fclose(cmitmsg);
 +                      return error("empty patch: '%s'", patch);
 +              }
        } while (isspace(peek));
        ungetc(peek, mi->input);
  
@@@ -1167,11 -1149,13 +1167,13 @@@ void clear_mailinfo(struct mailinfo *mi
        strbuf_release(&mi->inbody_header_accum);
        free(mi->message_id);
  
-       for (i = 0; mi->p_hdr_data[i]; i++)
-               strbuf_release(mi->p_hdr_data[i]);
+       if (mi->p_hdr_data)
+               for (i = 0; mi->p_hdr_data[i]; i++)
+                       strbuf_release(mi->p_hdr_data[i]);
        free(mi->p_hdr_data);
-       for (i = 0; mi->s_hdr_data[i]; i++)
-               strbuf_release(mi->s_hdr_data[i]);
+       if (mi->s_hdr_data)
+               for (i = 0; mi->s_hdr_data[i]; i++)
+                       strbuf_release(mi->s_hdr_data[i]);
        free(mi->s_hdr_data);
  
        while (mi->content < mi->content_top) {