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