Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 May 2012 06:05:06 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        "David E. O'Brien" <obrien@freebsd.org>
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r235797 - head/contrib/gcc
Message-ID:  <20120523050739.H3621@besplex.bde.org>
In-Reply-To: <201205221818.q4MII7lk019626@svn.freebsd.org>
References:  <201205221818.q4MII7lk019626@svn.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 22 May 2012, David E. O'Brien wrote:

> Log:
>  Do not incorrectly warn when printing a quad_t using "%qd" on 64-bit platforms.

I think I like this, since it is technically correct, and will find a
different set of type mismatches.

> Modified: head/contrib/gcc/c-format.c
> ==============================================================================
> --- head/contrib/gcc/c-format.c	Tue May 22 17:44:01 2012	(r235796)
> +++ head/contrib/gcc/c-format.c	Tue May 22 18:18:06 2012	(r235797)
> @@ -287,7 +287,11 @@ static const format_length_info printf_l
> {
>   { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
>   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
> +#ifdef __LP64__
> +  { "q", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
> +#else
>   { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
> +#endif
>   { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
>   { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
>   { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 },
>

Of course, %qd should never be used.  On LP32, quad_t is long long, while
on LP64, quad_t is long, so any use of %qd required messy ifdefs or
casting a quad_t arg to long long to work on LP64.  Now, %qd actually
matches quad_t on LP64, so casting to long long is no longer needed, but
anything that does it is broken and would require changing to cast to
quad_t, or perhaps to omit the cast.  You might find too much bugware that
(1) uses %qd
(2) uses it on args that don't always have type quad_t
(3) casts to long long.  Casting to quad_t didn't work on LP64 before, so
     probably nothing in FreeBSD does it.

Grepping for %q in /sys finds only a few uses of %q with a few type
mismatches (different mismatches before and after this commit).  (I
didn't grep for more compicated formats with stuff between the % and the
q.):

% ./compat/ndis/subr_ntoskrnl.c:	printf("timer sets: %qu\n", ntoskrnl_timer_sets);
% ./compat/ndis/subr_ntoskrnl.c:	printf("timer reloads: %qu\n", ntoskrnl_timer_reloads);
% ./compat/ndis/subr_ntoskrnl.c:	printf("timer cancels: %qu\n", ntoskrnl_timer_cancels);
% ./compat/ndis/subr_ntoskrnl.c:	printf("timer fires: %qu\n", ntoskrnl_timer_fires);

This was broken before on LP64.  It now works accidentally.  All these %qu
formats are bogus, since the variables don't have type quad_t; they have
type uint64_t.  Now that %q works, quad_t's are actually easier to print
that int64_t's since there is a format letter just for them.  But this
only helps if the variables actually have type quad_t.

% ./dev/esp/ncr53c9x.c:		panic("%s: lun %qx for ecb %p does not exist", __func__,
% ./dev/esp/ncr53c9x.c:			panic("%s: slot %d for lun %qx has %p instead of ecb "

This is under DIAGNOSTIC and is now broken.  Again the variable doesn't have
type [u_]quad_t.  It has type int64_t.  This is printed using the doubly-
incompatible format %qx (signed type but unsigned format; int64 type but
quad format letter).  Then to be bug for bug compatible with old gcc, this
incompatible format was cast to a different doubly-incompatible type.

% ./fs/msdosfs/msdosfs_vnops.c:		printf("    va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n",

This is under the non-option MSDOSFS_DEBUG.  It was broken before, but now
works, since va_bytes actually has type u_quad_t and was not bogusly cast
to unsigned long long).

% ./fs/nfsclient/nfs_clstate.c:			    printf("lck typ=%d fst=%qd end=%qd\n",
% ./fs/nfsclient/nfs_clstate.c:			    printf("lck typ=%d fst=%qd end=%qd\n",

These are under !__FreeBSD__ ifdefs.  The ifdefs are related to the type
errors.  The types are u_int64_t.  Under FreeBSD, they are printed
correctly with only 1 type error for each: they are bogusly cast to
intmax_t (sign error), then printed with %ju (this matches the sign of
the variables but is a sign error relative to the cast.  The errors
normally cancel).  Under !__FreeBSD__, they are printed using %qd,
without any casts.  There is now a sign error in the format, and type
mismatches.  This would now compiler under FreeBSD despite all the
type mismatches -- the sign error doesn't matter in practice; u_int64_t
matches u_quad_t on all supported arches, and after your changes the
logical mismatch is no longer detected by gcc.

% ./geom/geom_map.c:	ret = sscanf(line, "search:%qi:%qi:%63c",

This has more than the usual density of bugs:
- scanf() is unusable but is used
- %q format is used
- % the variables are further from being quad_t's than usual.  They are
   off_t's.  off_t happens to have type int64_t, so this works accidentally
   on all supported arches.
- %qi is an unusual spelling of %qd.

You didn't change gcc for scanf.  "q" for it still maps to FMT_LEN_ll.
The above should never have compiled on LP64.

% ./gnu/fs/xfs/FreeBSD/xfs_buf.c:		printf("bread failed specvp %p blkno %qd BBTOB(len) %ld\n",

The variable has type xfs_daddr_t, which is __s64, which is signed long long
int in xfs/FreeBSD.  This used to be compatible with %qd, but no longer is.
xfs shouldn't compile any more on LP64.

Now I prefer the old way, after fixing the bugs found by switching.
It finds more bugs under FreeBSD, and is bug for bug compatible with
distribution gcc and probably with other system's headers under
!FreeBSD.  Except under FreeBSD, I prefer %q to be an error.  The above
shows it only being used 12 times in /sys, with most uses of it being
bugs.  Fixing these bugs would leave about 1 correct use of it -- for
printing the quad_t in unreachable code in msdosfs.  This use would be
easy to avoid too (just cast to uintmax_t).  Uses in userland are
hopefully east to fix and avoid too.  In an old userland, there were
only about 50, with most in netstat/inet6.c, tcopy.c, ftpd, fsirand,
and contrib'ed code.  Of course you can't make it an error for the
contrib'ed code.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120523050739.H3621>