From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25554 invoked by alias); 14 Jun 2012 00:01:00 -0000 Received: (qmail 25545 invoked by uid 22791); 14 Jun 2012 00:00:59 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL,BAYES_00,RCVD_IN_HOSTKARMA_NO,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 14 Jun 2012 00:00:41 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 2C7761C71F8; Wed, 13 Jun 2012 20:00:41 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id FYHhzi9WTLt3; Wed, 13 Jun 2012 20:00:41 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id E633C1C70C5; Wed, 13 Jun 2012 20:00:40 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id 74594145616; Wed, 13 Jun 2012 17:00:38 -0700 (PDT) From: Joel Brobecker To: gdb-patches@sourceware.org Cc: Joel Brobecker Subject: [RFA] convert_doublest_to_floatformat: handle off-range values. Date: Thu, 14 Jun 2012 00:01:00 -0000 Message-Id: <1339632037-5252-1-git-send-email-brobecker@adacore.com> Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-06/txt/msg00452.txt.bz2 Hello, This is a patch where I would definitely appreciate some feedback from the floating-point gurus out there. I initially noticed the problem on x86_64-linux cross AVR, but I eventually managed to reproduce the problem on x86_64-linux native. I won't reproduce on x86-linux hosts, for reasons that are going to be apparent later. Here is a transcript showing the source of the problem: (gdb) p 1.6e309 $5 = -4.9509536758121243e-308 (gdb) p 1.6e-309 $6 = -5.1707209714097603e+307 What happens is that GDB is trying to convert the value it read (as a host "long double") into a target "double" value. The routine performing the conversion does not realize that 1.6e309 is just too large to fit in a double. Similarly, it does not notice that 1.6e-309 is too small to be represented. This patch enhances convert_doublest_to_floatformat to both handle floats that are too small and too large. The hesitation I have is that I am wondering whether the checks I am making might be making a few too many assumptions (maybe IEEE-centric?). The goal is to compute e_min and e_max, where e_min and e_max are the minimum and maximum acceptable values for the exponent. In IEEE floating-point values, the exponent is encoded as a biased unsigned integer. What if the exponent was encoded differently? For instance, I am wondering how things would work if the exponent was represented using a two's complement representation. My patch as it is would probably break. But, on the other hand, I don't see how non-IEEE representations could be handled with the current struct floatformat description we have. gdb/ChangeLog: * doublest.c (convert_doublest_to_floatformat): If the exponent is too small, treat the value as zero. If the exponent is too large, treat the value as infinity. Tested on avr with AdaCore's testsuite. Tested on x86_64-linux. No regression. Does it look OK for now? As for the testcase, I not sure what to do, because reproducing the problem depends on the host and target. I think that the simplest is to choose values that should trigger the problem on most 64bit targets, assuming that "double" is a 64bit IEEE floating point, and that "long double" has a bigger exponent size. The trick is to find an exponent that is large enough to exceed a double's capacity, while at the same not being so big that it exceeds the capacity of a long double. Hence the choice of 309 in the example at the start of this message, which once the decimal representation is represented in binary, becomes an exponent slightly greater than 1023, which is the e_max for doubles on x86_64-linux. --- gdb/doublest.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-) diff --git a/gdb/doublest.c b/gdb/doublest.c index c8c9e05..f683002 100644 --- a/gdb/doublest.c +++ b/gdb/doublest.c @@ -472,6 +472,28 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt, mant = frexp (dfrom, &exponent); #endif + if (exponent + fmt->exp_bias <= 0) + { + /* The value is too small to be expressed in the destination + type (not enough bits in the exponent. Treat as 0. */ + put_field (uto, order, fmt->totalsize, fmt->exp_start, + fmt->exp_len, 0); + put_field (uto, order, fmt->totalsize, fmt->man_start, + fmt->man_len, 0); + goto finalize_byteorder; + } + + if (exponent + fmt->exp_bias >= (1 << fmt->exp_len) - 1) + { + /* The value is too large to fit into the destination. + Treat as infinity. */ + put_field (uto, order, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + put_field (uto, order, fmt->totalsize, fmt->man_start, + fmt->man_len, 0); + goto finalize_byteorder; + } + put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len, exponent + fmt->exp_bias - 1); -- 1.7.1