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

ASan heap-use-after-free in tcpserver tests #303

Open
dmitrykobets-msft opened this issue Jul 10, 2023 · 0 comments
Open

ASan heap-use-after-free in tcpserver tests #303

dmitrykobets-msft opened this issue Jul 10, 2023 · 0 comments

Comments

@dmitrykobets-msft
Copy link

dmitrykobets-msft commented Jul 10, 2023

The MSVC Address Sanitizer detected a heap-use-after-free in test\tcp_server_test.cc.

The test-case testTCPServer1 calls tcp_client_thread.reset();, which frees the TCPClient::loop_ member of client:

TEST_UNIT(testTCPServer1) {
    // ...
    std::unique_ptr<evpp::EventLoopThread> tcp_client_thread(new evpp::EventLoopThread);
    // ...
    std::shared_ptr<evpp::TCPClient> client = StartTCPClient(tcp_client_thread->loop());
    // ...
    tcp_client_thread.reset(); // client->loop_ is freed
    tcp_server_thread.reset();
    tsrv.reset();
    assert(evpp::GetActiveEventCount() == 0);
} // ~TCPClient() called

But the ~TCPClient() destructor tries to access the loop_ member:
evpp\tcp_client.cc

TCPClient::~TCPClient() {
    // ...
    TCPConnPtr c = conn();
    // ...
}

TCPConnPtr TCPClient::conn() const {
    if (loop_->IsInLoopThread()) { // accessing freed memory `loop_`
        return conn_;
    } else {
        // ...
    }
}

Fix

One potential fix is to manually reset the client pointer first, inside the test-case:

TEST_UNIT(testTCPServer1) {
    // ...
    client.reset();  // free this first
    tcp_client_thread.reset();
    tcp_server_thread.reset();
    tsrv.reset();
    assert(evpp::GetActiveEventCount() == 0);
}

Alternatively, all of the reset() smartpointer calls can be removed in all of the tests in this file. Are these reset calls needed for testing?

Repro

To rebuild and run tests via MSVC with AddressSanitizer enabled:

# setup vcpkg
git clone F:\gitP\Microsoft\vcpkg
cd F:\gitP\Microsoft\vcpkg
bootstrap-vcpkg.bat 2>&1
vcpkg.exe install --recurse gflags glog openssl libevent thrift --triplet x64-windows --clean-after-build 2>&1
# setup evpp
mkdir F:\gitP\Qihoo360\evpp\build_amd64
cd F:\gitP\Qihoo360\evpp\build_amd64
set VSCMD_SKIP_SENDTELEMETRY=1 & "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -host_arch=amd64 -arch=amd64 & set _CL_= /fsanitize=address /GS- /wd5072 & set _LINK_= /InferASanLibs /incremental:no /debug
cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_VERSION=10.0.22621.0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=F:\gitP\Microsoft\vcpkg\scripts\buildsystems\vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows .. 2>&1
# build
msbuild /m /p:Platform=x64 /p:Configuration=Release safe-evpp.sln /t:Rebuild 2>&1
# test
cd F:\gitP\Qihoo360\evpp\build_amd64\bin\Release
evpp_unittest.exe --gtest_filter=-GtestObjectClass_testTimestamp.testTimestamp:GtestObjectClass_TestEventLoop1.TestEventLoop1:GtestObjectClass_testInvokerTimerCancel.testInvokerTimerCancel:GtestObjectClass_testHTTPRequest* 2>&1

To run only the problematic test-case:

evpp_unittest.exe --gtest_filter=GtestObjectClass_testTCPServer1.testTCPServer1 2>&1

AddressSanitizer output:

=================================================================
==11028==ERROR: AddressSanitizer: heap-use-after-free on address 0x12807f6fb654 at pc 0x7ff67651c2bb bp 0x0099ff75f2b0 sp 0x0099ff75f2b8
READ of size 4 at 0x12807f6fb654 thread T0
    #0 0x7ff67651c2ba in std::operator== C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\thread:242
    #1 0x7ff67651c2ba in evpp::EventLoop::IsInLoopThread F:\gitP\Qihoo360\evpp\evpp\event_loop.h:84
    #2 0x7ff67651c2ba in evpp::TCPClient::conn(void) const F:\gitP\Qihoo360\evpp\evpp\tcp_client.cc:138
    #3 0x7ff676519757 in evpp::TCPClient::~TCPClient(void) F:\gitP\Qihoo360\evpp\evpp\tcp_client.cc:26
    #4 0x7ff6764c7df2 in std::_Ref_count<class evpp::TCPClient>::_Destroy(void) C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\memory:1205
    #5 0x7ff67648d203 in std::_Ref_count_base::_Decref(void) C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\memory:1178
    #6 0x7ff6764c9b49 in std::_Ptr_base<evpp::TCPClient>::_Decref C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\memory:1403
    #7 0x7ff6764c9b49 in std::shared_ptr<evpp::TCPClient>::{dtor} C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\memory:1687
    #8 0x7ff6764c9b49 in GtestObjectClass_testTCPServer1_testTCPServer1_Test::TestBody(void) F:\gitP\Qihoo360\evpp\test\tcp_server_test.cc:101
    #9 0x7ff67643a2a7 in testing::internal::HandleSehExceptionsInMethodIfSupported<class testing::Test, void>(class testing::Test *, void (__cdecl testing::Test::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2063
    #10 0x7ff676439df9 in testing::internal::HandleExceptionsInMethodIfSupported<class testing::Test, void>(class testing::Test *, void (__cdecl testing::Test::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2114
    #11 0x7ff676469818 in testing::TestInfo::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2326
    #12 0x7ff67646944f in testing::TestCase::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2444
    #13 0x7ff676469f6e in testing::internal::UnitTestImpl::RunAllTests(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:4315
    #14 0x7ff67643a3c7 in testing::internal::HandleSehExceptionsInMethodIfSupported<class testing::internal::UnitTestImpl, bool>(class testing::internal::UnitTestImpl *, bool (__cdecl testing::internal::UnitTestImpl::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2063
    #15 0x7ff67643a1f9 in testing::internal::HandleExceptionsInMethodIfSupported<class testing::internal::UnitTestImpl, bool>(class testing::internal::UnitTestImpl *, bool (__cdecl testing::internal::UnitTestImpl::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2114
    #16 0x7ff676469b2d in testing::UnitTest::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:3926
    #17 0x7ff676476bf1 in RUN_ALL_TESTS F:\gitP\Qihoo360\evpp\3rdparty\gtest\gtest.h:2288
    #18 0x7ff676476bf1 in main F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest_main.cc:37
    #19 0x7ff676533333 in invoke_main C:\repos\msvc\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #20 0x7ff676533333 in __scrt_common_main_seh C:\repos\msvc\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #21 0x7ffa9cba4ddf  (C:\Windows\System32\KERNEL32.DLL+0x180014ddf)
    #22 0x7ffa9e19e44a  (C:\Windows\SYSTEM32\ntdll.dll+0x18007e44a)

0x12807f6fb654 is located 20 bytes inside of 272-byte region [0x12807f6fb640,0x12807f6fb750)
freed by thread T0 here:
    #0 0x7ff6765325e3 in operator delete(void *, unsigned __int64) C:\repos\msvc\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_win_delete_scalar_size_thunk.cpp:41
    #1 0x7ff67648d203 in std::_Ref_count_base::_Decref(void) C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\memory:1178
    #2 0x7ff6764dda62 in std::_Ptr_base<evpp::EventLoop>::_Decref C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\memory:1403
    #3 0x7ff6764dda62 in std::shared_ptr<evpp::EventLoop>::{dtor} C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\memory:1687
    #4 0x7ff6764dda62 in evpp::EventLoopThread::~EventLoopThread(void) F:\gitP\Qihoo360\evpp\evpp\event_loop_thread.cc:17
    #5 0x7ff6764c9aab in GtestObjectClass_testTCPServer1_testTCPServer1_Test::TestBody(void) F:\gitP\Qihoo360\evpp\test\tcp_server_test.cc:97
    #6 0x7ff67643a2a7 in testing::internal::HandleSehExceptionsInMethodIfSupported<class testing::Test, void>(class testing::Test *, void (__cdecl testing::Test::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2063
    #7 0x7ff676439df9 in testing::internal::HandleExceptionsInMethodIfSupported<class testing::Test, void>(class testing::Test *, void (__cdecl testing::Test::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2114
    #8 0x7ff676469818 in testing::TestInfo::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2326
    #9 0x7ff67646944f in testing::TestCase::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2444
    #10 0x7ff676469f6e in testing::internal::UnitTestImpl::RunAllTests(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:4315
    #11 0x7ff67643a3c7 in testing::internal::HandleSehExceptionsInMethodIfSupported<class testing::internal::UnitTestImpl, bool>(class testing::internal::UnitTestImpl *, bool (__cdecl testing::internal::UnitTestImpl::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2063
    #12 0x7ff67643a1f9 in testing::internal::HandleExceptionsInMethodIfSupported<class testing::internal::UnitTestImpl, bool>(class testing::internal::UnitTestImpl *, bool (__cdecl testing::internal::UnitTestImpl::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2114
    #13 0x7ff676469b2d in testing::UnitTest::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:3926
    #14 0x7ff676476bf1 in RUN_ALL_TESTS F:\gitP\Qihoo360\evpp\3rdparty\gtest\gtest.h:2288
    #15 0x7ff676476bf1 in main F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest_main.cc:37
    #16 0x7ff676533333 in invoke_main C:\repos\msvc\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #17 0x7ff676533333 in __scrt_common_main_seh C:\repos\msvc\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #18 0x7ffa9cba4ddf  (C:\Windows\System32\KERNEL32.DLL+0x180014ddf)
    #19 0x7ffa9e19e44a  (C:\Windows\SYSTEM32\ntdll.dll+0x18007e44a)

previously allocated by thread T0 here:
    #0 0x7ff676532555 in operator new(unsigned __int64) C:\repos\msvc\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_win_new_scalar_thunk.cpp:40
    #1 0x7ff6764dd5b8 in evpp::EventLoopThread::EventLoopThread(void) F:\gitP\Qihoo360\evpp\evpp\event_loop_thread.cc:9
    #2 0x7ff6764c952c in GtestObjectClass_testTCPServer1_testTCPServer1_Test::TestBody(void) F:\gitP\Qihoo360\evpp\test\tcp_server_test.cc:71
    #3 0x7ff67643a2a7 in testing::internal::HandleSehExceptionsInMethodIfSupported<class testing::Test, void>(class testing::Test *, void (__cdecl testing::Test::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2063
    #4 0x7ff676439df9 in testing::internal::HandleExceptionsInMethodIfSupported<class testing::Test, void>(class testing::Test *, void (__cdecl testing::Test::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2114
    #5 0x7ff676469818 in testing::TestInfo::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2326
    #6 0x7ff67646944f in testing::TestCase::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2444
    #7 0x7ff676469f6e in testing::internal::UnitTestImpl::RunAllTests(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:4315
    #8 0x7ff67643a3c7 in testing::internal::HandleSehExceptionsInMethodIfSupported<class testing::internal::UnitTestImpl, bool>(class testing::internal::UnitTestImpl *, bool (__cdecl testing::internal::UnitTestImpl::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2063
    #9 0x7ff67643a1f9 in testing::internal::HandleExceptionsInMethodIfSupported<class testing::internal::UnitTestImpl, bool>(class testing::internal::UnitTestImpl *, bool (__cdecl testing::internal::UnitTestImpl::*)(void), char const *) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:2114
    #10 0x7ff676469b2d in testing::UnitTest::Run(void) F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest.cc:3926
    #11 0x7ff676476bf1 in RUN_ALL_TESTS F:\gitP\Qihoo360\evpp\3rdparty\gtest\gtest.h:2288
    #12 0x7ff676476bf1 in main F:\gitP\Qihoo360\evpp\3rdparty\gtest\src\gtest_main.cc:37
    #13 0x7ff676533333 in invoke_main C:\repos\msvc\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #14 0x7ff676533333 in __scrt_common_main_seh C:\repos\msvc\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #15 0x7ffa9cba4ddf  (C:\Windows\System32\KERNEL32.DLL+0x180014ddf)
    #16 0x7ffa9e19e44a  (C:\Windows\SYSTEM32\ntdll.dll+0x18007e44a)

SUMMARY: AddressSanitizer: heap-use-after-free C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.36.32532\include\thread:242 in std::operator==
Shadow bytes around the buggy address:
  0x04ac8f05f670: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x04ac8f05f680: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
  0x04ac8f05f690: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x04ac8f05f6a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x04ac8f05f6b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
=>0x04ac8f05f6c0: fa fa fa fa fa fa fa fa fd fd[fd]fd fd fd fd fd
  0x04ac8f05f6d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x04ac8f05f6e0: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
  0x04ac8f05f6f0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x04ac8f05f700: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x04ac8f05f710: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa
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
==11028==ABORTING
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant