[Linux] 卸載 DLL 時,libcurl 的背景 thread 造成 crash?

[Linux] 卸載 DLL 時,libcurl 的背景 thread 造成 crash?

最近一直在查一個問題,

專案的程式在 unload 再 reload 某個 libX.so (化名)之後,

就很容易當掉 (crash)…

而且這個問題只會發生在 libX 在做網路連線,但連線逾時 (timeout) 的情況下…

如果網路連線正常,reload 是不會有問題的…

 

查了半天,目前是懷疑 libcurl 造成的問題…

因為 libX.so 會用 libcurl 做 HTTP 查詢,

從 curl_global_cleanup 說明網頁來看,它不是 thread-safe 的,

而且看來 libcurl 會自己偷偷建 thread,

如果 libX.so 被 unload 時,libcurl 自建的 thread 還在時,可能會 crash:

curl_global_cleanup does not block waiting for any libcurl-created threads to terminate (such as threads used for name resolving). If a module containing libcurl is dynamically unloaded while libcurl-created threads are still running then your program may crash or other corruption may occur. We recommend you do not run libcurl from any module that may be unloaded dynamically.

 

用 gdb 觀察一下 thread 建立的情形,似乎有符合這邊的敘述。

首先當我們 load libX.so 時,它會建立 5 根 thread,這是預期的:

[New Thread 0x7f59ab7fe700 (LWP 65115)]
[New Thread 0x7f59aaffd700 (LWP 65116)]
[New Thread 0x7f59aa7fc700 (LWP 65117)]
[New Thread 0x7f59a9ffb700 (LWP 65118)]
[New Thread 0x7f59a97fa700 (LWP 65119)]

 

libX.so 做完事情之後,這 5 根 thread 正常結束了:

[Thread 0x7f59a97fa700 (LWP 65119) exited]
[Thread 0x7f59a9ffb700 (LWP 65118) exited]
[Thread 0x7f59aa7fc700 (LWP 65117) exited]
[Thread 0x7f59aaffd700 (LWP 65116) exited]
[Thread 0x7f59ab7fe700 (LWP 65115) exited]

 

但這時有一根不知名的 thread 65264 被跑起來了:

[New Thread 0x7f59ab7fe700 (LWP 65264)]

 

如果這時去 unload 掉 libX.so,這根不知名 thread 就會 crash,

可能是因為跑到 curl_global_cleanup() 的關係:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f59ab7fe700 (LWP 65264)]

(gdb) bt
#0  0x00007f5a10e127ef in ?? ()
#1  0x00007f59e0017e08 in ?? ()
#2  0x00007f59e0017e10 in ?? ()
#3  0x00007f59ab7fde90 in ?? ()
#4  0x00007f59e0017e80 in ?? ()
#5  0x00007f5a31fa28c0 in ?? ()
#6  0x00007f5a30e5db90 in ?? () from /lib64/libc.so.6
#7  0x00007f59a9ffb9c0 in ?? ()
#8  0x0000000000000000 in ?? ()

 

如果在那不知名 therad 結束之後,才去 reload libX.so,就不會遇到 crash…

以上還屬於推測階段,但感覺上很像是 curl_global_cleanup 提到的問題。

以 libcurl 的建議來說,就是不要去動態 unload 掉 libX.so,

但我們的程式就是得這麼做,所以不是可接受的解法…

就先把這個問題記在這裡囉…


[2018/4/20 後記]

後來確認問題是因為新版的 curl 預設將 threaded resolver 打開,

因此 curl 會多產生一根 thread 來問 DNS。

由於本例中是 DNS 會問不到而逾時,

因此這根 thread 在逾時前都會存在,

導致 curl_global_cleanup() 執行時 crash…

 

簡單的解決方法是關掉 threaded resolver,

在編譯 curl 時,加上 –disable-threaded-resolver 選項,例如:

./configure --disable-threaded-resolver

 

這樣子 curl 就不會產生一個 DNS query thread 了~

(本頁面已被瀏覽過 32 次)

發表迴響

你的電子郵件位址並不會被公開。

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料