arch1t3cht / Aegisub

Cross-platform advanced subtitle editor, with new feature branches. Read the README on the feature branch.
http://www.aegisub.org
Other
805 stars 34 forks source link

Crash in agi::Thesaurus::Thesaurus with Boost 1.85.0 and GCC >= 13 #137

Closed mia-0 closed 1 month ago

mia-0 commented 6 months ago

When building with Boost 1.85.0 and GCC >= 13 with optimization level 2 or greater, Aegisub as well as the thesaurus test case crash here: https://github.com/arch1t3cht/Aegisub/blob/80491bacbfe2b684d1b2be0e031c72e27e39f85b/libaegisub/common/thesaurus.cpp#L48

The same does not occur with Clang 18 or lower optimization levels, so this might be a GCC bug.

System is openSUSE Tumbleweed 20240524.

Backtrace:

#0  0x00007ffff756c215 in __memcmp_avx2_movbe () from /lib64/libc.so.6
No symbol table info available.
#1  0x00000000005f3d80 in std::char_traits<char>::compare (__n=<optimized out>, __s2=<optimized out>, __s1=0x7fffffffd1a0 "Word 2")
    at /usr/include/c++/13/bits/char_traits.h:389
        __i = <optimized out>
#2  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::compare (this=0x7fffffffd190, __str=...)
    at /usr/include/c++/13/bits/basic_string.h:3189
        __size = <optimized out>
        __osize = 7458172
        __len = <optimized out>
        __r = <optimized out>
#3  std::operator< <char, std::char_traits<char>, std::allocator<char> > (__rhs=..., __lhs=...) at /usr/include/c++/13/bits/basic_string.h:3832
No locals.
#4  std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator() (__y=..., __x=..., this=<optimized out>)
    at /usr/include/c++/13/bits/stl_function.h:408
No locals.
#5  boost::container::flat_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, void>::priv_subscript (mk=..., this=<optimized out>)
    at /usr/include/boost/container/flat_map.hpp:1649
        k = @0x7fffffffd190: {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x7fffffffd1a0 "Word 2"}, _M_string_length = 6, {_M_local_buf = "Word 2\000\000\000\000\000\000\000\000\000", 
            _M_allocated_capacity = 55114705563479}}
        i = {m_ptr = 0x71cae8}
        k = <optimized out>
        i = <optimized out>
        m = <optimized out>
        v = <optimized out>
#6  boost::container::flat_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, void>::operator[] (x=..., this=<optimized out>) at /usr/include/boost/container/flat_map.hpp:753
No locals.
#7  agi::Thesaurus::Thesaurus (this=this@entry=0x7fffffffd4f0, dat_path=..., idx_path=...) at ../libaegisub/common/thesaurus.cpp:48
        pos = <optimized out>
        line = @0x7fffffffd288: {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x7fffffffd298 "Word 2|53"}, _M_string_length = 9, {_M_local_buf = "Word 2|53\000\000\000\000\000\000", 
            _M_allocated_capacity = 3854010495827865431}}
        __for_range = @0x7fffffffd210: {<agi::line_iterator_base> = {stream = 0x7fffffffd358, 
            conv = {<std::__shared_ptr<agi::charset::IconvWrapper, (__gnu_cxx::_Lock_policy)2>> = {<std::__shared_ptr_access<agi::charset::IconvWrapper, (__gnu_cxx::_Lock_policy)2, false, false>> = {<No data fields>}, _M_ptr = 0x0, _M_refcount = {_M_pi = 0x0}}, <No data fields>}, cr = 13, lf = 10, 
            width = 1}, <std::iterator<std::input_iterator_tag, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>> = {<No data fields>}, value = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, 
              _M_p = 0x7fffffffd248 "Word 1|6"}, _M_string_length = 8, {_M_local_buf = "Word 1|6\000\000\000\000\000\000\000", 
              _M_allocated_capacity = 3926066990354165591}}}
        __for_begin = {<agi::line_iterator_base> = {stream = 0x7fffffffd358, 
            conv = {<std::__shared_ptr<agi::charset::IconvWrapper, (__gnu_cxx::_Lock_policy)2>> = {<std::__shared_ptr_access<agi::charset::IconvWrapper, (__gnu_cxx::_Lock_policy)2, false, false>> = {<No data fields>}, _M_ptr = 0x0, _M_refcount = {_M_pi = 0x0}}, <No data fields>}, cr = 13, lf = 10, 
            width = 1}, <std::iterator<std::input_iterator_tag, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>> = {<No data fields>}, value = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, 
              _M_p = 0x7fffffffd298 "Word 2|53"}, _M_string_length = 9, {_M_local_buf = "Word 2|53\000\000\000\000\000\000", 
              _M_allocated_capacity = 3854010495827865431}}}
        __for_end = {<agi::line_iterator_base> = {stream = 0x0, 
            conv = {<std::__shared_ptr<agi::charset::IconvWrapper, (__gnu_cxx::_Lock_policy)2>> = {<std::__shared_ptr_access<agi::charset::IconvWrapper, (__gnu_cxx::_Lock_policy)2, false, false>> = {<No data fields>}, _M_ptr = 0x0, _M_refcount = {_M_pi = 0x0}}, <No data fields>}, cr = 13, lf = 10, 
            width = 1}, <std::iterator<std::input_iterator_tag, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>> = {<No data fields>}, value = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, 
              _M_p = 0x7fffffffd2e8 ""}, _M_string_length = 0, {_M_local_buf = '\000' <repeats 15 times>, _M_allocated_capacity = 0}}}
        idx_file = {file = {handle = 5}, region = {
            _M_t = {<std::__uniq_ptr_impl<boost::interprocess::mapped_region, std::default_delete<boost::interprocess::mapped_region> >> = {
                _M_t = {<std::_Tuple_impl<0, boost::interprocess::mapped_region*, std::default_delete<boost::interprocess::mapped_region> >> = {<std::_Tuple_impl<1, std::default_delete<boost::interprocess::mapped_region> >> = {<std::_Head_base<1, std::default_delete<boost::interprocess::mapped_region>, true>> = {
                        _M_head_impl = {<No data fields>}}, <No data fields>}, <std::_Head_base<0, boost::interprocess::mapped_region*, false>> = {
                      _M_head_impl = 0x71b300}, <No data fields>}, <No data fields>}}, <No data fields>}}, mapping_start = 0, file_size = 136}
        idx = {<boost::interprocess::basic_bufferbuf<char, std::char_traits<char> >> = {<std::basic_streambuf<char, std::char_traits<char> >> = {
              _vptr.basic_streambuf = 0x647408 <vtable for boost::interprocess::basic_ibufferstream<char, std::char_traits<char> >+24>, 
              _M_in_beg = 0x7ffff7fb7000 "UTF-8\n7\nWord 1|6\nWord 2|53\nWord 3|163\nToo few fields\nToo many fields|100|100\nNot a number|foo\nOut of range|195\nFurther out of range|196\n", 
              _M_in_cur = 0x7ffff7fb701b "Word 3|163\nToo few fields\nToo many fields|100|100\nNot a number|foo\nOut of range|195\nFurther out of range|196\n", _M_in_end = 0x7ffff7fb7088 "", _M_out_beg = 0x0, _M_out_cur = 0x0, _M_out_end = 0x0, _M_buf_locale = {static none = 0, static ctype = 1, static numeric = 2, 
                static collate = 4, static time = 8, static monetary = 16, static messages = 32, static all = 63, _M_impl = 0x6de920}}, m_mode = std::_S_in, 
            m_buffer = 0x7ffff7fb7000 "UTF-8\n7\nWord 1|6\nWord 2|53\nWord 3|163\nToo few fields\nToo many fields|100|100\nNot a number|foo\nOut of range|195\nFurther out of range|196\n", 
            m_length = 136}, <std::basic_istream<char, std::char_traits<char> >> = {<std::basic_ios<char, std::char_traits<char> >> = {<std::ios_base> = {
                _vptr.ios_base = 0x6474b8 <vtable for boost::interprocess::basic_ibufferstream<char, std::char_traits<char> >+200>, 
                static boolalpha = std::_S_boolalpha, static dec = std::_S_dec, static fixed = std::_S_fixed, static hex = std::_S_hex, 
                static internal = std::_S_internal, static left = std::_S_left, static oct = std::_S_oct, static right = std::_S_right, 
                static scientific = std::_S_scientific, static showbase = std::_S_showbase, static showpoint = std::_S_showpoint, 
                static showpos = std::_S_showpos, static skipws = std::_S_skipws, static unitbuf = std::_S_unitbuf, static uppercase = std::_S_uppercase, 
                static adjustfield = std::_S_adjustfield, static basefield = std::_S_basefield, static floatfield = std::_S_floatfield, 
                static badbit = std::_S_badbit, static eofbit = std::_S_eofbit, static failbit = std::_S_failbit, static goodbit = std::_S_goodbit, 
                static app = std::_S_app, static ate = std::_S_ate, static binary = std::_S_bin, static in = std::_S_in, static out = std::_S_out, 
                static trunc = std::_S_trunc, static __noreplace = std::_S_noreplace, static beg = std::_S_beg, static cur = std::_S_cur, 
                static end = std::_S_end, _M_precision = 6, _M_width = 0, _M_flags = 4098, _M_exception = std::_S_goodbit, 
                _M_streambuf_state = std::_S_goodbit, _M_callbacks = 0x0, _M_word_zero = {_M_pword = 0x0, _M_iword = 0}, _M_local_word = {{_M_pword = 0x0, 
                    _M_iword = 0}, {_M_pword = 0x0, _M_iword = 0}, {_M_pword = 0x0, _M_iword = 0}, {_M_pword = 0x0, _M_iword = 0}, {_M_pword = 0x0, 
                    _M_iword = 0}, {_M_pword = 0x0, _M_iword = 0}, {_M_pword = 0x0, _M_iword = 0}, {_M_pword = 0x0, _M_iword = 0}}, _M_word_size = 8, 
                _M_word = 0x7fffffffd3a8, _M_ios_locale = {static none = 0, static ctype = 1, static numeric = 2, static collate = 4, static time = 8, 
                  static monetary = 16, static messages = 32, static all = 63, _M_impl = 0x6de920}}, _M_tie = 0x0, _M_fill = 0 '\000', _M_fill_init = false, 
              _M_streambuf = 0x7fffffffd300, _M_ctype = 0x7ffff7a55920 <(anonymous namespace)::ctype_c>, _M_num_put = 0x7082f0, _M_num_get = 0x70c0a0}, 
            _vptr.basic_istream = 0x647490 <vtable for boost::interprocess::basic_ibufferstream<char, std::char_traits<char> >+160>, 
            _M_gcount = 0}, <No data fields>}
        encoding_name = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x7fffffffd160 "UTF-8"}, _M_string_length = 5, {_M_local_buf = "UTF-8\000\000\000\000\000\000\000\000\000\000", 
            _M_allocated_capacity = 241277752405}}
        unused_entry_count = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, 
            _M_p = 0x7fffffffd180 "7"}, _M_string_length = 1, {_M_local_buf = "7", '\000' <repeats 14 times>, _M_allocated_capacity = 55}}
        idx_file = <optimized out>
        idx = <optimized out>
        encoding_name = <optimized out>
        unused_entry_count = <optimized out>
        line = <optimized out>
        __for_range = <optimized out>
        __for_begin = <optimized out>
        __for_end = <optimized out>
        pos = <optimized out>
#8  0x000000000052270d in lagi_thes_parse_Test::TestBody (this=<optimized out>) at /usr/include/c++/13/bits/basic_string.tcc:242
No locals.
#9  0x000000000057ba3f in testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void> (location=0x6103c1 "the test body", 
    method=<optimized out>, object=0x71cfd0) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2424
No locals.
#10 testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void> (object=object@entry=0x71cfd0, method=<optimized out>, 
    location=location@entry=0x6103c1 "the test body") at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2479
No locals.
#11 0x000000000056faeb in testing::Test::Run (this=0x71cfd0) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2517
        impl = 0x6de680
        impl = <optimized out>
#12 testing::Test::Run (this=0x71cfd0) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2508
        impl = <optimized out>
#13 0x000000000056fcd0 in testing::TestInfo::Run (this=0x6f9ea0) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2693
        impl = 0x6de680
        repeater = 0x6de5c0
        start = 1717237242890
        test = 0x71cfd0
#14 0x000000000056fe3c in testing::TestInfo::Run (this=<optimized out>) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2668
        impl = <optimized out>
        repeater = <optimized out>
        start = <optimized out>
        test = <optimized out>
#15 testing::TestCase::Run (this=0x6f9fb0) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2811
        i = 0
        impl = 0x6de680
        repeater = 0x6de5c0
        start = 1717237242890
#16 0x0000000000572a70 in testing::TestCase::Run (this=<optimized out>) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2797
        impl = <optimized out>
        repeater = <optimized out>
        start = <optimized out>
        impl = <optimized out>
        repeater = <optimized out>
        start = <optimized out>
        i = <optimized out>
#17 testing::internal::UnitTestImpl::RunAllTests (this=<optimized out>) at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:5177
        test_index = 23
        start = 1717237242728
        i = 0
        gtest_is_initialized_before_run_all_tests = true
        in_subprocess_for_death_test = <optimized out>
        should_shard = <optimized out>
        has_tests_to_run = true
        failed = <optimized out>
        repeater = <optimized out>
        repeat = <optimized out>
        forever = <optimized out>
#18 0x000000000057bebf in testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (
    location=0x627160 "auxiliary test code (environments or event listeners)", method=<optimized out>, object=0x6de680)
    at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2424
No locals.
#19 testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (object=0x6de680, method=<optimized out>, 
    location=location@entry=0x627160 "auxiliary test code (environments or event listeners)")
    at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:2479
No locals.
#20 0x000000000056ffc2 in testing::UnitTest::Run (this=0x6cb220 <testing::UnitTest::GetInstance()::instance>)
    at ../subprojects/googletest-release-1.8.1/googletest/src/gtest.cc:4786
        in_death_test_child_process = <optimized out>
        premature_exit_file = {premature_exit_filepath_ = {
            _M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffffffd740 ""}, 
            _M_string_length = 0, {_M_local_buf = "\000\327\377\377\377\177\000\000&#W\000\000\000\000", _M_allocated_capacity = 140737488344832}}}
#21 0x0000000000439bd0 in RUN_ALL_TESTS () at ../subprojects/googletest-release-1.8.1/googletest/include/gtest/gtest.h:2341
No locals.
#22 main (argc=<optimized out>, argv=0x7fffffffd8f8) at ../tests/support/main.cpp:37
        retval = <optimized out>
mia-0 commented 6 months ago

Is there a genuine need to use Boost’s flat_map here, as opposed to just std::map? Performance-wise it doesn’t seem to matter in practice which implementation is used, so even if this is just a bug in either GCC or Boost, I would suggest replacing it.