Debugging stack data not assigned to a named variable - java

Is there a way to view stack elements like un-assigned return values or exceptions that not assigned to a local variable? (e.g. throw new ...)
For example, suppose I have code along the lines of:
public String foo(InputStream in) throws IOException {
NastyObj obj = null;
try {
obj = new NastyObj(in);
return (obj.read());
} finally {
if (obj != null) obj.close();
}
}
Is there any way to view the return or exception value without stepping to a higher level frame where it is assigned? This is particularly relevant with exceptions because you often have to step back up through a number of frames to find an actual handler.
I usually use the Eclipse debugging environment, but any answer is appreciated. Also, if this cannot be done, can you explain why? (JVM, JPDA limitation?)

The answer seems to be that both JPDA/JDI and Eclipse are deficient.
I’ve verified the following, but I’m not going to bother posting the code unless someone really needs it.
For the most part, JDI mirrors the structure of the code. Named locals for a given scope can be obtained through the debuggee thread’s current StackFrame. Unscoped locals and method arguments can be obtained through the debuggee thread’s current Method. However, in general where the documentation refers to a LocalVariable, it is a named local.
It IS possible to get the return value of a function, if the function is returning normally and you are using a 1.6 debugging setup (RFE). If the debugger listens for MethodExitEvent, then event.returnValue() gets the value returned after all the method has finished executing. According to the documentation, this event is NOT generated when a method terminates via a thrown exception.
The conclusion is that if you use JDI directly under Java 1.6, you can get the return value of a function before it's assigned to a local, if it returns normally. The Eclipse and Netbeans UIs don't support this. You can't get information about Exceptions that have been thrown but not caught yet.

Couldn't you just catch the IOException (and name it) and then rethrow it? (Don't know Java, but that's what I'd do in C++ and Python.) Of course, this answer is invalid if you can't edit the given code or are inspecting the state right now and need to know what it looks like... But if you can edit the code, that seems like the way to go.

Related

Weird negative length array created into Class.getDeclaredFields that makes JVM to throw a NegativeArraySizeException

I Use Java 15 openjdk and tried on Java 14
Include details about your goal
I'm making a RMI system in order to make instances of any object synchronisable between computers and make multiple engines works on the same object. With my system, when i want to synchronise an object, i generate a class that will extends the object class and then override every methods of the class in order to control if the method call must be delegated to the object or to perform a RMI request instead.
The class generation is divided in two part :
I generate the source code in which every non-final methods are overriden in order to add my delegating system. the code is generated in scala language, and this class yet does not extends from the class of the object to synchronise because scala don't let me override some methods, even if they are not final (it's a thing with scala's setters and getters), then i compile the code using the Scala Compiler.
I use javassist to modify the generated class and make it extends the expected class + i add some methods and modify anonfun methods in order to perform super calls.
What is happening when i see the exception ?
I have a module Server and a module Client, they both run the same code except that they have different implementation of the Engine module, which is where i define all features of my framework, my RMI system is a feature of the framework for example, and for this RMI system, absolutely no code is runned into the implementations modules.
In the Engine module, I've made a player command in my program that creates a synchronised list (of type scala.collections.mutable.ListBuffer), thus, with this command i can add some player objects to the list. for example, if i add a player to the list, it will be added in the local list of the program that executes the command, and a RMI request will be done to the other computers that hosts the list in order to make them add the same object in their list.
Now, if i enter something like player add id=7 name=testPlayer x=78 y=23, it will start to get completely weird :
First of all, this exception occurs only when the server program handles the RMI request, which is completely nonsensical because as i said, nothing is run in the implementation.
For example, if i enter the command on the server, the player will be added in it's local list, and a RMI request for the add method will be sent from the server to the client, but on the client, as it will handle the request, will not crash at all (i can spam the command, nothing breaks). So, if the server handles the RMI request, it throws me this error :
java.lang.NegativeArraySizeException: -531627648
at java.base/java.lang.Class.copyFields(Class.java:3538)
at java.base/java.lang.Class.getDeclaredFields(Class.java:2341)
at fr.linkit.engine.connection.packet.serialization.tree.ClassDescription.listAllSerialFields$1(ClassDescription.scala:45)
at fr.linkit.engine.connection.packet.serialization.tree.ClassDescription.listSerializableFields(ClassDescription.scala:52)
at fr.linkit.engine.connection.packet.serialization.tree.ClassDescription.<init>(ClassDescription.scala:23)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultClassProfile.<init>(DefaultClassProfile.scala:23)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultSerialContext.$anonfun$getClassProfile$1(DefaultSerialContext.scala:61)
at scala.collection.mutable.HashMap.getOrElseUpdate(HashMap.scala:454)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultSerialContext.getClassProfile(DefaultSerialContext.scala:61)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultNodeFinder.getClassProfile(DefaultNodeFinder.scala:49)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultNodeFinder.getSerialNodeForType(DefaultNodeFinder.scala:36)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultNodeFinder.getSerialNodeForRef(DefaultNodeFinder.scala:44)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultNodeFinder.$anonfun$listNodes$1(DefaultNodeFinder.scala:55)
at scala.collection.immutable.List.map(List.scala:246)
at fr.linkit.engine.connection.packet.serialization.tree.DefaultNodeFinder.listNodes(DefaultNodeFinder.scala:53)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ObjectNode$ObjectSerialNode.serialize(ObjectNode.scala:58)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.serializeItem$1(ArrayNode.scala:84)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.$anonfun$serialize$1(ArrayNode.scala:68)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.$anonfun$serialize$1$adapted(ArrayNode.scala:67)
at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.serialize(ArrayNode.scala:67)
at fr.linkit.engine.connection.packet.serialization.tree.LengthSign$.$anonfun$of$2(LengthSign.scala:62)
at fr.linkit.engine.connection.packet.serialization.tree.LengthSign$.$anonfun$of$2$adapted(LengthSign.scala:54)
at scala.collection.immutable.List.foreach(List.scala:333)
at fr.linkit.engine.connection.packet.serialization.tree.LengthSign$.of(LengthSign.scala:54)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ObjectNode$ObjectSerialNode.serialize(ObjectNode.scala:63)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.serializeItem$1(ArrayNode.scala:84)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.$anonfun$serialize$1(ArrayNode.scala:68)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.$anonfun$serialize$1$adapted(ArrayNode.scala:67)
at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
at fr.linkit.engine.connection.packet.serialization.tree.nodes.ArrayNode$ArraySerialNode.serialize(ArrayNode.scala:67)
at fr.linkit.engine.connection.packet.serialization.DefaultSerializer.serialize(DefaultSerializer.scala:34)
at fr.linkit.engine.connection.packet.serialization.SimpleTransferInfo.makeSerial(SimpleTransferInfo.scala:38)
at fr.linkit.engine.connection.packet.serialization.LazyPacketSerializationResult.bytes$lzycompute(LazyPacketSerializationResult.scala:27)
at fr.linkit.engine.connection.packet.serialization.LazyPacketSerializationResult.bytes(LazyPacketSerializationResult.scala:27)
at fr.linkit.engine.connection.packet.serialization.LazyPacketSerializationResult.writableBytes$lzycompute(LazyPacketSerializationResult.scala:30)
at fr.linkit.engine.connection.packet.serialization.LazyPacketSerializationResult.writableBytes(LazyPacketSerializationResult.scala:29)
at fr.linkit.server.connection.ExternalConnectionSession.send(ExternalConnectionSession.scala:53)
at fr.linkit.server.connection.ServerExternalConnection.$anonfun$sendPacket$1(ServerExternalConnection.scala:100)
at fr.linkit.engine.local.concurrency.pool.BusyWorkerPool.$anonfun$runLater$1(BusyWorkerPool.scala:351)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
at scala.util.Try$.apply(Try.scala:210)
at fr.linkit.engine.local.concurrency.pool.BusyWorkerPool.$anonfun$runLaterControl$1(BusyWorkerPool.scala:122)
at fr.linkit.engine.local.concurrency.SimpleAsyncTask.runTask(SimpleAsyncTask.scala:75)
at fr.linkit.engine.local.concurrency.pool.BusyWorkerThread.runTask(BusyWorkerThread.scala:67)
at fr.linkit.engine.local.concurrency.pool.BusyWorkerPool.$anonfun$runLaterControl$2(BusyWorkerPool.scala:132)
The exception occurs during the serialization of the response packet, (as we are performing a Remote Method Invocation, we have to send the return value of the method). In this case, the add method returns the instance of the list, so the packet will contains the instance of the list as a result value (sounds useless but i have to deal with this kind of situations). When the list gets serialized, it crashes here :
def listAllSerialFields(cl: Class[_]): Seq[Field] = {
if (cl == null)
return Seq.empty
val fields = cl.getDeclaredFields //Line 45, Here, the cl value is the generated class
fields
.filterNot(p => Modifier.isTransient(p.getModifiers) || Modifier.isStatic(p.getModifiers))
.tapEach(_.setAccessible(true))
.toList ++ listAllSerialFields(cl.getSuperclass)
}
Then, further in the method it crashes here :
private static Field[] copyFields(Field[] arg) {
Field[] out = new Field[arg.length]; //arg.length is -500 millions !
ReflectionFactory fact = getReflectionFactory();
for (int i = 0; i < arg.length; i++) {
out[i] = fact.copyField(arg[i]);
}
return out;
}
I suspect that it's the reflection data that causes that because, when i used the debugger to follow the thread execution, the jvm crashed when the debugger saw the referent field of the SoftReference<ReflectionData> Class.reflectionData field. But i repeat, on the client it does not crash, and my debugger can inspect the reflection data successfully.
EDIT -
If i call getDeclaredFields directly once the class get loaded (here for example):
var loader = puppetClass.getClassLoader
if (loader == null)
loader = getClass.getClassLoader //Use the Application's classloader
val classLoader = new GeneratedClassLoader(folderPath, loader, Seq(classOf[LinkitApplication].getClassLoader))
val clazz = Class.forName(wrapperClassName, false, classLoader).asInstanceOf[Class[_ <: PuppetWrapper[AnyRef]]]
println(s"CREATED CLASS ${clazz} IN THREAD = " + Thread.currentThread())
clazz.getDeclaredFields //Invoking a method in order to make the class load its reflectionData (causes fatal error if not made directly)
ClassMappings.putClass(clazz)
clazz
It will never crash or throw me the an exception, however, it still weird that i have to do that because only the server would oftenly crash, and when it crashes, it can does it in the exact same thread that have loaded the class...
This isn't really an answer to your original question, but re-iterates what was said in the comments. What you're doing is "unsafe", and the behavior is undefined. The fact that the workaround is working at all is somewhat incidental and cannot be relied upon. Maybe it works now, but in a future Java version it might fail.
The Unsafe class is going away once safe replacements exist for all of its useful capabilities. This will likely occur after the completion of the Panama project, which provides access to native memory. The VarHandle class is the replacement for direct field access, but it doesn't permit modifying final fields, and it likely never will. Such a backdoor prevents certain optimizations, and new Java features like "records" and "hidden classes" trust that final fields are really final. This behavior might apply to all classes at some point.
There's no planned safe alternative for allocating classes without a constructor, and so that's a problem too. The built-in Java serialization mechanism will have to continue using a backdoor until it's rewritten to use a different technique.
The safe technique is to generate a hidden constructor which performs deserialization and sets the final fields. It might also need dummy parameters to avoid conflicts with any other constructors. The constructor is added with an instrumentation agent which modifies serializable classes as they're loaded.
Ideally the hidden constructor should be private, but then accessing it becomes tricky. The agent should also define (or augment) a static class intializer which looks up the MethodHandle for the hidden constructor and passes it to some serialization framework layer. The private constructor will still be visible by any code which calls getDeclaredConstructors, but that's a relatively minor problem.
As for serializing the fields out in the first place, a VarHandle for each field can be passed along from the static initializer, or a private method is added which does the serialization. I think that the private method approach is better, and it just needs one MethodHandle for accessing it.
Thanks a lot for ones who tried to help me, and thanks to boneil for his answer because he made me become aware that Unsafe wasn't a great solution, but i still have to deal with it. However, i decided to answer because i just made a "discovery" with the Unsafe.allocateInstance method : When Unsafe allocates an instance, every fields of the objects are null but still neverless non detected as null by the JVM. I just had a case where i didn't knew why i got an exception in the init method of one of my allocated instances, i first started to think that it was called twice, but it turned out that i could'nt even debug the method execution with a breakpoint because it was making my JVM crash as soon as the debugger stops in the instance's method. Thus, as i could not use the debugger, i decided to use the plain old nooby printf statement, but still unable to debug as i got a NPE here :
(in java.lang.String.java)
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString(); //obj is null.
}
as you can see, the obj was null as it threw a NPE, but it still has been considerated as a normal instance. Therefore, by seeing this, i decided to use reflection to set the field that caused this issue as null (field.set(instance, null)), and i was able to print the entire object, and i was able to use the debugger ! So this means that it's an Unsafe thing that it does not even set fields' value to null, which is very anoying but, it's ok...
Now i think that my jvm crashed because as the debugger tried to introspect my allocated object, it received an NPE, even if it certainly check if the object was not null, thus, this made an internal error in the debugger, and then the JVM crashed.
EDIT: it seems like it's not just when memory is not initialised by Unsafe, "cursed null" fields looks to appear when Unsafe touches an object (putInt, putObject...). If an Unsafe method is invoked to put something in an object's memory, any null field of the object have a (high) chance to become a weird null field

CPLEX+JAVA: Retrieving Solution inside Heuristic Callback behaves weirdly

I have the following problem: I solve a large VRP with many synchronization constraints using CPLEX integrated with a heuristic component to improve incumbents. The general algorithm is as follows: If a new incumbent is found in CPLEX, or if a time limit is reached, I move to a heuristic, and try to improve the current incumbent. The former is done using an Incumbent Callback, the latter using a Heuristic Callback. While I am able to query all variables in the incumbent callback, I get some weird behavior in the heuristic callback:
When I query
this.getStatus().toString()
this returns "Optimal", even though the solution is not optimal yet (there is an incumbent, but still a rather large integrality gap). I made sure that the model actually queries the correct cplex object by looking into objective value and current integrality gap, they match the log. Then,
this.getIncumbentValue(v[n][i][j]);
fails (it also fails if I query the values using this.getIncumbentValues(v[n][i]);).
When I check in the model (using cplex.exportModel(String filename), all variables are present.
I was thinking that this might be related to the fact that I use CPLEX as a singleton, but the status is already "optimal" when I use the singleton for the first time (in the first iteration however, all variables can be queried, this problem only exists in the second iteration).
I create the singleton as such:
public static IloCplex getCplex() {
if (cplex == null) {
try {
cplex = new IloCplex();
} catch (IloException e) {
e.printStackTrace();
}
} else {
try {
cplex.clearModel();
cplex.setDefaults();
} catch (IloException e) {
e.printStackTrace();
}
}
return cplex;
}
Did I maybe do something wrong here?
EDIT: The exact error message including back trace is:
ilog.cplex.IloCplex$UnknownObjectException: CPLEX Error: object is unknown to IloCplex
at ilog.cplex.CpxNumVar.getVarIndexValue(CpxNumVar.java:295)
at ilog.cplex.IloCplex$MIPInfoCallback.getIndex(IloCplex.java:13648)
at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13807)
at ilog.cplex.IloCplex$MIPInfoCallback.getIncumbentValues(IloCplex.java:13785)
at SolverHybridCRP$InsertSolution.getV(SolverHybridCRP.java:2091)
at SolverHybridCRP$InsertSolution.improveIncumbent(SolverHybridCRP.java:2054)
at SolverHybridCRP$InsertSolution.main(SolverHybridCRP.java:2024)
at ilog.cplex.CpxCallback.callmain(CpxCallback.java:160)
at ilog.cplex.CpxHeuristicCallbackFunction.callIt(CpxHeuristicCallbackFunction.java:48)
at ilog.cplex.Cplex.CPXmipopt(Native Method)
at ilog.cplex.CplexI$SolveHandle.start(CplexI.java:2837)
at ilog.cplex.CplexI.solve(CplexI.java:2963)
at ilog.cplex.IloCplex.solve(IloCplex.java:10254)
at SolverHybridCRP.solveModel(SolverHybridCRP.java:1525)
at AppHelp.runtimeTest4(AppHelp.java:1218)
at AppHelp.main(AppHelp.java:61)
it occurs when I query ANY variable, but only after I query the cplex object the second time. (So: I start the program, it iterates over a lot of instances, the first instance is fine, all heuristic callbacks work, in all further iterations, I end up in the catch-block and get the above exception trace.)
That is why I assumed that maybe the singleton does not work exactly as supposed, and not everything is deleted from the first iteration.
Looking at the reference documentation you can see for IloCplex.HeuristicCallback.getStatus()
Returns the solution status for the current node.
This method returns the status of the solution found by the instance
of IloCplex at the current node during the last call to the method
IloCplex.HeuristicCallback.solve (which may have been called directly
in the callback or by IloCplex when processing the node just before
the callback is called).
In other words, the function does not return a global status but only a node-local status. It is expected that the node is currently solved to optimality when the callback is invoked.
With respect to the exception in the callback: you are trying to access a variable object that is not in the model being solved. Typical cases in which this happens are:
You created the variable but it does not appear in any constraints or in the objective, i.e., it is not used anywhere. You can force its usage by explicitly calling cplex.add() with the variable as argument.
The variable was created in a previous iteration and is no longer part of the model in the current iteration. A good way to debug this is to assing a name to each variable and have that name include the iteration index. Then in the exception handler print the name of the offending variable. That should give a very good hint about what is wrong.

Java 8 lambda mutable variable capture from method parameter?

I'm using AdoptOpenJDK jdk81212-b04 on Ubuntu Linux, running on Eclipse 4.13. I have a method in Swing that creates a lambda inside a lambda; both probably get called on separate threads. It looks like this (pseudocode):
private SwingAction createAction(final Data payload) {
System.out.println(System.identityHashCode(payload));
return new SwingAction(() -> {
System.out.println(System.identityHashCode(payload));
//do stuff
//show an "are you sure?" modal dialog and get a response
//show a file selection dialog
//when the dialog completes, create a worker and show a status:
showStatusDialogWithWorker(() -> new SwingWorker() {
protected String doInBackground() {
save(payload);
}
});
You can see that the lambdas are several layers deep, and that eventually the "payload" which was captured gets saved to a file, more or less.
But before considering the layers and the threads, let's go directly to the problem:
The first time I call createAction(), the two System.out.println() methods print the exact same hash code, indicating that the captured payload inside the lambda is the same I passed to createAction().
If I later call createAction() with a different payload, the two System.out.println() values printed are different! In particular, the second line printed always indicates the same value that was printed in step 1!!
I can repeat this over and over; the actual payload passed will keep getting a different identity hash code, while the second line printed (inside the lambda) will stay the same! Eventually something will click and suddenly the numbers will be the same again, but then they will diverge with the same behavior.
Is Java somehow caching the lambda, as well as the argument that is going to the lambda? But how is this possible? The payload argument is marked final, and besides, lambda captures have to be effectively final anyway!
Is there a Java 8 bug that doesn't recognize a lambda should not be cached if the captured variable is several lambdas deep?
Is there a Java 8 bug that is caching lambdas and lambda arguments across threads?
Or is there something that I don't understand about lambda capture method arguments versus method local variables?
First Failed Workaround Attempt
Yesterday I thought I could prevent this behavior simply by capturing the method parameter locally on the method stack:
private SwingAction createAction(final Data payload) {
final Data theRealPayload = payload;
System.out.println(System.identityHashCode(theRealPayload));
return new SwingAction(() -> {
System.out.println(System.identityHashCode(theRealPayload));
//do stuff
//show an "are you sure?" modal dialog and get a response
//show a file selection dialog
//when the dialog completes, create a worker and show a status:
showStatusDialogWithWorker(() -> new SwingWorker() {
protected String doInBackground() {
save(theRealPayload);
}
});
With that single line Data theRealPayload = payload, if I henceforth used theRealPayload instead of payload suddenly the bug no longer appeared, and every single time I called createAction(), the two printed lines indicate exactly the same instance of the captured variable.
However today this workaround has stopped working.
Separate Bug Fix Addresses Problem; But Why?
I found a separate bug that was throwing an exception inside showStatusDialogWithWorker(). Basically showStatusDialogWithWorker() is supposed to create the worker (in the passed lambda) and show a status dialog until the worker is finished. There was a bug that would create the worker correctly, but fail to create the dialog, throwing an exception that would bubble up and never get caught. I fixed this bug so that the showStatusDialogWithWorker() successfully shows the dialog when the worker is running and then closes it after the worker finishes. I can now no longer reproduce the lambda capture issue.
But why does something inside showStatusDialogWithWorker() relate to the problem at all? When I was printing out System.identityHashCode() outside and inside the lambda, and the values were differing, this was happening before showStatusDialogWithWorker() was being called, and before the exception was being thrown. Why should a later exception make a difference?
Besides, the fundamental question remains: how is it even possible that a final parameter passed by a method and captured by a lambda could ever change?
how is it even possible that a final parameter passed by a method and captured by a lambda could ever change?
It is not. As you have pointed out, unless there is a bug in the JVM, this cannot happen.
This is very difficult to pin down without a minimal reproducible example. Here are the observations you have made:
The first time I call createAction(), the two System.out.println() methods print the exact same hash code, indicating that the captured payload inside the lambda is the same I passed to createAction().
If I later call createAction() with a different payload, the two System.out.println() values printed are different! In particular, the second line printed always indicates the same value that was printed in step 1!!
One possible explanation that fits the evidence is that the lambda being called the second time is in fact the lambda from the first run, and the lambda that was created by the second run has been discarded. That would give the above observations, and would place the bug inside the code that you have not shown here.
Perhaps you could add some extra logging to record:
a) the ids of any lambdas created inside createAction at creation time (I think you would need to change the lambdas into anon classes that implement the callback interfaces with logging in their constructors)
b) the ids of the lambdas at the time of their invocation
I think that the above logging would be sufficient to prove or disprove my theory.
GL!
I don't find anything wrong with the captured lambdas in your code.
Your workaround doesn't change the local capturing as you just declared a new variable an assigned it to to the same reference.
The problem is most likely on your handling of the SwingAction created object.
I wouldn't be surprised if you find that printing the IdentityHashCode of that returned object where you are using it yields consistent values with your payloads. Or in other words, you may be using a previous reference to SwingAction.
Besides, the fundamental question remains: how is it even possible
that a final parameter passed by a method and captured by a lambda
could ever change?
This shouldn't be possible at the reference level, the variable can't be reassigned. The reference passed may be mutable itself though, but that doesn't apply to this case.

Constructor yields null - where to start?

I am creating a set of TestNG tests in eclipse for existing code that supposedly validates certificates against a CRL.
In my test, I create a new class to provide validation functions, like this:
public void testRevokedCertificate() throws Exception {
EmbeddedFileServer embeddedFileServer = new EmbeddedFileServer(CertificateResourceHelper.getResourcePath("."));
embeddedFileServer.start();
URL crlUrl = new URL("http://localhost:" + embeddedFileServer.getPort() + "/certs/" + "test_ca1.crl");
CachingValidCrlProvider prov = new CachingValidCrlProvider(crlUrl, publicKey, 1, 2);
assertNotNull(prov);
}
The constructor CachingValidCrlProvider(URL, publicKey, int, int) always returns null! This is a mystery to me, as the constructor does not look very special:
public CachingValidCrlProvider(URL crlUrl, PublicKey expectedPublicKey, int failedDownloadBackoffTimeInSeconds, int forcedCrlRefreshIntervalInSeconds) {
System.out.println("Creating CachingValidCrlProvider (this is never displayed)");
this.crlUrl = crlUrl;
this.expectedPublicKey = expectedPublicKey;
crlDownloadState = new CrlDownloadState(failedDownloadBackoffTimeInSeconds, forcedCrlRefreshIntervalInSeconds);
}
The first debug println() is somehow never reached since I cannot find the printed line in stdout.
AFAIK, one of the few ways constructors may yield null is when a static {} block fails somewhere down the line. However, I do not see any (there is one such block in the codebase but not reachable in this scenario).
How do I troubleshoot this issue?
Quote from an answer here on StackOverflow by Jon Skeet:
From section 15.9.4 of the JLS:
The value of a class instance creation expression is a reference to the newly created object of the specified class. Every time the expression is evaluated, a fresh object is created.
So no, it can never return null.
A constructor in Java CANNOT return null. The only case your object can be null is if you didn't call the constructor, or the constructor raised an exception.
EDIT:
As for your code, the most probable possibility IMO is that the code doesn't stop on your assertNotNull(prov), but never reaches it and instead crashes somewhere before. You should try using the debugger/more sysout.
Static Initialization Blocks are executed before anything else, So the code is reached, you just don't know it. I suggest you add a breakpoint in your static block, and use a debugger (included in eclipse or Intellij) to see when it fails. good luck.
Thank you all for the responses. They helped me get to the root cause. As it turned out, there was a mock initialization of this class in another test (there are ~300 existing tests by other people in this codebase).
Because the code uses singletons extensively, my call to new did not actually change anything to the already-initialized object.
I found this thanks to your remarks and hints which made me look in different parts of the codebase, thanks a lot.

What can cause IllegalMonitorStateException from inside a synchronized block?

We hit an extremely surprising exception today. Inside of a synchronized block, we call wait() and it throws IllegalMonitorStateException. What can cause this?
This is happening in well-tested open source code:
http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?view=markup#l222
We eliminated the obvious causes:
are we synchronized on the right variable? Yes, it's muxLock
is it a mutable variable? No, muxLock is final
are we using any weird "-XX:" JVM flags that might affect monitor behavior? No, but we are launching the JVM embedded inside a C++ app via JNI.
is this a strange JVM? No, it's Sun's 1.6.0_25 win/x64 JRE
is this a known JVM bug? Can't find anything relevant at http://bugs.sun.com/bugdatabase
So, I'm trying to think of more far-fetched explanations.
could an uncaught out-of-memory error cause the monitor state to be screwed up? We're looking at this, but we're seeing no evidence of memory errors yet.
UPDATE: (based on comment)
I've also verified from the stacktrace and breakpoint that the thread is indeed inside the synchronized block when the exception is thrown. It's not the case that some other unrelated code is emitting the exception (unless something is REALLY confusing Eclipse!)
The only suspicious thing I see that you are passing a reference to 'this' to some other object in your constructor. Is it possible (in fact, not unlikely) that, through weird re-ordering of things, if some other thread gets that reference to 'this' and calls the method that uses the muxlock, things can go extremely wrong.
The Java Language Specification is pretty specific about this:
An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.
In other words, if another thread gets hold of the 'this' reference before the constructor is finished, the final field 'muxlock' might not be correctly initialized yet. In general, publishing a reference to 'this' before the constructor has finished can be pretty dangerous, especially in threaded situations.
Some potentially useful discussion about such things:
http://madpropellerhead.com/random/20100328-java-final-fields-are-not-as-final-as-you-may-think
For some older, but still useful general discussion of why publishing 'this' in a constructor is a very bad idea in general, see for instance:
http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html
http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?r1=1069292&r2=1135026&diff_format=h
here i can see that timeout was added lately
make sure that startTimeout is > than 0 otherwise you will wait(0) or wait(-n) this probably cause IllegalMonitorStateException
EDIT: Ok above is a disaster But lets try this :
we are in Mux constructor : http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?view=markup
line 176 we create SocketChannelConnectionIO andd pass this after that we break and and different thread takes over .
in constructor of SocketChannelConnectionIO defined here : http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/SocketChannelConnectionIO.java?view=markup
line 112 we register to channel with the new handler().
handler recieaves something on chanel and function let say function handleReadReady is executed we synchronize on muxLock .
now we are still in constructor so object in final is still mutable !!!
let assume it changes , now we have something waiting on different muxLock
One in a million scenario
EDIT
http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?revision=1135026&view=co
Mux(SocketChannel channel,
int role, int initialInboundRation, int maxFragmentSize)
throws IOException
{
this.role = role;
if ((initialInboundRation & ~0x00FFFF00) != 0) {
throw new IllegalArgumentException(
"illegal initial inbound ration: " +
toHexString(initialInboundRation));
}
this.initialInboundRation = initialInboundRation;
this.maxFragmentSize = maxFragmentSize;
//LINE BELOW IS CAUSING PROBLEM it passes this to SocketChannelConnectionIO
this.connectionIO = new SocketChannelConnectionIO(this, channel);
//Lets assume it stops here we are still in constructor
//and we are not in synchronized block
directBuffersUseful = true;
}
now in constructor of SocketChannelConnectionIO
http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/SocketChannelConnectionIO.java?revision=1069292&view=co
SocketChannelConnectionIO(Mux mux, SocketChannel channel)
throws IOException
{
super(mux);
channel.configureBlocking(false);
this.channel = channel;
//Line below we are registering to the channel with mux that is still mutable
//this is the line that actually is causing the problem move that to
// start() and it should work
key = selectionManager.register(channel, new Handler());
}
move this code to start() should work key = selectionManager.register(channel, new Handler()); (i am assuming start is executet when we want to start prosessing)
/**
* Starts processing connection data.
*/
void start() throws IOException {
key = selectionManager.register(channel, new Handler());
key.renewInterestMask(SelectionKey.OP_READ);
}
But it would be much better not to create SocketChannelConnectionIO in the constructor of mux but maybe somewhere after that the same for second constructor creating StreamConnectionIO with this
The answer is in my opinion that its either a bug, or someone changed the object behind the reference despite its being final. If you can reproduce it, I recommend to set a read/write breakpoint on muxlock field to see if it is touched or not. You could check the identityhashcode of the muxlock in the first line of the synchronized block, and before waits and notifies with appropiate log entries or breakpoints. With reflection you can change final references. Quote from http://download.oracle.com/javase/6/docs/api/java/lang/reflect/Field.html:
"If the underlying field is final, the method throws an IllegalAccessException unless setAccessible(true) has succeeded for this field and this field is non-static. Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields, before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field."
Maybe its a bug in eclispe, and during debugging it somehow changes the field. Is it reproducable outside eclispe as well? Put a printstractrace in catch and see what happens.
Member variables are not as final as one would hope to. You should put the synchronized object into a final local variable, first. This does not explain why the member variable is altered, but if it fixes the problem you at least know that the member variable is really modified.

Categories