Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 May 2002 19:15:23 +1000 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Dima Dorfman <dima@trit.org>
Cc:        Dag-Erling Smorgrav <des@ofug.org>, <audit@FreeBSD.ORG>
Subject:   Re: %j for printf(9) 
Message-ID:  <20020528184446.W19885-100000@gamplex.bde.org>
In-Reply-To: <20020528001615.4BAC93E5E@turbine.trit.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 28 May 2002, Dima Dorfman wrote:

> Dag-Erling Smorgrav <des@ofug.org> wrote:
> > Dima Dorfman <dima@trit.org> writes:
> > > Attached is a patch that implements the %j length modifier in
> > > printf(9).
> >
> > Here's an alternative (IMHO less disruptive) patch, which also fixes
> > the default case.
>
> I still like my restructure, but since other people don't seem to
> share my opinion, I'm fine doing it another (your) way.  That said, I
> think your patch has some bugs that mine doesn't.  For example, this:
>
> 	printf("%ld\n", -4);
>
> yields "4294967292" with your patch, but not with mine (mine, and
> printf(3), yield "-4").  I think the attached patch (relative to
> subr_prf.c *with* your patch applied) fixes it.

Both are not incorrect, since the behaviour is undefined :-).
printf("%ld", -4L) would be a better example.

My objections to your restructuring are mostly related to getting the
conversions for this and other things things right.  Forcing everything
into a uintmax_t isn't really simple or correct, and the restructuring
depends on it.

> +++ subr_prf.c	Tue May 28 00:09:30 2002
> @@ -658,19 +658,19 @@
>  			if (jflag)
>  				num = va_arg(ap, uintmax_t);
>  			else if (qflag)
> -				num = va_arg(ap, u_quad_t);
> +				num = (u_quad_t)va_arg(ap, u_quad_t);
>  			else if (lflag)
> -				num = va_arg(ap, u_long);
> +				num = (u_long)va_arg(ap, u_long);
>  			else
> -				num = va_arg(ap, u_int);
> +				num = (u_int)va_arg(ap, u_int);

These casts are all no-ops.   va_arg() already gives the correct type.  This
type is unsigned, so there are no surprises promoting it to the type of `num'
(uintmax_t).

>  			goto nosign;
>  fetch_number:
>  			if (jflag)
> -				num = va_arg(ap, uintmax_t);
> +				num = va_arg(ap, intmax_t);

An (explicit but unnecessary) cast to uintmax_t would make some sense
here, since we are changing the value of an intmax_t to store it into
a uintmax_t.  The conversion happens by default but only clearly works
right on 2's complement machines.

>  			else if (qflag)
> -				num = va_arg(ap, u_quad_t);
> +				num = (quad_t)va_arg(ap, quad_t);

This cast also has no effect.  Changing the type in the va_arg() also
has no effect on any supported machine, but is necessary on machines
with quad_t smaller than intmax_t.  Explicit but null casts, first to
intmax_t and then to uintmax_t, might be good to show what is happening
here.

>  			else if (lflag)
> -				num = va_arg(ap, u_long);
> +				num = (long)va_arg(ap, long);

u_long was wrong in the same way as u_quad_t was wrong, except the wrongness
actually affects supported machines (ones with long smaller than intmax_t).

>  			else
>  				num = sign ? (uintmax_t)va_arg(ap, int) :
>  				    va_arg(ap, u_int);

I think this `sign' test is needed for the lflag and qflag cases too.  It
is needed to get the correct sign extension for promotion of types smaller
than `num'.  In rev.1.1, `int' was the only such type, but in theory
even long longs might be smaller that intmax_t.  Support for machines
with longs smaller than quads seems to be broken in -current.  This only
affects the %r and %z formats.

Bruce


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




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