Thoughts on adding getElementClass() method to StackTraceElement?

Nick Williams nicholas+openjdk at nicholaswilliams.net
Sat Jun 15 21:06:50 UTC 2013


On Jun 15, 2013, at 3:21 PM, Alan Bateman wrote:

> On 15/06/2013 19:33, Nick Williams wrote:
>> :
>> 
>> Looking at Throwable.java and Throwable.c, getStackTrace() ultimately calls JVM_GetStackTraceElement. Looking at jvm.c from Java 6 (I can't find JVM_GetStackTraceElement in newer versions of Java), JVM_GetStackTraceElement calls CVMgetStackTraceElement.
>> CVMgetStackTraceElement, in turn, then gets a copy of the native version of the Class object and uses it to populate the StackTraceElement's data. This leads me to believe that the task of adding a getElementClass() method to StackTraceElement would be as simple as:
>> 
>> 1) Adding a new constructor to StackTraceElement to preserve backwards compatibility, with the Class being null by default.
>> 2) Add the getStackTraceElement() method and backing private field.
>> 3) Add a CVMID_fieldWriteRef call to set the class to the backing private field.
>> 
>> I'm sure there are some idiosyncrasies I'm missing here, but overall this seems like a pretty trivial change. What do people think? Can this be worked in? .NET has had this ability since .NET 1.1 with the StackFrame class [2] and the StackTrace [3], which contains StackFrames. It provides more than just the Class (Type in .NET), it also provides the Method (MethodBase in .NET). It would greatly improve the efficiency of certain tasks not only in Log4j, but also in many other projects that I have found using getCallerClass() for the same purpose.
>> 
> Here's a discussion from last year on this topic:
> 
> http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-October/011665.html
> 
> -Alan.

Indeed. Looks like the discussion died somewhat after a while. No conclusion was ever made. Based on the discussion it the email, I would add some additional observations/behavior that I think should be considered:

1) The elementClass property (getElementClass method) should be the Class that matches StackTraceElement's className property. It should not be the type of the object that received the method invocation. Perhaps, then, it would be better to call it frameClass (getFrameClass), to make it more obvious that it's the class for the frame on the stack.

2) If elementClass is made to be the type of the object that received the method invocation, then an getMethod() method should also be added so that the Class that defined the method that was executed can be obtained. This might actually be the most versatile option. However, Method is not Serializable, so that must then be considered.

3) I'm okay with making the elementClass transient. I don't have a particular need for it to be serialized, and making it transient is the easiest way to solve some problems.

4) Vitaly's email said that StackFrame exposes the MethodBase (Method), but not the Type (Class). This is correct. I wasn't clear on this earlier. To get the frame Type you would use stackFrameInstance.GetMethod().DeclaringType.

5) I do think the elementClass (or whatever) property should be Weak. If a particular piece of code (foolishly) hangs on to a StackTraceElement instance, it could cause a ClassLoader memory leak, particularly in Java EE containers. Making it Weak is the safest approach. Existing code written for earlier versions of Java may hang on to StackTraceElements for whatever reason, and problems wouldn't begin to arise from that until the code was run on Java 8.

6) I don't think security is a major issue here. There's not a lot you can do with a Class instance without involving existing security checks. For example, you can inspect the Class's name, Package, CodeSource, etc., but you can't invoke methods, manipulate fields, or create an instance of the Class without security checks being performed. Let's consider three possible scenarios:

A) A Class loaded by a parent class loader obtains a StackTraceElement containing Classes loaded by a child class loader. I don't see a major issue here. The obvious scenario is a library loaded by a Servlet container obtaining a Class loaded within one of the web application class loaders. It's much more likely that this code will be "well behaved" and already has some kind of power over the child class loader anyway.

B) A Class loaded by a child class loader obtains a StackTraceElement containing Classes loaded by a sibling class loader. This would obviously be the more dangerous scenario (think: one web application accessing another web application's classes), but I don't think it's actually possible. I don't think a stack trace generated in one class loader can possibly make its way into code in a sibling class loader, and I know that an execution stack can't contain classes from two sibling class loaders (only from class loaders with parent/child relationships).

C) A Class loaded by a child class loader obtains a StackTraceElement containing Classes loaded by a parent class loader. There's no issue here. Child class loaders can already access classes from their parent class loaders.

I'd love for the conversation started in the original thread (that Alan pointed out) to pick up here and come to some kind of resolution. I think this could be a big help to developers, especially those creating diagnostic tools (like logging frameworks).

Nick


More information about the core-libs-dev mailing list