Skip to content

ThreadSanitizer triggers when calling fmt::print from multiple threads on at least GCC 12.2 up to and including GCC 14.3 #4755

Description

@jobpaardekooper

ThreadSanitizer triggers when calling fmt::print from multiple threads on at least x86_64 GCC 12.2 up to and including GCC 14.3

Minimal reproducible example:

https://godbolt.org/z/bGGxEc1oh

On the left, there is GCC 15.1 where I have not seen it trigger yet. On the right is GCC 12.2 where ThreadSanitizer triggers with very high consistency.

If this is a false positive, would it be possible to solve this by adding annotations to FMT ?

Godbolt does not show the full ThreadSanitizer log so here is one that I have from GCC 12.2 my local compilation:

>>> TSAN_OPTIONS=halt_on_error=1 playground
==================
WARNING: ThreadSanitizer: data race (pid=53700)
  Read of size 8 at 0x7fae30207788 by thread T2:
    #0 fmt::v12::detail::glibc_file<_IO_FILE>::init_buffer() ../subprojects/fmt/include/fmt/format-inl.h:1528 (targets_playground+0x25d4b)
    #1 fmt::v12::detail::file_print_buffer<_IO_FILE, void>::file_print_buffer(_IO_FILE*) ../subprojects/fmt/include/fmt/format-inl.h:1681 (targets_playground+0x22798)
    #2 fmt::v12::vprint(_IO_FILE*, fmt::v12::basic_string_view<char>, fmt::v12::basic_format_args<fmt::v12::context>) ../subprojects/fmt/include/fmt/format-inl.h:1740 (targets_playground+0x15eb3)
    #3 fmt::v12::vprint(fmt::v12::basic_string_view<char>, fmt::v12::basic_format_args<fmt::v12::context>) ../subprojects/fmt/include/fmt/format-inl.h:1752 (targets_playground+0x16054)
    #4 void fmt::v12::print<>(fmt::v12::fstring<>::t) ../subprojects/fmt/include/fmt/base.h:2963 (targets_playground+0x1270f)
    #5 operator() ../source/targets/playground/main.cpp:16 (targets_playground+0x1270f)
    #6 __invoke_impl<void, main()::<lambda()> > /usr/include/c++/12/bits/invoke.h:61 (targets_playground+0x131a0)
    #7 __invoke<main()::<lambda()> > /usr/include/c++/12/bits/invoke.h:96 (targets_playground+0x1311b)
    #8 _M_invoke<0> /usr/include/c++/12/bits/std_thread.h:252 (targets_playground+0x13080)
    #9 operator() /usr/include/c++/12/bits/std_thread.h:259 (targets_playground+0x1302a)
    #10 _M_run /usr/include/c++/12/bits/std_thread.h:210 (targets_playground+0x12fe4)
    #11 <null> <null> (libstdc++.so.6+0xd44a2)

  Previous write of size 8 at 0x7fae30207788 by thread T1:
    #0 fmt::v12::detail::glibc_file<_IO_FILE>::init_buffer() ../subprojects/fmt/include/fmt/format-inl.h:1531 (targets_playground+0x25dca)
    #1 fmt::v12::detail::file_print_buffer<_IO_FILE, void>::file_print_buffer(_IO_FILE*) ../subprojects/fmt/include/fmt/format-inl.h:1681 (targets_playground+0x22798)
    #2 fmt::v12::vprint(_IO_FILE*, fmt::v12::basic_string_view<char>, fmt::v12::basic_format_args<fmt::v12::context>) ../subprojects/fmt/include/fmt/format-inl.h:1740 (targets_playground+0x15eb3)
    #3 fmt::v12::vprint(fmt::v12::basic_string_view<char>, fmt::v12::basic_format_args<fmt::v12::context>) ../subprojects/fmt/include/fmt/format-inl.h:1752 (targets_playground+0x16054)
    #4 void fmt::v12::print<>(fmt::v12::fstring<>::t) ../subprojects/fmt/include/fmt/base.h:2963 (targets_playground+0x1270f)
    #5 operator() ../source/targets/playground/main.cpp:16 (targets_playground+0x1270f)
    #6 __invoke_impl<void, main()::<lambda()> > /usr/include/c++/12/bits/invoke.h:61 (targets_playground+0x131a0)
    #7 __invoke<main()::<lambda()> > /usr/include/c++/12/bits/invoke.h:96 (targets_playground+0x1311b)
    #8 _M_invoke<0> /usr/include/c++/12/bits/std_thread.h:252 (targets_playground+0x13080)
    #9 operator() /usr/include/c++/12/bits/std_thread.h:259 (targets_playground+0x1302a)
    #10 _M_run /usr/include/c++/12/bits/std_thread.h:210 (targets_playground+0x12fe4)
    #11 <null> <null> (libstdc++.so.6+0xd44a2)

  Location is global '_IO_2_1_stdout_' of size 224 at 0x7fae30207760 (libc.so.6+0x1d4788)

  Thread T2 (tid=53703, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd4578)
    #2 construct_at<std::thread, main()::<lambda()> > /usr/include/c++/12/bits/stl_construct.h:97 (targets_playground+0x12ce5)
    #3 construct<std::thread, main()::<lambda()> > /usr/include/c++/12/bits/alloc_traits.h:518 (targets_playground+0x129c4)
    #4 _M_realloc_insert<main()::<lambda()> > /usr/include/c++/12/bits/vector.tcc:462 (targets_playground+0x12ace)
    #5 emplace_back<main()::<lambda()> > /usr/include/c++/12/bits/vector.tcc:123 (targets_playground+0x12944)
    #6 main ../source/targets/playground/main.cpp:13 (targets_playground+0x1279e)

  Thread T1 (tid=53702, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd4578)
    #2 construct_at<std::thread, main()::<lambda()> > /usr/include/c++/12/bits/stl_construct.h:97 (targets_playground+0x12ce5)
    #3 construct<std::thread, main()::<lambda()> > /usr/include/c++/12/bits/alloc_traits.h:518 (targets_playground+0x129c4)
    #4 _M_realloc_insert<main()::<lambda()> > /usr/include/c++/12/bits/vector.tcc:462 (targets_playground+0x12ace)
    #5 emplace_back<main()::<lambda()> > /usr/include/c++/12/bits/vector.tcc:123 (targets_playground+0x12944)
    #6 main ../source/targets/playground/main.cpp:13 (targets_playground+0x1279e)

SUMMARY: ThreadSanitizer: data race ../subprojects/fmt/include/fmt/format-inl.h:1528 in fmt::v12::detail::glibc_file<_IO_FILE>::init_buffer()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions