fix(std-io): make uint128 decimal formatting safe (#2924)

* fix(std-io): make uint128 decimal formatting safe and add all-base
numeric coverage
---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
Fernando López Guevara
2026-02-11 19:50:16 -03:00
committed by GitHub
parent 7665720264
commit f079fa82b2
5 changed files with 243 additions and 34 deletions

View File

@@ -13,8 +13,7 @@ interface Printable
fn usz? to_format(Formatter* formatter) @optional;
}
faultdef BUFFER_EXCEEDED, INTERNAL_BUFFER_EXCEEDED, INVALID_FORMAT,
NOT_ENOUGH_ARGUMENTS, INVALID_ARGUMENT;
faultdef BUFFER_EXCEEDED, INTERNAL_BUFFER_EXCEEDED, INVALID_FORMAT, NOT_ENOUGH_ARGUMENTS, INVALID_ARGUMENT;
alias OutputFn = fn void?(void* buffer, char c);
alias FloatType = double;
@@ -34,14 +33,14 @@ macro bool is_struct_with_default_print($Type)
*>
macro usz? struct_to_format(value, Formatter* f, bool $force_dump)
{
var $Type = $typeof(value);
usz total = f.print("{ ")!;
$foreach $i, $member : $Type.membersof:
$if $i > 0:
total += f.print(", ")!;
$endif
$if $member.nameof != "":
total += f.printf("%s: ", $member.nameof)!;
var $Type = $typeof(value);
usz total = f.print("{ ")!;
$foreach $i, $member : $Type.membersof:
$if $i > 0:
total += f.print(", ")!;
$endif
$if $member.nameof != "":
total += f.printf("%s: ", $member.nameof)!;
$endif
$if ($force_dump &&& ($member.typeid.kindof == STRUCT || $member.typeid.kindof == BITSTRUCT)) |||
is_struct_with_default_print($member.typeid):
@@ -351,12 +350,12 @@ macro usz? @wrap_bad(Formatter* f, #action)
switch (err)
{
case BUFFER_EXCEEDED:
case INTERNAL_BUFFER_EXCEEDED:
return f.first_err(err)~;
default:
case INTERNAL_BUFFER_EXCEEDED:
return f.first_err(err)~;
default:
err = f.first_err(INVALID_ARGUMENT);
f.out_substr("<INVALID>")!;
return err~;
f.out_substr("<INVALID>")!;
return err~;
}
}
return len;
@@ -489,7 +488,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
self.flags.uppercase = true;
nextcase;
case 'h':
char[] out @noinit;
char[] out @noinit;
switch (current.type)
{
case char[]:

View File

@@ -541,7 +541,6 @@ const char[201] DIGIT_PAIRS @private =
"08182838485868788898"
"09192939495969798999";
fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
{
char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit;
@@ -574,10 +573,10 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
while (value >= 10)
{
if (len + 1 >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
char digit = (char)(value % 100);
char digit = (char)(value % 100U);
buf[len:2] = DIGIT_PAIRS[2 * digit:2];
len += 2;
value /= 100;
value /= 100U;
}
if (value > 0)
{
@@ -593,16 +592,16 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
value >>= 4;
}
while (value);
case 8:
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = '0' + (char)value & 0x7;
value >>= 3;
}
while (value);
default:
unreachable();
case 8:
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
buf[len++] = '0' + (char)value & 0x7;
value >>= 3;
}
while (value);
default:
unreachable();
}
}
return self.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
@@ -684,9 +683,9 @@ fn usz? Formatter.out_char(&self, any arg) @private
usz len = 1;
// pre padding
if (!self.flags.left)
{
len += self.pad(' ', self.width, len)!;
}
{
len += self.pad(' ', self.width, len)!;
}
// char output
Char32 c = types::any_to_int(arg, uint) ?? 0xFFFD;
@@ -708,8 +707,8 @@ fn usz? Formatter.out_char(&self, any arg) @private
self.out((char)(0x80 | (c & 0x3F)))!;
}
if (self.flags.left)
{
len += self.pad(' ', self.width, len)!;
{
len += self.pad(' ', self.width, len)!;
}
return len;
}