Merge branch 'jk/xmalloc'
authorJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:23 +0000 (16:41 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:23 +0000 (16:41 +0900)
The code is updated to check the result of memory allocation before
it is used in more places, by using xmalloc and/or xcalloc calls.

* jk/xmalloc:
progress: use xmalloc/xcalloc
xdiff: use xmalloc/xrealloc
xdiff: use git-compat-util
test-prio-queue: use xmalloc

1  2 
progress.c
diff --combined progress.c
index 6cde5959fac75ab2640f11346dd124c962d98067,699ac33c4f0609351a403e6779952c6c6ab7cb74..0318bdd41b2f40b6f3cedeb8ca72ead677038d6e
@@@ -8,12 -8,11 +8,12 @@@
   * published by the Free Software Foundation.
   */
  
 -#include "git-compat-util.h"
 +#include "cache.h"
  #include "gettext.h"
  #include "progress.h"
  #include "strbuf.h"
  #include "trace.h"
 +#include "utf8.h"
  
  #define TP_IDX_MAX      8
  
@@@ -35,12 -34,8 +35,12 @@@ struct progress 
        uint64_t total;
        unsigned last_percent;
        unsigned delay;
 +      unsigned sparse;
        struct throughput *throughput;
        uint64_t start_ns;
 +      struct strbuf counters_sb;
 +      int title_len;
 +      int split;
  };
  
  static volatile sig_atomic_t progress_update;
@@@ -83,64 -78,41 +83,64 @@@ static int is_foreground_fd(int fd
        return tpgrp < 0 || tpgrp == getpgid(0);
  }
  
 -static int display(struct progress *progress, uint64_t n, const char *done)
 +static void display(struct progress *progress, uint64_t n, const char *done)
  {
 -      const char *eol, *tp;
 +      const char *tp;
 +      struct strbuf *counters_sb = &progress->counters_sb;
 +      int show_update = 0;
 +      int last_count_len = counters_sb->len;
  
        if (progress->delay && (!progress_update || --progress->delay))
 -              return 0;
 +              return;
  
        progress->last_value = n;
        tp = (progress->throughput) ? progress->throughput->display.buf : "";
 -      eol = done ? done : "   \r";
        if (progress->total) {
                unsigned percent = n * 100 / progress->total;
                if (percent != progress->last_percent || progress_update) {
                        progress->last_percent = percent;
 -                      if (is_foreground_fd(fileno(stderr)) || done) {
 -                              fprintf(stderr, "%s: %3u%% (%"PRIuMAX"/%"PRIuMAX")%s%s",
 -                                      progress->title, percent,
 -                                      (uintmax_t)n, (uintmax_t)progress->total,
 -                                      tp, eol);
 -                              fflush(stderr);
 -                      }
 -                      progress_update = 0;
 -                      return 1;
 +
 +                      strbuf_reset(counters_sb);
 +                      strbuf_addf(counters_sb,
 +                                  "%3u%% (%"PRIuMAX"/%"PRIuMAX")%s", percent,
 +                                  (uintmax_t)n, (uintmax_t)progress->total,
 +                                  tp);
 +                      show_update = 1;
                }
        } else if (progress_update) {
 +              strbuf_reset(counters_sb);
 +              strbuf_addf(counters_sb, "%"PRIuMAX"%s", (uintmax_t)n, tp);
 +              show_update = 1;
 +      }
 +
 +      if (show_update) {
                if (is_foreground_fd(fileno(stderr)) || done) {
 -                      fprintf(stderr, "%s: %"PRIuMAX"%s%s",
 -                              progress->title, (uintmax_t)n, tp, eol);
 +                      const char *eol = done ? done : "\r";
 +                      size_t clear_len = counters_sb->len < last_count_len ?
 +                                      last_count_len - counters_sb->len + 1 :
 +                                      0;
 +                      size_t progress_line_len = progress->title_len +
 +                                              counters_sb->len + 2;
 +                      int cols = term_columns();
 +
 +                      if (progress->split) {
 +                              fprintf(stderr, "  %s%*s", counters_sb->buf,
 +                                      (int) clear_len, eol);
 +                      } else if (!done && cols < progress_line_len) {
 +                              clear_len = progress->title_len + 1 < cols ?
 +                                          cols - progress->title_len : 0;
 +                              fprintf(stderr, "%s:%*s\n  %s%s",
 +                                      progress->title, (int) clear_len, "",
 +                                      counters_sb->buf, eol);
 +                              progress->split = 1;
 +                      } else {
 +                              fprintf(stderr, "%s: %s%*s", progress->title,
 +                                      counters_sb->buf, (int) clear_len, eol);
 +                      }
                        fflush(stderr);
                }
                progress_update = 0;
 -              return 1;
        }
 -
 -      return 0;
  }
  
  static void throughput_string(struct strbuf *buf, uint64_t total,
@@@ -167,12 -139,10 +167,10 @@@ void display_throughput(struct progres
        now_ns = getnanotime();
  
        if (!tp) {
-               progress->throughput = tp = calloc(1, sizeof(*tp));
-               if (tp) {
-                       tp->prev_total = tp->curr_total = total;
-                       tp->prev_ns = now_ns;
-                       strbuf_init(&tp->display, 0);
-               }
+               progress->throughput = tp = xcalloc(1, sizeof(*tp));
+               tp->prev_total = tp->curr_total = total;
+               tp->prev_ns = now_ns;
+               strbuf_init(&tp->display, 0);
                return;
        }
        tp->curr_total = total;
                display(progress, progress->last_value, NULL);
  }
  
 -int display_progress(struct progress *progress, uint64_t n)
 +void display_progress(struct progress *progress, uint64_t n)
  {
 -      return progress ? display(progress, n, NULL) : 0;
 +      if (progress)
 +              display(progress, n, NULL);
  }
  
  static struct progress *start_progress_delay(const char *title, uint64_t total,
 -                                           unsigned delay)
 +                                           unsigned delay, unsigned sparse)
  {
-       struct progress *progress = malloc(sizeof(*progress));
-       if (!progress) {
-               /* unlikely, but here's a good fallback */
-               fprintf(stderr, "%s...\n", title);
-               fflush(stderr);
-               return NULL;
-       }
+       struct progress *progress = xmalloc(sizeof(*progress));
        progress->title = title;
        progress->total = total;
        progress->last_value = -1;
        progress->last_percent = -1;
        progress->delay = delay;
 +      progress->sparse = sparse;
        progress->throughput = NULL;
        progress->start_ns = getnanotime();
 +      strbuf_init(&progress->counters_sb, 0);
 +      progress->title_len = utf8_strwidth(title);
 +      progress->split = 0;
        set_progress_signal();
        return progress;
  }
  
  struct progress *start_delayed_progress(const char *title, uint64_t total)
  {
 -      return start_progress_delay(title, total, 2);
 +      return start_progress_delay(title, total, 2, 0);
  }
  
  struct progress *start_progress(const char *title, uint64_t total)
  {
 -      return start_progress_delay(title, total, 0);
 +      return start_progress_delay(title, total, 0, 0);
 +}
 +
 +/*
 + * Here "sparse" means that the caller might use some sampling criteria to
 + * decide when to call display_progress() rather than calling it for every
 + * integer value in[0 .. total).  In particular, the caller might not call
 + * display_progress() for the last value in the range.
 + *
 + * When "sparse" is set, stop_progress() will automatically force the done
 + * message to show 100%.
 + */
 +struct progress *start_sparse_progress(const char *title, uint64_t total)
 +{
 +      return start_progress_delay(title, total, 0, 1);
 +}
 +
 +struct progress *start_delayed_sparse_progress(const char *title,
 +                                             uint64_t total)
 +{
 +      return start_progress_delay(title, total, 2, 1);
 +}
 +
 +static void finish_if_sparse(struct progress *progress)
 +{
 +      if (progress &&
 +          progress->sparse &&
 +          progress->last_value != progress->total)
 +              display_progress(progress, progress->total);
  }
  
  void stop_progress(struct progress **p_progress)
  {
 +      finish_if_sparse(*p_progress);
 +
        stop_progress_msg(p_progress, _("done"));
  }
  
@@@ -316,7 -245,6 +308,7 @@@ void stop_progress_msg(struct progress 
                free(buf);
        }
        clear_progress_signal();
 +      strbuf_release(&progress->counters_sb);
        if (progress->throughput)
                strbuf_release(&progress->throughput->display);
        free(progress->throughput);