This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
c/6586: -ftrapv doesn't catch multiplication overflow
- From: Bruno Haible <bruno at clisp dot org>
- To: gcc-gnats at gcc dot gnu dot org
- Date: Mon, 6 May 2002 21:56:26 +0200 (CEST)
- Subject: c/6586: -ftrapv doesn't catch multiplication overflow
>Number: 6586
>Category: c
>Synopsis: -ftrapv doesn't catch multiplication overflow
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: unassigned
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon May 06 13:06:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: Bruno Haible
>Release: 3.1 20020423 (prerelease)
>Organization:
GNU hackers
>Environment:
System: Linux linuix 2.4.18-4GB #1 Wed Mar 27 13:57:05 UTC 2002 i686 unknown
Architecture: i686
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: ../configure --prefix=/packages/gnu-snapshot --enable-shared --enable-version-specific-runtime-libs --enable-nls
>Description:
Multiplication overflow is not caught by -ftrapv in 50% of the cases, on
average.
$ cat foo.c
int foo (int x, int y)
{
return x * y;
}
int main ()
{
foo(600000000,1024);
return 0;
}
$ gcc -v
Lecture des spécification à partir de /packages/gnu-snapshot/lib/gcc-lib/i686-pc-linux-gnu/3.1/specs
Configuré avec: ../configure --prefix=/packages/gnu-snapshot --enable-shared --enable-version-specific-runtime-libs --enable-nls
Modèle de thread: single
version gcc 3.1 20020423 (prerelease)
$ gcc -ftrapv foo.c
$ ./a.out
$ echo $?
0
The reason is simply a broken __mulvsi3 implementation in libgcc2.c.
Other -ftrapv helper functions are broken as well:
- __subvsi3 may not behave correctly if b = -0x80000000.
- __subvdi3 has an obvious typo that could cause wrong results.
- __mulvsi3 has a wrong overflow check.
- __absvdi2 has an obvious typo that could cause wrong results.
- __mulvdi3 has a wrong overflow check.
>How-To-Repeat:
See above
>Fix:
Here is a patch.
2002-05-04 Bruno Haible <bruno@clisp.org>
* libgcc2.c (__subvsi3): Remove simplification that would not work
when subtracting -0x80000000.
(__subvdi3): Remove simplification that would return a wrong result.
(__mulvsi3): Fix overflow check.
(__absvdi2): Fix simplification that would return a wrong result.
(__mulvdi3): Fix overflow check.
*** libgcc2.c.bak 2002-04-03 06:20:51.000000000 +0200
--- libgcc2.c 2002-05-04 23:24:22.000000000 +0200
***************
*** 1,7 ****
/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
! 2000, 2001 Free Software Foundation, Inc.
This file is part of GCC.
--- 1,7 ----
/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
! 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
***************
*** 98,106 ****
Wtype
__subvsi3 (Wtype a, Wtype b)
{
- #ifdef L_addvsi3
- return __addvsi3 (a, (-b));
- #else
DWtype w;
w = a - b;
--- 98,103 ----
***************
*** 109,115 ****
abort ();
return w;
- #endif
}
#endif
--- 106,111 ----
***************
*** 117,125 ****
DWtype
__subvdi3 (DWtype a, DWtype b)
{
- #ifdef L_addvdi3
- return (a, (-b));
- #else
DWtype w;
w = a - b;
--- 113,118 ----
***************
*** 128,146 ****
abort ();
return w;
- #endif
}
#endif
#ifdef L_mulvsi3
Wtype
__mulvsi3 (Wtype a, Wtype b)
{
DWtype w;
! w = a * b;
! if (((a >= 0) == (b >= 0)) ? w < 0 : w > 0)
abort ();
return w;
--- 121,141 ----
abort ();
return w;
}
#endif
#ifdef L_mulvsi3
+ #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
Wtype
__mulvsi3 (Wtype a, Wtype b)
{
DWtype w;
! w = (DWtype) a * (DWtype) b;
! if (((a >= 0) == (b >= 0))
! ? (UDWtype) w > (UDWtype) (((DWtype) 1 << (WORD_SIZE - 1)) - 1)
! : (UDWtype) w < (UDWtype) ((DWtype) -1 << (WORD_SIZE - 1)))
abort ();
return w;
***************
*** 204,211 ****
DWtype w = a;
if (a < 0)
! #ifdef L_negvsi2
! w = __negvsi2 (a);
#else
w = -a;
--- 199,206 ----
DWtype w = a;
if (a < 0)
! #ifdef L_negvdi2
! w = __negvdi2 (a);
#else
w = -a;
***************
*** 218,234 ****
#endif
#ifdef L_mulvdi3
DWtype
__mulvdi3 (DWtype u, DWtype v)
{
! DWtype w;
! w = u * v;
! if (((u >= 0) == (v >= 0)) ? w < 0 : w > 0)
! abort ();
! return w;
}
#endif
--- 213,344 ----
#endif
#ifdef L_mulvdi3
+ #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
DWtype
__mulvdi3 (DWtype u, DWtype v)
{
! /* The unchecked multiplication needs 3 Wtype x Wtype multiplications, but
! the checked multiplication needs only 2 Wtype x Wtype multiplications. */
! DWunion uu, vv;
! uu.ll = u;
! vv.ll = v;
! if (__builtin_expect (uu.s.high == uu.s.low >> (WORD_SIZE - 1), 1))
! {
! /* u fits into a single Wtype. */
! if (__builtin_expect (vv.s.high == vv.s.low >> (WORD_SIZE - 1), 1))
! {
! /* v fits into a single Wtype as well. */
! /* A single multiplication. No overflow risk. */
! return (DWtype) uu.s.low * (DWtype) vv.s.low;
! }
! else
! {
! /* Two multiplications. */
! DWunion w0, w1;
! w0.ll = (UDWtype) (UWtype) uu.s.low * (UDWtype) (UWtype) vv.s.low;
! w1.ll = (UDWtype) (UWtype) uu.s.low * (UDWtype) (UWtype) vv.s.high;
! if (vv.s.high < 0)
! w1.s.high -= uu.s.low;
! if (uu.s.low < 0)
! w1.ll -= vv.ll;
! w1.ll += (UWtype) w0.s.high;
! if (__builtin_expect (w1.s.high == w1.s.low >> (WORD_SIZE - 1), 1))
! {
! w0.s.high = w1.s.low;
! return w0.ll;
! }
! }
! }
! else
! {
! if (__builtin_expect (vv.s.high == vv.s.low >> (WORD_SIZE - 1), 1))
! {
! /* v fits into a single Wtype. */
! /* Two multiplications. */
! DWunion w0, w1;
!
! w0.ll = (UDWtype) (UWtype) uu.s.low * (UDWtype) (UWtype) vv.s.low;
! w1.ll = (UDWtype) (UWtype) uu.s.high * (UDWtype) (UWtype) vv.s.low;
! if (uu.s.high < 0)
! w1.s.high -= vv.s.low;
! if (vv.s.low < 0)
! w1.ll -= uu.ll;
! w1.ll += (UWtype) w0.s.high;
! if (__builtin_expect (w1.s.high == w1.s.low >> (WORD_SIZE - 1), 1))
! {
! w0.s.high = w1.s.low;
! return w0.ll;
! }
! }
! else
! {
! /* A few sign checks and a single multiplication. */
! if (uu.s.high >= 0)
! {
! if (vv.s.high >= 0)
! {
! if (uu.s.high == 0 && vv.s.high == 0)
! {
! DWtype w;
!
! w = (UDWtype) (UWtype) uu.s.low
! * (UDWtype) (UWtype) vv.s.low;
! if (__builtin_expect (w >= 0, 1))
! return w;
! }
! }
! else
! {
! if (uu.s.high == 0 && vv.s.high == (Wtype) -1)
! {
! DWunion ww;
!
! ww.ll = (UDWtype) (UWtype) uu.s.low
! * (UDWtype) (UWtype) vv.s.low;
! ww.s.high -= uu.s.low;
! if (__builtin_expect (ww.s.high < 0, 1))
! return ww.ll;
! }
! }
! }
! else
! {
! if (vv.s.high >= 0)
! {
! if (uu.s.high == (Wtype) -1 && vv.s.high == 0)
! {
! DWunion ww;
!
! ww.ll = (UDWtype) (UWtype) uu.s.low
! * (UDWtype) (UWtype) vv.s.low;
! ww.s.high -= vv.s.low;
! if (__builtin_expect (ww.s.high < 0, 1))
! return ww.ll;
! }
! }
! else
! {
! if (uu.s.high == (Wtype) -1 && vv.s.high == (Wtype) -1)
! {
! DWunion ww;
!
! ww.ll = (UDWtype) (UWtype) uu.s.low
! * (UDWtype) (UWtype) vv.s.low;
! ww.s.high -= uu.s.low;
! ww.s.high -= vv.s.low;
! if (__builtin_expect (ww.s.high >= 0, 1))
! return ww.ll;
! }
! }
! }
! }
! }
!
! /* Overflow. */
! abort ();
}
#endif
>Release-Note:
>Audit-Trail:
>Unformatted: