You are not logged in.

#1 2010-04-13 04:16:05

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,111
Website

[solved][C] input validation with strtod()

I'm using strtod() in an RPN implementation, and I'm working on input validation. As per strtod(3), I've written the following conditional to catch input overflow.

...
      errno = 0;
      op1 = strtod(token, &endPtr);
      if ((errno == ERANGE && (op1 == HUGE_VALF || op1 == HUGE_VALL)) || (errno != 0 && op1 == 0)) {
        printf("Error: Input overflow.\n");
        clearstack();
        return 1;
      }
...

Except that when I enter something that would definitely overflow, this conditional is never entered. Furthermore, errno is never set. What am I missing?

A link to the full code can be found here

Last edited by falconindy (2010-04-13 17:49:15)

Offline

#2 2010-04-13 04:29:08

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [solved][C] input validation with strtod()

Well the first wrong thing I see is that you should really test if fabs(op1) is HUGE_VAL{F,L}.

The second thing is, why so complicated a test?  errno != 0 should be all you need.

The third thing is, if errno is really not being set, are you sure you're really overflowing?  doubles go up to about 1.8e308 on most arches.

Offline

#3 2010-04-13 10:50:27

bobdob
Member
Registered: 2008-06-13
Posts: 138

Re: [solved][C] input validation with strtod()

Here is a little program I wrote to test this, and it seems to work:

$ cat test.c 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>

int main ()
{
    char *input = NULL, *end = NULL;
    size_t input_len = 0;
    double output = 0.0;

    if (getline (&input, &input_len, stdin) != -1) {
        errno = 0;
        end = input + input_len;
        output = strtod (input, &end);

        if (errno == ERANGE) {
            if (fabs (output) == 0) {
                printf ("Underflow occured\n");
            } else if (fabs (output) == HUGE_VAL) {
                printf ("Overflow occured\n");
            }
        } else {
            printf ("%e\n", output);
        }
    }

    free (input);
    return 0;
}
$ perl -e 'print (1..100)' | ./a.out
1.234568e+191
$ perl -e 'print (1..1000)' | ./a.out
Overflow occured

Hope this is helpful.

Offline

#4 2010-04-13 17:00:20

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,111
Website

Re: [solved][C] input validation with strtod()

tavianator wrote:

Well the first wrong thing I see is that you should really test if fabs(op1) is HUGE_VAL{F,L}.

The second thing is, why so complicated a test?  errno != 0 should be all you need.

Fair enough. This is the first time I'm really dealing with floating point ops in C.

tavianator wrote:

The third thing is, if errno is really not being set, are you sure you're really overflowing?  doubles go up to about
1.8e308 on most arches.

Huh... wouldn't an unsigned double be, at most, 2^128 - 1 and more likely 2^64 - 1? I'm dealing with signed, so its then half that. Sure enough, sizeof(double) returns 8.

Also, this is what made me think I'm hitting overflow.

> 111111111111111111111111111111111111111111111111111111111111111111111111111111111111 1 *
 = 111111111111111105547424803279259724863245197668615715838829352563602489955831513088.000
>

Hmm. If I go even further, I eventually do hit an overflow error. However, that still leaves me a little baffled as to the results above. Is this a result of the decimal precision inherent in a double?

Offline

#5 2010-04-13 17:26:43

wuischke
Member
From: Suisse Romande
Registered: 2007-01-06
Posts: 630

Re: [solved][C] input validation with strtod()

A double works a bit different. It stores a mantissa (15-16 digits for a double, iirc) and an exponent, similar to the scientific notation of 0.123456*e^100. (Wiki for more info: http://en.wikipedia.org/wiki/IEEE_754-1985)

So these are two separate issues:

1. Overflow of the exponent -> you have a number bigger than 10^308 (* some constant, which I don't remember)
2. Loss of precision, because you can only store 15-16 digits.

Offline

#6 2010-04-13 17:49:04

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,111
Website

Re: [solved][C] input validation with strtod()

wuischke wrote:

A double works a bit different. It stores a mantissa (15-16 digits for a double, iirc) and an exponent, similar to the scientific notation of 0.123456*e^100. (Wiki for more info: http://en.wikipedia.org/wiki/IEEE_754-1985)

So these are two separate issues:

1. Overflow of the exponent -> you have a number bigger than 10^308 (* some constant, which I don't remember)
2. Loss of precision, because you can only store 15-16 digits.

Got it. Thanks for the link. I think I know where to dig, now.

Offline

Board footer

Powered by FluxBB