Useful message about NullPointerException

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Useful message about NullPointerException

Pi Ke
We frequently see NullPointerException in our logs. It's really a big headache when we see a NullPointerException and it is encapsulated in another exception as we don't know which object is null and it is throwing an Exception. Is there any way we can get to know the object type or the object variable name where the object is null and it is throwing a NullPointerException? i.e, instead of just saying there is a NullPointerException, can we add some friendly message?
Programmer
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Bernd Eckenfels-4
Am Wed, 21 Jan 2015 05:45:08 -0700 (MST)
schrieb pike <[hidden email]>:

> We frequently see NullPointerException in our logs. It's really a big
> headache when we see a NullPointerException and it is encapsulated in
> another exception as we don't know which object is null and it is
> throwing an Exception. Is there any way we can get to know the object
> type or the object variable name where the object is null and it is
> throwing a NullPointerException? i.e, instead of just saying there is
> a NullPointerException, can we add some friendly message?

Note that if you keep the stack information in an exception it points
(most of the time) exactly to the location where the null access
happens.

I can imagine it is rather hard for the VM to add more informations.
Your best bet is to avoid the NPEs and log the exceptions properly.

Gruss
Bernd
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

kedar mhaswade
On Mon, Jan 26, 2015 at 11:20 AM, Bernd Eckenfels <[hidden email]>
wrote:

> Am Wed, 21 Jan 2015 05:45:08 -0700 (MST)
> schrieb pike <[hidden email]>:
>
> > We frequently see NullPointerException in our logs. It's really a big
> > headache when we see a NullPointerException and it is encapsulated in
> > another exception as we don't know which object is null and it is
> > throwing an Exception. Is there any way we can get to know the object
> > type or the object variable name where the object is null and it is
> > throwing a NullPointerException? i.e, instead of just saying there is
> > a NullPointerException, can we add some friendly message?
>
> Note that if you keep the stack information in an exception it points
> (most of the time) exactly to the location where the null access
> happens.
>
>
​Maybe the objects in question are not talking only to their immediate
friends <https://en.wikipedia.org/wiki/Law_of_Demeter>?
This happens when we tend to do something like *a.getB().getC()* and we
can't tell by looking at the NPE stack trace (which works on lines of
source code) if *a* was null or what *a.getB()* returned was null.

I can imagine it is rather hard for the VM to add more informations.
> Your best bet is to avoid the NPEs and log the exceptions properly.


> Gruss
> Bernd
>
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Pi Ke
In reply to this post by Bernd Eckenfels-4
Bernd Eckenfels-4 wrote
Am Wed, 21 Jan 2015 05:45:08 -0700 (MST)
schrieb pike <[hidden email]>:

> We frequently see NullPointerException in our logs. It's really a big
> headache when we see a NullPointerException and it is encapsulated in
> another exception as we don't know which object is null and it is
> throwing an Exception. Is there any way we can get to know the object
> type or the object variable name where the object is null and it is
> throwing a NullPointerException? i.e, instead of just saying there is
> a NullPointerException, can we add some friendly message?

Note that if you keep the stack information in an exception it points
(most of the time) exactly to the location where the null access
happens.

I can imagine it is rather hard for the VM to add more informations.
Your best bet is to avoid the NPEs and log the exceptions properly.

Gruss
Bernd
This is acually not helpful in some situations. For example, as what kedar has mentioned, if there is a call "a.getB().getC()" and a NPE  is thrown. There might be two situations:
1. a is null;
2. a.getB() is null

So it would be better if there can be one friendly message which indicates what is null.
Programmer
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Pi Ke
In reply to this post by kedar mhaswade
kedar mhaswade wrote
On Mon, Jan 26, 2015 at 11:20 AM, Bernd Eckenfels <[hidden email]>
wrote:

> Am Wed, 21 Jan 2015 05:45:08 -0700 (MST)
> schrieb pike <[hidden email]>:
>
> > We frequently see NullPointerException in our logs. It's really a big
> > headache when we see a NullPointerException and it is encapsulated in
> > another exception as we don't know which object is null and it is
> > throwing an Exception. Is there any way we can get to know the object
> > type or the object variable name where the object is null and it is
> > throwing a NullPointerException? i.e, instead of just saying there is
> > a NullPointerException, can we add some friendly message?
>
> Note that if you keep the stack information in an exception it points
> (most of the time) exactly to the location where the null access
> happens.
>
>
​Maybe the objects in question are not talking only to their immediate
friends <https://en.wikipedia.org/wiki/Law_of_Demeter>?
This happens when we tend to do something like *a.getB().getC()* and we
can't tell by looking at the NPE stack trace (which works on lines of
source code) if *a* was null or what *a.getB()* returned was null.

I can imagine it is rather hard for the VM to add more informations.
> Your best bet is to avoid the NPEs and log the exceptions properly.


> Gruss
> Bernd
>
Hmm, based on the JVM specification, there is Descriptor structure which can be used to describe the name and type of a field or method in a class. I think, the JVM can use this info to display the type of the object which is null when NPE is thrown.

Furthermore, I think the constant pool also includes all the information about the fields in a class. They can be used as well.
Programmer
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Chris Newland
In reply to this post by Pi Ke
Hi,

If the contract for a method allows a null return you should really handle
it defensively. Null checks are cheap in terms of performance.

If you *have* to chain method calls like that then you could drop each
call onto a new source line and the stack trace will show you which call
was on the null object:

public class NullTest
{
    class B {
        private String c = null;
        public String getC() { return c; }
    }

    class A {
        private B b = null;
        public B getB() { return b; }
    }

    public NullTest() {
        new A()
        .getB()
        .getC() // NPE here indicates getB() returned null
        .length();
    }

    public static void main(String[] args) {
        new NullTest();
    }
}

Regards,

Chris
@chriswhocodes

On Tue, January 27, 2015 11:47, pike wrote:

> Bernd Eckenfels-4 wrote
>
>> Am Wed, 21 Jan 2015 05:45:08 -0700 (MST)
>> schrieb pike &lt;
>
>> pike630@
>
>> &gt;:
>>
>>
>>> We frequently see NullPointerException in our logs. It's really a big
>>>  headache when we see a NullPointerException and it is encapsulated
>>> in another exception as we don't know which object is null and it is
>>> throwing an Exception. Is there any way we can get to know the object
>>>  type or the object variable name where the object is null and it is
>>> throwing a NullPointerException? i.e, instead of just saying there is
>>>  a NullPointerException, can we add some friendly message?
>>
>> Note that if you keep the stack information in an exception it points
>> (most of the time) exactly to the location where the null access
>> happens.
>>
>> I can imagine it is rather hard for the VM to add more informations.
>> Your best bet is to avoid the NPEs and log the exceptions properly.
>>
>>
>> Gruss
>> Bernd
>>
>
> This is acually not helpful in some situations. For example, as what
> kedar has mentioned, if there is a call "a.getB().getC()" and a NPE  is
> thrown. There might be two situations:
> 1. a is null;
> 2. a.getB() is null
>
>
> So it would be better if there can be one friendly message which
> indicates what is null.
>
>
>
> --
> View this message in context:
> http://openjdk.5641.n7.nabble.com/Useful-message-about-NullPointerExcepti
> on-tp213240p213842.html Sent from the OpenJDK Core Libraries mailing list
> archive at Nabble.com.
>


Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Pi Ke
Chris Newland wrote
Hi,

If the contract for a method allows a null return you should really handle
it defensively. Null checks are cheap in terms of performance.

If you *have* to chain method calls like that then you could drop each
call onto a new source line and the stack trace will show you which call
was on the null object:

public class NullTest
{
    class B {
        private String c = null;
        public String getC() { return c; }
    }

    class A {
        private B b = null;
        public B getB() { return b; }
    }

    public NullTest() {
        new A()
        .getB()
        .getC() // NPE here indicates getB() returned null
        .length();
    }

    public static void main(String[] args) {
        new NullTest();
    }
}

Regards,

Chris
@chriswhocodes

On Tue, January 27, 2015 11:47, pike wrote:
> Bernd Eckenfels-4 wrote
>
>> Am Wed, 21 Jan 2015 05:45:08 -0700 (MST)
>> schrieb pike <
>
>> pike630@
>
>> >:
>>
>>
>>> We frequently see NullPointerException in our logs. It's really a big
>>>  headache when we see a NullPointerException and it is encapsulated
>>> in another exception as we don't know which object is null and it is
>>> throwing an Exception. Is there any way we can get to know the object
>>>  type or the object variable name where the object is null and it is
>>> throwing a NullPointerException? i.e, instead of just saying there is
>>>  a NullPointerException, can we add some friendly message?
>>
>> Note that if you keep the stack information in an exception it points
>> (most of the time) exactly to the location where the null access
>> happens.
>>
>> I can imagine it is rather hard for the VM to add more informations.
>> Your best bet is to avoid the NPEs and log the exceptions properly.
>>
>>
>> Gruss
>> Bernd
>>
>
> This is acually not helpful in some situations. For example, as what
> kedar has mentioned, if there is a call "a.getB().getC()" and a NPE  is
> thrown. There might be two situations:
> 1. a is null;
> 2. a.getB() is null
>
>
> So it would be better if there can be one friendly message which
> indicates what is null.
>
>
>
> --
> View this message in context:
> http://openjdk.5641.n7.nabble.com/Useful-message-about-NullPointerExcepti
> on-tp213240p213842.html Sent from the OpenJDK Core Libraries mailing list
> archive at Nabble.com.
>
You are advising we should stick to the best coding style. But many times, not everyone can stick to this. If you are handling something written by others and you have no access to the source, you would appreciate if NPE can provide more friendly message like "The object reference a.getB() is null"...
Programmer
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Florian Weimer-5
In reply to this post by Pi Ke
On 01/21/2015 01:45 PM, pike wrote:
> We frequently see NullPointerException in our logs. It's really a big
> headache when we see a NullPointerException and it is encapsulated in
> another exception as we don't know which object is null and it is throwing
> an Exception. Is there any way we can get to know the object type or the
> object variable name where the object is null and it is throwing a
> NullPointerException?

The line number gives you the position in the source code, and from
that, you can usually figure out the static type.  If this is not
helpful in your case, you need to say why (no debugging information?
multiple candidates per line?).

The dynamic type is a different matter though, because null has no
specific type at run time.  It may be possible to provide type
information in theory, at a cost, but this would best be prototyped
through byte code rewriting.  Nullable annotations would also help to
pin-point location of the first leak, and you could record that
(including a stack trace) if you want something really fancy.  Whether
it is helpful for legacy code, I don't know.  There should be some
research projects out there covering this area.

--
Florian Weimer / Red Hat Product Security
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

kedar mhaswade
When the JVM executes instructions like getfield
<http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.getfield>,
getstatic, invokevirtual etc. with *objref* on the operand stack and if
*objref* is null, an NPE is thrown. It appears that the JVM could tell us
more about which *objref* was null at run-time. Candidate for an RFE?

That aside, (and Chris's trick is nice), but if you have no access to the
source for the offending code, life is hard in general, isn't it? Because
if you can't have control over the source, making that source run on a
platform where such an RFE would be perhaps fixed (a future release of the
JDK) would be even harder, no?

On Tue, Jan 27, 2015 at 5:14 AM, Florian Weimer <[hidden email]> wrote:

> On 01/21/2015 01:45 PM, pike wrote:
> > We frequently see NullPointerException in our logs. It's really a big
> > headache when we see a NullPointerException and it is encapsulated in
> > another exception as we don't know which object is null and it is
> throwing
> > an Exception. Is there any way we can get to know the object type or the
> > object variable name where the object is null and it is throwing a
> > NullPointerException?
>
> The line number gives you the position in the source code, and from
> that, you can usually figure out the static type.  If this is not
> helpful in your case, you need to say why (no debugging information?
> multiple candidates per line?).
>
> The dynamic type is a different matter though, because null has no
> specific type at run time.  It may be possible to provide type
> information in theory, at a cost, but this would best be prototyped
> through byte code rewriting.  Nullable annotations would also help to
> pin-point location of the first leak, and you could record that
> (including a stack trace) if you want something really fancy.  Whether
> it is helpful for legacy code, I don't know.  There should be some
> research projects out there covering this area.
>
> --
> Florian Weimer / Red Hat Product Security
>
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Pi Ke
kedar mhaswade wrote
When the JVM executes instructions like getfield
<http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.getfield>,
getstatic, invokevirtual etc. with *objref* on the operand stack and if
*objref* is null, an NPE is thrown. It appears that the JVM could tell us
more about which *objref* was null at run-time. Candidate for an RFE?
Yes, agree with you on this. Actually the JVM has some information about which reference is null when the NPE is thrown. It's reasonable if this kind of information can be provided when NPE is thrown. This will save much time for debugging.

kedar mhaswade wrote
That aside, (and Chris's trick is nice), but if you have no access to the
source for the offending code, life is hard in general, isn't it? Because
if you can't have control over the source, making that source run on a
platform where such an RFE would be perhaps fixed (a future release of the
JDK) would be even harder, no?
It's quite common that someone may have no access to the source code which throws the NPE. For example, API developers may often not be able to access user's source code, the only thing they can get are a bunch of logs.
Programmer
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Seán Coffey
In reply to this post by kedar mhaswade
Adding hotspot-dev to this mail thread also as it's relevant to hotspot.
(complete thread at
http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-January/031015.html)

As one who often has to dig through application logs and JDK issues, I
think this would certainly be a useful addition to the NPE handling
process. If the VM has extra info on the exact object that caused the
NPE, it should be output in that exception. "a.getB().getC()" is a good
example of the different code paths one has to go down to determine
where the NPE could have arisen from.

regards,
Sean.

On 27/01/2015 14:34, kedar mhaswade wrote:

> When the JVM executes instructions like getfield
> <http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.getfield>,
> getstatic, invokevirtual etc. with *objref* on the operand stack and if
> *objref* is null, an NPE is thrown. It appears that the JVM could tell us
> more about which *objref* was null at run-time. Candidate for an RFE?
>
> That aside, (and Chris's trick is nice), but if you have no access to the
> source for the offending code, life is hard in general, isn't it? Because
> if you can't have control over the source, making that source run on a
> platform where such an RFE would be perhaps fixed (a future release of the
> JDK) would be even harder, no?
>
> On Tue, Jan 27, 2015 at 5:14 AM, Florian Weimer <[hidden email]> wrote:
>
>> On 01/21/2015 01:45 PM, pike wrote:
>>> We frequently see NullPointerException in our logs. It's really a big
>>> headache when we see a NullPointerException and it is encapsulated in
>>> another exception as we don't know which object is null and it is
>> throwing
>>> an Exception. Is there any way we can get to know the object type or the
>>> object variable name where the object is null and it is throwing a
>>> NullPointerException?
>> The line number gives you the position in the source code, and from
>> that, you can usually figure out the static type.  If this is not
>> helpful in your case, you need to say why (no debugging information?
>> multiple candidates per line?).
>>
>> The dynamic type is a different matter though, because null has no
>> specific type at run time.  It may be possible to provide type
>> information in theory, at a cost, but this would best be prototyped
>> through byte code rewriting.  Nullable annotations would also help to
>> pin-point location of the first leak, and you could record that
>> (including a stack trace) if you want something really fancy.  Whether
>> it is helpful for legacy code, I don't know.  There should be some
>> research projects out there covering this area.
>>
>> --
>> Florian Weimer / Red Hat Product Security
>>

Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Florian Weimer-5
On 01/27/2015 03:57 PM, Seán Coffey wrote:

> Adding hotspot-dev to this mail thread also as it's relevant to hotspot.
> (complete thread at
> http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-January/031015.html)
>
>
> As one who often has to dig through application logs and JDK issues, I
> think this would certainly be a useful addition to the NPE handling
> process. If the VM has extra info on the exact object that caused the
> NPE, it should be output in that exception. "a.getB().getC()" is a good
> example of the different code paths one has to go down to determine
> where the NPE could have arisen from.

Maybe it's possible to add a byte code office to the exception it self,
or the stack trace?  Especially the former wouldn't need much additional
allocation.

--
Florian Weimer / Red Hat Product Security
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Peter Levart
In reply to this post by kedar mhaswade
On 01/27/2015 03:34 PM, kedar mhaswade wrote:
> When the JVM executes instructions like getfield
> <http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.getfield>,
> getstatic, invokevirtual etc. with *objref* on the operand stack and if
> *objref* is null, an NPE is thrown. It appears that the JVM could tell us
> more about which *objref* was null at run-time. Candidate for an RFE?

In general it is hard to deduce the meaningfull source of null *objref*
on the operand stack by analyzing the surrounding bytecodes. It could be
a result of complex logic executed by bytecodes. Imagine the following:

int length(boolean first, String s1, String s2) {
     return (first ? s1 : s2).length();
}

...the analysis would have to trace the live execution so that it could
be rolled-back to the meaningful source of null *objref*.

All VM might semi-realistically do is report the action VM was trying to
perform when it dereferenced a null *objref*. Like
"NullPointerException: while invoking method Xxxx.yyyy on a null
target", or "NullPointerException: while de-referencing instance field
Xxxx.yyyy of a null reference"

But what does this help if you don't have access to sources? Might be a
hint, but not much.

If you have access to sources, then perhaps an easier solution would be
for stack traces to include column number in addition to line number of
location in source that resulted in bytecodes that include the one that
triggered the NPE.

There is already a RFE for that:

     https://bugs.openjdk.java.net/browse/JDK-8020204

It seems that javac part is already there. The VM part and public API
part (StackTraceElement) is not, though.

Regards, Peter

>
> That aside, (and Chris's trick is nice), but if you have no access to the
> source for the offending code, life is hard in general, isn't it? Because
> if you can't have control over the source, making that source run on a
> platform where such an RFE would be perhaps fixed (a future release of the
> JDK) would be even harder, no?
>
> On Tue, Jan 27, 2015 at 5:14 AM, Florian Weimer <[hidden email]> wrote:
>
>> On 01/21/2015 01:45 PM, pike wrote:
>>> We frequently see NullPointerException in our logs. It's really a big
>>> headache when we see a NullPointerException and it is encapsulated in
>>> another exception as we don't know which object is null and it is
>> throwing
>>> an Exception. Is there any way we can get to know the object type or the
>>> object variable name where the object is null and it is throwing a
>>> NullPointerException?
>> The line number gives you the position in the source code, and from
>> that, you can usually figure out the static type.  If this is not
>> helpful in your case, you need to say why (no debugging information?
>> multiple candidates per line?).
>>
>> The dynamic type is a different matter though, because null has no
>> specific type at run time.  It may be possible to provide type
>> information in theory, at a cost, but this would best be prototyped
>> through byte code rewriting.  Nullable annotations would also help to
>> pin-point location of the first leak, and you could record that
>> (including a stack trace) if you want something really fancy.  Whether
>> it is helpful for legacy code, I don't know.  There should be some
>> research projects out there covering this area.
>>
>> --
>> Florian Weimer / Red Hat Product Security
>>

Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

David Holmes
Adding back in hotspot-dev to this reply

There have been previous RFEs for this dating back to 2006 - most closed
as duplicates and the main one eventually closed as "will not fix"
simply due to it being a low priority RFE for 8 years.

Also see:

https://bugs.openjdk.java.net/browse/JDK-6717558

On 28/01/2015 2:01 AM, Peter Levart wrote:

> On 01/27/2015 03:34 PM, kedar mhaswade wrote:
>> When the JVM executes instructions like getfield
>> <http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.getfield>,
>>
>> getstatic, invokevirtual etc. with *objref* on the operand stack and if
>> *objref* is null, an NPE is thrown. It appears that the JVM could tell us
>> more about which *objref* was null at run-time. Candidate for an RFE?
>
> In general it is hard to deduce the meaningfull source of null *objref*
> on the operand stack by analyzing the surrounding bytecodes. It could be
> a result of complex logic executed by bytecodes. Imagine the following:
>
> int length(boolean first, String s1, String s2) {
>      return (first ? s1 : s2).length();
> }
>
> ...the analysis would have to trace the live execution so that it could
> be rolled-back to the meaningful source of null *objref*.

Exactly right - all the VM knows at that exact point is that the thing
on the stack is an object reference - if its value is null that doesn't
tell you where that came from. You have to look around to see what
pushed that objRef onto the stack. Might be doable from the interpreter,
but from compiled code?

> All VM might semi-realistically do is report the action VM was trying to
> perform when it dereferenced a null *objref*. Like
> "NullPointerException: while invoking method Xxxx.yyyy on a null
> target", or "NullPointerException: while de-referencing instance field
> Xxxx.yyyy of a null reference"
>
> But what does this help if you don't have access to sources? Might be a
> hint, but not much.

As I said there may be some context to assist with how the null was
introduced, but in general it isn't something that is readily apparent -
especially in compiled code.

> If you have access to sources, then perhaps an easier solution would be
> for stack traces to include column number in addition to line number of
> location in source that resulted in bytecodes that include the one that
> triggered the NPE.
>
> There is already a RFE for that:
>
>      https://bugs.openjdk.java.net/browse/JDK-8020204

Once past suggestion has been to include the ByteCode Index (BCI) as
part of the exception stacktrace information:

https://bugs.openjdk.java.net/browse/JDK-4185378

David
-----

> It seems that javac part is already there. The VM part and public API
> part (StackTraceElement) is not, though.
>
> Regards, Peter
>
>>
>> That aside, (and Chris's trick is nice), but if you have no access to the
>> source for the offending code, life is hard in general, isn't it? Because
>> if you can't have control over the source, making that source run on a
>> platform where such an RFE would be perhaps fixed (a future release of
>> the
>> JDK) would be even harder, no?
>>
>> On Tue, Jan 27, 2015 at 5:14 AM, Florian Weimer <[hidden email]>
>> wrote:
>>
>>> On 01/21/2015 01:45 PM, pike wrote:
>>>> We frequently see NullPointerException in our logs. It's really a big
>>>> headache when we see a NullPointerException and it is encapsulated in
>>>> another exception as we don't know which object is null and it is
>>> throwing
>>>> an Exception. Is there any way we can get to know the object type or
>>>> the
>>>> object variable name where the object is null and it is throwing a
>>>> NullPointerException?
>>> The line number gives you the position in the source code, and from
>>> that, you can usually figure out the static type.  If this is not
>>> helpful in your case, you need to say why (no debugging information?
>>> multiple candidates per line?).
>>>
>>> The dynamic type is a different matter though, because null has no
>>> specific type at run time.  It may be possible to provide type
>>> information in theory, at a cost, but this would best be prototyped
>>> through byte code rewriting.  Nullable annotations would also help to
>>> pin-point location of the first leak, and you could record that
>>> (including a stack trace) if you want something really fancy.  Whether
>>> it is helpful for legacy code, I don't know.  There should be some
>>> research projects out there covering this area.
>>>
>>> --
>>> Florian Weimer / Red Hat Product Security
>>>
>
Reply | Threaded
Open this post in threaded view
|

Re: Useful message about NullPointerException

Peter Levart
On 01/28/2015 03:30 AM, David Holmes wrote:

>> If you have access to sources, then perhaps an easier solution would be
>> for stack traces to include column number in addition to line number of
>> location in source that resulted in bytecodes that include the one that
>> triggered the NPE.
>>
>> There is already a RFE for that:
>>
>> https://bugs.openjdk.java.net/browse/JDK-8020204
>
> Once past suggestion has been to include the ByteCode Index (BCI) as
> part of the exception stacktrace information:
>
> https://bugs.openjdk.java.net/browse/JDK-4185378
>
> David

Right,

I checked per-method CharacterRangeTable that gets emitted by javac
-Xjcov option, and unfortunately it is of limited use. The
CharacterRangeTable contains mappings from byte code index ranges
(start-bci, end-bci) -> character ranges (start-line, start-column,
end-line, end-column) of adequate code in source file. The ranges I have
observed have 2 granularities: "statement" and "block". For example, the
following program:


public class CharRangeTest {

     String str() {
         return "ABC";
     }

     public static void main(String[] args) {
         int i = new CharRangeTest().str().substring(1).length();
         System.out.println(i);
     }
}


Compiles to the following bytecodes for main method:

   public static void main(java.lang.String[]);
     descriptor: ([Ljava/lang/String;)V
     flags: ACC_PUBLIC, ACC_STATIC
     Code:
       stack=2, locals=2, args_size=1
          0: new           #3                  // class CharRangeTest
          3: dup
          4: invokespecial #4                  // Method "<init>":()V
          7: invokevirtual #5                  // Method
str:()Ljava/lang/String;
         10: iconst_1
         11: invokevirtual #6                  // Method
java/lang/String.substring:(I)Ljava/lang/String;
         14: invokevirtual #7                  // Method
java/lang/String.length:()I
         17: istore_1
         18: getstatic     #8                  // Field
java/lang/System.out:Ljava/io/PrintStream;
         21: iload_1
         22: invokevirtual #9                  // Method
java/io/PrintStream.println:(I)V
         25: return
       LineNumberTable:
         line 11: 0
         line 12: 18
         line 13: 25
       CharacterRangeTable:
              0, 17,   2c09,   2c41,    1        //  0, 17, 11:09,  
11:65, statement
             18, 24,   3009,   301f,    1        // 18, 24, 12:09,  
12:31, statement
              0, 25,   282c,   3406,    2        //  0, 25, 10:44,  
13:06, block



CharacterRangeTable says that bytecodes at indexes 0 to 17 map to source
code from (line 11, column 9) to (line 11, column 64) and that this
range is a "statement". Unfortunately, the assignment to i of the result
of the whole chain of invocations is a single Java "statement":

int i = new CharRangeTest().str().substring(1).length();

So if NPE happens anywhere in this statement, we could only pin-point
the statement and not a particular null dereference. The only time this
would give us some additional info is when there are more statements in
the line, like:

     x.doSomething(); y.doSomeMore();

...but such code formatting is very rare if non-existent.


If adding column number to StackTraceElement (JDK-8020204) is currently
not an easy thing to do, since it would require javac changes, adding
byte code index (JDK-4185378 ) is trivial:


http://cr.openjdk.java.net/~plevart/jdk9-dev/StackTraceElement.byteCodeIndex/jdk.webrev.01/

http://cr.openjdk.java.net/~plevart/jdk9-dev/StackTraceElement.byteCodeIndex/hotspot.webrev.01/


With this patch, I get the following style of stack-traces:

Exception in thread "main" java.io.FileNotFoundException: /tmp/x (No
such file or directory)
         at java.io.FileInputStream.open0(Native Method)
         at java.io.FileInputStream.open[2](FileInputStream.java:195)
         at java.io.FileInputStream.<init>[97](FileInputStream.java:138)
         at java.io.FileInputStream.<init>[17](FileInputStream.java:93)
         at Test.dump[9](Test.java:12)
         at Test.main[3](Test.java:19)


The numbers in square brackets are byte code indexes that pin-point the
location in byte code. With the help of javap, one can use this info to
find out the cause of exception even without having access to sources.


Regards, Peter