title: JVMTI agent crashes
body: <p>I'm working on implementation of eraser data-race detection algorithm as JVMTI agent.
  When I try to run some example inputs to test my code, the JVM crashes, with dumps like the following (may show other stack traces for the same error as well):</p>
  
  <p><code>FATAL ERROR in native method: Using JNIEnv in the wrong thread
      at Proxy.monitor_enter_(Native Method)
      at Proxy.monitor_enter(Proxy.java:30)
      at ex1.LifeThreads.setNeighborThreadChange(LifeThreads.java:36)
      at ex1.LifeThreads.neighbor(LifeThreads.java:425)
      at ex1.LifeThreads.standardItr(LifeThreads.java:321)
      at ex1.LifeThreads.run(LifeThreads.java:462)</code></p>
  
  <p>(This kind of post-mortem trace is possible to obtain with -Xcheck:jni option to Sun JVM)</p>
  
  <p>In the code I do the same kind of instrumentation as shown in various JDK samples (heapViewer, heapTracker, etc. via some proxy java class with native methods). <code>Proxy.monitor_enter_</code> native method is invoked after each <code>monitorenter</code> instruction.</p>
  
  <p>This is the code for monitor_enter_:</p>
  
  <pre><code>void native_monitor_exit(JNIEnv *jni, jclass klass, jthread thread_id, jobject obj)
  {
      scoped_lock( agent::instance()-&gt;jvmti(), agent::instance()-&gt;monitor_ );
          if( agent::instance()-&gt;death_active_)
                  return;
  
      std::string name = agent::instance()-&gt;thread_name( thread_id );
          thread_t* thread = get_thread( thread_id );
          if( thread == 0 )
              return;
          jobject global_ref = agent::instance()-&gt;jni()-&gt;NewGlobalRef( obj );
          if( global_ref == 0 )
                  fatal_error("Out of memory while trying to create new global ref.");
  
      logger::instance()-&gt;level(1) &lt;&lt; "MONITOR ENTER"
                  &lt;&lt; "\n\t" &lt;&lt; "jthread name= " &lt;&lt; name
                  &lt;&lt; "\n\t" &lt;&lt; "thread_t= " &lt;&lt; thread &lt;&lt; " " &lt;&lt; *thread
                  &lt;&lt; "\n\t" &lt;&lt; "monitor gl= " &lt;&lt; global_ref
                  &lt;&lt; std::endl;
  
          thread-&gt;lock( lock(global_ref) );
  }
  </code></pre>
  
  <p>, where <code>scoped_lock</code> basically is a scoped lock for JVMTI Raw Monitor enter/exit,
  <code>thread_t</code> is just a struct wrapping some <code>std::vector</code>, where instance of class <code>lock</code> (that itself merely wraps <code>jobject</code> global reference <code>global_ref</code>) is stored, when <code>thread-&gt;lock( lock(global_ref))</code> is invoked.</p>
  
  <p>JVMTI env. is cached globally in agent singleton, whereas, JNI env, which is thread-local is reloaded each time prior to its use (which is not that efficient, but for now I do not care), as shown below:</p>
  
  <pre><code>    JNIEnv* jni()
  {
      jint res;
      JNIEnv* env = 0;
      res = jvm()-&gt;GetEnv( (void**)&amp;env, JNI_VERSION_1_2 );
      if( res == JNI_EDETACHED )
      {
          res = jvm()-&gt;AttachCurrentThread( (void **)&amp;env, 0 );
          if( res != JNI_OK || env == 0 )
              fatal_error( "ERROR: Unable to create JNIEnv by attach, error=%d\n", res );
      }
          else if( res != JNI_OK || env == 0 )
          fatal_error( "ERROR: Unable to create JNIEnv, error=%d\n", res );
      }
      return env;
  }
  </code></pre>