avr-libc-dev
[Top][All Lists]
Advanced

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

Re: [avr-libc-dev] [bugs #10420] sscanf(), If there is a decimal number


From: Theodore A. Roth
Subject: Re: [avr-libc-dev] [bugs #10420] sscanf(), If there is a decimal number followed by the character '_' in the buffer, you can't get the the number.
Date: Fri, 17 Sep 2004 11:22:51 -0700 (PDT)

On Thu, 16 Sep 2004, anonymous wrote:

> Summary:  sscanf(), If there is a decimal number followed by the
> character '_' in the buffer, you can't get the the number.
>
> Original Submission:  I think there may be some troubles with the
> function sscanf(),
>
> Lets have a look at the following example:
>
> void mc(void)
> {
>     char buf[64] = "<1/dr_2_600";
>     int addr,port,speed;
>
>     sscanf(buf,"<%d/dr_%d_%d",&addr,&port,&speed);
>     printf("addr=%d,port=%d,speed=%dn",addr,port,speed);
>     return;
> }
>
> The expecting results are: addr=1, port=2,speed=600.
> However,the actual results are: addr=1,port=28600, and 'speed' gets a
> invalid value.

I think I've isolated the problem code. The 2 and the 600 are getting
scanned correctly, but the '_' between them in buf is getting converted
to an '8'.

Here's the code in question (from vfscanf.c out of HEAD):

    375                 for (;;) {
    376                     j = tolower(i);
    377                     j -= '0';
    378                     if (j > 9)
    379                         j -= 'a' - '0' - 10;
    380                     if (j < 0 || j >= base) {
    381                         ungetc(i, stream);
    382                         break;
    383                     }

So '_' is 0x5f in ascii. Line 377, subtracts '0', but line 379 adds it
back. So line 379 is really just doing this:

  j = '_' - 'a' + 10 = 0x5f - 0x61 + 0x0a = 8

So we can see where the magic '8' came from in the example's
"port=28600" result. Obviously, (0 < j <= base) evaluates true in this
case, so this code is logically flawed. For grins, I changed the
example's buf to be "<1/dr_2\\600" and got the "port=25600" result I
expected.

I have attached a patch that seems to fix the problem for me. Tested on
a mega128, using both "<1/dr_2_600" and "<1/dr_2\\600" for buf and the
respective fmt strings.

If anyone has a better fix, speak up. Otherwise, I'll commit this to
head and 1.0 tomorrow morning and close the bug.

One other thing. line 379 is hideous. The distribution of the
subtraction via the '-=' operator makes this code very difficult to read
and understand what it is doing exactly. This is a case where parens
should be used:

  j -= ('a' + '0' + 10);

is so much more explicit and makes the code easier to understand.

---
Ted Roth
PGP Key ID: 0x18F846E9
Jabber ID: address@hidden

Attachment: avr-libc-bug-10420.diff
Description: Text document


reply via email to

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