7

I work on a project using Java 8

We have a negative test similar to this:

public Integer g(Object data)
{
    try
    {
        Double d = (Double)data;
    }
    catch(ClassCastException ex)
    {
        if( ex.getMessage() == null )
        {
            return 1;
        }
    }
    return 0;
}

@Test
public void h()
{
    Integer count = 0;
    for( Integer idx = 0; idx < 100000; idx++ )
    {
        // The test
        count += g(0.7312345f);
    }
    System.out.println("Total ClassCastException's with null message: "+count);
}

The negative test expects the exception java.lang.ClassCastException with message "java.lang.Float cannot be cast to java.lang.Double" and it sometimes gets null message

I tried to debug it in eclipse but somehow when attached to debugger the exception and message were as expected all the time

E. Levy
  • 73
  • 1
  • 1
  • 6
  • Could you provide a [mcve] of this. What is the `//otherwise negative test fails.....` – AxelH Nov 09 '16 at 11:27
  • replaced pseudo code with actual code – E. Levy Nov 09 '16 at 12:23
  • So you should precise that this is a code made to generate this "bug" of exception without message. Because this is not clear at all. – AxelH Nov 09 '16 at 13:02
  • My guess for the reason the exception is different some times is that some times it's running in the interpreted (for example, when debugging), some times in the compiled native code. Your Java code gets compiled to JVM bytecode, and that bytecode is either interpreted at run-time or re-compiled into native code, depending on your JVM and it's settings. – coladict Nov 09 '16 at 13:20
  • And where is the stacktrace ? – Antoniossss Nov 09 '16 at 13:34
  • simplified the code more above – E. Levy Nov 09 '16 at 13:46
  • Whe running in debugger it does not occur, when printing from Thread.currentThread().getStackTrace() it is only: ... invoke->invoke0->h->g – E. Levy Nov 09 '16 at 14:13

2 Answers2

9

It's not a JVM bug, it's a feature ;) - See NullPointerException in Java with no StackTrace - you need to add the -XX:-OmitStackTraceInFastThrow option to the JVM args and then you'll have stack traces all the time (but slightly slower exception throwing).

Community
  • 1
  • 1
stevestorey
  • 448
  • 3
  • 7
  • It is not about NPE, this bug cause no message for **ava.lang.ClassCastException**. At java doc null message is available for NPE only, but this is not NPE! – mger1979 Apr 05 '19 at 01:22
  • The `OmitStackTraceInFastThrow` option applies to *all* exception types, not just NPE. NPE just happens to be the one you're most likely to notice it on. It's definitely applicable to `ClassCastException` as well. – stevestorey Apr 21 '22 at 20:23
8

Running the complete example as given by AxelH in OpenJDK 8 revealed my suspicions to be correct.

Copying, so it doesn't go away (which he said he will delete):

public class Main{

    int cnt = 0, cntNull = 0;
    public static void main(String[] args) { 
        new Main().test();
    }

    public void test(){
        for( Integer idx = 0; idx < 200000; idx++ )
        {
            loseType(0.45642f, idx);
        }
        System.out.println(cnt + " error");
        System.out.println(cntNull + " null");
    }

    public void loseType(Object data, Integer i){
        try{
            gainType((Double)data);
        } catch(ClassCastException e){
            cnt++;
            if(e.getMessage() == null){
                cntNull++;
            }
        }
    }

    public void gainType(Double x){

    }
}

Compile with javac Main.java then run with java -Xmixed Main (same as default java Main) and your exception often has a null message. Run it with java -Xint Main and it is never null.

The reason is in mixed mode it uses the runtime interpreter until the class is compiled, then moves over to it, but using -Xint makes it always use the interpreter, in which the message is always present. It seems the compiled native code has a bug that creates the exception without a proper message.

coladict
  • 4,799
  • 1
  • 16
  • 27
  • I checked it too, in eclipse and in the application, the -Xint indeed solved the problem, just that it is some 5x or 10x slower (as expected of course) – E. Levy Nov 09 '16 at 14:35
  • Accepted and intended to open a bug for Java 8 (this issue occurs also in recent Java 8u112), b/c working in interpreter mode is very slow. Thanks AlexH and coladict – E. Levy Nov 09 '16 at 15:59