2016-02-01 96 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()。