Bug 184303 - Incorrect computation with unsigned math
Summary: Incorrect computation with unsigned math
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 3
Classification: Red Hat
Component: gcc
Version: 3.0
Hardware: x86_64
OS: Linux
medium
high
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2006-03-07 22:05 UTC by Brian Sutin
Modified: 2007-11-30 22:07 UTC (History)
0 users

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2006-03-11 19:57:32 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)

Description Brian Sutin 2006-03-07 22:05:37 UTC
On HP xv9300 Opteron workstation with fully patched RH WS3, the following program:

----------------------------------------------

#include <stdio.h>

int main()
    {
    unsigned char buffer[4] ;

    buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0x82 ;

    unsigned long L ;
    L = buffer[3] + ( buffer[2] << 8 ) + ( buffer[1] << 16 ) + ( buffer[0] << 24 ) ;

    printf( "L      = 0x%08x\n", L ) ;
    printf( "L / 2  = 0x%08x\n", L / 2 ) ;
    printf( "L >> 1 = 0x%08x\n", L >> 1 ) ;

    printf( "\n" ) ;

    L = 0x81818181 ;

    printf( "L      = 0x%08x\n", L ) ;
    printf( "L / 2  = 0x%08x\n", L / 2 ) ;
    printf( "L >> 1 = 0x%08x\n", L >> 1 ) ;

    return 0 ;
    }

-------------------------------------------------------------------------
when compiled with g++, gives the following result:

------------------------------------------------------------------
L      = 0x82828282
L / 2  = 0xc1414141
L >> 1 = 0xc1414141

L      = 0x81818181
L / 2  = 0x40c0c0c0
L >> 1 = 0x40c0c0c0
-------------------------------------------------------------------
The first set of results are clearly wrong; the math has been done with
signed arithmatic.

Comment 1 Brian Sutin 2006-03-08 23:02:49 UTC
I just noticed that the second part of my program should have had L = 
0x82828282, which would then make the bug in the first part more obvious.
One for me, one for gcc...

Comment 2 Jakub Jelinek 2006-03-11 19:57:32 UTC
There is nothing wrong on what GCC does (and the testcase is invalid).
printf is a vararg function, so the type of the var you pass to it must match
the corresponding format string specifier.  Either %08lx and L (resp. L / 2,
L >> 1), or %08x and (int) L etc.
If you use the former, you'll see what is GCC doing more clearly in the first
case:
L      = 0xffffffff82828282
L / 2  = 0x7fffffffc1414141
L >> 1 = 0x7fffffffc1414141
which is expected, as ( buffer[0] << 24 ) expression according to ISO C and
ISO C++ rules has type int (unsigned char is promoted to (signed) int)
and (((unsigned char) 0x82) << 24) thus is on two's complement arches where int
is 32-bit is -2113929216, when converted to unsigned long 0xffffffff82000000.


Note You need to log in before you can comment on or make changes to this bug.