chromium引發的crash

chromium作爲瀏覽器架構,除提供給瀏覽器做渲染引擎之外,還作爲android平臺上webview的主要構成部分,提供給包括瀏覽器等諸多web app作爲數據加載及渲染只用;

經常遇到某第三方軟件調用webview過程中出現crash,如下一例做參考,調試定位native webview 的crash。

遇到一個crash問題,第三方應用com.whty.wicity.china, monkey過程中出現了crash,可復現,crash log如下:
ABI: 'arm'
pid: 1043, tid: 1531, name: WorkerPool/1531  >>> com.whty.wicity.china <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    r0 00000000  r1 00000000  r2 80000000  r3 00000000
    r4 ffffffff  r5 a0113220  r6 aa120ae0  r7 a0113220
    r8 00000000  r9 00000001  sl aa13c380  fp 00000000
    ip ac649d88  sp 8497f3f8  lr ac611c09  pc ac5dab1c  cpsr 60070030
    d0  6974747568732073  d1  3a6e776f6420676e
    d2  0000000000000000  d3  0000000000000000
    d4  e4dc8b4d3b1d2cb7  d5  551baf3358041d64
    d6  e4740430bf0cabe7  d7  044b8d39302f0ef3
    d8  0000000000000000  d9  0000000000000000
    d10 0000000000000000  d11 0000000000000000
    d12 0000000000000000  d13 0000000000000000
    d14 0000000000000000  d15 0000000000000000
    d16 0000000000000000  d17 0000000000000000
    d18 0000000000000000  d19 0000000000000000
    d20 400140e308f51835  d21 4000000000000000
    d22 3fd999999997fa04  d23 3fe5555555555593
    d24 8f97f8788f97f7e0  d25 8f97f9a88f97f910
    d26 0000000200000002  d27 0000000200000002
    d28 0000000200000002  d29 0000000200000002
    d30 0000000600000006  d31 0000000003424c7c
    scr 28000093


backtrace:
    #00 pc 00018b1c  /system/lib/libc.so (strlen+71)
    #01 pc 0004fc05  /system/lib/libc.so (__strlen_chk+4)
    #02 pc 0032cf4d  /system/lib/libart.so (_ZN3art6Thread6AttachEPKcbP8_jobjectb+136)
    #03 pc 00318217  /system/lib/libart.so (_ZN3art7Runtime19AttachCurrentThreadEPKcbP8_jobjectb+66)
    #04 pc 0023bf9b  /system/lib/libart.so (_ZN3art3JII27AttachCurrentThreadInternalEP7_JavaVMPP7_JNIEnvPvb+330)
    #05 pc 01a6f073  /system/app/webview/webview.apk (offset 0x80d000)
    #06 pc 00704767  /system/app/webview/webview.apk (offset 0x80d000)
    #07 pc 0070f0c1  /system/app/webview/webview.apk (offset 0x80d000)
    #08 pc 0070f581  /system/app/webview/webview.apk (offset 0x80d000)
    #09 pc 0070ec23  /system/app/webview/webview.apk (offset 0x80d000)
    #10 pc 0070f999  /system/app/webview/webview.apk (offset 0x80d000)
    #11 pc 0070f7bd  /system/app/webview/webview.apk (offset 0x80d000)
    #12 pc 01a9e64b  /system/app/webview/webview.apk (offset 0x80d000)
    #13 pc 01aa17af  /system/app/webview/webview.apk (offset 0x80d000)
    #14 pc 01a9e493  /system/app/webview/webview.apk (offset 0x80d000)
    #15 pc 00047133  /system/lib/libc.so (_ZL15__pthread_startPv+22)
    #16 pc 00019e5d  /system/lib/libc.so (__start_thread+6)


調試如下:
1. 請測試同事提供corefile及symbol文件
2. 進入prebuild的gcc下的gdb,加載
set  solib-search-path /symbols/system/lib/
file symbols/system/bin/app_process32
core-file corefile/core-1043****
加載模塊代碼 directory + code
打出調用棧如下:
(gdb) bt
#0  strlen () at bionic/libc/arch-arm/cortex-a15/bionic/strlen.S:100
#1  0xac611c08 in __strlen_chk (s=0x0, s_len=4294967295) at bionic/libc/bionic/__strlen_chk.cpp:59
#2  0xa9f41f50 in strlen (s=0x0) at bionic/libc/include/string.h:324
#3  length (__s=<optimized out>) at external/libcxx/include/string:640
#4  operator<<<std::__1::char_traits<char> > (__os=..., __str=<optimized out>) at external/libcxx/include/ostream:894
#5  art::Thread::Attach (thread_name=0x0, as_daemon=<optimized out>, thread_group=<optimized out>, create_peer=<optimized out>) at art/runtime/thread.cc:756
#6  0xa9f2d21a in art::Runtime::AttachCurrentThread (this=<optimized out>, thread_name=0x0, as_daemon=false, thread_group=0x0, create_peer=true) at art/runtime/runtime.cc:1499
#7  0xa9e50f9e in art::JII::AttachCurrentThreadInternal (vm=<optimized out>, p_env=0x8497f4fc, raw_args=<optimized out>, as_daemon=false) at art/runtime/java_vm_ext.cc:401
#8  0x98a66074 in AttachCurrentThread (thr_args=0x0, p_env=0x8497f4fc, this=<optimized out>) at ../../third_party/android_tools/ndk/platforms/android-16/arch-arm/usr/include/jni.h:1091
#9  base::android::AttachCurrentThread () at ../../base/android/jni_android.cc:46
#10 0x976fb76a in net::android::VerifyX509CertChain (cert_chain=..., auth_type=..., host=..., status=status@entry=0x8497f584, is_issued_by_known_root=is_issued_by_known_root@entry=0x8dc64978, 
    verified_chain=verified_chain@entry=0x8497f590) at ../../net/android/network_library.cc:32
#11 0x977060c4 in net::(anonymous namespace)::VerifyFromAndroidTrustManager (cert_bytes=..., hostname=..., verify_result=verify_result@entry=0x8dc6495c) at ../../net/cert/cert_verify_proc_android.cc:39
#12 0x97706584 in net::CertVerifyProcAndroid::VerifyInternal (this=<optimized out>, cert=<optimized out>, hostname=..., ocsp_response=..., flags=14, crl_set=0x0, additional_trust_anchors=..., 
    verify_result=0x8dc6495c) at ../../net/cert/cert_verify_proc_android.cc:180
#13 0x97705c24 in net::CertVerifyProc::Verify (this=0xa2bac420, cert=0x84b37780, hostname=..., ocsp_response=..., flags=14, flags@entry=6, crl_set=0x0, additional_trust_anchors=..., 
    verify_result=verify_result@entry=0x8dc6495c) at ../../net/cert/cert_verify_proc.cc:252
#14 0x9770699c in net::DoVerifyOnWorkerThread (verify_proc=..., cert=..., hostname=..., ocsp_response=..., flags=6, crl_set=..., additional_trust_anchors=..., error=0x8dc64958, result=0x8dc6495c)
    at ../../net/cert/multi_threaded_cert_verifier.cc:242
#15 0x977067be in Run<scoped_refptr<net::CertVerifyProc> const&, scoped_refptr<net::X509Certificate> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int const&, scoped_refptr<net::CRLSet> const&, std::__1::vector<scoped_refptr<net::X509Certificate>, std::__1::allocator<scoped_refptr<net::X509Certificate> > > const&, int* const&, net::CertVerifyResult* const&> (this=<synthetic pointer>) at ../../base/bind_internal.h:159
#16 MakeItSo<scoped_refptr<net::CertVerifyProc> const&, scoped_refptr<net::X509Certificate> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int const&, scoped_refptr<net::CRLSet> const&, std::__1::vector<scoped_refptr<net::X509Certificate>, std::__1::allocator<scoped_refptr<net::X509Certificate> > > const&, int* const&, net::CertVerifyResult* const&> (runnable=...) at ../../base/bind_internal.h:311
#17 base::internal::Invoker<base::IndexSequence<0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u>, base::internal::BindState<base::internal::RunnableAdapter<void (*)(scoped_refptr<net::CertVerifyProc> const&, scoped_refptr<net::X509Certificate> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int, scoped_refptr<net::CRLSet> const&, std::__1::vector<scoped_refptr<net::X509Certificate>, std::__1::allocator<scoped_refptr<net::X509Certificate> > > const&, int*, net::CertVerifyResult*)>, void (scoped_refptr<net::CertVerifyProc> const&, scoped_refptr<net::X509Certificate> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int, scoped_refptr<net::CRLSet> const&, std::__1::vector<scoped_refptr<net::X509Certificate>, std::__1::allocator<scoped_refptr<net::X509Certificate> > > const&, int*, net::CertVerifyResult*), scoped_refptr<net::CertVerifyProc> const&, scoped_refptr<net::X509Certificate> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int&, scoped_refptr<net::CRLSet> const&, std::__1::vector<scoped_refptr<net::X509Certificate>, std::__1::allocator<scoped_refptr<net::X509Certificate> > > const&, int*, net::CertVerifyResult*>, base::internal::InvokeHelper<false, void, base::internal::RunnableAdapter<void (*)(scoped_refptr<net::CertVerifyProc> const&, scoped_refptr<net::X509Certificate> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int, scoped_refptr<net::CRLSet> const&, std::__1::vector<scoped_refptr<net::X509Certificate>, std::__1::allocator<scoped_refptr<net::X509Certificate> > > const&, int*, net::CertVerifyResult*)> >, void ()>::Run(base::internal::BindStateBase*) (base=<optimized out>) at ../../base/bind_internal.h:364
#18 0x98a9564c in Run (this=0x8dc648d4) at ../../base/callback.h:397
#19 base::(anonymous namespace)::PostTaskAndReplyRelay::Run (this=0x8dc648b8) at ../../base/threading/post_task_and_reply_impl.cc:43
#20 0x98a987b0 in Run (this=0x8497f8a0) at ../../base/callback.h:397
#21 base::(anonymous namespace)::WorkerThread::ThreadMain (this=0x86d57d18) at ../../base/threading/worker_pool_posix.cc:93
#22 0x98a95494 in base::(anonymous namespace)::ThreadFunc (params=<optimized out>) at ../../base/threading/platform_thread_posix.cc:70
#23 0xac609134 in __pthread_start (arg=0x8497f920) at bionic/libc/bionic/pthread_create.cpp:198
#24 0xac5dbe5e in __start_thread (fn=0x80000000, arg=0x0) at bionic/libc/bionic/clone.cpp:41




分析:
1. 在當前f 0幀,list顯示源碼,找到100行:
(gdb) list
95     ands    ip, ip, #0x80808080
96     bne     .L_zero_in_second_register
97
98     .p2align 2
99 .L_mainloop:
100     ldrd    r2, r3, [r1], #8
101
102     pld     [r1, #64]
103
104     sub     ip, r2, #0x01010101


2. disassemble
Dump of assembler code for function strlen:
   0xac5daad4 <+0>: pld [r0]
   0xac5daad8 <+4>: mov r1, r0
   0xac5daada <+6>: ands.w r3, r0, #7
   0xac5daade <+10>: beq.n 0xac5dab1c <strlen+72>
   0xac5daae0 <+12>: rsb r3, r3, #8
   0xac5daae4 <+16>: movs.w r12, r3, lsl #31
   0xac5daae8 <+20>: beq.n 0xac5daaf0 <strlen+28>
   0xac5daaea <+22>: ldrb.w r2, [r1], #1
   0xac5daaee <+26>: cbz r2, 0xac5dab42 <strlen+110>
   0xac5daaf0 <+28>: bcc.n 0xac5dab04 <strlen+48>
   0xac5daaf2 <+30>: ands.w r12, r3, #2
   0xac5daaf6 <+34>: beq.n 0xac5dab04 <strlen+48>
   0xac5daaf8 <+36>: ldrb.w r2, [r1], #1
   0xac5daafc <+40>: cbz r2, 0xac5dab42 <strlen+110>
   0xac5daafe <+42>: ldrb.w r2, [r1], #1
   0xac5dab02 <+46>: cbz r2, 0xac5dab42 <strlen+110>
   0xac5dab04 <+48>: tst.w r3, #4
   0xac5dab08 <+52>: beq.n 0xac5dab1c <strlen+72>
   0xac5dab0a <+54>: ldr.w r3, [r1], #4
   0xac5dab0e <+58>: sub.w r12, r3, #16843009 ; 0x1010101
   0xac5dab12 <+62>: bic.w r12, r12, r3
   0xac5dab16 <+66>: ands.w r12, r12, #2155905152 ; 0x80808080
   0xac5dab1a <+70>: bne.n 0xac5dab76 <strlen+162>
=> 0xac5dab1c <+72>: ldrd r2, r3, [r1], #8
   0xac5dab20 <+76>: pld [r1, #64] ; 0x40
   0xac5dab24 <+80>: sub.w r12, r2, #16843009 ; 0x1010101


3. info register 顯示寄存器信息
r0             0x0 0
r1             0x0 0
r2             0x80000000 2147483648
r3             0x0 0
r4             0xffffffff 4294967295
r5             0xa0113220 2685481504
r6             0xaa120ae0 2853309152
r7             0xa0113220 2685481504
r8             0x0 0
r9             0x1 1
r10            0xaa13c380 2853421952
r11            0x0 0
r12            0xac649d88 2892275080
sp             0x8497f3f8 0x8497f3f8
lr             0xac611c09 -1402921975
pc             0xac5dab1c 0xac5dab1c <strlen+72>
cpsr           0x60070030 1611071536


4. 追蹤上一幀變量傳入 f 1:
54 * }
55 *
56 * or anytime strlen reads beyond an object boundary.
57 */
58 extern "C" size_t __strlen_chk(const char* s, size_t s_len) {
59   size_t ret = strlen(s);
60
61   if (__predict_false(ret >= s_len)) {
62     __fortify_chk_fail("strlen: prevented read past end of buffer", 0);
63   }
即59行,計算strlen(s),p 一下s,顯示
(gdb) p s
$1 = 0x0
s爲空地址,導致的後邊strlen的crash


5. 繼續追蹤上一層 f 2,string.h文件
08__BIONIC_FORTIFY_INLINE
309size_t strlen(const char *s) {
310    size_t bos = __bos(s);
311
312#if !defined(__clang__)
313    // Compiler doesn't know destination size. Don't call __strlen_chk
314    if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
315        return __builtin_strlen(s);
316    }
317
318    size_t slen = __builtin_strlen(s);
319    if (__builtin_constant_p(slen)) {
320        return slen;
321    }
322#endif /* !defined(__clang__) */
323
324    return __strlen_chk(s, bos);


chromium走的clang編譯器,所以直接調到__strlen_chk(s, bos), s=0x0,爲傳入參數,繼續向上追蹤s的來源


6. 進入f3
 static inline size_t length(const char_type* __s) {return strlen(__s);}
入參爲內聯函數length的入參,繼續向上;


7. 進入f4
892 operator<<(basic_ostream<char, _Traits>& __os, const char* __str)
893 {
894     return _VSTD::__put_character_sequence(__os, __str, _Traits::length(__str));
895 }
s來自const char* __str,也就是最後一個參數,還要繼續上行


8. 進入f5
745Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group,
746                       bool create_peer) {
747  Runtime* runtime = Runtime::Current();
748  if (runtime == nullptr) {
749    LOG(ERROR) << "Thread attaching to non-existent runtime: " << thread_name;
750    return nullptr;
751  }
752  Thread* self;
753  {
754    MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
755    if (runtime->IsShuttingDownLocked()) {
756      LOG(WARNING) << "Thread attaching while runtime is shutting down: " << thread_name;
757      return nullptr;
758    } else {
759      Runtime::Current()->StartThreadBirth();
760      self = new Thread(as_daemon);
761      bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
762      Runtime::Current()->EndThreadBirth();
763      if (!init_success) {
764        delete self;
765        return nullptr;
766      }
767    }
768  }


756行, LOG打印, thread_name就是後面的s, 打印p thread_name
(gdb) p thread_name
$3 = 0x0
下面要檢查爲什麼thread_name = 0x0;我們看到thread_name就是attach的入參,中間沒有賦值;因此繼續向上追溯


9. 進入f6 ,沒有變量修改,直接透傳,進入f7
f 6
1496 bool Runtime::AttachCurrentThread(const char* thread_name, bool as_daemon, jobject thread_group,
1497                                   bool create_peer) {
1498   ScopedTrace trace(__FUNCTION__);
1499   return Thread::Attach(thread_name, as_daemon, thread_group, create_peer) != nullptr;
1500 }




f7
367  static jint AttachCurrentThreadInternal(JavaVM* vm, JNIEnv** p_env, void* raw_args, bool as_daemon) {
368    if (vm == nullptr || p_env == nullptr) {
369      return JNI_ERR;
370    }
371
372    // Return immediately if we're already attached.
373    Thread* self = Thread::Current();
374    if (self != nullptr) {
375      *p_env = self->GetJniEnv();
376      return JNI_OK;
377    }
378
379    Runtime* runtime = reinterpret_cast<JavaVMExt*>(vm)->GetRuntime();
380
381    // No threads allowed in zygote mode.
382    if (runtime->IsZygote()) {
383      LOG(ERROR) << "Attempt to attach a thread in the zygote";
384      return JNI_ERR;
385    }
386
387    JavaVMAttachArgs* args = static_cast<JavaVMAttachArgs*>(raw_args);
388    const char* thread_name = nullptr;
389    jobject thread_group = nullptr;
390    if (args != nullptr) {
391      if (IsBadJniVersion(args->version)) {
392        LOG(ERROR) << "Bad JNI version passed to "
393                   << (as_daemon ? "AttachCurrentThreadAsDaemon" : "AttachCurrentThread") << ": "
394                   << args->version;
395        return JNI_EVERSION;
396      }
397      thread_name = args->name;
398      thread_group = args->group;
399    }
400
401    if (!runtime->AttachCurrentThread(thread_name, as_daemon, thread_group,
402                                      !runtime->IsAotCompiler())) {
403      *p_env = nullptr;
404      return JNI_ERR;
405    } else {
406      *p_env = Thread::Current()->GetJniEnv();
407      return JNI_OK;
408    }
409  }
410};


文件java_vm_ext.cc中401行傳入的thread_name, 爲null,從代碼上看thread_name爲空有2種情況:
A. thread_name = args->name 爲空
B. args 爲空導致const char* thread_name = nullptr 未進入後面的賦值語句。
因此繼續向上追溯;檢查args 也就是raw_args的值;
由於raw_args也就是AttachCurrentThreadInternal(JavaVM* vm, JNIEnv** p_env, void* raw_args, bool as_daemon) 入參的void* raw_args
因此向上追溯
328  static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
329    return AttachCurrentThreadInternal(vm, p_env, thr_args, false);
330  }
AttachCurrentThread封裝了AttachCurrentThreadInternal,thr_args透傳;


10. 進入f 8
90     jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)
1091     { return functions->AttachCurrentThread(this, p_env, thr_args); }
這裏是個jni映射,繼續追


11. 進入f 9
#9  base::android::AttachCurrentThread () at ../../base/android/jni_android.cc:46
46   jint ret = g_jvm->AttachCurrentThread(&env, NULL);


可以看到AttachCurrentThread入參直接傳入的NULL,也就是f7幀,args爲空;因此thread_name賦值而爲空,且使用了clang編譯器,進行 __strlen_chk,導致後面log打印的時候的crash;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章