bug-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: gawk crash with long floating-point numbers


From: Andrew J. Schorr
Subject: Re: gawk crash with long floating-point numbers
Date: Fri, 4 Nov 2005 09:07:05 -0500
User-agent: Mutt/1.4.1i

On Thu, Nov 03, 2005 at 10:59:03PM +0000, Joseph S. Myers wrote:
> Running "gawk -f zex2 </dev/null" with the attached testcase script zex2 
> yields a crash with gawk 3.1.5 on i686-pc-linux-gnu:

Interesting.  It looks like the problem is in format_tree in this
code (line 1178):

                        (void) sprintf(obufout, cpbuf,
                                       (int) fw, (int) prec, (double) tmpval);

The same problem exists in version 3.1.4.  With a debugging statement
inserted before that sprintf, using your test case, we see that:

debug: fw = 0, prec = 6, tmpval = 1e+307, ofre = 511, cpbuf = %*.*f
debug: fw = 0, prec = 6, tmpval = 1e+307, ofre = 196, cpbuf = %*.*f

So when it goes to print the second (307-digit) float, there are only
196 remaining spaces in the output buffer, so it overflows.

The code above where it says:

                        chksize(fw + prec + 9); /* 9 == slop */

is supposed to protect against this, but fw seems to be 0 in this
case.  So I guess the logic is not valid here.

There seem to be 2 possible ways of fixing this:

1. Try to fix the chksize call to have a proper estimate of the
length of the output to be printed.

2. Use snprintf to detect whether we need more space.

Option #2 seems easier, but I'm not sure whether there's some
reason to want to avoid that...

And by the way, doesn't the chksize macro have a bug?
Currently it says:

#define chksize(l)  if ((l) > ofre) { \
        size_t olen = obufout - obuf; \
        erealloc(obuf, char *, osiz * 2, "format_tree"); \
        obufout = obuf + olen; \
        ofre += osiz; \
        osiz *= 2; \
}

But how do we know that doubling the size of the
buffer will increase the size sufficiently?  Shouldn't it
be something like this?

#define chksize(l)  if ((l) > ofre) { \
        size_t olen = obufout - obuf; \
        size_t delta = osiz+l-ofre; \ 
        erealloc(obuf, char *, osiz + delta, "format_tree"); \
        obufout = obuf + olen; \
        ofre += delta; \
        osiz += delta; \
}

Possible patch attached.

Regards,
Andy

Attachment: builtin.patch
Description: Text document


reply via email to

[Prev in Thread] Current Thread [Next in Thread]