4

Using gcc 4.7:

$ gcc --version
gcc (GCC) 4.7.0 20120505 (prerelease)

Code listing (test.c):

#include <stdint.h>

struct test {
    int before;

    char start[0];
    unsigned int v1;
    unsigned int v2;
    unsigned int v3;
    char end[0];

    int after;
};

int main(int argc, char **argv)
{
  int x, y;

  x = ((uintptr_t)(&((struct test*)0)->end)) - ((uintptr_t)(&((struct test*)0)->start));
  y = ((&((struct test*)0)->end)) - ((&((struct test*)0)->start));

  return x + y;
}

Compile & execute

$ gcc -Wall -o test test.c && ./test
Floating point exception

The SIGFPE is caused by the second assignment (y = ...). In the assembly listing, there is a division on this line? Note that the only difference between x= and y= is casting to (uintptr_t).

Wade
  • 3,585
  • 2
  • 22
  • 27

1 Answers1

8

Disregarding the undefined behaviour due to violation of constarints in the standard, what gcc does here is to calculate the difference between two pointers to char[0] - &(((struct test*)0)->start) and &(((struct test*)0)->end), and divide that difference by the size of a char[0], which of course is 0, so you get a division by 0.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • And for historical reasons in UNIX an integer division by `0` yields a Floating point exception (SIGFPE signal) – ouah Sep 25 '12 at 22:09
  • Is that a UNIX (and derivatives) speciality? I thought it was an x86 thing. – Daniel Fischer Sep 25 '12 at 22:09
  • Good question I know it is the case for x86 on UNIX but I'm not sure it is the case for other systems. – ouah Sep 25 '12 at 22:11
  • If anybody definitely knows, please ping @ouah too. I'd be interested to know for sure. – Daniel Fischer Sep 25 '12 at 22:13
  • Tested integer division by `0` on a Linux armv6l, it also gives a Floating point exception. – ouah Sep 25 '12 at 22:26
  • @ouah It's a POSIX thing. `signal.h` defines `FPE_INTDIV` and `FPE_INTOVF` for use with `sigaction` when using `SA_SIGINFO` (`SIGFPE` is defined as _Erroneous arithmetic operation_). Also note that `SIGINT` has a different meaning, so anything resembling that could be confusing, and there are not many longish signal names. – ninjalj Sep 25 '12 at 22:46
  • @ouah: of course, the previous comment is true on systems that trap on integer divide by zero and/or integer overflow. Some systems may not do that, and I hope they are not required to send the corresponding signal. – ninjalj Sep 25 '12 at 22:53
  • @ninjalj I bet some UNIX systems with some more exotic processors could have undefined behavior on an asm `divide` by `0` instruction and couly actually respond randomly. – ouah Sep 25 '12 at 22:55
  • apparently on mips system the divide instruction does not trap on zero division and `gcc` will add extra code to check for `0` and trap on this processor. A SIGPFE will then be issued. (See the default `-mdivide-traps` option) By compiling with `-mno-check-zero-division` the extra check for `0` is disabled, the divide instruction will not trap and no signal SIGFPE will be sent, but the behavior of the program will be undefined. – ouah Sep 25 '12 at 23:18
  • Regarding C and POSIX requirements. C does not require the implementation to issue a SIGFPE signal (on an integer division by zero for example) *(C11, 7.11p4) "An implementation need not generate any of these signals, except as a result of explicit calls to the raise function"* and this is the same for POSIX: see this POSIX accepted resolution defect that clarifies the situation: http://austingroupbugs.net/view.php?id=536 – ouah Sep 26 '12 at 08:52