[comp.lang.perl] Bug in Perl 3.0/6 under SunOS 4.0x on Sun3

casper@fwi.uva.nl (Casper H.S. Dik) (12/17/89)

Hi,

When I was tracing some processes with trace, I used perl to
add/substract pointers.

At that point I noticed that 'printf("%x", some negative value);'
always yielded '0'. At first, I suspected a compiler bug, because it
worked fine on Sun4's. 

% perl -v
$Header: perly.c,v 3.0.1.2 89/11/17 15:34:42 lwall Locked $
Patch level: 6

Show bug on sun3:
sun3% perl -e 'printf("%x\n", -1);'
0
Not on a sun4:
% rsh sun4 perl -e \'printf'("%x\n", -1);'\' 
ffffffff

I traced this problem to do_sprintf (doarg.c).

What happens is that the number -1 is stored in a double. It then is
cast to an unsigned int, before being passed to sprintf:
doarg.c:549:	    (void)sprintf(buf,s,(unsigned int)str_gnum(*(sarg++)));

K&R2 $A6.3 Integer and Floating (page 197) says:
 "(...); if the resulting value cannot be represented in the integral type,
  the behavior is undefined.
  In particular, the result of converting negative floating values to
  unsigned integral types is not specified."

Apparently, most compilers treat this as (int) and then stuff the bits
in an unsigned.
The Sun3 compiler (SunOS 4.0.1/4.0.3, any flag) does not and is correct in
it's behaviour.

Simply casting to int and then to unsigned int isn't the solution.
This could cost you half of the unsigned integers. (Same goes for long).

Any suggestions? 

With grep I found several more of these casts, but I have no idea of their
implications.

--cd
--
Casper H.S. Dik				VCP/HIP: +31205922022
University of Amsterdam     |		casper@fwi.uva.nl
The Netherlands             |		casper%fwi.uva.nl@hp4nl.nluug.nl

Andrew.Vignaux@comp.vuw.ac.nz (Andrew Vignaux) (12/31/89)

In article <291@fwi.uva.nl> casper@fwi.uva.nl (Casper H.S. Dik) writes:
>sun3% perl -e 'printf("%x\n", -1);'
>0
>doarg.c:549:	    (void)sprintf(buf,s,(unsigned int)str_gnum(*(sarg++)));

The unsigned casts went in after my bug report about
	printf("%x\n", 0x82c3060c);
core dumping on some machines (HP9000/300 & /800) due to the bad
double->int conversion.

I was never very happy about my suggestion to just put in the casts, because
	printf("%x\n", 12345678901234567890);
can still dump core or give bogus results.

You can't do very much about protecting perl from this sort of thing.
The best method probably is to examine the format string and perform
the appropriate conversion -- which is exactly what happens now (bar
any core-dump prevention).  Unfortunately, it means that -1 can't be
"%x"d.  Anyway, core dumping is better than printing some other number
(unless Larry wants to put BIGNUMs into perl ;-)

Andrew
-- 
Domain address: Andrew.Vignaux@comp.vuw.ac.nz