2016-02-01 94 views
1

我在ART上測試Dexposed,它隨機在art :: ReferenceMapVisitor :: VisitQuickFrame()中崩潰。 我認爲dexposed可以處理堆棧幀錯誤:ART Runtime上的Dexposed崩潰

 .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()->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 

用於在hookMethodNative:

static void com_taobao_android_dexposed_DexposedBridge_hookMethodNative(JNIEnv *env, jclass, jobject java_method......) { 
    ArtMethod *art_method = ArtMethod::FromReflectedMethod(soa, java_method); 
    ...... 
    art_method->SetEntryPointFromQuickCompiledCode((void *) art_quick_dexposed_invoke_handler); 
    art_method->SetAccessFlags((art_method->GetAccessFlags() & ~kAccNative)); 
} 

功能VisitQuickFrame是在art/runtime/thread.cc,它在map.RegWidth(),它是訪問map.data_[1]時墜毀檢索自ArtMethod::GetEntryPointFromQuickCompiledCode

private: 
void VisitQuickFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 
    StackReference<mirror::ArtMethod>* cur_quick_frame = GetCurrentQuickFrame(); 
    mirror::ArtMethod* m = cur_quick_frame->AsMirrorPtr(); 
    mirror::ArtMethod* old_method = m; 
    visitor_(reinterpret_cast<mirror::Object**>(&m), 0 /*ignored*/, this); 
    if (m != old_method) { 
    cur_quick_frame->Assign(m); 
    } 

    // Process register map (which native and runtime methods don't have) 
    if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) { 
    const uint8_t* native_gc_map = m->GetNativeGcMap(sizeof(void*)); 
    CHECK(native_gc_map != nullptr) << PrettyMethod(m); 
    const DexFile::CodeItem* code_item = m->GetCodeItem(); 
    DCHECK(code_item != nullptr) << 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<size_t>(code_item->registers_size_)); 
    if (num_regs > 0) { 
    ...... 

上述彙編代碼複製自art/runtime/arch/arm/quick_entrypoints_arm.S

/* 
    * 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()->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 

它是否正確保存/恢復堆棧幀?

崩潰回溯:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 
Build fingerprint: 'google/hammerhead/hammerhead:5.1.1/LMY48I/2074855:user/release-keys' 
Revision: '11' 
ABI: 'arm' 
pid: 16711, tid: 16727, name: Binder_1 >>> joker.li.dexposeltest <<< 
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<art::RootCallbackVisitor>::VisitQuickFrame()+333) 
    #01 pc 0023dcb9 /system/lib/libart.so (art::ReferenceMapVisitor<art::RootCallbackVisitor>::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&), 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/[email protected]@boot.oat 

回答

0

1,藝術鉤打破現有技術的堆棧佈局:

class ArtMethod{ 

    ... 

    // Total size in bytes of the frame 

    size_t frame_size_in_bytes_; 

    ... 

} 

「的frame_size_in_bytes是對應的快速幀的幀的部分也就是。 ,它是從ArtMethod *存儲到下一個Quick幀的幀的大小,在內部,JNI幀被註冊到該地址,並且幀大小被用於棧走。 --- https://code.google.com/p/android/issues/detail?id=79204

因此,運行時在堆棧中獲取了一個錯誤的ArtMethod指針。

2,StackVisitor :: WalkStack()檢查編譯後的代碼是否在dex中有相應的操作碼。

藝術掛鉤應該修復這些或避免調用WalkStack()。