Skip to content

Commit c26d320

Browse files
author
Andy C
committed
[builtin/printf] Fix integer truncation by using mops::BigInt
I think we still have a year 2038 problem to fix. Can test that.
1 parent bfef2b6 commit c26d320

File tree

5 files changed

+25
-23
lines changed

5 files changed

+25
-23
lines changed

builtin/printf_osh.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -299,29 +299,27 @@ def _Percent(self, pr, part, varargs, locs):
299299
# %(...)T and %d share this complex integer conversion logic
300300

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

307305
else:
308306
# 'a is interpreted as the ASCII value of 'a'
309307
if len(s) >= 1 and s[0] in '\'"':
310308
if len(s) == 1:
311309
# NUL after quote
312-
d = 0
310+
d = mops.ZERO
313311
else:
314312
# TODO: utf-8 decode s[1:] to be more
315313
# correct. Probably depends on issue #366,
316314
# a utf-8 library.
317-
d = ord(s[1])
315+
d = mops.IntWiden(ord(s[1]))
318316

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

326324
else:
327325
if has_arg:
@@ -361,33 +359,34 @@ def _Percent(self, pr, part, varargs, locs):
361359
# used: -1 represents the current time, and -2 represents the
362360
# time the shell was invoked." from
363361
# https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html#index-printf
364-
if d == -1: # the current time
362+
if mops.Equal(d, mops.MINUS_ONE): # -1 is current time
363+
# TODO: 2038 problem
365364
ts = time_.time()
366-
elif d == -2: # the shell start time
365+
elif mops.Equal(d, mops.MINUS_TWO): # -2 is shell start time
367366
ts = self.shell_start_time
368367
else:
369-
ts = d
368+
ts = mops.BigTruncate(d)
370369

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

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

382-
big_d = mops.IntWiden(d)
383382
if typ == 'o':
384-
s = mops.ToOctal(big_d)
383+
s = mops.ToOctal(d)
385384
elif typ == 'x':
386-
s = mops.ToHexLower(big_d)
385+
s = mops.ToHexLower(d)
387386
elif typ == 'X':
388-
s = mops.ToHexUpper(big_d)
387+
s = mops.ToHexUpper(d)
389388
else: # diu
390-
s = mops.ToStr(big_d) # without spaces like ' -42 '
389+
s = mops.ToStr(d) # without spaces like ' -42 '
391390

392391
# There are TWO different ways to ZERO PAD, and they differ on
393392
# the negative sign! See spec/builtin-printf

mycpp/gc_mops.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace mops {
1313
const BigInt ZERO = BigInt{0};
1414
const BigInt ONE = BigInt{1};
1515
const BigInt MINUS_ONE = BigInt{-1};
16+
const BigInt MINUS_TWO = BigInt{-2}; // for printf
1617

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

mycpp/gc_mops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ typedef int64_t BigInt;
2121
extern const BigInt ZERO;
2222
extern const BigInt ONE;
2323
extern const BigInt MINUS_ONE;
24+
extern const BigInt MINUS_TWO;
2425

2526
BigStr* ToStr(BigInt b);
2627
BigStr* ToOctal(BigInt b);

mycpp/mops.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def __hash__(self):
4949
ZERO = BigInt(0)
5050
ONE = BigInt(1)
5151
MINUS_ONE = BigInt(-1)
52+
MINUS_TWO = BigInt(-2) # for printf
5253

5354

5455
def ToStr(b):

spec/builtin-printf.test.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ printf '[%X]\n' \'ab # extra chars ignored
357357
358358
#### unsigned / octal / hex big
359359
360-
for big in $(( 1 << 32 )) $(( 1 << 63 )); do
360+
for big in $(( 1 << 32 )) $(( (1 << 63) - 1 )); do
361361
printf '[%u]\n' $big
362362
printf '[%o]\n' $big
363363
printf '[%x]\n' $big
@@ -371,10 +371,10 @@ done
371371
[100000000]
372372
[100000000]
373373

374-
[9223372036854775808]
375-
[1000000000000000000000]
376-
[8000000000000000]
377-
[8000000000000000]
374+
[9223372036854775807]
375+
[777777777777777777777]
376+
[7fffffffffffffff]
377+
[7FFFFFFFFFFFFFFF]
378378

379379
## END
380380

0 commit comments

Comments
 (0)