collabora-online/test/HttpRequestTests.cpp

712 lines
25 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* Copyright the Collabora Online contributors.
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <config.h>
#include "ConfigUtil.hpp"
#include <HttpTestServer.hpp>
#include <Poco/URI.h>
#include <Poco/Net/AcceptCertificateHandler.h>
#include <Poco/Net/InvalidCertificateHandler.h>
#include <Poco/Net/SSLManager.h>
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/StreamCopier.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <string>
#include <test/lokassert.hpp>
#if ENABLE_SSL
#include "Ssl.hpp"
#include <net/SslSocket.hpp>
#endif
#include <net/ServerSocket.hpp>
#include <net/DelaySocket.hpp>
#include <net/HttpRequest.hpp>
#include <FileUtil.hpp>
#include <Util.hpp>
#include <helpers.hpp>
#include <cppunit/extensions/HelperMacros.h>
/// When enabled, in addition to the loopback
/// server, an external server will be used
/// to check for regressions.
// #define ENABLE_EXTERNAL_REGRESSION_CHECK
/// http::Request unit-tests.
class HttpRequestTests final : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE(HttpRequestTests);
CPPUNIT_TEST(testSslHostname);
CPPUNIT_TEST(testInvalidURI);
CPPUNIT_TEST(testBadResponse);
CPPUNIT_TEST(testGoodResponse);
CPPUNIT_TEST(testSimpleGet);
CPPUNIT_TEST(testSimpleGetSync);
CPPUNIT_TEST(testChunkedGetSync);
CPPUNIT_TEST(test500GetStatuses); // Slow.
#ifdef ENABLE_EXTERNAL_REGRESSION_CHECK
CPPUNIT_TEST(testChunkedGetSync_External);
CPPUNIT_TEST(testSimplePost_External);
#endif
CPPUNIT_TEST(testTimeout);
CPPUNIT_TEST(testOnFinished_Complete);
CPPUNIT_TEST(testOnFinished_Timeout);
CPPUNIT_TEST_SUITE_END();
void testSslHostname();
void testInvalidURI();
void testBadResponse();
void testGoodResponse();
void testSimpleGet();
void testSimpleGetSync();
void testChunkedGetSync();
void test500GetStatuses();
void testChunkedGetSync_External();
void testSimplePost_External();
void testTimeout();
void testOnFinished_Complete();
void testOnFinished_Timeout();
static constexpr std::chrono::seconds DefTimeoutSeconds{ 5 };
std::string _localUri;
SocketPoll _pollServerThread;
std::shared_ptr<ServerSocket> _socket;
int _port;
static const int SimulatedLatencyMs = 0;
public:
HttpRequestTests()
: _pollServerThread("HttpServerPoll")
, _port(0)
{
#if ENABLE_SSL
Poco::Net::initializeSSL();
// Just accept the certificate anyway for testing purposes
Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> invalidCertHandler
= new Poco::Net::AcceptCertificateHandler(false);
Poco::Net::Context::Params sslParams;
Poco::Net::Context::Ptr sslContext
= new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, sslParams);
Poco::Net::SSLManager::instance().initializeClient(nullptr, invalidCertHandler, sslContext);
#endif
}
~HttpRequestTests()
{
#if ENABLE_SSL
Poco::Net::uninitializeSSL();
#endif
}
class ServerSocketFactory final : public SocketFactory
{
std::shared_ptr<Socket> create(const int physicalFd, Socket::Type type) override
{
int fd = physicalFd;
#if !MOBILEAPP
if (HttpRequestTests::SimulatedLatencyMs > 0)
fd = Delay::create(HttpRequestTests::SimulatedLatencyMs, physicalFd);
#endif
#if ENABLE_SSL
if (helpers::haveSsl())
return StreamSocket::create<SslStreamSocket>(
std::string(), fd, type, false, std::make_shared<ServerRequestHandler>());
else
return StreamSocket::create<StreamSocket>(std::string(), fd, type, false,
std::make_shared<ServerRequestHandler>());
#else
return StreamSocket::create<StreamSocket>(std::string(), fd, type, false,
std::make_shared<ServerRequestHandler>());
#endif
}
};
void setUp()
{
LOG_INF("HttpRequestTests::setUp");
std::shared_ptr<SocketFactory> factory = std::make_shared<ServerSocketFactory>();
_port = 9990;
for (int i = 0; i < 40; ++i, ++_port)
{
// Try listening on this port.
LOG_INF("HttpRequestTests::setUp: creating socket to listen on port " << _port);
_socket = ServerSocket::create(ServerSocket::Type::Local, _port, Socket::Type::IPv4,
_pollServerThread, factory);
if (_socket)
break;
}
if (helpers::haveSsl())
_localUri = "https://127.0.0.1:" + std::to_string(_port);
else
_localUri = "http://127.0.0.1:" + std::to_string(_port);
_pollServerThread.startThread();
_pollServerThread.insertNewSocket(_socket);
}
void tearDown()
{
LOG_INF("HttpRequestTests::tearDown");
_pollServerThread.stop();
_socket.reset();
}
};
constexpr std::chrono::seconds HttpRequestTests::DefTimeoutSeconds;
void HttpRequestTests::testSslHostname()
{
#if ENABLE_SSL
constexpr auto testname = __func__;
if (helpers::haveSsl())
{
const std::string host = "localhost";
std::shared_ptr<SslStreamSocket> socket = StreamSocket::create<SslStreamSocket>(
host, _port, Socket::Type::All, false, std::make_shared<ServerRequestHandler>());
LOK_ASSERT_EQUAL(host, socket->getSslServername());
}
#endif
}
void HttpRequestTests::testInvalidURI()
{
constexpr auto testname = __func__;
try
{
// Cannot create from a blank URI.
http::Session::createHttp(std::string());
LOK_ASSERT_FAIL("Exception expected from http::Session::createHttp for invalid URI");
}
catch (const std::exception& ex)
{
// Pass.
}
}
void HttpRequestTests::testBadResponse()
{
constexpr auto testname = __func__;
const std::string URL = "/inject/" + Util::bytesToHexString("\0\0xa", 2);
http::Request httpRequest(URL);
auto httpSession = http::Session::create(_localUri);
if (httpSession)
{
httpSession->setTimeout(std::chrono::seconds(1));
const std::shared_ptr<const http::Response> httpResponse =
httpSession->syncRequest(httpRequest);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Error);
}
}
void HttpRequestTests::testGoodResponse()
{
constexpr auto testname = __func__;
// Inject the following response:
// HTTP/1.1 200 OK
// Date: Wed, 02 Jun 2021 02:30:52 GMT
// Content-Type: text/html; charset=utf-8
// Content-Length: 0
const std::string URL =
"/inject/"
"485454502F312E3120323030204F4B0D0A446174653A205765642C203032204A756E20323032312030323A3330"
"3A353220474D540D0A436F6E74656E742D547970653A20746578742F68746D6C3B20636861727365743D757466"
"2D380D0A436F6E74656E742D4C656E6774683A20300D0A0D0A";
http::Request httpRequest(URL);
auto httpSession = http::Session::create(_localUri);
if (httpSession)
{
httpSession->setTimeout(std::chrono::seconds(1));
const std::shared_ptr<const http::Response> httpResponse =
httpSession->syncRequest(httpRequest);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Complete);
LOK_ASSERT(!httpResponse->statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse->statusLine().reasonPhrase().empty());
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
LOK_ASSERT(httpResponse->statusLine().statusCategory() ==
http::StatusLine::StatusCodeClass::Successful);
LOK_ASSERT_EQUAL(std::string("HTTP/1.1"), httpResponse->statusLine().httpVersion());
LOK_ASSERT_EQUAL(std::string("OK"), httpResponse->statusLine().reasonPhrase());
LOK_ASSERT_EQUAL(std::string("text/html; charset=utf-8"),
httpResponse->header().getContentType());
LOK_ASSERT_EQUAL(std::string("Wed, 02 Jun 2021 02:30:52 GMT"),
httpResponse->header().get("Date"));
LOK_ASSERT_EQUAL(std::string(), httpResponse->getBody());
}
}
void HttpRequestTests::testSimpleGet()
{
constexpr auto testname = __func__;
constexpr auto URL = "/";
// Start the polling thread.
wsd: test: fix heap-use-after-free In HttpRequestTests::test500GetStatuses, since we reused the http::Session without removing from SocketPoll, it is possible for the poll thread to access the Session object while we create a new request, where we replace its Response and Socket members. To avoid that, we can try to remove the http::Session instance from the SocketPoll. Alternatively, we can create a new one for each request, which is what we do here. Below is the results of ASan, for the record. ==949494==ERROR: AddressSanitizer: heap-use-after-free on address 0x61700005afe0 at pc 0x55dc0c092c75 bp 0x7f8b539e5a10 sp 0x7f8b539e5a08 READ of size 4 at 0x61700005afe0 thread T10 (HttpAsyncReqPol) #0 0x55dc0c092c74 in http::Response::logPrefix(std::ostream&) const /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 #1 0x55dc0c08f499 in http::Response::readData(char const*, long) /home/ash/prj/lo/online/test/../net/HttpRequest.cpp:641:5 #2 0x55dc0c0998c9 in http::Session::handleIncomingMessage(SocketDisposition&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1248:41 #3 0x55dc0c0f0c3b in StreamSocket::handlePoll(SocketDisposition&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, int) /home/ash/prj/lo/online/test/../net/Socket.hpp:1339:33 #4 0x55dc0c0b092d in SocketPoll::poll(long) /home/ash/prj/lo/online/test/../net/Socket.cpp:444:34 #5 0x55dc0c10407c in SocketPoll::poll(std::chrono::duration<long, std::ratio<1l, 1000000l> >) /home/ash/prj/lo/online/test/../net/Socket.hpp:691:61 #6 0x55dc0c10407c in SocketPoll::pollingThread() /home/ash/prj/lo/online/test/../net/Socket.hpp:648:13 #7 0x55dc0c0ac445 in SocketPoll::pollingThreadEntry() /home/ash/prj/lo/online/test/../net/Socket.cpp:299:9 #8 0x55dc0c12b6b9 in void std::__invoke_impl<void, void (SocketPoll::*)(), SocketPoll*>(std::__invoke_memfun_deref, void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #9 0x55dc0c12b590 in std::__invoke_result<void (SocketPoll::*)(), SocketPoll*>::type std::__invoke<void (SocketPoll::*)(), SocketPoll*>(void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #10 0x55dc0c12b574 in void std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:264:13 #11 0x55dc0c12b463 in std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:271:11 #12 0x55dc0c12b463 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:215:13 #13 0x7f8b5a08cde3 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6de3) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #14 0x7f8b59e4c608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8 #15 0x7f8b59d44132 in __clone /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95 0x61700005afe0 is located 736 bytes inside of 744-byte region [0x61700005ad00,0x61700005afe8) freed by thread T0 here: LLVMSymbolizer: error reading file: No such file or directory #0 0x55dc0bfe43dd in operator delete(void*) (/home/ash/prj/lo/online/test/unithttplib+0x20d3dd) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1fe168 in std::_Sp_counted_ptr<http::Response*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:380:9 #2 0x55dc0c033768 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:158:6 #3 0x55dc0c0335d5 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:733:11 #4 0x55dc0c1f972c in std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1183:31 #5 0x55dc0c1f972c in std::enable_if<__sp_is_constructible<http::Response, http::Response>::value, void>::type std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::reset<http::Response>(http::Response*) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1309:4 #6 0x55dc0c1f972c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:19 #7 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #8 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #9 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #10 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #11 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #12 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #13 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #14 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #15 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #16 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #17 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #18 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #19 0x7ffdc354a41f ([stack]+0x2b41f) previously allocated by thread T0 here: #0 0x55dc0bfe3b7d in operator new(unsigned long) (/home/ash/prj/lo/online/test/unithttplib+0x20cb7d) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1f969c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:25 #2 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #3 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) Thread T10 (HttpAsyncReqPol) created by T0 here: #0 0x55dc0bf922bc in __interceptor_pthread_create (/home/ash/prj/lo/online/test/unithttplib+0x1bb2bc) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x7f8b5a08d0a8 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd70a8) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #2 0x55dc0c0aa467 in SocketPoll::startThread() /home/ash/prj/lo/online/test/../net/Socket.cpp:238:23 #3 0x55dc0c1b57b3 in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:482:16 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) SUMMARY: AddressSanitizer: heap-use-after-free /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 in http::Response::logPrefix(std::ostream&) const Shadow bytes around the buggy address: 0x0c2e800035a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c2e800035f0: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fa fa fa 0x0c2e80003600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2e80003610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003620: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003630: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003640: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 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 ==949494==ABORTING Change-Id: I5e1539c3adbab9b5027d84cc1dbab4b90271c458 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-06-20 13:56:50 +02:00
SocketPoll pollThread("AsyncReqPoll");
pollThread.startThread();
http::Request httpRequest(URL);
//TODO: test with both SSL and Unencrypted.
static constexpr http::Session::Protocol Protocols[]
= { http::Session::Protocol::HttpUnencrypted, http::Session::Protocol::HttpSsl };
for (const http::Session::Protocol protocol : Protocols)
{
#if ENABLE_SSL
if (protocol != http::Session::Protocol::HttpSsl)
#else
if (protocol != http::Session::Protocol::HttpUnencrypted)
#endif
{
continue; // Skip, unsupported.
}
auto httpSession = http::Session::create(_localUri);
httpSession->setTimeout(DefTimeoutSeconds);
std::condition_variable cv;
std::mutex mutex;
bool timedout = true;
httpSession->setFinishedHandler([&](const std::shared_ptr<http::Session>&) {
std::lock_guard<std::mutex> lock(mutex);
timedout = false;
cv.notify_all();
});
std::unique_lock<std::mutex> lock(mutex);
LOK_ASSERT(httpSession->asyncRequest(httpRequest, pollThread));
// Use Poco to get the same URL in parallel.
const auto pocoResponse = helpers::pocoGetRetry(Poco::URI(_localUri + URL));
cv.wait_for(lock, DefTimeoutSeconds);
const std::shared_ptr<const http::Response> httpResponse = httpSession->response();
LOK_ASSERT_EQUAL_MESSAGE("Timed out waiting for the onFinished handler", false, timedout);
LOK_ASSERT(httpResponse->state() == http::Response::State::Complete);
LOK_ASSERT(!httpResponse->statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse->statusLine().reasonPhrase().empty());
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
LOK_ASSERT(httpResponse->statusLine().statusCategory()
== http::StatusLine::StatusCodeClass::Successful);
LOK_ASSERT_EQUAL(pocoResponse.second, httpResponse->getBody());
}
pollThread.joinThread();
}
void HttpRequestTests::testSimpleGetSync()
{
constexpr auto testname = "simpleGetSync";
const auto data = Util::rng::getHexString(Util::rng::getNext() % 1024);
const auto body = std::string(data.data(), data.size());
const std::string URL = "/echo/" + body;
TST_LOG("Requesting URI: [" << URL << ']');
const auto pocoResponse = helpers::pocoGet(Poco::URI(_localUri + URL));
http::Request httpRequest(URL);
auto httpSession = http::Session::create(_localUri);
httpSession->setTimeout(std::chrono::seconds(1));
for (int i = 0; i < 5; ++i)
{
TST_LOG("Request #" << i);
const std::shared_ptr<const http::Response> httpResponse
= httpSession->syncRequest(httpRequest);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Complete);
LOK_ASSERT(!httpResponse->statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse->statusLine().reasonPhrase().empty());
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
LOK_ASSERT(httpResponse->statusLine().statusCategory()
== http::StatusLine::StatusCodeClass::Successful);
LOK_ASSERT_EQUAL(std::string("HTTP/1.1"), httpResponse->statusLine().httpVersion());
LOK_ASSERT_EQUAL(std::string("OK"), httpResponse->statusLine().reasonPhrase());
LOK_ASSERT_EQUAL(pocoResponse.second, httpResponse->getBody());
LOK_ASSERT_EQUAL(body, httpResponse->getBody());
}
}
void HttpRequestTests::testChunkedGetSync()
{
constexpr auto testname = "chunkedGetSync";
const auto data = Util::rng::getHexString(Util::rng::getNext() % 1024);
const auto body = std::string(data.data(), data.size());
const std::string URL = "/echo/chunked/" + body;
TST_LOG("Requesting URI: [" << URL << ']');
const auto pocoResponse = helpers::pocoGet(Poco::URI(_localUri + URL));
http::Request httpRequest(URL);
auto httpSession = http::Session::create(_localUri);
httpSession->setTimeout(DefTimeoutSeconds);
for (int i = 0; i < 5; ++i)
{
TST_LOG("Request #" << i);
const std::shared_ptr<const http::Response> httpResponse
= httpSession->syncRequest(httpRequest);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Complete);
LOK_ASSERT(!httpResponse->statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse->statusLine().reasonPhrase().empty());
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
LOK_ASSERT(httpResponse->statusLine().statusCategory()
== http::StatusLine::StatusCodeClass::Successful);
LOK_ASSERT_EQUAL(std::string("HTTP/1.1"), httpResponse->statusLine().httpVersion());
LOK_ASSERT_EQUAL(std::string("OK"), httpResponse->statusLine().reasonPhrase());
LOK_ASSERT_EQUAL(pocoResponse.second, httpResponse->getBody());
LOK_ASSERT_EQUAL(body, httpResponse->getBody());
}
}
void HttpRequestTests::testChunkedGetSync_External()
{
constexpr auto testname = "chunkedGetSync_External";
const std::string hostname = "http://anglesharp.azurewebsites.net";
const std::string URL = "/Chunked";
TST_LOG("Requesting URI: [" << hostname << URL << ']');
const auto pocoResponse = helpers::pocoGet(Poco::URI(hostname + URL));
http::Request httpRequest(URL);
auto httpSession = http::Session::create(hostname);
httpSession->setTimeout(DefTimeoutSeconds);
for (int i = 0; i < 5; ++i)
{
TST_LOG("Request #" << i);
const std::shared_ptr<const http::Response> httpResponse
= httpSession->syncRequest(httpRequest);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Complete);
LOK_ASSERT(!httpResponse->statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse->statusLine().reasonPhrase().empty());
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
LOK_ASSERT(httpResponse->statusLine().statusCategory()
== http::StatusLine::StatusCodeClass::Successful);
LOK_ASSERT_EQUAL(std::string("HTTP/1.1"), httpResponse->statusLine().httpVersion());
LOK_ASSERT_EQUAL(std::string("OK"), httpResponse->statusLine().reasonPhrase());
LOK_ASSERT_EQUAL(pocoResponse.second, httpResponse->getBody());
}
}
/// Compare the response from Poco with ours.
/// @checkReasonPhrase controls whether we compare the Reason Phrase too or not.
/// This is useful for when a status code is recognized by one and not the other.
/// @checkBody controls whether we compare the body content or not.
/// This is useful when we don't care about the content of the body, just that
/// there is some content at all or not.
static void compare(const Poco::Net::HTTPResponse& pocoResponse, const std::string& pocoBody,
const http::Response& httpResponse, bool checkReasonPhrase, bool checkBody,
const std::string& testname)
{
LOK_ASSERT_EQUAL_MESSAGE("Response state", httpResponse.state(),
http::Response::State::Complete);
LOK_ASSERT(!httpResponse.statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse.statusLine().reasonPhrase().empty());
if (checkBody)
LOK_ASSERT_EQUAL_MESSAGE("Body", pocoBody, httpResponse.getBody());
else
LOK_ASSERT_EQUAL_MESSAGE("Body empty?", pocoBody.empty(), httpResponse.getBody().empty());
LOK_ASSERT_EQUAL_MESSAGE("Status Code", static_cast<unsigned>(pocoResponse.getStatus()),
static_cast<unsigned>(httpResponse.statusLine().statusCode()));
if (checkReasonPhrase)
LOK_ASSERT_EQUAL_MESSAGE("Reason Phrase", Util::toLower(pocoResponse.getReason()),
Util::toLower(httpResponse.statusLine().reasonPhrase()));
else
LOK_ASSERT_EQUAL_MESSAGE("Reason Phrase empty?", pocoResponse.getReason().empty(),
httpResponse.statusLine().reasonPhrase().empty());
LOK_ASSERT_EQUAL_MESSAGE("hasContentLength", pocoResponse.hasContentLength(),
httpResponse.header().hasContentLength());
if (checkBody && pocoResponse.hasContentLength())
LOK_ASSERT_EQUAL_MESSAGE("ContentLength", pocoResponse.getContentLength(),
httpResponse.header().getContentLength());
}
/// This test requests specific *reponse* codes from
/// the server to test the handling of all possible
/// response status codes.
/// It exercises a few hundred requests/responses.
void HttpRequestTests::test500GetStatuses()
{
constexpr auto testname = "test500GetStatuses ";
wsd: test: fix heap-use-after-free In HttpRequestTests::test500GetStatuses, since we reused the http::Session without removing from SocketPoll, it is possible for the poll thread to access the Session object while we create a new request, where we replace its Response and Socket members. To avoid that, we can try to remove the http::Session instance from the SocketPoll. Alternatively, we can create a new one for each request, which is what we do here. Below is the results of ASan, for the record. ==949494==ERROR: AddressSanitizer: heap-use-after-free on address 0x61700005afe0 at pc 0x55dc0c092c75 bp 0x7f8b539e5a10 sp 0x7f8b539e5a08 READ of size 4 at 0x61700005afe0 thread T10 (HttpAsyncReqPol) #0 0x55dc0c092c74 in http::Response::logPrefix(std::ostream&) const /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 #1 0x55dc0c08f499 in http::Response::readData(char const*, long) /home/ash/prj/lo/online/test/../net/HttpRequest.cpp:641:5 #2 0x55dc0c0998c9 in http::Session::handleIncomingMessage(SocketDisposition&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1248:41 #3 0x55dc0c0f0c3b in StreamSocket::handlePoll(SocketDisposition&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, int) /home/ash/prj/lo/online/test/../net/Socket.hpp:1339:33 #4 0x55dc0c0b092d in SocketPoll::poll(long) /home/ash/prj/lo/online/test/../net/Socket.cpp:444:34 #5 0x55dc0c10407c in SocketPoll::poll(std::chrono::duration<long, std::ratio<1l, 1000000l> >) /home/ash/prj/lo/online/test/../net/Socket.hpp:691:61 #6 0x55dc0c10407c in SocketPoll::pollingThread() /home/ash/prj/lo/online/test/../net/Socket.hpp:648:13 #7 0x55dc0c0ac445 in SocketPoll::pollingThreadEntry() /home/ash/prj/lo/online/test/../net/Socket.cpp:299:9 #8 0x55dc0c12b6b9 in void std::__invoke_impl<void, void (SocketPoll::*)(), SocketPoll*>(std::__invoke_memfun_deref, void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #9 0x55dc0c12b590 in std::__invoke_result<void (SocketPoll::*)(), SocketPoll*>::type std::__invoke<void (SocketPoll::*)(), SocketPoll*>(void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #10 0x55dc0c12b574 in void std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:264:13 #11 0x55dc0c12b463 in std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:271:11 #12 0x55dc0c12b463 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:215:13 #13 0x7f8b5a08cde3 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6de3) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #14 0x7f8b59e4c608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8 #15 0x7f8b59d44132 in __clone /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95 0x61700005afe0 is located 736 bytes inside of 744-byte region [0x61700005ad00,0x61700005afe8) freed by thread T0 here: LLVMSymbolizer: error reading file: No such file or directory #0 0x55dc0bfe43dd in operator delete(void*) (/home/ash/prj/lo/online/test/unithttplib+0x20d3dd) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1fe168 in std::_Sp_counted_ptr<http::Response*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:380:9 #2 0x55dc0c033768 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:158:6 #3 0x55dc0c0335d5 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:733:11 #4 0x55dc0c1f972c in std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1183:31 #5 0x55dc0c1f972c in std::enable_if<__sp_is_constructible<http::Response, http::Response>::value, void>::type std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::reset<http::Response>(http::Response*) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1309:4 #6 0x55dc0c1f972c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:19 #7 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #8 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #9 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #10 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #11 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #12 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #13 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #14 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #15 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #16 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #17 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #18 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #19 0x7ffdc354a41f ([stack]+0x2b41f) previously allocated by thread T0 here: #0 0x55dc0bfe3b7d in operator new(unsigned long) (/home/ash/prj/lo/online/test/unithttplib+0x20cb7d) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1f969c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:25 #2 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #3 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) Thread T10 (HttpAsyncReqPol) created by T0 here: #0 0x55dc0bf922bc in __interceptor_pthread_create (/home/ash/prj/lo/online/test/unithttplib+0x1bb2bc) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x7f8b5a08d0a8 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd70a8) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #2 0x55dc0c0aa467 in SocketPoll::startThread() /home/ash/prj/lo/online/test/../net/Socket.cpp:238:23 #3 0x55dc0c1b57b3 in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:482:16 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) SUMMARY: AddressSanitizer: heap-use-after-free /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 in http::Response::logPrefix(std::ostream&) const Shadow bytes around the buggy address: 0x0c2e800035a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c2e800035f0: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fa fa fa 0x0c2e80003600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2e80003610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003620: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003630: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003640: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 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 ==949494==ABORTING Change-Id: I5e1539c3adbab9b5027d84cc1dbab4b90271c458 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-06-20 13:56:50 +02:00
// These should live longer than the pollThread,
// in case the socket isn't removed by the time we
// join (at the end of this function) and these
// by-then should still be in scope.
std::condition_variable cv;
std::mutex mutex;
bool timedout = true;
wsd: test: fix heap-use-after-free In HttpRequestTests::test500GetStatuses, since we reused the http::Session without removing from SocketPoll, it is possible for the poll thread to access the Session object while we create a new request, where we replace its Response and Socket members. To avoid that, we can try to remove the http::Session instance from the SocketPoll. Alternatively, we can create a new one for each request, which is what we do here. Below is the results of ASan, for the record. ==949494==ERROR: AddressSanitizer: heap-use-after-free on address 0x61700005afe0 at pc 0x55dc0c092c75 bp 0x7f8b539e5a10 sp 0x7f8b539e5a08 READ of size 4 at 0x61700005afe0 thread T10 (HttpAsyncReqPol) #0 0x55dc0c092c74 in http::Response::logPrefix(std::ostream&) const /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 #1 0x55dc0c08f499 in http::Response::readData(char const*, long) /home/ash/prj/lo/online/test/../net/HttpRequest.cpp:641:5 #2 0x55dc0c0998c9 in http::Session::handleIncomingMessage(SocketDisposition&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1248:41 #3 0x55dc0c0f0c3b in StreamSocket::handlePoll(SocketDisposition&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, int) /home/ash/prj/lo/online/test/../net/Socket.hpp:1339:33 #4 0x55dc0c0b092d in SocketPoll::poll(long) /home/ash/prj/lo/online/test/../net/Socket.cpp:444:34 #5 0x55dc0c10407c in SocketPoll::poll(std::chrono::duration<long, std::ratio<1l, 1000000l> >) /home/ash/prj/lo/online/test/../net/Socket.hpp:691:61 #6 0x55dc0c10407c in SocketPoll::pollingThread() /home/ash/prj/lo/online/test/../net/Socket.hpp:648:13 #7 0x55dc0c0ac445 in SocketPoll::pollingThreadEntry() /home/ash/prj/lo/online/test/../net/Socket.cpp:299:9 #8 0x55dc0c12b6b9 in void std::__invoke_impl<void, void (SocketPoll::*)(), SocketPoll*>(std::__invoke_memfun_deref, void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #9 0x55dc0c12b590 in std::__invoke_result<void (SocketPoll::*)(), SocketPoll*>::type std::__invoke<void (SocketPoll::*)(), SocketPoll*>(void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #10 0x55dc0c12b574 in void std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:264:13 #11 0x55dc0c12b463 in std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:271:11 #12 0x55dc0c12b463 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:215:13 #13 0x7f8b5a08cde3 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6de3) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #14 0x7f8b59e4c608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8 #15 0x7f8b59d44132 in __clone /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95 0x61700005afe0 is located 736 bytes inside of 744-byte region [0x61700005ad00,0x61700005afe8) freed by thread T0 here: LLVMSymbolizer: error reading file: No such file or directory #0 0x55dc0bfe43dd in operator delete(void*) (/home/ash/prj/lo/online/test/unithttplib+0x20d3dd) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1fe168 in std::_Sp_counted_ptr<http::Response*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:380:9 #2 0x55dc0c033768 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:158:6 #3 0x55dc0c0335d5 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:733:11 #4 0x55dc0c1f972c in std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1183:31 #5 0x55dc0c1f972c in std::enable_if<__sp_is_constructible<http::Response, http::Response>::value, void>::type std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::reset<http::Response>(http::Response*) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1309:4 #6 0x55dc0c1f972c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:19 #7 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #8 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #9 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #10 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #11 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #12 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #13 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #14 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #15 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #16 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #17 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #18 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #19 0x7ffdc354a41f ([stack]+0x2b41f) previously allocated by thread T0 here: #0 0x55dc0bfe3b7d in operator new(unsigned long) (/home/ash/prj/lo/online/test/unithttplib+0x20cb7d) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1f969c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:25 #2 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #3 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) Thread T10 (HttpAsyncReqPol) created by T0 here: #0 0x55dc0bf922bc in __interceptor_pthread_create (/home/ash/prj/lo/online/test/unithttplib+0x1bb2bc) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x7f8b5a08d0a8 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd70a8) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #2 0x55dc0c0aa467 in SocketPoll::startThread() /home/ash/prj/lo/online/test/../net/Socket.cpp:238:23 #3 0x55dc0c1b57b3 in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:482:16 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) SUMMARY: AddressSanitizer: heap-use-after-free /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 in http::Response::logPrefix(std::ostream&) const Shadow bytes around the buggy address: 0x0c2e800035a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c2e800035f0: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fa fa fa 0x0c2e80003600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2e80003610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003620: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003630: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003640: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 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 ==949494==ABORTING Change-Id: I5e1539c3adbab9b5027d84cc1dbab4b90271c458 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-06-20 13:56:50 +02:00
auto onFinished = [&](const std::shared_ptr<http::Session>&)
{
std::lock_guard<std::mutex> lock(mutex);
timedout = false;
cv.notify_all();
wsd: test: fix heap-use-after-free In HttpRequestTests::test500GetStatuses, since we reused the http::Session without removing from SocketPoll, it is possible for the poll thread to access the Session object while we create a new request, where we replace its Response and Socket members. To avoid that, we can try to remove the http::Session instance from the SocketPoll. Alternatively, we can create a new one for each request, which is what we do here. Below is the results of ASan, for the record. ==949494==ERROR: AddressSanitizer: heap-use-after-free on address 0x61700005afe0 at pc 0x55dc0c092c75 bp 0x7f8b539e5a10 sp 0x7f8b539e5a08 READ of size 4 at 0x61700005afe0 thread T10 (HttpAsyncReqPol) #0 0x55dc0c092c74 in http::Response::logPrefix(std::ostream&) const /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 #1 0x55dc0c08f499 in http::Response::readData(char const*, long) /home/ash/prj/lo/online/test/../net/HttpRequest.cpp:641:5 #2 0x55dc0c0998c9 in http::Session::handleIncomingMessage(SocketDisposition&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1248:41 #3 0x55dc0c0f0c3b in StreamSocket::handlePoll(SocketDisposition&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, int) /home/ash/prj/lo/online/test/../net/Socket.hpp:1339:33 #4 0x55dc0c0b092d in SocketPoll::poll(long) /home/ash/prj/lo/online/test/../net/Socket.cpp:444:34 #5 0x55dc0c10407c in SocketPoll::poll(std::chrono::duration<long, std::ratio<1l, 1000000l> >) /home/ash/prj/lo/online/test/../net/Socket.hpp:691:61 #6 0x55dc0c10407c in SocketPoll::pollingThread() /home/ash/prj/lo/online/test/../net/Socket.hpp:648:13 #7 0x55dc0c0ac445 in SocketPoll::pollingThreadEntry() /home/ash/prj/lo/online/test/../net/Socket.cpp:299:9 #8 0x55dc0c12b6b9 in void std::__invoke_impl<void, void (SocketPoll::*)(), SocketPoll*>(std::__invoke_memfun_deref, void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #9 0x55dc0c12b590 in std::__invoke_result<void (SocketPoll::*)(), SocketPoll*>::type std::__invoke<void (SocketPoll::*)(), SocketPoll*>(void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #10 0x55dc0c12b574 in void std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:264:13 #11 0x55dc0c12b463 in std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:271:11 #12 0x55dc0c12b463 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:215:13 #13 0x7f8b5a08cde3 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6de3) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #14 0x7f8b59e4c608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8 #15 0x7f8b59d44132 in __clone /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95 0x61700005afe0 is located 736 bytes inside of 744-byte region [0x61700005ad00,0x61700005afe8) freed by thread T0 here: LLVMSymbolizer: error reading file: No such file or directory #0 0x55dc0bfe43dd in operator delete(void*) (/home/ash/prj/lo/online/test/unithttplib+0x20d3dd) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1fe168 in std::_Sp_counted_ptr<http::Response*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:380:9 #2 0x55dc0c033768 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:158:6 #3 0x55dc0c0335d5 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:733:11 #4 0x55dc0c1f972c in std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1183:31 #5 0x55dc0c1f972c in std::enable_if<__sp_is_constructible<http::Response, http::Response>::value, void>::type std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::reset<http::Response>(http::Response*) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1309:4 #6 0x55dc0c1f972c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:19 #7 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #8 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #9 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #10 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #11 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #12 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #13 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #14 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #15 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #16 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #17 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #18 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #19 0x7ffdc354a41f ([stack]+0x2b41f) previously allocated by thread T0 here: #0 0x55dc0bfe3b7d in operator new(unsigned long) (/home/ash/prj/lo/online/test/unithttplib+0x20cb7d) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1f969c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:25 #2 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #3 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) Thread T10 (HttpAsyncReqPol) created by T0 here: #0 0x55dc0bf922bc in __interceptor_pthread_create (/home/ash/prj/lo/online/test/unithttplib+0x1bb2bc) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x7f8b5a08d0a8 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd70a8) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #2 0x55dc0c0aa467 in SocketPoll::startThread() /home/ash/prj/lo/online/test/../net/Socket.cpp:238:23 #3 0x55dc0c1b57b3 in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:482:16 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) SUMMARY: AddressSanitizer: heap-use-after-free /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 in http::Response::logPrefix(std::ostream&) const Shadow bytes around the buggy address: 0x0c2e800035a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c2e800035f0: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fa fa fa 0x0c2e80003600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2e80003610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003620: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003630: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003640: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 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 ==949494==ABORTING Change-Id: I5e1539c3adbab9b5027d84cc1dbab4b90271c458 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-06-20 13:56:50 +02:00
};
// Start the polling thread.
SocketPoll pollThread("AsyncReqPoll");
pollThread.startThread();
constexpr http::StatusLine::StatusCodeClass statusCodeClasses[] = {
http::StatusLine::StatusCodeClass::Informational,
http::StatusLine::StatusCodeClass::Successful,
http::StatusLine::StatusCodeClass::Redirection,
http::StatusLine::StatusCodeClass::Client_Error,
http::StatusLine::StatusCodeClass::Server_Error
};
int curStatusCodeClass = -1;
for (unsigned statusCode = 100; statusCode < 512; ++statusCode)
{
wsd: test: fix heap-use-after-free In HttpRequestTests::test500GetStatuses, since we reused the http::Session without removing from SocketPoll, it is possible for the poll thread to access the Session object while we create a new request, where we replace its Response and Socket members. To avoid that, we can try to remove the http::Session instance from the SocketPoll. Alternatively, we can create a new one for each request, which is what we do here. Below is the results of ASan, for the record. ==949494==ERROR: AddressSanitizer: heap-use-after-free on address 0x61700005afe0 at pc 0x55dc0c092c75 bp 0x7f8b539e5a10 sp 0x7f8b539e5a08 READ of size 4 at 0x61700005afe0 thread T10 (HttpAsyncReqPol) #0 0x55dc0c092c74 in http::Response::logPrefix(std::ostream&) const /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 #1 0x55dc0c08f499 in http::Response::readData(char const*, long) /home/ash/prj/lo/online/test/../net/HttpRequest.cpp:641:5 #2 0x55dc0c0998c9 in http::Session::handleIncomingMessage(SocketDisposition&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1248:41 #3 0x55dc0c0f0c3b in StreamSocket::handlePoll(SocketDisposition&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, int) /home/ash/prj/lo/online/test/../net/Socket.hpp:1339:33 #4 0x55dc0c0b092d in SocketPoll::poll(long) /home/ash/prj/lo/online/test/../net/Socket.cpp:444:34 #5 0x55dc0c10407c in SocketPoll::poll(std::chrono::duration<long, std::ratio<1l, 1000000l> >) /home/ash/prj/lo/online/test/../net/Socket.hpp:691:61 #6 0x55dc0c10407c in SocketPoll::pollingThread() /home/ash/prj/lo/online/test/../net/Socket.hpp:648:13 #7 0x55dc0c0ac445 in SocketPoll::pollingThreadEntry() /home/ash/prj/lo/online/test/../net/Socket.cpp:299:9 #8 0x55dc0c12b6b9 in void std::__invoke_impl<void, void (SocketPoll::*)(), SocketPoll*>(std::__invoke_memfun_deref, void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #9 0x55dc0c12b590 in std::__invoke_result<void (SocketPoll::*)(), SocketPoll*>::type std::__invoke<void (SocketPoll::*)(), SocketPoll*>(void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #10 0x55dc0c12b574 in void std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:264:13 #11 0x55dc0c12b463 in std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:271:11 #12 0x55dc0c12b463 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:215:13 #13 0x7f8b5a08cde3 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6de3) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #14 0x7f8b59e4c608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8 #15 0x7f8b59d44132 in __clone /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95 0x61700005afe0 is located 736 bytes inside of 744-byte region [0x61700005ad00,0x61700005afe8) freed by thread T0 here: LLVMSymbolizer: error reading file: No such file or directory #0 0x55dc0bfe43dd in operator delete(void*) (/home/ash/prj/lo/online/test/unithttplib+0x20d3dd) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1fe168 in std::_Sp_counted_ptr<http::Response*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:380:9 #2 0x55dc0c033768 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:158:6 #3 0x55dc0c0335d5 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:733:11 #4 0x55dc0c1f972c in std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1183:31 #5 0x55dc0c1f972c in std::enable_if<__sp_is_constructible<http::Response, http::Response>::value, void>::type std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::reset<http::Response>(http::Response*) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1309:4 #6 0x55dc0c1f972c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:19 #7 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #8 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #9 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #10 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #11 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #12 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #13 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #14 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #15 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #16 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #17 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #18 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #19 0x7ffdc354a41f ([stack]+0x2b41f) previously allocated by thread T0 here: #0 0x55dc0bfe3b7d in operator new(unsigned long) (/home/ash/prj/lo/online/test/unithttplib+0x20cb7d) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1f969c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:25 #2 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #3 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) Thread T10 (HttpAsyncReqPol) created by T0 here: #0 0x55dc0bf922bc in __interceptor_pthread_create (/home/ash/prj/lo/online/test/unithttplib+0x1bb2bc) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x7f8b5a08d0a8 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd70a8) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #2 0x55dc0c0aa467 in SocketPoll::startThread() /home/ash/prj/lo/online/test/../net/Socket.cpp:238:23 #3 0x55dc0c1b57b3 in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:482:16 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) SUMMARY: AddressSanitizer: heap-use-after-free /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 in http::Response::logPrefix(std::ostream&) const Shadow bytes around the buggy address: 0x0c2e800035a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c2e800035f0: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fa fa fa 0x0c2e80003600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2e80003610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003620: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003630: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003640: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 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 ==949494==ABORTING Change-Id: I5e1539c3adbab9b5027d84cc1dbab4b90271c458 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-06-20 13:56:50 +02:00
auto httpSession = http::Session::create(_localUri);
httpSession->setTimeout(DefTimeoutSeconds);
httpSession->setFinishedHandler(onFinished);
const std::string url = "/status/" + std::to_string(statusCode);
http::Request httpRequest;
httpRequest.setUrl(url);
TST_LOG("Requesting Status Code [" << statusCode << "]: " << url);
std::unique_lock<std::mutex> lock(mutex);
timedout = true; // Assume we timed out until we prove otherwise.
LOK_ASSERT(httpSession->asyncRequest(httpRequest, pollThread));
// Get via Poco in parallel.
std::pair<std::shared_ptr<Poco::Net::HTTPResponse>, std::string> pocoResponse;
if (statusCode > 100)
pocoResponse = helpers::pocoGetRetry(Poco::URI(_localUri + url));
#ifdef ENABLE_EXTERNAL_REGRESSION_CHECK
std::pair<std::shared_ptr<Poco::Net::HTTPResponse>, std::string> pocoResponseExt;
if (statusCode > 100)
pocoResponseExt = helpers::pocoGet(false, "httpbin.org", 80, url);
#endif
const std::shared_ptr<const http::Response> httpResponse = httpSession->response();
cv.wait_for(lock, DefTimeoutSeconds, [&]() { return httpResponse->done(); });
TST_LOG("Finished async GET: " << url);
httpSession->asyncShutdown(); // Request to shutdown.
LOK_ASSERT_EQUAL(http::Response::State::Complete, httpResponse->state());
LOK_ASSERT(!httpResponse->statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse->statusLine().reasonPhrase().empty());
if (statusCode % 100 == 0)
++curStatusCodeClass;
LOK_ASSERT(httpResponse->statusLine().statusCategory()
== statusCodeClasses[curStatusCodeClass]);
LOK_ASSERT_EQUAL(statusCode,
static_cast<unsigned>(httpResponse->statusLine().statusCode()));
// Poco throws exception "No message received" for 1xx Status Codes.
if (statusCode > 100)
{
compare(*pocoResponse.first, pocoResponse.second, *httpResponse, true, true, testname);
#ifdef ENABLE_EXTERNAL_REGRESSION_CHECK
// These Status Codes are not recognized by httpbin.org,
// so we get "unknown" and must skip comparing them.
const bool checkReasonPhrase
= (statusCode != 103 && statusCode != 208 && statusCode != 413 && statusCode != 414
&& statusCode != 416 && statusCode != 421 && statusCode != 425
&& statusCode != 440 && statusCode != 508 && statusCode != 511);
const bool checkBody = (statusCode != 402 && statusCode != 418);
compare(*pocoResponseExt.first, pocoResponseExt.second, *httpResponse,
checkReasonPhrase, checkBody, testname);
#endif
}
}
pollThread.joinThread();
}
void HttpRequestTests::testSimplePost_External()
{
constexpr auto testname = __func__;
const std::string Host = "httpbin.org";
const char* URL = "/post";
// Start the polling thread.
wsd: test: fix heap-use-after-free In HttpRequestTests::test500GetStatuses, since we reused the http::Session without removing from SocketPoll, it is possible for the poll thread to access the Session object while we create a new request, where we replace its Response and Socket members. To avoid that, we can try to remove the http::Session instance from the SocketPoll. Alternatively, we can create a new one for each request, which is what we do here. Below is the results of ASan, for the record. ==949494==ERROR: AddressSanitizer: heap-use-after-free on address 0x61700005afe0 at pc 0x55dc0c092c75 bp 0x7f8b539e5a10 sp 0x7f8b539e5a08 READ of size 4 at 0x61700005afe0 thread T10 (HttpAsyncReqPol) #0 0x55dc0c092c74 in http::Response::logPrefix(std::ostream&) const /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 #1 0x55dc0c08f499 in http::Response::readData(char const*, long) /home/ash/prj/lo/online/test/../net/HttpRequest.cpp:641:5 #2 0x55dc0c0998c9 in http::Session::handleIncomingMessage(SocketDisposition&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1248:41 #3 0x55dc0c0f0c3b in StreamSocket::handlePoll(SocketDisposition&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, int) /home/ash/prj/lo/online/test/../net/Socket.hpp:1339:33 #4 0x55dc0c0b092d in SocketPoll::poll(long) /home/ash/prj/lo/online/test/../net/Socket.cpp:444:34 #5 0x55dc0c10407c in SocketPoll::poll(std::chrono::duration<long, std::ratio<1l, 1000000l> >) /home/ash/prj/lo/online/test/../net/Socket.hpp:691:61 #6 0x55dc0c10407c in SocketPoll::pollingThread() /home/ash/prj/lo/online/test/../net/Socket.hpp:648:13 #7 0x55dc0c0ac445 in SocketPoll::pollingThreadEntry() /home/ash/prj/lo/online/test/../net/Socket.cpp:299:9 #8 0x55dc0c12b6b9 in void std::__invoke_impl<void, void (SocketPoll::*)(), SocketPoll*>(std::__invoke_memfun_deref, void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #9 0x55dc0c12b590 in std::__invoke_result<void (SocketPoll::*)(), SocketPoll*>::type std::__invoke<void (SocketPoll::*)(), SocketPoll*>(void (SocketPoll::*&&)(), SocketPoll*&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #10 0x55dc0c12b574 in void std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:264:13 #11 0x55dc0c12b463 in std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:271:11 #12 0x55dc0c12b463 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (SocketPoll::*)(), SocketPoll*> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/thread:215:13 #13 0x7f8b5a08cde3 (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6de3) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #14 0x7f8b59e4c608 in start_thread /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8 #15 0x7f8b59d44132 in __clone /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95 0x61700005afe0 is located 736 bytes inside of 744-byte region [0x61700005ad00,0x61700005afe8) freed by thread T0 here: LLVMSymbolizer: error reading file: No such file or directory #0 0x55dc0bfe43dd in operator delete(void*) (/home/ash/prj/lo/online/test/unithttplib+0x20d3dd) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1fe168 in std::_Sp_counted_ptr<http::Response*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:380:9 #2 0x55dc0c033768 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:158:6 #3 0x55dc0c0335d5 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:733:11 #4 0x55dc0c1f972c in std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1183:31 #5 0x55dc0c1f972c in std::enable_if<__sp_is_constructible<http::Response, http::Response>::value, void>::type std::__shared_ptr<http::Response, (__gnu_cxx::_Lock_policy)2>::reset<http::Response>(http::Response*) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/shared_ptr_base.h:1309:4 #6 0x55dc0c1f972c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:19 #7 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #8 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #9 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #10 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #11 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #12 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #13 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #14 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #15 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #16 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #17 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #18 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #19 0x7ffdc354a41f ([stack]+0x2b41f) previously allocated by thread T0 here: #0 0x55dc0bfe3b7d in operator new(unsigned long) (/home/ash/prj/lo/online/test/unithttplib+0x20cb7d) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x55dc0c1f969c in http::Session::newRequest(http::Request) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1174:25 #2 0x55dc0c1ee08b in http::Session::asyncRequest(http::Request const&, SocketPoll&) /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:1079:9 #3 0x55dc0c1b718f in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:515:9 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) Thread T10 (HttpAsyncReqPol) created by T0 here: #0 0x55dc0bf922bc in __interceptor_pthread_create (/home/ash/prj/lo/online/test/unithttplib+0x1bb2bc) (BuildId: 7954f6bea5efa6c39ca02e7033c014e826b9f5fd) #1 0x7f8b5a08d0a8 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd70a8) (BuildId: c90e6603c7cdf84713cd445700a575d3ea446d9b) #2 0x55dc0c0aa467 in SocketPoll::startThread() /home/ash/prj/lo/online/test/../net/Socket.cpp:238:23 #3 0x55dc0c1b57b3 in HttpRequestTests::test500GetStatuses() /home/ash/prj/lo/online/test/HttpRequestTests.cpp:482:16 #4 0x55dc0c219ec9 in void std::__invoke_impl<void, void (HttpRequestTests::*&)(), HttpRequestTests*&>(std::__invoke_memfun_deref, void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:73:14 #5 0x55dc0c219de0 in std::__invoke_result<void (HttpRequestTests::*&)(), HttpRequestTests*&>::type std::__invoke<void (HttpRequestTests::*&)(), HttpRequestTests*&>(void (HttpRequestTests::*&)(), HttpRequestTests*&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:95:14 #6 0x55dc0c219dbc in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::__call<void, 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:416:11 #7 0x55dc0c219d47 in void std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>::operator()<void>() /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:499:17 #8 0x55dc0c219d47 in void std::__invoke_impl<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::__invoke_other, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:60:14 #9 0x55dc0c219d47 in std::enable_if<is_invocable_r_v<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>, void>::type std::__invoke_r<void, std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&>(std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()>&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/invoke.h:110:2 #10 0x55dc0c219a72 in std::_Function_handler<void (), std::_Bind<void (HttpRequestTests::* (HttpRequestTests*))()> >::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:291:9 #11 0x55dc0c09776b in std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/std_function.h:622:14 #12 0x55dc0c219713 in CppUnit::TestCaller<HttpRequestTests>::runTest() /usr/include/cppunit/TestCaller.h:175:7 #13 0x7f8b5ab23614 in CppUnit::TestCaseMethodFunctor::operator()() const (/usr/lib/x86_64-linux-gnu/libcppunit-1.15.so.1+0x24614) (BuildId: 4329d55843a6cf32b3e88d4d9aec95035315b163) #14 0x7ffdc354a41f ([stack]+0x2b41f) SUMMARY: AddressSanitizer: heap-use-after-free /home/ash/prj/lo/online/test/../net/HttpRequest.hpp:835:66 in http::Response::logPrefix(std::ostream&) const Shadow bytes around the buggy address: 0x0c2e800035a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e800035e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c2e800035f0: fd fd fd fd fd fd fd fd fd fd fd fd[fd]fa fa fa 0x0c2e80003600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c2e80003610: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003620: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003630: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c2e80003640: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 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 ==949494==ABORTING Change-Id: I5e1539c3adbab9b5027d84cc1dbab4b90271c458 Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
2022-06-20 13:56:50 +02:00
SocketPoll pollThread("AsyncReqPoll");
pollThread.startThread();
http::Request httpRequest(URL, http::Request::VERB_POST);
// Write the test data to file.
const char data[] = "abcd-qwerty!!!";
const std::string path = FileUtil::getSysTempDirectoryPath() + "/test_http_post";
std::ofstream ofs(path, std::ios::binary);
ofs.write(data, sizeof(data) - 1); // Don't write the terminating null.
ofs.close();
httpRequest.setBodyFile(path);
auto httpSession = http::Session::createHttpSsl(Host);
httpSession->setTimeout(DefTimeoutSeconds);
std::condition_variable cv;
std::mutex mutex;
bool timedout = true;
httpSession->setFinishedHandler([&](const std::shared_ptr<http::Session>&) {
std::lock_guard<std::mutex> lock(mutex);
timedout = false;
cv.notify_all();
});
std::unique_lock<std::mutex> lock(mutex);
LOK_ASSERT(httpSession->asyncRequest(httpRequest, pollThread));
cv.wait_for(lock, DefTimeoutSeconds);
const std::shared_ptr<const http::Response> httpResponse = httpSession->response();
LOK_ASSERT(httpResponse->state() == http::Response::State::Complete);
LOK_ASSERT(!httpResponse->statusLine().httpVersion().empty());
LOK_ASSERT(!httpResponse->statusLine().reasonPhrase().empty());
LOK_ASSERT_EQUAL(http::StatusCode::OK, httpResponse->statusLine().statusCode());
LOK_ASSERT(httpResponse->statusLine().statusCategory()
== http::StatusLine::StatusCodeClass::Successful);
const std::string body = httpResponse->getBody();
LOK_ASSERT(!body.empty());
std::cerr << "[" << body << "]\n";
LOK_ASSERT(body.find(data) != std::string::npos);
pollThread.joinThread();
}
void HttpRequestTests::testTimeout()
{
constexpr auto testname = __func__;
const char* URL = "/timeout";
http::Request httpRequest(URL);
auto httpSession = http::Session::create(_localUri);
httpSession->setTimeout(std::chrono::milliseconds(1)); // Very short interval.
const std::shared_ptr<const http::Response> httpResponse
= httpSession->syncRequest(httpRequest);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Timeout);
}
void HttpRequestTests::testOnFinished_Complete()
{
constexpr auto testname = __func__;
const char* URL = "/";
http::Request httpRequest(URL);
auto httpSession = http::Session::create(_localUri);
bool completed = false;
httpSession->setFinishedHandler([&](const std::shared_ptr<http::Session>& session) {
LOK_ASSERT(session->response()->done());
LOK_ASSERT(session->response()->state() == http::Response::State::Complete);
completed = true;
return true;
});
const std::shared_ptr<const http::Response> httpResponse
= httpSession->syncRequest(httpRequest);
LOK_ASSERT(completed);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Complete);
}
void HttpRequestTests::testOnFinished_Timeout()
{
constexpr auto testname = __func__;
const char* URL = "/timeout";
http::Request httpRequest(URL);
auto httpSession = http::Session::create(_localUri);
httpSession->setTimeout(std::chrono::milliseconds(1)); // Very short interval.
bool completed = false;
httpSession->setFinishedHandler([&](const std::shared_ptr<http::Session>& session) {
LOK_ASSERT(session->response()->done());
LOK_ASSERT(session->response()->state() == http::Response::State::Timeout);
completed = true;
return true;
});
const std::shared_ptr<const http::Response> httpResponse
= httpSession->syncRequest(httpRequest);
LOK_ASSERT(completed);
LOK_ASSERT(httpResponse->done());
LOK_ASSERT(httpResponse->state() == http::Response::State::Timeout);
}
CPPUNIT_TEST_SUITE_REGISTRATION(HttpRequestTests);
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */