JDK-4822846 : AsyncGetCallTrace: guarantee(get_thread() == thread, "must be the same thread...
  • Type: Bug
  • Status: Resolved
  • Resolution: Fixed
  • Component: vm-legacy
  • Sub-Component: jvmpi
  • Priority: P4
  • Affected Version: 1.4.1,1.4.2
  • OS: solaris_8
  • CPU: sparc
  • Submit Date: 2003-02-24
  • Updated Date: 2003-07-18
  • Resolved Date: 2003-06-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
1.4.2_02 02Resolved
Related Reports
Relates :  
###@###.### 2003-02-24

Stress testing of the AsyncGetCallTrace() interface has exposed an
intermittent guarantee failure:

# guarantee(get_thread() == thread, "must be the same thread, quickly")
# Error ID : src/share/vm/runtime/threadLocalStorage.cp, 66

During JNI DetachCurrentThread(), the ThreadLocalStorage reference for
exiting JavaThread is set to NULL. However, an AsyncGetCallTrace() call
causes the cached thread info to be refreshed and we fail the guarantee.
Here is a partial stack trace:

  [29] report_fatal(file_name = 0xfefd20ca "/work/ws/hotspot/main/baseline-exp/s
rc/share/vm/runtime/threadLocalStorage.cpp", line_no = 66, format = 0xfefd2119 "
must be the same thread, quickly", ...), line 139 in "debug.cpp"
  [30] ThreadLocalStorage::set_thread(thread = (nil)), line 66 in "threadLocalSt
  [31] Thread::delete_thread_and_TLS_current(this = 0x3e440), line 88 in "thread
  [32] jni_DetachCurrentThread(vm = 0xff08a304), line 2501 in "jni.cpp"
  [33] main(0xffbef208, 0xffbef2a4, 0xffbef2b4, 0x28800, 0x0, 0x0), at 0x11d48

The complete stack trace for the java_g crash is attached as threads.log.335.
In this particular failure, the VM crashed will trying to print out the
message about the guarantee failure, but that does not really obscure the
original failure.

The failure reproduces with a less informative message with the java cmd:

# Error ID: 5448524541442C4F43414C33544F524147450E4350500042

The ErrorID maps to: threadLocalStorage.cpp, 66

Here is a snippet of the stack trace for the java cmd crash:

  [6] report_fatal(0xfefdbc35, 0x42, 0xfefdbc84, 0xfeff4000, 0xfa17fef0, 0x0), a
t 0xfee34a7c
  [7] ThreadLocalStorage::set_thread(0x0, 0xffffffc4, 0xff013178, 0xffff8000, 0x
7f, 0x0), at 0xfec522a4
  [8] _start(0xe3010, 0xfebf0c00, 0x0, 0x0, 0x0, 0x0), at 0xfecc5e4c

The complete stack trace for the java cmd crash is attached as threads.log.40.

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.4.2_02 tiger FIXED IN: 1.4.2_02 tiger INTEGRATED IN: 1.4.2_02 tiger tiger-b08

EVALUATION ###@###.### 2003-02-24 AsyncGetCallTrace() creates a ResetNoHandleMark object on entry. The constructor for this object calls JavaThread::current() which sends us down the path of refreshing the thread cache. If we happen to receive a SIGPROF signal at the right point in set_thread(), then we will refresh the thread cache after set_thread() has cleared the cache entry. This will cause the guarantee() to fail because the thread cache won't match the current "set" value. The ResetNoHandleMark object should not have been created so early so I need to move it to just before it is needed. My testing showed one more problem with JavaThreads. I needed to add a check for JavaThread::is_exiting() to make sure that we didn't get caught in the window between the start of JavaThread::exit() and being taken off the threads list.

SUGGESTED FIX ###@###.### 2003-03-12 Here is the context diff for the suggested fix: ------- src/share/vm/prims/forte.cpp ------- *** /tmp/geta25695 Wed Mar 12 16:49:01 2003 --- /tmp/getb25695 Wed Mar 12 16:49:01 2003 *************** *** 196,201 **** --- 196,202 ---- // static void forte_fill_call_trace_given_top(JavaThread* thd, JVMPI_CallTrace* trace, int depth, frame top_frame) { + ResetNoHandleMark rnhm; frame walkframe; methodOop method; *************** *** 301,312 **** extern "C" { void AsyncGetCallTrace(JVMPI_CallTrace *trace, jint depth, void* ucontext) { - ResetNoHandleMark rnhm; - JavaThread* thread; ucontext_t* uc = (ucontext_t*) ucontext; ! if (!((trace->env_id) && (thread = JavaThread::thread_from_jni_environment(trace->env_id)))) { trace->num_frames = 0; return; } --- 302,314 ---- extern "C" { void AsyncGetCallTrace(JVMPI_CallTrace *trace, jint depth, void* ucontext) { JavaThread* thread; ucontext_t* uc = (ucontext_t*) ucontext; ! if (trace->env_id == NULL || ! (thread = JavaThread::thread_from_jni_environment(trace->env_id)) == NULL || ! thread->is_exiting()) { ! // bad env_id, thread has exited or thread is exiting so return no frames trace->num_frames = 0; return; }