• Jeff King's avatar
    decimal_width: avoid integer overflow · d306f3d3
    Jeff King authored
    The decimal_width function originally appeared in blame.c as
    "lineno_width", and was designed for calculating the
    print-width of small-ish integer values (line numbers in
    text files). In ec7ff5ba, it was made into a reusable
    function, and in dc801e71, we started using it to align
    Binary files in a diffstat show byte counts rather than line
    numbers, meaning they can be quite large (e.g., consider
    adding or removing a 2GB file). decimal_width is not up to
    the challenge for two reasons:
      1. It takes the value as an "int", whereas large files may
         easily surpass this. The value may be truncated, in
         which case we will produce an incorrect value.
      2. It counts "up" by repeatedly multiplying another
         integer by 10 until it surpasses the value.  This can
         cause an infinite loop when the value is close to the
         largest representable integer.
         For example, consider using a 32-bit signed integer,
         and a value of 2,140,000,000 (just shy of 2^31-1).
         We will count up and eventually see that 1,000,000,000
         is smaller than our value. The next step would be to
         multiply by 10 and see that 10,000,000,000 is too
         large, ending the loop. But we can't represent that
         value, and we have signed overflow.
         This is technically undefined behavior, but a common
         behavior is to lose the high bits, in which case our
         iterator will certainly be less than the number. So
         we'll keep multiplying, overflow again, and so on.
    This patch changes the argument to a uintmax_t (the same
    type we use to store the diffstat information for binary
    filese), and counts "down" by repeatedly dividing our value
    by 10.
    Signed-off-by: default avatarJeff King <peff@peff.net>
    Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
pager.c 3.46 KB