JDK-4998314 : compute_compiled_exc_handler() called with pending exception
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 1.4.2_02
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2004-02-20
  • Updated: 2004-06-11
  • Resolved: 2004-04-06
See comments section; RE might decide this belongs in compiler2
if code is specific to c2 (opto/runtime). Filing under hotspot/runtime_system
for initial evaluation.

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.4.2_05 generic tiger-beta2 FIXED IN: 1.4.2_05 tiger-beta2 INTEGRATED IN: 1.4.2_05 tiger-b46 tiger-beta2 VERIFIED IN: 1.4.2_05

SUGGESTED FIX ###@###.### 2004-03-31 Cleanup pending exceptions after exit from VM (after return from handle_exception_C_helper()): overwrite a processed exception (if it is not ThreadDeath) with a pending exception and process it (call handle_exception_C_helper() again). http://analemma.sfbay.sun.com/net/prt-archiver.sfbay/export2/archived_workspaces/main/c2_baseline/2004/20040329193754.kvn.4895131/workspace/webrevs/webrev-2004.03.29/index.html src/share/vm/opto/runtime.cpp *************** *** 1046,1057 **** debug_only(NoHandleMark __hm;) nmethod* nm = NULL; address handler_address = NULL; ! { // Enter the VM ResetNoHandleMark rnhm; handler_address = handle_exception_C_helper(thread, nm); ! } // Back in java: Use no oops, DON'T safepoint // Now check to see if the handler we are returning is in a now --- 1046,1070 ---- debug_only(NoHandleMark __hm;) nmethod* nm = NULL; address handler_address = NULL; ! bool overwrite_exception = false; ! do { // Enter the VM ResetNoHandleMark rnhm; handler_address = handle_exception_C_helper(thread, nm); ! overwrite_exception = false; ! if (thread->has_pending_exception()) { ! // A pending exception could be created during exit from VM (4998314). ! // If a processed exception is not ThreadDeath overwrite it with ! // the pending exception and process it. ! if (!thread->exception_oop()->is_a(SystemDictionary::threaddeath_klass())) { ! thread->set_exception_oop(thread->pending_exception()); ! overwrite_exception = true; ! } ! thread->clear_pending_exception(); // Cleanup a pending exception. ! } ! } while (overwrite_exception); ! // Back in java: Use no oops, DON'T safepoint // Now check to see if the handler we are returning is in a now

EVALUATION From looking at this in the SA I believe the what occurs is this. A thread is has the following call stack java/net/SocketInputStream.socketRead0 java/net/SocketInputStream.read([BII)I IE/Iona/Orbix2/CORBA/SocketConnection IE/Iona/Orbix2/CORBA/ClientConnection.run() java/lang/Thread.run() at least the top 2 frames are compiled. socketRead0 is an native method, though I don't think that's required for this bug to occur. socketRead0 returns with an exception, java.net.SocketException: Socket closed. This is the oop at 0xd708bc38 in the core file. The compiled native wrapper dispatches the exception correctly and eventually calls into the ExceptionBlob which calls OptoRuntime::handle_exception_C which is a JRT_ENTRY, meaning it can safepoint on it's way out of the VM. The exception lookup code decides that it should return to the exception handler of the called compiled frame, read. On the way out of the VM a safepoint occurs and Thread.stop() is called in another thread on this thread. This installs an instance of java/lang/ThreadDeath in the pending async exception field. This is oop 0xd7087d98 in the core file. Part of the logic in JavaThread::send_thread_stop is to deoptimize the caller frame under certain conditions, namely if the last frame is a runtime stub or a safepoint blob. In this case the last frame is the exception blob which is neither of these. So the ThreaDeath get's installed in pending exception and we return to the compiled Java code. C2's exception dispatch path keeps the current exception in the thread's exception_oop field. So know the thread has both an exception the exception_oop and in the pending_exception field. When it reenters the exception blob from SocketInputStream.read it calls compute_compiled_exc_handler which eventually dies when it installs the ExceptionMark because the pending exception is set. So the straightforward fix is to add the exception blob to things that cause the caller frame to deopt in send_thread_stop. ###@###.### 2004-03-02 ###@###.### 2004-03-23 The small test (in the comments) confirms this evaluation.