Closed ma8ma closed 2 years ago
問題は、build flag に -lcrypt
をつけているにも拘わらず、Wl,--as-needed
をつけて -fsanitizer=address -fsanitizer=undefined
でcompileすると、多分 link時には libasan.so の中にある crypt が先にみつかり、libcrypt.soにリンクされず、しかし libasan.so の中の cryptは「何らかの初期化みたいなのが必要と思われ?」、「crypt関数の『実体』がnullptrをさしたままになっていて?」crashする、みたいな挙動になっているっぽいです。
一応リンカのオプションをいじれるか見てみます リンクをたどるとlibxcryptはasan有効のときテストをスキップしてるのでクラッシュの回避策を入れて触らないのが無難でしょうか https://github.com/besser82/libxcrypt/commit/3aa82ccd3a3fecea7e6a9d0f9c85c56e2e04bb78
gcc-11 は打ち消すオプションを追加すればasan有効でもプレビュー表示とテスト通りました edit: clang-13(バックエンドがlibstdc++)でもできました
diff --git a/src/meson.build b/src/meson.build
index a3f7e47243..d76692177e 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -118,4 +118,5 @@ jdim_exe = executable(
include_directories : jdim_incs,
link_with : jdim_libs,
install : true,
+ link_args : ['-Wl,--no-as-needed'],
)
diff --git a/test/meson.build b/test/meson.build
index 2589b9c9ba..435b6b06e2 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -22,5 +22,6 @@ test_exe = executable(
dependencies : deps,
include_directories : jdim_incs,
link_with : jdim_libs,
+ link_args : ['-Wl,--no-as-needed'],
)
test('gtest tests', test_exe)
生成されたbuild.ninjaを見ると-Wl,--as-needed
の後ろに打ち消すオプション-Wl,--no-as-needed
が入ります
LINK_ARGS = -fsanitize=address -Wl,--as-needed -Wl,--no-undefined -Wl,--start-group src/article/libarticle.a src/bbslist/libbbslist.a src/board/libboard.a src/config/libconfig.a src/control/libcontrol.a src/dbimg/libdbimg.a src/dbtree/libdbtree.a src/history/libhistory.a src/icons/libicon.a src/image/libimage.a src/jdlib/libjdlib.a src/message/libmessage.a src/skeleton/libskeleton.a src/sound/libsound.a src/xml/libxml.a -Wl,--no-as-needed (省略) -Wl,--end-group
export LDFLAGS="$LDFLAGS -Wl,--push-state,--no-as-needed -lcrypt -Wl,--pop-state"
だけでもきちんとlibcrypt.soにリンクされて、大丈夫のようです。意図としては、なるべく-Wl,--as-needed
を使いたいんだけど、-lcrypt
だけは必ずリンクさせる、というものです。
ただ、全体に-Wl,--no-as-needed
を付けるのが簡単ではありますかね。
追加の検証でgcc8とgcc9はクラッシュしないことを確認しました。 gcc10、gcc11で起こるようです。
問題のポイントを考えると
対応策の候補は
mesonがデフォルトで-Wl,--as-needed
を追加していてそれが私の環境(ubuntu)でクラッシュの引き金になったようです。
ディストロの事情を追いきれていませんがdebianのgccパッケージがas-neededのパッチを入れてるようで./configureはデフォルトでas-neededを追加しないためasanを有効にしてもクラッシュしませんでした。
何はともあれ、AddressSanitizerを有効にするときの注意をREADMEかINSTALLに追加したいと思います。
READMEに注意書きを追加しましたのでissueを閉じます (#944) 検証とアドバイスありがとうございました :+1:
この問題は llvm 17 と gcc 14 で修正されるようです。
It was fixed with the GCC 14 imported into rawhide.
Ubuntu 23.10 の clang 17 を使ってテストしたところ segfault は発生しませんでした。
$ CC=clang-17 CXX=clang++-17 meson setup asan17 -Doptimization=1 -Db_sanitize=address,undefined -Dcpp_args="-Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Werror=return-type -Werror=implicit-fallthrough -Werror=narrowing -Werror=uninitialized" -Dcpp_link_args="-Wl,-z,now,-z,relro -Wl,-Bsymbolic-functions"
$ time meson compile -C asan17
$ time meson test --gdb -C asan17
(snip)
[ PASSED ] 614 tests.
[バージョン] JDim 0.11.0-20240330(git:3e9c8d5407)
[ディストリ ] Ubuntu 23.10 (x86_64)
[パッケージ] バイナリ/ソース( <配布元> )
[ DE/WM ] KDE
[ gtkmm ] 3.24.8
[ glibmm ] 2.66.6
[ TLS lib ] GnuTLS 3.8.1
[ そ の 他 ]
同じディストロでgcc 13を使ってテストしたところ segfaultが発生しました。
$ meson setup asan-gcc13 -Doptimization=1 -Db_sanitize=address,undefined -Dcpp_args="-Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Werror=return-type -Werror=implicit-fallthrough -Werror=narrowing -Werror=uninitialized" -Dcpp_link_args="-Wl,-z,now,-z,relro -Wl,-Bsymbolic-functions"
$ time meson compile -C asan-gcc13
$ time meson test --gdb -C asan-gcc13
(snip)
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ??? ()
#1 0x00007ffff7889b7e in __interceptor_crypt_r (key=0x7ffff2584670 "A", salt=0x7ffff2c10090 "H.", data=0x7ffff2c10140)
at ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:10212
#2 0x000055555ac429a7 in create_trip_conventional (key="A") at ../src/jdlib/misctrip.cpp:235
#3 0x000055555ac438b2 in MISC::get_trip (utf8str="A", encoding=encoding@entry=Encoding::sjis) at ../src/jdlib/misctrip.cpp:272
#4 0x0000555559bbf241 in (anonymous namespace)::get_trip_sjis (u8key="A") at ../test/gtest_jdlib_misctrip.cpp:20
#5 (anonymous namespace)::GetTripTest_trip8_sjis_A_Test::TestBody (this=<optimized out>) at ../test/gtest_jdlib_misctrip.cpp:30
#6 0x000055555b1611af in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ()
#7 0x000055555b14e6b6 in testing::Test::Run() ()
#8 0x000055555b14e875 in testing::TestInfo::Run() ()
#9 0x000055555b14e9a7 in testing::TestSuite::Run() ()
#10 0x000055555b156f24 in testing::internal::UnitTestImpl::RunAllTests() ()
#11 0x000055555b161797 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ()
#12 0x000055555b14eb28 in testing::UnitTest::Run() ()
#13 0x0000555559459bb4 in main ()
gcc 14 で segfault が発生しないか確かめてreadmeなどを更新したいと思います。
kubuntu 24.04 で gcc14 を試してみたところトリップ生成でクラッシュしなくなりました。 readmeなどを更新していきたいと思います。
OSとツールチェーン
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04 LTS
Release: 24.04
Codename: noble
$ g++-14 --version
g++-14 (Ubuntu 14-20240412-0ubuntu1) 14.0.1 20240412 (experimental) [master r14-9935-g67e1433a94f]
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
meson setup
$ CC=gcc-14 CXX=g++-14 meson setup asan-gcc14 -Doptimization=1 -Db_sanitize=address,undefined -Dcpp_args="-Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Werror=return-type -Werror=implicit-fallthrough -Werror=narrowing -Werror=uninitialized" -Dcpp_link_args="-Wl,-z,now,-z,relro -Wl,-Bsymbolic-functions"
jdimの動作環境
[バージョン] JDim 0.11.0-20240519(git:3753e4edb8)
[ディストリ ] Ubuntu 24.04 LTS (x86_64)
[パッケージ] バイナリ/ソース( <配布元> )
[ DE/WM ] KDE
[ gtkmm ] 3.24.9
[ glibmm ] 2.66.7
[ TLS lib ] GnuTLS 3.8.3
[ そ の 他 ]
AddressSanitizerが有効だとトリップ生成時にクラッシュする
edit(2022-03-26): コメント末尾に回避策を追記
バグの説明
コンパイラのオプション AddressSanitizer(ASan) を有効にしてビルドすると 書き込みビューのプレビュー表示でトリップを生成するときにクラッシュしました。
再現の方法
#
を入力して続いて任意の文字列)を入力するやりたかったこと・期待する結果
プレビュー表示にしてもクラッシュしない テストプログラムがクラッシュせず終了する
スクリーンショット
jdimがクラッシュしたときのログ
``` AddressSanitizer:DEADLYSIGNAL ================================================================= ==87359==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7ffe6439cb70 sp 0x7ffe6439c2f8 T0) ==87359==Hint: pc points to the zero page. ==87359==The signal is caused by a READ memory access. ==87359==Hint: address points to the zero page. #0 0x0 (テストプログラムがクラッシュしたときのログ
``` [1/5] Generating buildinfo.h with a custom command (wrapped by meson to capture output) Running main() from /build/googletest-OI1WhS/googletest-1.10.0.20201025/googletest/src/gtest_main.cc [==========] Running 192 tests from 25 test suites. [----------] Global test environment set-up. [----------] 6 tests from CookieManager_GetCookieByHost [ RUN ] CookieManager_GetCookieByHost.no_data [ OK ] CookieManager_GetCookieByHost.no_data (0 ms) [ RUN ] CookieManager_GetCookieByHost.single_value [ OK ] CookieManager_GetCookieByHost.single_value (0 ms) [ RUN ] CookieManager_GetCookieByHost.multiple_values [ OK ] CookieManager_GetCookieByHost.multiple_values (0 ms) [ RUN ] CookieManager_GetCookieByHost.empty_values [ OK ] CookieManager_GetCookieByHost.empty_values (0 ms) [ RUN ] CookieManager_GetCookieByHost.parsing_domain [ OK ] CookieManager_GetCookieByHost.parsing_domain (0 ms) [ RUN ] CookieManager_GetCookieByHost.parsing_path [ OK ] CookieManager_GetCookieByHost.parsing_path (0 ms) [----------] 6 tests from CookieManager_GetCookieByHost (0 ms total) [----------] 1 test from CookieManager_DeleteCookieByHost [ RUN ] CookieManager_DeleteCookieByHost.delete_toplevel [ OK ] CookieManager_DeleteCookieByHost.delete_toplevel (0 ms) [----------] 1 test from CookieManager_DeleteCookieByHost (0 ms total) [----------] 4 tests from Iconv_ToAsciiFromUtf8 [ RUN ] Iconv_ToAsciiFromUtf8.empty [ OK ] Iconv_ToAsciiFromUtf8.empty (1 ms) [ RUN ] Iconv_ToAsciiFromUtf8.helloworld [ OK ] Iconv_ToAsciiFromUtf8.helloworld (0 ms) [ RUN ] Iconv_ToAsciiFromUtf8.hiragana [ OK ] Iconv_ToAsciiFromUtf8.hiragana (0 ms) [ RUN ] Iconv_ToAsciiFromUtf8.subdivision_flag [ OK ] Iconv_ToAsciiFromUtf8.subdivision_flag (0 ms) [----------] 4 tests from Iconv_ToAsciiFromUtf8 (1 ms total) [----------] 7 tests from Iconv_ToUtf8FromMs932 [ RUN ] Iconv_ToUtf8FromMs932.empty [ OK ] Iconv_ToUtf8FromMs932.empty (1 ms) [ RUN ] Iconv_ToUtf8FromMs932.helloworld [ OK ] Iconv_ToUtf8FromMs932.helloworld (0 ms) [ RUN ] Iconv_ToUtf8FromMs932.hiragana [ OK ] Iconv_ToUtf8FromMs932.hiragana (0 ms) [ RUN ] Iconv_ToUtf8FromMs932.hex_a0 [ OK ] Iconv_ToUtf8FromMs932.hex_a0 (0 ms) [ RUN ] Iconv_ToUtf8FromMs932.mojibake_fix_inequality_sign_pattern1 [ OK ] Iconv_ToUtf8FromMs932.mojibake_fix_inequality_sign_pattern1 (1 ms) [ RUN ] Iconv_ToUtf8FromMs932.mojibake_fix_inequality_sign_pattern2 [ OK ] Iconv_ToUtf8FromMs932.mojibake_fix_inequality_sign_pattern2 (0 ms) [ RUN ] Iconv_ToUtf8FromMs932.mapping_error [ OK ] Iconv_ToUtf8FromMs932.mapping_error (0 ms) [----------] 7 tests from Iconv_ToUtf8FromMs932 (2 ms total) [----------] 4 tests from Regex_NamedOrNumTest [ RUN ] Regex_NamedOrNumTest.invalid_both_arguments [ OK ] Regex_NamedOrNumTest.invalid_both_arguments (0 ms) [ RUN ] Regex_NamedOrNumTest.prioritize_named_capture [ OK ] Regex_NamedOrNumTest.prioritize_named_capture (0 ms) [ RUN ] Regex_NamedOrNumTest.unregistered_name [ OK ] Regex_NamedOrNumTest.unregistered_name (0 ms) [ RUN ] Regex_NamedOrNumTest.register_invalid_name [ OK ] Regex_NamedOrNumTest.register_invalid_name (0 ms) [----------] 4 tests from Regex_NamedOrNumTest (0 ms total) [----------] 10 tests from Utf8BytesTest [ RUN ] Utf8BytesTest.null_data [ OK ] Utf8BytesTest.null_data (0 ms) [ RUN ] Utf8BytesTest.ascii [ OK ] Utf8BytesTest.ascii (0 ms) [ RUN ] Utf8BytesTest.two_bytes [ OK ] Utf8BytesTest.two_bytes (0 ms) [ RUN ] Utf8BytesTest.three_bytes [ OK ] Utf8BytesTest.three_bytes (0 ms) [ RUN ] Utf8BytesTest.four_bytes [ OK ] Utf8BytesTest.four_bytes (0 ms) [ RUN ] Utf8BytesTest.obsolete_four_bytes [ OK ] Utf8BytesTest.obsolete_four_bytes (0 ms) [ RUN ] Utf8BytesTest.obsolete_five_bytes [ OK ] Utf8BytesTest.obsolete_five_bytes (0 ms) [ RUN ] Utf8BytesTest.obsolete_six_bytes [ OK ] Utf8BytesTest.obsolete_six_bytes (0 ms) [ RUN ] Utf8BytesTest.invalid_byte [ OK ] Utf8BytesTest.invalid_byte (0 ms) [ RUN ] Utf8BytesTest.invalid_seq [ OK ] Utf8BytesTest.invalid_seq (0 ms) [----------] 10 tests from Utf8BytesTest (1 ms total) [----------] 7 tests from MISC_DateToTimeTest [ RUN ] MISC_DateToTimeTest.empty_input [ OK ] MISC_DateToTimeTest.empty_input (0 ms) [ RUN ] MISC_DateToTimeTest.invalid_format [ OK ] MISC_DateToTimeTest.invalid_format (0 ms) [ RUN ] MISC_DateToTimeTest.unix_epoch [ OK ] MISC_DateToTimeTest.unix_epoch (0 ms) [ RUN ] MISC_DateToTimeTest.non_gmt_wont_be_parsed [ OK ] MISC_DateToTimeTest.non_gmt_wont_be_parsed (0 ms) [ RUN ] MISC_DateToTimeTest.iso8601_wont_be_parsed [ OK ] MISC_DateToTimeTest.iso8601_wont_be_parsed (0 ms) [ RUN ] MISC_DateToTimeTest.one_hundred_million [ OK ] MISC_DateToTimeTest.one_hundred_million (0 ms) [ RUN ] MISC_DateToTimeTest.wrong_day_will_be_parsed [ OK ] MISC_DateToTimeTest.wrong_day_will_be_parsed (0 ms) [----------] 7 tests from MISC_DateToTimeTest (0 ms total) [----------] 5 tests from MISC_TimetToStrTest [ RUN ] MISC_TimetToStrTest.time_normal [ OK ] MISC_TimetToStrTest.time_normal (0 ms) [ RUN ] MISC_TimetToStrTest.time_no_year [ OK ] MISC_TimetToStrTest.time_no_year (0 ms) [ RUN ] MISC_TimetToStrTest.time_week [ OK ] MISC_TimetToStrTest.time_week (0 ms) [ RUN ] MISC_TimetToStrTest.time_passed [ OK ] MISC_TimetToStrTest.time_passed (0 ms) [ RUN ] MISC_TimetToStrTest.time_second [ OK ] MISC_TimetToStrTest.time_second (0 ms) [----------] 5 tests from MISC_TimetToStrTest (0 ms total) [----------] 13 tests from GetTripTest [ RUN ] GetTripTest.trip8_sjis_empty [ OK ] GetTripTest.trip8_sjis_empty (0 ms) [ RUN ] GetTripTest.trip8_sjis_A AddressSanitizer:DEADLYSIGNAL ================================================================= ==87690==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7ffc4dacbe80 sp 0x7ffc4dacb608 T0) ==87690==Hint: pc points to the zero page. ==87690==The signal is caused by a READ memory access. ==87690==Hint: address points to the zero page. #0 0x0 (動作環境
edit: gcc8, gcc9ではクラッシュしない gcc10, gcc11ではクラッシュした
追加の情報
https://src.fedoraproject.org/rpms/jd/blob/b2d927b8daced575e4c8619f1b2dd85772b46f70/f/jd.spec
https://bugzilla.redhat.com/show_bug.cgi?id=1827338
https://github.com/google/sanitizers/issues/1365
AddressSanitizerを有効にすると
crypt
、crypt_r
関数が差し替えられるようですが、 差し替えに問題があり関数が正常にリンクされずクラッシュするようです。edit(2022-03-26): ASanを有効にするときクラッシュを回避する方法
事前に環境変数 LDFLAGS を設定してビルドする
または、mesonのコマンドラインオプション
-Db_asneeded
でフラグを変更する