Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firestore: string_format.h: fix use-after-free bug when internally formatting strings #14306

Merged
merged 10 commits into from
Jan 9, 2025

Conversation

dconeybe
Copy link
Contributor

@dconeybe dconeybe commented Jan 6, 2025

This PR fixes the following use-after-free bug detected by the test TEST(StringFormatTest, Pointer) when run under ASAN:

11: =================================================================
11: ==22796==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f2c74931b50 at pc 0x7f2c778fb42e bp 0x7ffd9a727650 sp 0x7ffd9a726df8
11: READ of size 12 at 0x7f2c74931b50 thread T0
11:     #0 0x7f2c778fb42d in memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115
11:     #1 0x7f2c76f68754 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (/lib/x86_64-linux-gnu/libstdc++.so.6+0x168754) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
11:     #2 0x7f2c76f6a04f in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_append(char const*, unsigned long) (/lib/x86_64-linux-gnu/libstdc++.so.6+0x16a04f) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
11:     #3 0x5614e57b39ba in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.cc:51
11:     #4 0x5614e57b3ead in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.cc:75
11:     #5 0x5614e57b40af in firebase::firestore::util::internal::StringFormatPieces[abi:cxx11](char const*, std::initializer_list<absl::lts_20240116::string_view>) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.cc:109
11:     #6 0x5614e5438c42 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > firebase::firestore::util::StringFormat<int*>(char const*, int* const&) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.h:161
11:     #7 0x5614e54312cc in firebase::firestore::util::StringFormatTest_Pointer_Test::TestBody() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/test/unit/util/string_format_test.cc:79
11:     #8 0x5614e557ad6a in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2653
11:     #9 0x5614e5569d7c in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2689
11:     #10 0x5614e5514a1d in testing::Test::Run() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2728
11:     #11 0x5614e5516094 in testing::TestInfo::Run() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2874
11:     #12 0x5614e5517266 in testing::TestSuite::Run() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:3052
11:     #13 0x5614e553e811 in testing::internal::UnitTestImpl::RunAllTests() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:6020
11:     #14 0x5614e557e31a in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2653
11:     #15 0x5614e556cb59 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2689
11:     #16 0x5614e553afc5 in testing::UnitTest::Run() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:5599
11:     #17 0x5614e55ab633 in RUN_ALL_TESTS() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/include/gtest/gtest.h:2334
11:     #18 0x5614e55ab57f in main /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest_main.cc:64
11:     #19 0x7f2c76a2a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
11:     #20 0x7f2c76a2a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
11:     #21 0x5614e506e074 in _start (/home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/Firestore/core/test/unit/util/firestore_util_test+0x14b074) (BuildId: eefa62cc1c83814a55da36f74af7d7609da19e60)
11: 
11: Address 0x7f2c74931b50 is located in stack of thread T0 at offset 80 in frame
11:     #0 0x5614e543b899 in firebase::firestore::util::FormatArg::FormatArg<int>(int*, firebase::firestore::util::internal::FormatChoice<4>) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.h:128
11: 
11:   This frame has 2 object(s):
11:     [32, 48) '<unknown>'
11:     [64, 96) '<unknown>' <== Memory access at offset 80 is inside this variable
11: HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
11:       (longjmp and C++ exceptions *are* supported)
11: SUMMARY: AddressSanitizer: stack-use-after-return ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115 in memcpy
11: Shadow bytes around the buggy address:
11:   0x7f2c74931880: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931900: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931980: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931a00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931a80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11: =>0x7f2c74931b00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5[f5]f5 f5 f5 f5 f5
11:   0x7f2c74931b80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931c00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931c80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931d00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11:   0x7f2c74931d80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
11: Shadow byte legend (one shadow byte represents 8 application bytes):
11:   Addressable:           00
11:   Partially addressable: 01 02 03 04 05 06 07 
11:   Heap left redzone:       fa
11:   Freed heap region:       fd
11:   Stack left redzone:      f1
11:   Stack mid redzone:       f2
11:   Stack right redzone:     f3
11:   Stack after return:      f5
11:   Stack use after scope:   f8
11:   Global redzone:          f9
11:   Global init order:       f6
11:   Poisoned by user:        f7
11:   Container overflow:      fc
11:   Array cookie:            ac
11:   Intra object redzone:    bb
11:   ASan internal:           fe
11:   Left alloca redzone:     ca
11:   Right alloca redzone:    cb
11: ==22796==ABORTING

The real issue here is that Firestore is using the class absl::AlphaNum in a way that it was not intended to be used. Namely, AlphaNum explicitly documents that

The AlphaNum class acts as the main parameter type for StrCat() and
StrAppend(), providing efficient conversion of numeric, boolean, decimal,
and hexadecimal values (through the Dec and Hex types) into strings.
AlphaNum should only be used as a function parameter. Do not instantiate
AlphaNum directly as a stack variable.

https://github.com/abseil/abseil-cpp/blob/506f1072c03dc35ba7bc447fd9651cc90e22e816/absl/strings/str_cat.h#L311C1-L315C45

However, the Firestore SDK uses it in a different way, by creating a subclass of it, named FormatArg:

class FormatArg : public absl::AlphaNum {

The problem is that one of the constructors of FormatArg calls through to a constructor of AlphaNum that relies on the lifetime extension of a C++ temporary used as function argument for a reference-type parameter. This works just fine when AlphaNum is used as a direct argument to StrCat(), as is intended. However, when used in that way that Firestore does, the StringifySink temporary argument is destroyed prematurely, causing a dangling reference to its internal std::string, causing a use-after-free bug when that dangling reference is used.

Although use-after-free is technically undefined behavior, it manifested in my case by this code

int value = 4;
StringFormat("Hello %s", &value);

returning "Hello \x90\x15#T\xFD\x7F\0\0\x88\x15#T" instead of the expected "Hello 7ffffdc94440". Notice how the text after "Hello" is "garbage" in the former case, but is the expected hex-formatted memory address in the latter case. The latter case was produced with the fix in this PR applied.

This fix works by having the StringifySink be created by the caller of the FormatArg constructor (by virtue of it being a default parameter with a default value) and passing along a reference to that StringifySink. This gains the correct lifetime extension of the StringifySink object and fixes the use-after-free.

There are, however, two drawbacks to this fix: (a) the StringifySink class is an internal, implementation detail of absl that really should not be used by Firestore and (b) it incurs the cost of creating and destroying a StringifySink object even for constructors that don't need it. With respect to (a), since we have pinned to a specific version of absl we should be good and with respect to (b) I hope that the compiler will elide the StringifySink constructor calls altogether when the object is not needed since its constructors and destructor have no apparent side effects.

I had originally thought that this was a bug in absl; however, after discussion with the absl developers, the root cause was identified as unintended use of the AlphaNum class. Googlers can see b/388000898 for the whole discussion.

@dconeybe dconeybe self-assigned this Jan 6, 2025
dconeybe added a commit that referenced this pull request Jan 6, 2025
…feMemoizerMemoryLeakFix

This PR is now based on #14306
@dconeybe dconeybe marked this pull request as ready for review January 6, 2025 20:33
@dconeybe dconeybe requested a review from cherylEnkidu January 6, 2025 20:36
…lso check that the expected hex address is indeed contained in the actual formatted string.
@dconeybe
Copy link
Contributor Author

dconeybe commented Jan 9, 2025

AI(dconeybe) Add a TODO to improve this implementation in the future to avoid using the absl-internal class StringifySink.

Update: Done: 72833ca

@dconeybe
Copy link
Contributor Author

dconeybe commented Jan 9, 2025

As an interesting observation, here is another use-after-free bug caught by address sanitizer that will be fixed by this PR:

return StringFormat("%s (%x)", GetDebugName(), this);

Namely, when formatting the this argument it will access freed memory.

For completeness, here is the report from ASAN:

[ RUN      ] StreamTest.ObserverReceivesStreamCloseOnError
=================================================================
==20201==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f8fc31585d0 at pc 0x7f8fcb47d96f bp 0x7f8fc79febd0 sp 0x7f8fc79fe378
READ of size 13 at 0x7f8fc31585d0 thread T509
    #0 0x7f8fcb47d96e in strlen ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:391
    #1 0x5591e3cef0dd in absl::lts_20240116::string_view::StrlenInternal(char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/abseil-cpp/absl/strings/string_view.h:684
    #2 0x5591e3cef012 in absl::lts_20240116::string_view::string_view(char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/abseil-cpp/absl/strings/string_view.h:200
    #3 0x5591e4401851 in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.cc:61
    #4 0x5591e4401b6a in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.cc:80
    #5 0x5591e4401d07 in firebase::firestore::util::internal::StringFormatPieces[abi:cxx11](char const*, std::initializer_list<absl::lts_20240116::string_view>) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.cc:109
    #6 0x5591e42364ec in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > firebase::firestore::util::StringFormat<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, firebase::firestore::remote::Stream const*>(char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, firebase::firestore::remote::Stream const* const&) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.h:161
    #7 0x5591e4232fcd in firebase::firestore::remote::Stream::GetDebugDescription[abi:cxx11]() const /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/remote/stream.cc:383
    #8 0x5591e4232575 in firebase::firestore::remote::Stream::OnStreamFinish(firebase::firestore::util::Status const&) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/remote/stream.cc:357
    #9 0x5591e41b2e9a in firebase::firestore::remote::GrpcStream::FinishAndNotify(firebase::firestore::util::Status const&) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/remote/grpc_stream.cc:179
    #10 0x5591e41b4a06 in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/remote/grpc_stream.cc:321
    #11 0x5591e41b6c82 in __invoke_impl<void, firebase::firestore::remote::GrpcStream::OnOperationFailed()::<lambda(const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&)>&, const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&> /usr/include/c++/13/bits/invoke.h:61
    #12 0x5591e41b66ae in __invoke_r<void, firebase::firestore::remote::GrpcStream::OnOperationFailed()::<lambda(const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&)>&, const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&> /usr/include/c++/13/bits/invoke.h:150
    #13 0x5591e41b5f91 in _M_invoke /usr/include/c++/13/bits/std_function.h:290
    #14 0x5591e41b9918 in std::function<void (std::shared_ptr<firebase::firestore::remote::GrpcCompletion> const&)>::operator()(std::shared_ptr<firebase::firestore::remote::GrpcCompletion> const&) const (/home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/Firestore/core/test/unit/remote/firestore_remote_test+0xd86918) (BuildId: e193f25adbe9c81ac1779df2f3b987d94e8a6689)
    #15 0x5591e41b515a in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/remote/grpc_stream.cc:342
    #16 0x5591e41b6d88 in __invoke_impl<void, firebase::firestore::remote::GrpcStream::NewCompletion(firebase::firestore::remote::Type, const OnSuccess&)::<lambda(bool, const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&)>&, bool, const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&> /usr/include/c++/13/bits/invoke.h:61
    #17 0x5591e41b6977 in __invoke_r<void, firebase::firestore::remote::GrpcStream::NewCompletion(firebase::firestore::remote::Type, const OnSuccess&)::<lambda(bool, const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&)>&, bool, const std::shared_ptr<firebase::firestore::remote::GrpcCompletion>&> /usr/include/c++/13/bits/invoke.h:150
    #18 0x5591e41b60f8 in _M_invoke /usr/include/c++/13/bits/std_function.h:290
    #19 0x5591e417d75f in std::function<void (bool, std::shared_ptr<firebase::firestore::remote::GrpcCompletion> const&)>::operator()(bool, std::shared_ptr<firebase::firestore::remote::GrpcCompletion> const&) const /usr/include/c++/13/bits/std_function.h:591
    #20 0x5591e417c0dd in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/remote/grpc_completion.cc:95
    #21 0x5591e417c99f in __invoke_impl<void, firebase::firestore::remote::GrpcCompletion::Complete(bool)::<lambda()>&> /usr/include/c++/13/bits/invoke.h:61
    #22 0x5591e417c83f in __invoke_r<void, firebase::firestore::remote::GrpcCompletion::Complete(bool)::<lambda()>&> /usr/include/c++/13/bits/invoke.h:150
    #23 0x5591e417c618 in _M_invoke /usr/include/c++/13/bits/std_function.h:290
    #24 0x5591e3dcc11b in std::function<void ()>::operator()() const /usr/include/c++/13/bits/std_function.h:591
    #25 0x5591e43e7365 in firebase::firestore::util::AsyncQueue::ExecuteBlocking(std::function<void ()> const&) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/async_queue.cc:89
    #26 0x5591e43e814c in operator() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/async_queue.cc:144
    #27 0x5591e43e9f09 in __invoke_impl<void, firebase::firestore::util::AsyncQueue::Wrap(const Operation&)::<lambda()>&> /usr/include/c++/13/bits/invoke.h:61
    #28 0x5591e43e9bb8 in __invoke_r<void, firebase::firestore::util::AsyncQueue::Wrap(const Operation&)::<lambda()>&> /usr/include/c++/13/bits/invoke.h:150
    #29 0x5591e43e9843 in _M_invoke /usr/include/c++/13/bits/std_function.h:290
    #30 0x5591e3dcc11b in std::function<void ()>::operator()() const /usr/include/c++/13/bits/std_function.h:591
    #31 0x5591e440398b in firebase::firestore::util::Task::ExecuteAndRelease() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/task.cc:102
    #32 0x5591e4411904 in firebase::firestore::util::ExecutorStd::PollingThread(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/executor_std.cc:180
    #33 0x5591e441dcf4 in void std::__invoke_impl<void, void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState> >(std::__invoke_other, void (*&&)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&&) /usr/include/c++/13/bits/invoke.h:61
    #34 0x5591e441dba8 in std::__invoke_result<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState> >::type std::__invoke<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState> >(void (*&&)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&&) /usr/include/c++/13/bits/invoke.h:96
    #35 0x5591e441daca in void std::thread::_Invoker<std::tuple<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState> > >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/13/bits/std_thread.h:292
    #36 0x5591e441da61 in std::thread::_Invoker<std::tuple<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState> > >::operator()() /usr/include/c++/13/bits/std_thread.h:299
    #37 0x5591e441d795 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState> > > >::_M_run() /usr/include/c++/13/bits/std_thread.h:244
    #38 0x7f8fcaaecdb3  (/lib/x86_64-linux-gnu/libstdc++.so.6+0xecdb3) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
    #39 0x7f8fcb45ea41 in asan_thread_start ../../../../src/libsanitizer/asan/asan_interceptors.cpp:234
    #40 0x7f8fca69ca93  (/lib/x86_64-linux-gnu/libc.so.6+0x9ca93) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #41 0x7f8fca729c3b  (/lib/x86_64-linux-gnu/libc.so.6+0x129c3b) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)

Address 0x7f8fc31585d0 is located in stack of thread T509 at offset 80 in frame
    #0 0x5591e4236e73 in firebase::firestore::util::FormatArg::FormatArg<firebase::firestore::remote::Stream const>(firebase::firestore::remote::Stream const*, firebase::firestore::util::internal::FormatChoice<4>) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/string_format.h:128

  This frame has 2 object(s):
    [32, 48) '<unknown>'
    [64, 96) '<unknown>' <== Memory access at offset 80 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
Thread T509 created by T0 here:
    #0 0x7f8fcb4f51f9 in pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:245
    #1 0x7f8fcaaeceb0 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/lib/x86_64-linux-gnu/libstdc++.so.6+0xeceb0) (BuildId: ca77dae775ec87540acd7218fa990c40d1c94ab1)
    #2 0x5591e441a496 in std::thread::thread<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&, void>(void (*&&)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&) /usr/include/c++/13/bits/std_thread.h:164
    #3 0x5591e44185be in void std::__new_allocator<std::thread>::construct<std::thread, void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&>(std::thread*, void (*&&)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&) /usr/include/c++/13/bits/new_allocator.h:191
    #4 0x5591e44185be in void std::allocator_traits<std::allocator<std::thread> >::construct<std::thread, void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&>(std::allocator<std::thread>&, std::thread*, void (*&&)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&) /usr/include/c++/13/bits/alloc_traits.h:538
    #5 0x5591e44185be in void std::vector<std::thread, std::allocator<std::thread> >::_M_realloc_insert<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&>(__gnu_cxx::__normal_iterator<std::thread*, std::vector<std::thread, std::allocator<std::thread> > >, void (*&&)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&) /usr/include/c++/13/bits/vector.tcc:468
    #6 0x5591e44171e0 in void std::vector<std::thread, std::allocator<std::thread> >::emplace_back<void (*)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&>(void (*&&)(std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>), std::shared_ptr<firebase::firestore::util::ExecutorStd::SharedState>&) /usr/include/c++/13/bits/vector.tcc:123
    #7 0x5591e441079b in firebase::firestore::util::ExecutorStd::ExecutorStd(int) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/executor_std.cc:67
    #8 0x5591e4417b85 in std::__detail::_MakeUniq<firebase::firestore::util::ExecutorStd>::__single_object std::make_unique<firebase::firestore::util::ExecutorStd, int>(int&&) /usr/include/c++/13/bits/unique_ptr.h:1070
    #9 0x5591e4412732 in firebase::firestore::util::Executor::CreateSerial(char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/src/util/executor_std.cc:248
    #10 0x5591e432d5c2 in firebase::firestore::testutil::ExecutorForTesting(char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/test/unit/testutil/async_testing.cc:51
    #11 0x5591e432d889 in firebase::firestore::testutil::AsyncQueueForTesting() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/test/unit/testutil/async_testing.cc:55
    #12 0x5591e3f9972e in firebase::firestore::remote::StreamTest::StreamTest() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/test/unit/remote/stream_test.cc:151
    #13 0x5591e3fa0add in firebase::firestore::remote::StreamTest_ObserverReceivesStreamCloseOnError_Test::StreamTest_ObserverReceivesStreamCloseOnError_Test() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/Firestore/core/test/unit/remote/stream_test.cc:315
    #14 0x5591e3fa0b3f in testing::internal::TestFactoryImpl<firebase::firestore::remote::StreamTest_ObserverReceivesStreamCloseOnError_Test>::CreateTest() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/include/gtest/internal/gtest-internal.h:456
    #15 0x5591e404179a in testing::Test* testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::TestFactoryBase, testing::Test*>(testing::internal::TestFactoryBase*, testing::Test* (testing::internal::TestFactoryBase::*)(), char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2653
    #16 0x5591e402fafc in testing::Test* testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::TestFactoryBase, testing::Test*>(testing::internal::TestFactoryBase*, testing::Test* (testing::internal::TestFactoryBase::*)(), char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2689
    #17 0x5591e3fd9b62 in testing::TestInfo::Run() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2864
    #18 0x5591e3fdad72 in testing::TestSuite::Run() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:3052
    #19 0x5591e400231d in testing::internal::UnitTestImpl::RunAllTests() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:6020
    #20 0x5591e4044c5e in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:2653
    #21 0x5591e40320a5 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (/home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/Firestore/core/test/unit/remote/firestore_remote_test+0xbff0a5) (BuildId: e193f25adbe9c81ac1779df2f3b987d94e8a6689)
    #22 0x5591e3ffead1 in testing::UnitTest::Run() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest.cc:5599
    #23 0x5591e4074907 in RUN_ALL_TESTS() /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/include/gtest/gtest.h:2334
    #24 0x5591e4074853 in main /home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/external/src/googletest/googletest/src/gtest_main.cc:64
    #25 0x7f8fca62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #26 0x7f8fca62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #27 0x5591e3cd25e4 in _start (/home/runner/work/firebase-ios-sdk/firebase-ios-sdk/build/Firestore/core/test/unit/remote/firestore_remote_test+0x89f5e4) (BuildId: e193f25adbe9c81ac1779df2f3b987d94e8a6689)

SUMMARY: AddressSanitizer: stack-use-after-return ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:391 in strlen
Shadow bytes around the buggy address:
  0x7f8fc3158300: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f8fc3158380: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
  0x7f8fc3158400: f1 f1 f1 f1 00 f2 f2 f2 00 00 00 00 f3 f3 f3 f3
  0x7f8fc3158480: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f8fc3158500: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
=>0x7f8fc3158580: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5[f5]f5 f5 f5 f5 f5
  0x7f8fc3158600: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
  0x7f8fc3158680: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 00 00 00 00
  0x7f8fc3158700: f1 f1 f1 f1 00 00 f2 f2 00 00 00 00 f3 f3 f3 f3
  0x7f8fc3158780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f8fc3158800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==20201==ABORTING
Test #10: firestore_remote_test ............***Failed    6.87 sec

@dconeybe dconeybe merged commit 01061ea into main Jan 9, 2025
35 checks passed
@dconeybe dconeybe deleted the dconeybe/StringFormatStringifySinkUseAfterFreeFix branch January 9, 2025 23:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants