Code

Merge branch 'jm/maint-diff-words-with-sbe' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 26 May 2011 16:43:00 +0000 (09:43 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 26 May 2011 16:43:00 +0000 (09:43 -0700)
* jm/maint-diff-words-with-sbe:
  do not read beyond end of malloc'd buffer

1  2 
diff.c

diff --combined diff.c
index ba45a7df112da57b567e723bae695b330cfdfdba,f90c7a896b814930952c42a7acde55fa8cf20e2b..9a8012e362fe2bc08d4ecce21e68972579c3693b
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -23,7 -23,7 +23,7 @@@
  #endif
  
  static int diff_detect_rename_default;
 -static int diff_rename_limit_default = 200;
 +static int diff_rename_limit_default = 400;
  static int diff_suppress_blank_empty;
  int diff_use_color_default = -1;
  static const char *diff_word_regex_cfg;
@@@ -245,15 -245,6 +245,15 @@@ static int fill_mmfile(mmfile_t *mf, st
        return 0;
  }
  
 +/* like fill_mmfile, but only for size, so we can avoid retrieving blob */
 +static unsigned long diff_filespec_size(struct diff_filespec *one)
 +{
 +      if (!DIFF_FILE_VALID(one))
 +              return 0;
 +      diff_populate_filespec(one, 1);
 +      return one->size;
 +}
 +
  static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
  {
        char *ptr = mf->ptr;
@@@ -615,20 -606,22 +615,20 @@@ static void diff_words_append(char *lin
        buffer->text.ptr[buffer->text.size] = '\0';
  }
  
 -struct diff_words_style_elem
 -{
 +struct diff_words_style_elem {
        const char *prefix;
        const char *suffix;
        const char *color; /* NULL; filled in by the setup code if
                            * color is enabled */
  };
  
 -struct diff_words_style
 -{
 +struct diff_words_style {
        enum diff_words_type type;
        struct diff_words_style_elem new, old, ctx;
        const char *newline;
  };
  
 -struct diff_words_style diff_words_styles[] = {
 +static struct diff_words_style diff_words_styles[] = {
        { DIFF_WORDS_PORCELAIN, {"+", "\n"}, {"-", "\n"}, {" ", "\n"}, "~\n" },
        { DIFF_WORDS_PLAIN, {"{+", "+}"}, {"[-", "-]"}, {"", ""}, "\n" },
        { DIFF_WORDS_COLOR, {"", ""}, {"", ""}, {"", ""}, "\n" }
@@@ -1050,8 -1043,16 +1050,16 @@@ static void fn_out_consume(void *priv, 
                        emit_line(ecbdata->opt, plain, reset, line, len);
                        fputs("~\n", ecbdata->opt->file);
                } else {
-                       /* don't print the prefix character */
-                       emit_line(ecbdata->opt, plain, reset, line+1, len-1);
+                       /*
+                        * Skip the prefix character, if any.  With
+                        * diff_suppress_blank_empty, there may be
+                        * none.
+                        */
+                       if (line[0] != '\n') {
+                             line++;
+                             len--;
+                       }
+                       emit_line(ecbdata->opt, plain, reset, line, len);
                }
                return;
        }
@@@ -1242,7 -1243,7 +1250,7 @@@ static void show_stats(struct diffstat_
        uintmax_t max_change = 0, max_len = 0;
        int total_files = data->nr;
        int width, name_width;
 -      const char *reset, *set, *add_c, *del_c;
 +      const char *reset, *add_c, *del_c;
        const char *line_prefix = "";
        struct strbuf *msg = NULL;
  
  
        /* Find the longest filename and max number of changes */
        reset = diff_get_color_opt(options, DIFF_RESET);
 -      set   = diff_get_color_opt(options, DIFF_PLAIN);
        add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
        del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
  
@@@ -1538,36 -1540,8 +1546,36 @@@ static void show_dirstat(struct diff_op
                struct diff_filepair *p = q->queue[i];
                const char *name;
                unsigned long copied, added, damage;
 +              int content_changed;
 +
 +              name = p->two->path ? p->two->path : p->one->path;
 +
 +              if (p->one->sha1_valid && p->two->sha1_valid)
 +                      content_changed = hashcmp(p->one->sha1, p->two->sha1);
 +              else
 +                      content_changed = 1;
 +
 +              if (!content_changed) {
 +                      /*
 +                       * The SHA1 has not changed, so pre-/post-content is
 +                       * identical. We can therefore skip looking at the
 +                       * file contents altogether.
 +                       */
 +                      damage = 0;
 +                      goto found_damage;
 +              }
  
 -              name = p->one->path ? p->one->path : p->two->path;
 +              if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) {
 +                      /*
 +                       * In --dirstat-by-file mode, we don't really need to
 +                       * look at the actual file contents at all.
 +                       * The fact that the SHA1 changed is enough for us to
 +                       * add this file to the list of results
 +                       * (with each file contributing equal damage).
 +                       */
 +                      damage = 1;
 +                      goto found_damage;
 +              }
  
                if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
                        diff_populate_filespec(p->one, 0);
                /*
                 * Original minus copied is the removed material,
                 * added is the new material.  They are both damages
 -               * made to the preimage. In --dirstat-by-file mode, count
 -               * damaged files, not damaged lines. This is done by
 -               * counting only a single damaged line per file.
 +               * made to the preimage.
 +               * If the resulting damage is zero, we know that
 +               * diffcore_count_changes() considers the two entries to
 +               * be identical, but since content_changed is true, we
 +               * know that there must have been _some_ kind of change,
 +               * so we force all entries to have damage > 0.
                 */
                damage = (p->one->size - copied) + added;
 -              if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0)
 +              if (!damage)
                        damage = 1;
  
 +found_damage:
                ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
                dir.files[dir.nr].name = name;
                dir.files[dir.nr].changed = damage;
@@@ -2117,28 -2087,25 +2125,28 @@@ static void builtin_diffstat(const cha
                data->is_unmerged = 1;
                return;
        }
 -      if (complete_rewrite) {
 +
 +      if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
 +              data->is_binary = 1;
 +              data->added = diff_filespec_size(two);
 +              data->deleted = diff_filespec_size(one);
 +      }
 +
 +      else if (complete_rewrite) {
                diff_populate_filespec(one, 0);
                diff_populate_filespec(two, 0);
                data->deleted = count_lines(one->data, one->size);
                data->added = count_lines(two->data, two->size);
 -              goto free_and_return;
        }
 -      if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
 -              die("unable to read files to diff");
  
 -      if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
 -              data->is_binary = 1;
 -              data->added = mf2.size;
 -              data->deleted = mf1.size;
 -      } else {
 +      else {
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                xdemitconf_t xecfg;
  
 +              if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
 +                      die("unable to read files to diff");
 +
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
                xpp.flags = o->xdl_opts;
                              &xpp, &xecfg);
        }
  
 - free_and_return:
        diff_free_filespec_data(one);
        diff_free_filespec_data(two);
  }
@@@ -4381,20 -4349,20 +4389,20 @@@ void diff_change(struct diff_options *o
                DIFF_OPT_SET(options, HAS_CHANGES);
  }
  
 -void diff_unmerge(struct diff_options *options,
 -                const char *path,
 -                unsigned mode, const unsigned char *sha1)
 +struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)
  {
 +      struct diff_filepair *pair;
        struct diff_filespec *one, *two;
  
        if (options->prefix &&
            strncmp(path, options->prefix, options->prefix_length))
 -              return;
 +              return NULL;
  
        one = alloc_filespec(path);
        two = alloc_filespec(path);
 -      fill_filespec(one, sha1, mode);
 -      diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1;
 +      pair = diff_queue(&diff_queued_diff, one, two);
 +      pair->is_unmerged = 1;
 +      return pair;
  }
  
  static char *run_textconv(const char *pgm, struct diff_filespec *spec,