Merge branch 'rs/strbuf-read-once-reset-length'
authorJunio C Hamano <gitster@pobox.com>
Wed, 27 Dec 2017 19:16:24 +0000 (11:16 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 27 Dec 2017 19:16:24 +0000 (11:16 -0800)
Leakfix.

* rs/strbuf-read-once-reset-length:
strbuf: release memory on read error in strbuf_read_once()

1  2 
strbuf.c
diff --combined strbuf.c
index 323c49ceb35cb053434248df869578e649ccadc0,0809bca2562a4c970e0405b69de3ed095f3c6e26..ac5a7ab62d554fb292d29df9cb618a336c5336c0
+++ b/strbuf.c
@@@ -204,6 -204,13 +204,6 @@@ void strbuf_addbuf(struct strbuf *sb, c
        strbuf_setlen(sb, sb->len + sb2->len);
  }
  
 -void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
 -{
 -      strbuf_grow(sb, len);
 -      memcpy(sb->buf + sb->len, sb->buf + pos, len);
 -      strbuf_setlen(sb, sb->len + len);
 -}
 -
  void strbuf_addchars(struct strbuf *sb, int c, size_t n)
  {
        strbuf_grow(sb, n);
@@@ -386,12 -393,15 +386,15 @@@ ssize_t strbuf_read(struct strbuf *sb, 
  
  ssize_t strbuf_read_once(struct strbuf *sb, int fd, size_t hint)
  {
+       size_t oldalloc = sb->alloc;
        ssize_t cnt;
  
        strbuf_grow(sb, hint ? hint : 8192);
        cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
        if (cnt > 0)
                strbuf_setlen(sb, sb->len + cnt);
+       else if (oldalloc == 0)
+               strbuf_release(sb);
        return cnt;
  }
  
@@@ -442,17 -452,6 +445,17 @@@ int strbuf_getcwd(struct strbuf *sb
                        strbuf_setlen(sb, strlen(sb->buf));
                        return 0;
                }
 +
 +              /*
 +               * If getcwd(3) is implemented as a syscall that falls
 +               * back to a regular lookup using readdir(3) etc. then
 +               * we may be able to avoid EACCES by providing enough
 +               * space to the syscall as it's not necessarily bound
 +               * to the same restrictions as the fallback.
 +               */
 +              if (errno == EACCES && guessed_len < PATH_MAX)
 +                      continue;
 +
                if (errno != ERANGE)
                        break;
        }
@@@ -476,7 -475,6 +479,7 @@@ int strbuf_getwholeline(struct strbuf *
        /* Translate slopbuf to NULL, as we cannot call realloc on it */
        if (!sb->alloc)
                sb->buf = NULL;
 +      errno = 0;
        r = getdelim(&sb->buf, &sb->alloc, term, fp);
  
        if (r > 0) {
@@@ -779,47 -777,14 +782,47 @@@ char *xstrfmt(const char *fmt, ...
        return ret;
  }
  
 -void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm)
 +void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
 +                   int tz_offset, int suppress_tz_name)
  {
 +      struct strbuf munged_fmt = STRBUF_INIT;
        size_t hint = 128;
        size_t len;
  
        if (!*fmt)
                return;
  
 +      /*
 +       * There is no portable way to pass timezone information to
 +       * strftime, so we handle %z and %Z here.
 +       */
 +      for (;;) {
 +              const char *percent = strchrnul(fmt, '%');
 +              strbuf_add(&munged_fmt, fmt, percent - fmt);
 +              if (!*percent)
 +                      break;
 +              fmt = percent + 1;
 +              switch (*fmt) {
 +              case '%':
 +                      strbuf_addstr(&munged_fmt, "%%");
 +                      fmt++;
 +                      break;
 +              case 'z':
 +                      strbuf_addf(&munged_fmt, "%+05d", tz_offset);
 +                      fmt++;
 +                      break;
 +              case 'Z':
 +                      if (suppress_tz_name) {
 +                              fmt++;
 +                              break;
 +                      }
 +                      /* FALLTHROUGH */
 +              default:
 +                      strbuf_addch(&munged_fmt, '%');
 +              }
 +      }
 +      fmt = munged_fmt.buf;
 +
        strbuf_grow(sb, hint);
        len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
  
                 * output contains at least one character, and then drop the extra
                 * character before returning.
                 */
 -              struct strbuf munged_fmt = STRBUF_INIT;
 -              strbuf_addf(&munged_fmt, "%s ", fmt);
 +              strbuf_addch(&munged_fmt, ' ');
                while (!len) {
                        hint *= 2;
                        strbuf_grow(sb, hint);
                        len = strftime(sb->buf + sb->len, sb->alloc - sb->len,
                                       munged_fmt.buf, tm);
                }
 -              strbuf_release(&munged_fmt);
                len--; /* drop munged space */
        }
 +      strbuf_release(&munged_fmt);
        strbuf_setlen(sb, sb->len + len);
  }