Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Documentation on line numbers in stack traces

Is there any clear documentation on Java stack trace line numbers?
How are they "calculated" when printing a stack-trace (the logic behind it, not the implementaton)?

To show you why I'm confused, take the following code snippet:

public static void main(String[] args) {
        String evilString = null;
        System.out.println(new StringBuilder()
                .append(evilString.toLowerCase()));
        evilString.toUpperCase();
    }

It gives: Exception in thread "main" java.lang.NullPointerException at be.company.training.ocjp6.App.main(App.java:28)

While the following piece of code:

public static void main(String[] args) {
        String evilString = null;
        System.out.println(new StringBuilder()
                .append("".toLowerCase()));
        evilString.toUpperCase();
    }

Gives: Exception in thread "main" java.lang.NullPointerException at be.company.training.ocjp6.App.main(App.java:30)

So I understand that running the chain of StringBuilder methods makes it being treated as 1 line (the StringBuilder code starts at line 28 in my editor). But if the error happens in the evilString.toUpperCase() snippet, we're back on track with line 30.

I want to know so that when I see a stacktrace, I can know for sure on what line the error happened (chaining methods (on multiple lines) is very common in the code I'm looking at).

like image 567
AndrewBourgeois Avatar asked Jan 02 '12 15:01

AndrewBourgeois


People also ask

How do I read a stack trace file?

To read this stack trace, start at the top with the Exception's type - ArithmeticException and message The denominator must not be zero . This gives an idea of what went wrong, but to discover what code caused the Exception, skip down the stack trace looking for something in the package com.

How do you write a stack trace?

Java Stack Trace ExampleMain() called a(). A() called b(), and b() called c(), which called d(). Finally, d() called dumpStack(), which generated the output. This Java stack trace gives us a picture of what the program did, in the order that it did it.

What does the stack trace contain?

The stack trace, also called a backtrace, consists of a collection of stack records, which store an application's movement during its execution. The stack trace includes information about program subroutines and can be used to debug or troubleshoot and is often used to create log files.

Which method is used to check stack trace?

You can obtain a stack trace from a thread – by calling the getStackTrace method on that Thread instance. This invocation returns an array of StackTraceElement, from which details about stack frames of the thread can be extracted.


1 Answers

Seems like this is compiler dependent as @kdgregory noted.

Here's my java -version:

java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-10M3527)
Java HotSpot(TM) Client VM (build 20.4-b02-402, mixed mode)

With this code, I NPE on line 9 per the stack trace (which matches the physical line number in the source)

public static void main(String[] args) { 
    String evilString = null;
    System.out.println(new StringBuilder()
        .append(
                evilString.toLowerCase()));  // <--- NPE here (line 9)
}

So I dug a little deeper using javap:

This is the line number table for main as shown by javap -l

(line number table shows source line: instruction-offset

public static void main(java.lang.String[]);
LineNumberTable: 
line 6: 0
line 7: 2
line 9: 12
line 8: 16
line 7: 19
line 10: 22

source line 9 starts at offset 12.

javap -c to disassemble shows this:

public static void main(java.lang.String[]);
Code:
0:  aconst_null
1:  astore_1
2:  getstatic   #16; //Field java/lang/System.out:Ljava/io/PrintStream;
5:  new #22; //class java/lang/StringBuilder
8:  dup
9:  invokespecial   #24; //Method java/lang/StringBuilder."<init>":()V
12: aload_1                                                    <--- closest line in the line number table
13: invokevirtual   #25; //Method java/lang/String.toLowerCase:()Ljava/lang/String;       <--- NPE here
16: invokevirtual   #31; //Method java/lang/StringBuilder.append:      (Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual   #35; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
22: return

my guess: when the exception is hit at the invokevirtual at offset 13, the jvm looks up the closest prior entry in the line number table and puts that in the stack trace.

like image 141
Rob H Avatar answered Sep 18 '22 05:09

Rob H