6

I wrote a very simple c program:

#include<stdio.h>

int main(){
    int a=2;
    int b=0;
    printf("%d\n", a/b);
}

and run it with strace: strace ./a.out and get below output (only paste tail part)

... ...
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f04c7fb8000, 4096, PROT_READ) = 0
munmap(0x7f04c7f96000, 127640)          = 0
--- SIGFPE (Floating point exception) @ 0 (0) ---
+++ killed by SIGFPE +++
Floating point exception

The output matches my expectation, as it was killed by SIGFPE signal.

However, the same program written in Java, doesn't get SIGFPE signal, does anybody know how java processes "divide by zero" exception?

public class Main {

  public static void main(String[] args) {
    int a = 2;
    int b = 0;
    System.out.println(a / b);
  }
}

strace java -Xcomp Main

... ...
mprotect(0xf6949000, 8171520, PROT_READ|PROT_WRITE) = 0
mprotect(0xf6949000, 8171520, PROT_READ|PROT_EXEC) = 0
munmap(0xf774f000, 5727)                = 0
mmap2(NULL, 331776, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xfffffffff68d0000
mprotect(0xf68d0000, 4096, PROT_NONE)   = 0
clone(child_stack=0xf6920494, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xf6920bd8, tls=0xf6920bd8, child_tidptr=0xff9c5520) = 958
futex(0xf6920bd8, FUTEX_WAIT, 958, NULL) = 0
exit_group(0)  
Ghostman
  • 6,042
  • 9
  • 34
  • 53
zhangfaen
  • 63
  • 4
  • There's no floating point there. Why are you expecting a floating-point signal? And did your 'C' code really use ints? – user207421 Nov 21 '11 at 07:33
  • 3
    You got a Java-level exception right? DivisionByZeroException or something. Is that not good enough? Are you interested in how the JVM talks to the processor? – Thilo Nov 21 '11 at 07:35
  • 1
    Perhaps I'm missing something but wouldn't you just catch the DivideByZeroException in Java? – Gaff Nov 21 '11 at 07:35
  • 2
    Why would you expect them to be the same? The two languages have nothing in common. – skaffman Nov 21 '11 at 07:35
  • 4
    I think he's asking how the VM does it internally, not how to catch it in Java code. – Boann Nov 21 '11 at 07:51
  • 1
    Yes, as Boann said, I am interested in how VM does internally. ~ – zhangfaen Nov 21 '11 at 08:28
  • @EJP The SIGFPE signal reports a fatal arithmetic error. Although the name is derived from “floating-point exception”, this signal actually covers all arithmetic errors, including division by zero and overflow. – Koray Tugay Jun 03 '15 at 18:29
  • @skaffman C and Java has nothing in common? Really? – Koray Tugay Jun 03 '15 at 18:38

5 Answers5

8

Here, it raises a SIGFPE.

You forgot to tell strace to follow children. Add the -f option to strace and you should see something similar to:

[pid  2304] read(3, "\312\376\272\276\0\0\0001\0n\n\0\23\0I\t\0\3\0J\7\0K\n\0L\0M\n\0N\0"..., 2369) = 2369
[pid  2304] --- SIGFPE (Floating point exception) @ 0 (0) ---
[pid  2304] rt_sigreturn(0x1c50800)     = 5
[pid  2304] write(2, "Exception in thread \"main\" ", 27Exception in thread "main" ) = 27
[pid  2304] write(2, "java.lang.ArithmeticException: /"..., 40java.lang.ArithmeticException: / by zero) = 40
[pid  2304] write(2, "\n", 1
ninjalj
  • 42,493
  • 9
  • 106
  • 148
6

Obviously this is because JVM has something like this in its code:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void fpe_handler(int signum) {
  printf("JVM throws an ArithmeticException here...\n");
  exit (1);
}

int main() {
  int a = 5;
  int b = 0;
  signal(SIGFPE, fpe_handler);
  printf("%d\n", a / b);
  return 0;
}

Also JVM runs multiple threads (see clone() in the log above or do ps -eLf when java is running) so that strace output is just incomplete.

If a little more detail, unhandled SIGFPE indicates an error in the program, in which it occurred. And if java would be killed by SIGFPE, it would indicate than an error is in JVM, but not in your app, running inside JVM.

praetorian droid
  • 2,989
  • 1
  • 17
  • 19
5

In contrast to (normal) C compile program, Java program runs on a runtime, and not on the processor, and is not platform dependent. Dividing by zero in java triggers ArithmeticException like this:

Exception in thread "main" java.lang.ArithmeticException: / by zero

From JLS:

An exception is thrown for one of three reasons:

An abnormal execution condition was synchronously detected by the Java virtual machine. Such conditions arise because:

evaluation of an expression violates the normal semantics of the language, such as an integer divide by zero, as summarized in §15.6

an error occurs in loading or linking part of the program (§12.2, §12.3)

some limitation on a resource is exceeded, such as using too much memory

Community
  • 1
  • 1
MByD
  • 135,866
  • 28
  • 264
  • 277
  • 1
    Hmm.. Although we say Java program runs on a runtime, it finally runs on processor. In addition, I added parameter "-Xcomp", which means that JIT must compile every method into local processor instructions. In addition more, both program run on top of linux, so I expect both raise SIGFPE signal. – zhangfaen Nov 21 '11 at 08:31
  • That's true, but if I'm not mistaken, such things are checked by the runtime before executed. – MByD Nov 21 '11 at 08:33
  • checking divisor for 0 before executed is very costed, I don't think VM does that thing. – zhangfaen Nov 21 '11 at 08:41
  • 2
    For this particular sample code, I would not be surprised if the compiler "optimizes" this into a "throw new ArithmeticException" statement. ;) – Stein G. Strindhaug Nov 21 '11 at 10:29
  • @zhangfaen: see Stein's comment above this one. Try to divide by a variable you read from args. – ninjalj Nov 21 '11 at 21:09
  • Below code still doesn't raise SIGFPE. public class Main { private static void f(int a, int b) { System.out.println(a / b); } public static void main(String[] args) { for (int i = 0; i < 100; i++) { f(2, 0); } } }, – zhangfaen Nov 22 '11 at 03:06
  • C runs on a runtime environment as well. – Koray Tugay Jun 03 '15 at 18:33
  • @KorayTugay - I used a wrong wording, Java runs on a virtual machine, not a runtime. BUT C is not running in such an environment. It's a language that compiles to a machine code before execution, and there is no translation (in most cases) from the compiled C program to the processor instructions, as the compiled program is constructed of the CPU instructions (unless you count in-cpu macro code as such, which is not). – MByD Jun 03 '15 at 19:53
  • @MByD Well Java has a run-time, here I am using the word as "runtime environment". C also has a runtime environment I would say. Yes the compiled code is constructed of the CPU instructions, yet a compiled C program still needs a loader for example. You can see this answer: http://stackoverflow.com/a/3900802/1173112 – Koray Tugay Jun 03 '15 at 19:59
  • @KorayTugay Again, bad wording from my part. sorry about that. Yet the difference between the runtime environment of a C program and of a Java program are nothing alike. – MByD Jun 03 '15 at 20:08
  • @MByD No, I just want to share knowladge. Regards. – Koray Tugay Jun 03 '15 at 20:11
2

It might be that VM tests the divisor for 0 manually in emulated bytecode (for simplicity of implementation), but for performance will still switch to detecting the SIGFPE signal in JIT'd code. Try putting the division code in its own subroutine and call it in a loop thousands of times to ensure it gets compiled.

Boann
  • 48,794
  • 16
  • 117
  • 146
1

Java runs in a virtual machine (the JVM), which abstracts the hardware from the program. Most errors in a Java program will cause Java Exceptions and not trigger any native cpu or os error codes. I'd guess this code will throw an ArithmeticException (or something like that).

Stein G. Strindhaug
  • 5,077
  • 2
  • 28
  • 41
  • 1
    Yes, it throws ArithmeticException, but how? – zhangfaen Nov 21 '11 at 09:16
  • Once JIT'ed, the JVM just lets the CPU do the division in hardware, so it ought to behave exactly like other native applications, with the same CPU interruption, OS interaction, and handover to the process. – Johan Boulé Feb 01 '21 at 22:00