Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4381996
Votes 0
Synopsis Java Bytecode Verification impossible [2]
Category java:compiler
Reported Against merlin-beta , kest-sol-fcs , merlin-beta2 , merlin-beta3
Release Fixed 1.4.2(mantis)
State 10-Fix Delivered, Verified, bug
Priority: 4-Low
Related Bugs 4494152
Submit Date 23-OCT-2000
Description
javac no longer generates the jsr instruction, instead inlining the finally
clause.  Consequently, code with deeply nested try-finally blocks may generate
more byte code than before.  In the extreme case, synthetic Java source code
that deeply nests try-finally blocks may generate more bytecode in a single
method than can be expressed in the bytecode file format, even though such code
used to compile without problems.  This particular problem may be seen in some
JSP implementations.  In general, you should avoid the try-finally language
construct in synthetic Java source code.

If you do run into this problem but you cannot modify the generator of your
synthetic code, you can use the following flag to cause javac to once again
generate jsr instructions for try-finally blocks

	-XDjsrlimit=0




java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)


The following legal Java program is rejected by any Java Bytecode
verifier I have tried. The program shows that Java Bytecode Verification
is not possible as described in the Java Virtual Machine Specification.

Remark: The example program shows a different problem than in my
previous bug report. There are no "break" statements and labels involved
in this program.

public class Test {
  int test(boolean b) {
    int i;
    try {
      if (b) return 1;
      i = 2;
    } finally {
      if (b) i = 3;
    }
    return i;
  }
}

tomis> java -version
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)
tomis> javac Test.java
tomis> java Test
Exception in thread "main" java.lang.VerifyError: (class: Test, method: test
signature: (Z)I) Register 2 contains wrong type

What is the problem? The variable i is modified by the subroutine S
corresponding to the finally block. The variable i, however, is
"unusable" at the end of S, since S is called before the "return 1" and
after the try block. When S is called before the "return 1" variable i
is "unusable" and it remains "unusable", since there is a path from the
beginning to the end of S which does not have an "istore i"
instruction. Hence, at the of the try block, the variable "i" is
unusable in the eyes of the bytecode verifier and therefore also at the
end of the method at the "return i" instruction.

Solution? Restrict the "rules of definite assignment" in the JLS for
16.2.14 "try statement" such that the above program is no longer legal.

 
http://java.sun.com/docs/books/jls/second_edition/html/defAssign.doc.html#26242

  V is definitely assigned after the try statement iff the following
  is true:
     V is definitely assigned after the finally block.
(Review ID: 111235) 
======================================================================
Work Around
N/A
Evaluation
I believe this is true.

 xxxxx@xxxxx  2000-12-04

I believe these two bugs are caused by the interaction of jsr 
generated by javac and the verifier.  In a sense, they are
compiler bugs and not spec bugs because we could fix these 
problems by not using jsr.

We are considering a new verifier scheme for 1.5 that would 
require the compiler to stop generating jsr.

See also 4494152.

 xxxxx@xxxxx  2002-01-17

The Mantis (1.4.2) javac compiler avoids using jsr instructions most
of the time.  This test case will not fail in Mantis, though
with some effort one could construct a test case that does.

 xxxxx@xxxxx  2002-07-08

Yes, compilers may choose not to generate jsrs (or generate them only in
simple cases). I would encourage compilers to stop the use of jsrs altogether.
Future versions of the class file format may deprecate jsrs.

So I am reclassifying this as a compiler bug.


 xxxxx@xxxxx  2002-07-08
Comments
  
  Include a link with my name & email   

Submitted On 08-JUL-2003
svachalek
This is faulty logic: just because you can make a problem go
away by dropping a bomb on it doesn't make it a military
problem.  It is clearly a verifier bug, code should not
verify differently just because you inlined a jsr.  The
ramifications of this solution are much worse than the
original problem--possible exponential explosion of bytecode
( #4739388) and more importantly the breakage of many
bytecode based tools such as for coverage and metrics.


Submitted On 15-SEP-2003
rob_d_clark
+1 for svachalek's comment... how can you call this a compiler 
bug?!?  JSR serves a purpose (ie. not causing the method size 
to explode with all the duplicated bytecode).   PLEASE DO NOT 
DEPRECATE JSR or JSR_W unless you are planning a reasonable 
alternative (and inlining the finally is not reasonable)!




Submitted On 09-MAR-2004
astid
Consider this example:

int i = 1;
try
{
  if(b == 0) j = j/k;
}
catch(ArithmeticException e)
{
  // do something
}
finally
{
  i = 2;
}

Regardless of exception occuring or not, dynamic code 
analysis tools that operate on bytecode can correctly 
infer that i=2 does not depend on any value inside the 
try block - IF there is no inlining, and the finally block is 
generated using JSR/RET.

with inlining this example gets equivalent to this on 
bytecode level:

int i = 1;
try
{
  if(b == 0) j = j/k;
  i = 2;
}
catch(ArithmeticException e)
{
  i = 2;
}

If b == k == 0, an analysis tool can no longer determine 
this, because there is no longer a single i=2 statement 
that is reachable from all paths in the code, but rather 
there are now *two* statements, one for each path. 
Therefore, if b==k==0 and an exception is thrown, i=2 
in the catch block gets executed, and a runtime 
analysis tool will incorrectly determine that the value of 
i depends on the value of b (since the statement would 
not execute if b weren't 0). Such runtime analysis tools 
are becoming mainstream (dynamic slicing etc.) as 
debugging and reengineering aids, and inlining finally 
blocks will make their accuracy worse.


Submitted On 17-MAR-2004
staerk
Another solution for the problem would have been that the
javac compiler
inserts code that initializes local variables in certain
situations.

Consider the following try-finally statement:

  try TryBlock finally FinallyBlock

If a variable x is definitely assigned after TryBlock but not
after FinallyBlock and if there is an assignment to x in
FinallyBlock, then the compiler has to insert code that
initializes x.

In the original example code, the variable `i' would be such a 
candidate.

BTW: Microsofts .NET runtime system initializes *all* local
variables
with default values in verified code ...


Submitted On 03-JUL-2004
themis25
It's a valid java program rejected by the bytecode verifier



PLEASE NOTE: JDK6 is formerly known as Project Mustang