www.delorie.com/djgpp/bugs/show.cgi   search  
Bug 000148

When Created: 04/14/1997 17:47:36
Against DJGPP version: 2.01
By whom: sidney@ch.twi.tudelft.nl
Abstract: scanf(), fscanf() in libc fail on "%lX" conversion
The scanf() problem will be exhibited when running the following program:

=== START OF CODE FRAGMENT

#include <stdio.h>

void buggy(void)
{
  long CRC;
  scanf("%lX",&CRC);
}

int main(void)
{
  buggy();
  return 0;
}

=== END OF CODE FRAGMENT

When I run this, and type any hex number (say, DEADBEAF) I get a segment
violation error signal. The trouble is in scanf(); the hex conversion seems to
work ok, but somehow has a faulty side effect (probably destroying some crucial
info on the stack).

Workaround added: 04/14/1997 17:48:27
By whom: sidney@ch.twi.tudelft.nl
use "%lx" instead of "lX" (no capital X)

Note added: 07/11/1997 18:40:52
By whom: sidney@ch.twi.tudelft.nl
The problem seems to be in the following code, from

  djgpp\src\libcnsi\stdio\doscan.c (around line 100):

=======
    if (isupper(ch)) {
      /* ch = tolower(ch);
	 gcc gives warning: ANSI C forbids braced
	 groups within expressions */
      ch += 'a' - 'A';
      if (size==LONG)
        size = LONGDOUBLE;
      else
        size = LONG;
    }
=====

I fail to understand what is meant by the comment; it seems to be explaining
why "ch+='a'-'A';" is used instead of "ch=tolower(ch);" yet it compiles without
warning with -Wall -ansi -pedantic.

The problem, however, is in the "if" statement. The "libc" interpretation of
capital "X" is changed to "long" here, while "lX" is changed to "long long".
This is not in accordance with the ANSI specs, I think (though I'm just 99.9%
sure about it): "%X" should scan a regular int instead of a long int, just
as "%x" does.

It's certainly not the way GNU libc handles this! Also, the compiler, thru the
__attribute__ ((format ...)) feature, starts complaining on the following code,
when using the -Wall flag:

=====
#include <stdio.h>
int main(void)
{
  long x;
  long long xx;
  scanf("%X",&x);
  scanf("%lX",&xx);
  printf("%08lX %016llX\n",x,xx);
  return 0;
}
=====

...But this code works with DJGPP libc.

Of course, this explains the strange behaviour of the program in the original
bug report: scanf with "%lX" format destroys 8 bytes of data on the stack,
while only four bytes are reserved.

Hope this helps.

Solution added: 04/18/1999 10:00:49
By whom: eliz@is.elta.co.il
This is solved in WIP and will be in v2.03.  Here's a patch:

*** src/libc/ansi/stdio/doscan.c~0      Tue Oct 28 19:35:18 1997                
--- src/libc/ansi/stdio/doscan.c        Fri Apr 16 13:00:56 1999                
*************** _doscan_low(FILE *iop, int (*scan_getc)(                        
*** 98,107 ****                                                                 
         gcc gives warning: ANSI C forbids braced                               
         groups within expressions */                                           
        ch += 'a' - 'A';                                                        
!       if (size==LONG)                                                         
!         size = LONGDOUBLE;                                                    
!       else if (size != LONGDOUBLE)                                            
!         size = LONG;                                                          
      }                                                                         
      if (ch == '\0')                                                           
        return(-1);                                                             
--- 98,117 ----                                                                 
         gcc gives warning: ANSI C forbids braced                               
         groups within expressions */                                           
        ch += 'a' - 'A';                                                        
!       /* The following if clause is an extension of ANSI/Posix spec: it       
!        allows to use %D, %U, %I etc. to store value in a long (rather         
!        than an int) and %lD, %lU etc. to store value in a long long.          
!        This extension is supported by some compilers (e.g. Borland C).        
!        Old pre-ANSI compilers, such as Turbo C 2.0, also interpreted          
!        %E, %F and %G to store in a double (rather than a float), but          
!        this contradicts the ANSI Standard, so we don't support it.  */        
!       if (ch == 'd' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'x')      
!       {                                                                       
!       if (size==LONG && ch != 'x') /* ANSI: %lX is long, not long long */     
!         size = LONGDOUBLE;                                                    
!       else if (size != LONGDOUBLE)                                            
!         size = LONG;                                                          
!       }                                                                       
      }                                                                         
      if (ch == '\0')                                                           
        return(-1);

Fixed in version on 04/22/1999 09:00:47
By whom: eliz@is.elta.co.il



  webmaster   donations   bookstore     delorie software   privacy  
  Copyright 2010   by DJ Delorie     Updated Jul 2010