Bug 72024 - LONG_MIN / 1 sends a "Floating exception"
Summary: LONG_MIN / 1 sends a "Floating exception"
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: alpha (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-alpha (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-09-23 08:30 UTC by Patrick Pelissier
Modified: 2004-12-08 22:56 UTC (History)
0 users

See Also:


Attachments
divrem.txt (511 bytes, text/plain)
2004-10-10 00:03 UTC, Peter Edwards
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Patrick Pelissier 2004-09-23 08:30:27 UTC
The following program:

#include <limits.h>
int f(long a, long b);
int main()
{
  return f(LONG_MIN, 1);
}
int f(long a, long b)
{
  return a / b;
}

produces a "Floating exception (core dumped)" on alpha-unknown-freebsd5.2.1
(spe149.testdrive.hp.com) with:
gcc version 3.4.2 and gcc version 3.3.3 [FreeBSD] 20031106.

The test program was compiled without any flags:
spe149.testdrive.hp.com> /tmp/make/bin/gcc test3.c
spe149.testdrive.hp.com> ./a.out
Floating exception (core dumped)
spe149.testdrive.hp.com> /tmp/make/bin/gcc -v
Reading specs from /tmp/make/lib/gcc/alpha-unknown-freebsd5.2.1/3.4.2/specs
Configured with: ./configure --prefix=/tmp/gcc : (reconfigured) ./configure
--prefix=/tmp/gcc : (reconfigured) ./configure --prefix=/tmp/make
--enable-languages=c
Thread model: posix
gcc version 3.4.2

The problem seems to be in the internal function "__divq" which produces the exception.

(See also
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17613 )
Comment 1 Peter Edwards freebsd_committer 2004-10-10 00:03:13 UTC
Ooh a good excuse to look at Alpha assembler. (/me googles for the alpha 
instruction set.)

(Can someone on the -alpha list tell me if this reasoning is correct, 
and if I should commit the patch?)

Alpha appears not to have an integer division instruction, so this is 
implemented by divq(), the source of which is generated from 
"src/lib/libc/alpha/gen/divrem4"

(For reading the macros when preprocessing as divq, S is true, OP is 
"div", and WORDSIZE is 64)

If I'm reading it correctly, the start of this function decides what 
sign the result should have, then gets the absolute value of each 
operand, (search for "subq zero, A, A" and "subq zero, B, B".) Note, for 
"LONG_MIN", or 0x8000000000000000, 2's compliment subtraction for zero 
gives back the 0x8000000000000000

The body of the work is done with logical shifts, so everything still 
works when treating the dividend as an unsigned long.

At the end of the function, the code takes the calculated result, and 
decides if it needs to negate it:

>         /* Check to see if we should negate it. */
>         subqv   zero, RESULT, T_0
>         cmovlbs NEG, T_0, RESULT


The "v" here means "trap overflows", which is why we blow up. LONG_MIN 
is the only value that _can_ blow up here, and you can only reach this 
case if you start with LONG_MIN / 1, if my reasoning isn't flawed.
So, I think it's perfectly safe to remove the "v" from the subq 
instruction. i.e., I think the attached patch is correct.
Comment 2 Peter Edwards freebsd_committer 2004-10-10 03:12:19 UTC
Er,
After realising that this source came from NetBSD, I checked their CVS 
repo, and found it already fixed there with an equivalent patch.

There's also an equivalent in the kernel: 
/usr/src/sys/alpha/alpha/divrem.m4. The kernel case might be a security 
issue if you could find a syscall that would do arbitrary (assuming not 
by zero!) division of 64-bit values.
Comment 3 Peter Edwards freebsd_committer 2004-12-08 22:55:59 UTC
State Changed
From-To: open->closed

Fix committed to 6-current and 5-stable