title: Dexposed crash on ART Runtime
body: <p>I was testing <a href="https://github.com/alibaba/dexposed" rel="nofollow">Dexposed</a> on ART, it crashed randomly at art::ReferenceMapVisitor::VisitQuickFrame().
  I think dexposed may process the stack frames incorrectly:</p>
  
  <pre><code>     .extern artQuickDexposedInvokeHandler
  ENTRY art_quick_dexposed_invoke_handler
      SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
      str     r0, [sp, #0]           @ place proxy method at bottom of frame
      mov     r2, r9                 @ pass Thread::Current
      mov     r3, sp                 @ pass SP
      blx     artQuickDexposedInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
      ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()-&gt;exception_
      add     sp, #16                @ skip r1-r3, 4 bytes padding.
      .cfi_adjust_cfa_offset -16
      cbnz    r2, 1f                 @ success if no exception is pending
      RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
      bx      lr                     @ return on success
  1:
      RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
      DELIVER_PENDING_EXCEPTION
  END art_quick_dexposed_invoke_handler
  </code></pre>
  
  <p>is used in hookMethodNative:</p>
  
  <pre><code>static void com_taobao_android_dexposed_DexposedBridge_hookMethodNative(JNIEnv *env, jclass, jobject java_method......) {
      ArtMethod *art_method = ArtMethod::FromReflectedMethod(soa, java_method);
      ......
      art_method-&gt;SetEntryPointFromQuickCompiledCode((void *) art_quick_dexposed_invoke_handler);
      art_method-&gt;SetAccessFlags((art_method-&gt;GetAccessFlags() &amp; ~kAccNative));
  }
  </code></pre>
  
  <p>The function VisitQuickFrame is in <code>art/runtime/thread.cc</code>, it crashed when accessing <code>map.data_[1]</code> in map.RegWidth() which was retrieved from <code>ArtMethod::GetEntryPointFromQuickCompiledCode</code></p>
  
  <pre><code>private:
  void VisitQuickFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    StackReference&lt;mirror::ArtMethod&gt;* cur_quick_frame = GetCurrentQuickFrame();
    mirror::ArtMethod* m = cur_quick_frame-&gt;AsMirrorPtr();
    mirror::ArtMethod* old_method = m;
    visitor_(reinterpret_cast&lt;mirror::Object**&gt;(&amp;m), 0 /*ignored*/, this);
    if (m != old_method) {
      cur_quick_frame-&gt;Assign(m);
    }
  
    // Process register map (which native and runtime methods don't have)
    if (!m-&gt;IsNative() &amp;&amp; !m-&gt;IsRuntimeMethod() &amp;&amp; !m-&gt;IsProxyMethod()) {
      const uint8_t* native_gc_map = m-&gt;GetNativeGcMap(sizeof(void*));
      CHECK(native_gc_map != nullptr) &lt;&lt; PrettyMethod(m);
      const DexFile::CodeItem* code_item = m-&gt;GetCodeItem();
      DCHECK(code_item != nullptr) &lt;&lt; PrettyMethod(m);  // Can't be nullptr or how would we compile its instructions?
      NativePcOffsetToReferenceMap map(native_gc_map);
      size_t num_regs = std::min(map.RegWidth() * 8,
                                 static_cast&lt;size_t&gt;(code_item-&gt;registers_size_));
      if (num_regs &gt; 0) {
    ......
  </code></pre>
  
  <p>the assemble codes above is copied from <code>art/runtime/arch/arm/quick_entrypoints_arm.S</code>:</p>
  
  <pre><code>    /*
       * Called by managed code that is attempting to call a method on a proxy class. On entry
       * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
       * frame size of the invoked proxy method agrees with a ref and args callee save frame.
       */
       .extern artQuickProxyInvokeHandler
  ENTRY art_quick_proxy_invoke_handler
      SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
      str     r0, [sp, #0]           @ place proxy method at bottom of frame
      mov     r2, r9                 @ pass Thread::Current
      mov     r3, sp                 @ pass SP
      blx     artQuickProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
      ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()-&gt;exception_
      add     sp, #16                @ skip r1-r3, 4 bytes padding.
      .cfi_adjust_cfa_offset -16
      cbnz    r2, 1f                 @ success if no exception is pending
      RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
      bx      lr                     @ return on success
  1:
      RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
      DELIVER_PENDING_EXCEPTION
  END art_quick_proxy_invoke_handler
  </code></pre>
  
  <p>Does it save/restore the stack frame correctly? </p>
  
  <p>Crash backtrace:</p>
  
  <pre><code>*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
  Build fingerprint: 'google/hammerhead/hammerhead:5.1.1/LMY48I/2074855:user/release-keys'
  Revision: '11'
  ABI: 'arm'
  pid: 16711, tid: 16727, name: Binder_1  &gt;&gt;&gt; joker.li.dexposeltest &lt;&lt;&lt;
  signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xd101755d
      r0 b487a600  r1 71db5d14  r2 71db5d14  r3 711e23a8
      r4 b3749ba8  r5 d101755c  r6 b47faa70  r7 001c1448
      r8 b3749a00  r9 c52d968f  sl b47f83e8  fp b4623ad1
      ip fffffaa8  sp b37499b8  lr 0000fff8  pc b4732696  cpsr a0070030
      d0  0000000000000000  d1  0000000000000000
      d2  0000000000000000  d3  0000000000000000
      d4  b4a23400b4a24800  d5  b4a25800b4a24c00
      d6  b4a27400aec3b400  d7  b4a2a800b4a28800
      d8  0000000000001a50  d9  0000000000000000
      d10 0000000000000000  d11 0000000000000000
      d12 0000000000000000  d13 0000000000000000
      d14 0000000000000000  d15 0000000000000000
      d16 be9b62b000000000  d17 0000000000004000
      d18 0000000000004000  d19 0000000000000000
      d20 00000000c8baf094  d21 00000000003d3dcb
      d22 70f7634070f76340  d23 0000000004352858
      d24 0000000000014d1e  d25 000000000000039d
      d26 00000000000150bb  d27 00000000000d0e49
      d28 00000000044236a1  d29 0000000000004000
      d30 0000000000000001  d31 0000000000000000
      scr 80000011
  
  backtrace:
      #00 pc 0023d696  /system/lib/libart.so (art::ReferenceMapVisitor&lt;art::RootCallbackVisitor&gt;::VisitQuickFrame()+333)
      #01 pc 0023dcb9  /system/lib/libart.so (art::ReferenceMapVisitor&lt;art::RootCallbackVisitor&gt;::VisitFrame()+224)
      #02 pc 00231959  /system/lib/libart.so (art::StackVisitor::WalkStack(bool)+276)
      #03 pc 002336b3  /system/lib/libart.so (art::Thread::VisitRoots(void (*)(art::mirror::Object**, void*, art::RootInfo const&amp;), void*)+994)
      #04 pc 0012db67  /system/lib/libart.so (art::gc::collector::CheckpointMarkThreadRoots::Run(art::Thread*)+126)
      #05 pc 00240455  /system/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*)+296)
      #06 pc 0012c7b1  /system/lib/libart.so (art::gc::collector::MarkSweep::MarkRootsCheckpoint(art::Thread*, bool)+96)
      #07 pc 0013021d  /system/lib/libart.so (art::gc::collector::MarkSweep::PreCleanCards()+172)
      #08 pc 00130393  /system/lib/libart.so (art::gc::collector::MarkSweep::MarkingPhase()+126)
      #09 pc 00130479  /system/lib/libart.so (art::gc::collector::MarkSweep::RunPhases()+176)
      #10 pc 00127067  /system/lib/libart.so (art::gc::collector::GarbageCollector::Run(art::gc::GcCause, bool)+246)
      #11 pc 001460af  /system/lib/libart.so (art::gc::Heap::CollectGarbageInternal(art::gc::collector::GcType, art::gc::GcCause, bool)+1406)
      #12 pc 00201357  /system/lib/libart.so (art::VMDebug_countInstancesOfClass(_JNIEnv*, _jclass*, _jclass*, unsigned char)+294)
      #13 pc 0001a3ed  /data/dalvik-cache/arm/system@framework@boot.oat
  </code></pre>