From cb502775107ce5f6f22e9b47c9c77300859864b4 Mon Sep 17 00:00:00 2001 From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Date: Wed, 19 Mar 2014 05:48:00 +0100 Subject: [PATCH] cmd/gc: check exponent overflow and underflow in mparith A too large float constant is an error. A too small float constant is rounded to zero. Fixes #7419 Update #6902 LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/76730046 --- src/cmd/gc/go.h | 1 + src/cmd/gc/mparith1.c | 11 ++++++++--- src/cmd/gc/mparith3.c | 34 +++++++++++++++++++++++++++++----- test/fixedbugs/issue7419.go | 25 +++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 test/fixedbugs/issue7419.go diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 151032eb90..36d5167594 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -1255,6 +1255,7 @@ void mpmovecflt(Mpflt *a, double c); void mpmulfltflt(Mpflt *a, Mpflt *b); void mpnegflt(Mpflt *a); void mpnorm(Mpflt *a); +void mpsetexp(Mpflt *a, int exp); int mptestflt(Mpflt *a); int sigfig(Mpflt *a); diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c index 41412c416d..19310a7c8c 100644 --- a/src/cmd/gc/mparith1.c +++ b/src/cmd/gc/mparith1.c @@ -416,7 +416,7 @@ mpatoflt(Mpflt *a, char *as) if(eb) { if(dp) goto bad; - a->exp += ex; + mpsetexp(a, a->exp+ex); goto out; } @@ -427,8 +427,13 @@ mpatoflt(Mpflt *a, char *as) mppow10flt(&b, ex-dp); mpmulfltflt(a, &b); } else { - mppow10flt(&b, dp-ex); - mpdivfltflt(a, &b); + if((short)(dp-ex) != dp-ex) { + mpmovecflt(a, 0.0); + } + else { + mppow10flt(&b, dp-ex); + mpdivfltflt(a, &b); + } } } diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c index f8344c9b4e..da5372cd83 100644 --- a/src/cmd/gc/mparith3.c +++ b/src/cmd/gc/mparith3.c @@ -22,6 +22,27 @@ sigfig(Mpflt *a) return i+1; } +/* + * sets the exponent. + * a too large exponent is an error. + * a too small exponent rounds the number to zero. + */ +void +mpsetexp(Mpflt *a, int exp) { + if((short)exp != exp) { + if(exp > 0) { + yyerror("float constant is too large"); + a->exp = 0x7fff; + } + else { + mpmovecflt(a, 0); + } + } + else { + a->exp = exp; + } +} + /* * shifts the leading non-zero * word of the number to Mpnorm @@ -60,7 +81,7 @@ mpnorm(Mpflt *a) } mpshiftfix(&a->val, s); - a->exp -= s; + mpsetexp(a, a->exp-s); } /// implements float arihmetic @@ -95,7 +116,7 @@ mpaddfltflt(Mpflt *a, Mpflt *b) if(s < 0) { // b is larger, shift a right mpshiftfix(&a->val, s); - a->exp -= s; + mpsetexp(a, a->exp-s); mpaddfixfix(&a->val, &b->val, 0); goto out; } @@ -131,7 +152,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b) } mpmulfract(&a->val, &b->val); - a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1; + mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1); mpnorm(a); if(Mpdebug) @@ -171,7 +192,7 @@ mpdivfltflt(Mpflt *a, Mpflt *b) // divide mpdivfract(&a->val, &c.val); - a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1; + mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1); mpnorm(a); if(Mpdebug) @@ -199,7 +220,10 @@ mpgetflt(Mpflt *a) while((a->val.a[Mpnorm-1] & Mpsign) == 0) { mpshiftfix(&a->val, 1); - a->exp -= 1; + mpsetexp(a, a->exp-1); // can set 'a' to zero + s = sigfig(a); + if(s == 0) + return 0; } // the magic numbers (64, 63, 53, 10, -1074) are diff --git a/test/fixedbugs/issue7419.go b/test/fixedbugs/issue7419.go new file mode 100644 index 0000000000..39b454c059 --- /dev/null +++ b/test/fixedbugs/issue7419.go @@ -0,0 +1,25 @@ +// run + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 7419: odd behavior for float constants underflowing to 0 + +package main + +import ( + "os" +) + +var x = 1e-779137 +var y = 1e-779138 + +func main() { + if x != 0 { + os.Exit(1) + } + if y != 0 { + os.Exit(2) + } +}