aboutsummaryrefslogtreecommitdiff
path: root/lib/std/fmt/errol.zig
diff options
context:
space:
mode:
authorEvan Haas <evan@lagerdata.com>2022-04-03 08:47:17 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-04-04 16:04:35 -0400
commitb4bf3bdf7eac05c5e4ff887294385946f4dd5f3f (patch)
tree714937345eadfd8ccb5332ae87179083260e4029 /lib/std/fmt/errol.zig
parent364e53f3bf6b5aa4e5e7eba5d790c5b957007067 (diff)
downloadzig-b4bf3bdf7eac05c5e4ff887294385946f4dd5f3f.tar.gz
zig-b4bf3bdf7eac05c5e4ff887294385946f4dd5f3f.zip
std.fmt: Fix incorrect behavior with large floating point integers.
I consider this an interim workaround/hack until #1299 is finished. There is a bug in the original C implementation of the errol3 (and errol4) algorithm that can result in undefined behavior or an obviously incorrect result (leading ':' in the output) This change checks for those two problems and uses a slower fallback path if they occur. I can't guarantee that this will always produce the correct result, but since the workaround is only used if the original algorithm is guaranteed to fail, it should never turn a previously-correct result into an incorrect one. Fixes #11283
Diffstat (limited to 'lib/std/fmt/errol.zig')
-rw-r--r--lib/std/fmt/errol.zig7
1 files changed, 6 insertions, 1 deletions
diff --git a/lib/std/fmt/errol.zig b/lib/std/fmt/errol.zig
index e98c23f6ec..29dd2b7a63 100644
--- a/lib/std/fmt/errol.zig
+++ b/lib/std/fmt/errol.zig
@@ -106,7 +106,10 @@ fn errol3u(val: f64, buffer: []u8) FloatDecimal {
} else if (val >= 16.0 and val < 9.007199254740992e15) {
return errolFixed(val, buffer);
}
+ return errolSlow(val, buffer);
+}
+fn errolSlow(val: f64, buffer: []u8) FloatDecimal {
// normalize the midpoint
const e = math.frexp(val).exponent;
@@ -336,7 +339,9 @@ fn errolInt(val: f64, buffer: []u8) FloatDecimal {
var buf_index = u64toa(m64, buffer) - 1;
if (mi != 0) {
- buffer[buf_index - 1] += @boolToInt(buffer[buf_index] >= '5');
+ const round_up = buffer[buf_index] >= '5';
+ if (buf_index == 0 or (round_up and buffer[buf_index - 1] == '9')) return errolSlow(val, buffer);
+ buffer[buf_index - 1] += @boolToInt(round_up);
} else {
buf_index += 1;
}