Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 May 2002 12:00:59 -0700
From:      Terry Lambert <tlambert2@mindspring.com>
To:        Akinori MUSHA <knu@iDaemons.org>
Cc:        audit@FreeBSD.org, current@FreeBSD.org
Subject:   Re: moused(8): char signed-ness problem with gcc 3.1
Message-ID:  <3CE2B06B.BF034A4E@mindspring.com>
References:  <86sn4t8fzp.wl@archon.local.idaemons.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Akinori MUSHA wrote:
> I observed gcc 2.95.4 and gcc 3.1 interpret (or maybe optimize) the
> following code differently (CFLAGS=-O):
> 
> int main(void)
> {
>   unsigned char i = 127;
>   printf("%d\n", ((char)(i << 1)) / 2);
>   return 0;
> }
> 

Cool...

> gcc 2.95.4 says it's -1,

Promotion of operand to int; conversion to lvalue type after
the operation.

> whereas gcc 3.1 says it's 127.

Promotion of operand to lvalue type.

> On FreeBSD
> char should be signed, so I suspect it's a (optimization) bug of gcc
> 3.1 which should be fixed.  Or we'll have to do a mass audit of the
> whole src tree to check and fix the similar expressions.

Technically, I think, because of the parenthesis, that GCC 2.95 is
right, and GCC 3.1 is wrong.  Given that the conversion to "char"
is done prior to the division, it should happen first.

From the assembly, it looks like 3.1 is treating "/2" as ">>1",
and illegally canceling out the "<<1" with the ">>1" *before* the
conversion.  Or maybe it's the conversion to int that happens on
the stack value for a %d argument to printf...

Maybe one of out C standards people can define when the conversion
is defined to occur, so we can get a real ruling.

Note that:

int main(void)
{
        unsigned char i = 127;
        printf("%d\n", (char)((i << 1) / 2));
        return 0;
}

...yields 127 on gcc 2.95, so it's definitely order of conversion
being totally screwed by gcc 3.1.

Basically, it's assuming commutability where it's not present.


> In any case, this behavior makes moused(8) return a stupid value of
> 127 when you roll the mouse wheel up under ps/2-sysmouse-intellimouse
> protocol.  Attached is a patch that makes the whole expression look
> more logical and works around the above behavior at the same time.

[ ... ]

> -           act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1))/2;
> +           act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1)) >> 1;

This is *soooooooooo* counter intuitive that it's evil!

-- Terry

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




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