Bug 19994

Summary: sscanf() fails on 64-bit operations
Product: Base System Reporter: Jin Guojun <jin>
Component: miscAssignee: Bill Fenner <fenner>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Jin Guojun 2000-07-17 23:50:01 UTC
	sscanf(), and maybe scanf ..., fails on 64-bit operation.

	On Solaris, IRIX and Linux systems, the code below outputs:

	% hextodec -r 963870220966261
	0x00036CA286215975

	% hextodec 0x00036CA286215975
	963870220966261

	% hextodec 0x2804C6B886215975
	2883648157250574709


	Under FreeBSD
 	% hextodec -r 963870220966261
	0x2804C6B886215975

	% hextodec 0x00036CA286215975
	2883648157250574709

	% hextodec 0x2804C6B886215975	# this seems correct
	2883648157250574709

How-To-Repeat: 
	main(argc, argv)
	{
	int rev, i = 1;
		if (!strcmp(argv[i], "-r"))	{
			rev = 1;
			i++;
		} else	rev = 0;
	{
        int64_t h;
                rev ? sscanf(argv[i], "%lld", &h) : sscanf(argv[i], "%llx", &h);
                printf(rev ? "0x%016llX\n": "%lld\n", h);
        }
	}
Comment 1 Bruce Evans 2000-07-18 00:41:10 UTC
On Mon, 17 Jul 2000, Jin Guojun wrote:

> >How-To-Repeat:
> 
> 	main(argc, argv)
> 	{
> 	int rev, i = 1;
> 		if (!strcmp(argv[i], "-r"))	{
> 			rev = 1;
> 			i++;
> 		} else	rev = 0;
> 	{
>         int64_t h;
>                 rev ? sscanf(argv[i], "%lld", &h) : sscanf(argv[i], "%llx", &h);
>                 printf(rev ? "0x%016llX\n": "%lld\n", h);
>         }
> 	}

64-bit types are unportable.  FreeBSD's scanf only supports reading "quad"
types using %qd format.

FreeBSD's scanf also has some overflow handling bugs from misusing strtoq
to handle non-quads.

Bruce

Bruce
Comment 2 Jin Guojun 2000-07-18 02:09:50 UTC
On Mon, 17 Jul 2000, Bruce Evans <bde@zeta.org.au> wrote:

> > >How-To-Repeat:
> > 
> >       main(argc, argv)
> >       {
> >       int rev, i = 1;
> >               if (!strcmp(argv[i], "-r"))     {
> >                       rev = 1;
> >                       i++;
> >               } else  rev = 0;
> >       {
> >         int64_t h;
> >                 rev ? sscanf(argv[i], "%lld", &h) : sscanf(argv[i], "%llx", &h
> );
> >                 printf(rev ? "0x%016llX\n": "%lld\n", h);
> >         }
> >       }
> 
> 64-bit types are unportable.  FreeBSD's scanf only supports reading "quad"
> types using %qd format.
> 
> FreeBSD's scanf also has some overflow handling bugs from misusing strtoq
> to handle non-quads.

Shall we have "%lld" in FreeBSD to make it portable with other systems?

	-Jin
Comment 3 grossman 2001-02-18 18:04:05 UTC
Hi,

I really think we should support %lld with *scanf. After all, we support
it with *printf. It bit me when trying to compile the latest ORBit (0.5.7).
Here's a patch that does the trick.

Bye, Rolf

Index: stdio/vfscanf.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/stdio/vfscanf.c,v
retrieving revision 1.14
diff -c -r1.14 vfscanf.c
*** stdio/vfscanf.c	1999/08/28 00:01:20	1.14
--- stdio/vfscanf.c	2001/02/18 18:03:04
***************
*** 165,171 ****
  			flags |= SUPPRESS;
  			goto again;
  		case 'l':
! 			flags |= LONG;
  			goto again;
  		case 'q':
  			flags |= QUAD;
--- 165,174 ----
  			flags |= SUPPRESS;
  			goto again;
  		case 'l':
! 			if (flags & LONG)
! 				flags |= QUAD;
! 			else
! 				flags |= LONG;
  			goto again;
  		case 'q':
  			flags |= QUAD;
***************
*** 265,276 ****
  			nconversions++;
  			if (flags & SUPPRESS)	/* ??? */
  				continue;
! 			if (flags & SHORT)
! 				*va_arg(ap, short *) = nread;
  			else if (flags & LONG)
  				*va_arg(ap, long *) = nread;
! 			else if (flags & QUAD)
! 				*va_arg(ap, quad_t *) = nread;
  			else
  				*va_arg(ap, int *) = nread;
  			continue;
--- 268,279 ----
  			nconversions++;
  			if (flags & SUPPRESS)	/* ??? */
  				continue;
! 			if (flags & QUAD)
! 				*va_arg(ap, quad_t *) = nread;
  			else if (flags & LONG)
  				*va_arg(ap, long *) = nread;
! 			else if (flags & SHORT)
! 				*va_arg(ap, short *) = nread;
  			else
  				*va_arg(ap, int *) = nread;
  			continue;
***************
*** 555,566 ****
  				if (flags & POINTER)
  					*va_arg(ap, void **) =
  						(void *)(u_long)res;
- 				else if (flags & SHORT)
- 					*va_arg(ap, short *) = res;
- 				else if (flags & LONG)
- 					*va_arg(ap, long *) = res;
  				else if (flags & QUAD)
  					*va_arg(ap, quad_t *) = res;
  				else
  					*va_arg(ap, int *) = res;
  				nassigned++;
--- 558,569 ----
  				if (flags & POINTER)
  					*va_arg(ap, void **) =
  						(void *)(u_long)res;
  				else if (flags & QUAD)
  					*va_arg(ap, quad_t *) = res;
+ 				else if (flags & LONG)
+ 					*va_arg(ap, long *) = res;
+ 				else if (flags & SHORT)
+ 					*va_arg(ap, short *) = res;
  				else
  					*va_arg(ap, int *) = res;
  				nassigned++;
Comment 4 Mike Heffner freebsd_committer freebsd_triage 2001-06-30 05:07:17 UTC
Responsible Changed
From-To: freebsd-bugs->roam

It's rumored that Peter has been thinking about fixing this
Comment 5 Bill Fenner freebsd_committer freebsd_triage 2002-02-25 18:39:27 UTC
Responsible Changed
From-To: roam->fenner

I'm working on c99 support for scanf, which includes %lld.
Comment 6 Bill Fenner freebsd_committer freebsd_triage 2002-05-07 19:02:12 UTC
State Changed
From-To: open->patched

I added c99 %lld support in rev 1.22 of vfscanf.c
Comment 7 Mark Linimon freebsd_committer freebsd_triage 2004-08-31 02:13:00 UTC
State Changed
From-To: patched->closed

Committed back in 2002.