Skip to content

Commit

Permalink
[builtin/printf] Fix integer truncation by using mops::BigInt
Browse files Browse the repository at this point in the history
I think we still have a year 2038 problem to fix.  Can test that.
  • Loading branch information
Andy C committed Jun 25, 2024
1 parent bfef2b6 commit c26d320
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 23 deletions.
35 changes: 17 additions & 18 deletions builtin/printf_osh.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,29 +299,27 @@ def _Percent(self, pr, part, varargs, locs):
# %(...)T and %d share this complex integer conversion logic

if match.LooksLikeInteger(s):
# note: spaces like ' -42 ' accepted and normalized
# TODO: use mops.FromStr()
# And mylib.hex_lower() etc. may have to change
d = int(s)
# Note: spaces like ' -42 ' accepted and normalized
d = mops.FromStr(s)

else:
# 'a is interpreted as the ASCII value of 'a'
if len(s) >= 1 and s[0] in '\'"':
if len(s) == 1:
# NUL after quote
d = 0
d = mops.ZERO
else:
# TODO: utf-8 decode s[1:] to be more
# correct. Probably depends on issue #366,
# a utf-8 library.
d = ord(s[1])
d = mops.IntWiden(ord(s[1]))

# No argument means -1 for %(...)T as in Bash #
# Reference Manual 4.2 "If no argument is
# specified, conversion behaves as if -1 had been
# given."
elif not has_arg and part.type.id == Id.Format_Time:
d = -1
d = mops.MINUS_ONE

else:
if has_arg:
Expand Down Expand Up @@ -361,33 +359,34 @@ def _Percent(self, pr, part, varargs, locs):
# used: -1 represents the current time, and -2 represents the
# time the shell was invoked." from
# https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html#index-printf
if d == -1: # the current time
if mops.Equal(d, mops.MINUS_ONE): # -1 is current time
# TODO: 2038 problem
ts = time_.time()
elif d == -2: # the shell start time
elif mops.Equal(d, mops.MINUS_TWO): # -2 is shell start time
ts = self.shell_start_time
else:
ts = d
ts = mops.BigTruncate(d)

s = time_.strftime(typ[1:-2], time_.localtime(ts))
if precision >= 0:
s = s[:precision] # truncate

else: # typ in 'diouxX'
# Disallowed because it depends on 32- or 64- bit
if d < 0 and typ in 'ouxX':
if mops.Greater(mops.ZERO, d) and typ in 'ouxX':
# TODO: Don't truncate it
e_die(
"Can't format negative number %d with %%%s" % (d, typ),
part.type)
"Can't format negative number with %%%s: %d" %
(typ, mops.BigTruncate(d)), part.type)

big_d = mops.IntWiden(d)
if typ == 'o':
s = mops.ToOctal(big_d)
s = mops.ToOctal(d)
elif typ == 'x':
s = mops.ToHexLower(big_d)
s = mops.ToHexLower(d)
elif typ == 'X':
s = mops.ToHexUpper(big_d)
s = mops.ToHexUpper(d)
else: # diu
s = mops.ToStr(big_d) # without spaces like ' -42 '
s = mops.ToStr(d) # without spaces like ' -42 '

# There are TWO different ways to ZERO PAD, and they differ on
# the negative sign! See spec/builtin-printf
Expand Down
1 change: 1 addition & 0 deletions mycpp/gc_mops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace mops {
const BigInt ZERO = BigInt{0};
const BigInt ONE = BigInt{1};
const BigInt MINUS_ONE = BigInt{-1};
const BigInt MINUS_TWO = BigInt{-2}; // for printf

static const int kInt64BufSize = 32; // more than twice as big as kIntBufSize

Expand Down
1 change: 1 addition & 0 deletions mycpp/gc_mops.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ typedef int64_t BigInt;
extern const BigInt ZERO;
extern const BigInt ONE;
extern const BigInt MINUS_ONE;
extern const BigInt MINUS_TWO;

BigStr* ToStr(BigInt b);
BigStr* ToOctal(BigInt b);
Expand Down
1 change: 1 addition & 0 deletions mycpp/mops.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def __hash__(self):
ZERO = BigInt(0)
ONE = BigInt(1)
MINUS_ONE = BigInt(-1)
MINUS_TWO = BigInt(-2) # for printf


def ToStr(b):
Expand Down
10 changes: 5 additions & 5 deletions spec/builtin-printf.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ printf '[%X]\n' \'ab # extra chars ignored
#### unsigned / octal / hex big
for big in $(( 1 << 32 )) $(( 1 << 63 )); do
for big in $(( 1 << 32 )) $(( (1 << 63) - 1 )); do
printf '[%u]\n' $big
printf '[%o]\n' $big
printf '[%x]\n' $big
Expand All @@ -371,10 +371,10 @@ done
[100000000]
[100000000]

[9223372036854775808]
[1000000000000000000000]
[8000000000000000]
[8000000000000000]
[9223372036854775807]
[777777777777777777777]
[7fffffffffffffff]
[7FFFFFFFFFFFFFFF]

## END

Expand Down

0 comments on commit c26d320

Please sign in to comment.