Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erroneous for-loops in Java?

Tags:

I observed erroneous behaviour running the following java-code:

public class Prototype {   public static void main(String[] args) {     final int start = Integer.MAX_VALUE/2;     final int end = Integer.MAX_VALUE;     {       long b = 0;       for (int i = start; i < end; i++) {         b++;       }       System.out.println(b);     }     {       long b = 0;       for (int i = start; i < end; i++) {         b++;       }       System.out.println(b);     }   } } 

Both loops do exactly the same. Nevertheless, the second one outputs a non-deterministic erroneous value. I'm running the code on Linux using Version:

java version "1.6.0_25" Java(TM) SE Runtime Environment (build 1.6.0_25-b06) Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode) 

Sample Output:

1073741811 141312 

Can you reproduce it? Is it a bug?

Edit: Strange

final int end = Integer.MAX_VALUE - 1; 

works fine.

like image 635
Sebastian Avatar asked Aug 09 '11 11:08

Sebastian


People also ask

What are 3 types of loops encountered in Java?

Looping in Java Java provides three repetition statements/looping statements that enable programmers to control the flow of execution by repetitively performing a set of statements as long as the continuation condition remains true. These three looping statements are called for, while, and do… while statements.

What are loops used for in Java?

In computer programming, loops are used to repeat a block of code. For example, if you want to show a message 100 times, then rather than typing the same code 100 times, you can use a loop. In Java, there are three types of loops.

Which loop is best to use if the loop may or may not need to run at all in Java?

Therefore, in this basic example, a Repeat loop is the better choice.


1 Answers

I'm able to reproduce it with the .class file produced by Eclipse, but not when compiling on the command line with javac.

The bytecode generated differs:

javac output

public static void main(java.lang.String[]);   Code:    0:   lconst_0    1:   lstore_3    2:   ldc #2; //int 1073741823    4:   istore  5    6:   iload   5    8:   ldc #3; //int 2147483647    10:  if_icmpge   23    13:  lload_3    14:  lconst_1    15:  ladd    16:  lstore_3    17:  iinc    5, 1    20:  goto    6    23:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;    26:  lload_3    27:  invokevirtual   #5; //Method java/io/PrintStream.println:(J)V    30:  lconst_0    31:  lstore_3    32:  ldc #2; //int 1073741823    34:  istore  5    36:  iload   5    38:  ldc #3; //int 2147483647    40:  if_icmpge   53    43:  lload_3    44:  lconst_1    45:  ladd    46:  lstore_3    47:  iinc    5, 1    50:  goto    36    53:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;    56:  lload_3    57:  invokevirtual   #5; //Method java/io/PrintStream.println:(J)V    60:  return 

For something easier to read, here is the Grimp output produced by Soot:

    java.lang.String[] r0;     long l0, l2;     int i1, i3;      r0 := @parameter0;     l0 = 0L;     i1 = 1073741823;   label0:     if i1 >= 2147483647 goto label1;      l0 = l0 + 1L;     i1 = i1 + 1;     goto label0;   label1:     java.lang.System.out.println(l0);     l2 = 0L;     i3 = 1073741823;   label2:     if i3 >= 2147483647 goto label3;      l2 = l2 + 1L;     i3 = i3 + 1;     goto label2;   label3:     java.lang.System.out.println(l2);     return; 

Eclipse compiler output

public static void main(java.lang.String[]);   Code:    0:   ldc #16; //int 1073741823    2:   istore_1    3:   ldc #17; //int 2147483647    5:   istore_2    6:   lconst_0    7:   lstore_3    8:   ldc #16; //int 1073741823    10:  istore  5    12:  goto    22    15:  lload_3    16:  lconst_1    17:  ladd    18:  lstore_3    19:  iinc    5, 1    22:  iload   5    24:  ldc #17; //int 2147483647    26:  if_icmplt   15    29:  getstatic   #18; //Field java/lang/System.out:Ljava/io/PrintStream;    32:  lload_3    33:  invokevirtual   #24; //Method java/io/PrintStream.println:(J)V    36:  lconst_0    37:  lstore_3    38:  ldc #16; //int 1073741823    40:  istore  5    42:  goto    52    45:  lload_3    46:  lconst_1    47:  ladd    48:  lstore_3    49:  iinc    5, 1    52:  iload   5    54:  ldc #17; //int 2147483647    56:  if_icmplt   45    59:  getstatic   #18; //Field java/lang/System.out:Ljava/io/PrintStream;    62:  lload_3    63:  invokevirtual   #24; //Method java/io/PrintStream.println:(J)V    66:  return 

Grimp output:

    java.lang.String[] r0;     int i0, i1, i3, i5;     long l2, l4;      r0 := @parameter0;     i0 = 1073741823;     i1 = 2147483647;     l2 = 0L;     i3 = 1073741823;     goto label1;   label0:     l2 = l2 + 1L;     i3 = i3 + 1;   label1:     if i3 < 2147483647 goto label0;      java.lang.System.out.println(l2);     l4 = 0L;     i5 = 1073741823;     goto label3;   label2:     l4 = l4 + 1L;     i5 = i5 + 1;   label3:     if i5 < 2147483647 goto label2;      java.lang.System.out.println(l4);     return; 

Interestingly, the javac-produced version uses if_icmpge as an exit condition (>= 2147483647) on an int, which shouldn't make sense (the equal does, but not the greater than). Both look correct, though, so I'd suspect a JVM bug.

like image 75
Bruno Avatar answered Oct 05 '22 17:10

Bruno