Skip to content

Commit f126e40

Browse files
committed
Merge branch 'release/v1.1.11'
2 parents de9d770 + 7d21ac7 commit f126e40

File tree

8 files changed

+74
-27
lines changed

8 files changed

+74
-27
lines changed

.github/workflows/run.sh

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ build() {
2121
}
2222

2323
build_testing() {
24-
if [[ $# -lt 1 ]]; then
25-
echo "Build folder is absent"
24+
if [[ $# -lt 2 ]]; then
25+
echo "Build folder and/or build type are absent"
2626
return 1
2727
fi
2828

2929
declare -r folder="$1"
30+
declare -r build_type="$2"
3031

31-
build "$folder" "testing" "-DSTREAMCLIENT_BUILD_TESTING=ON" \
32+
build "$folder" "testing" "-DCMAKE_BUILD_TYPE=$build_type" \
33+
"-DSTREAMCLIENT_BUILD_TESTING=ON" \
3234
"-DSTREAMCLIENT_BUILD_DOCS=OFF" \
3335
"-DSTREAMCLIENT_BUILD_EXAMPLES=OFF" \
3436
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"\
@@ -46,10 +48,12 @@ collect_coverage() {
4648
}
4749

4850
if [[ "$1" == "test" ]] ; then
49-
build_testing "build"
51+
build_testing "build-tsan" "Tsan"
52+
build_testing "build-asan" "Asan"
53+
build_testing "build-ubsan" "Ubsan"
5054

5155
elif [[ "$1" == "coverage" ]] ; then
52-
build_testing "build"
56+
build_testing "build" "Debug"
5357
collect_coverage "build"
5458

5559
elif [[ "$1" == "collect-coverage" ]] ; then

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@
4141
.idea/
4242
.gradle/
4343
build/
44+
build-*/
4445
coverage-build/
4546
coverage.*

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## 1.1.11 (2021-08-20)
2+
3+
### Bug Fixes
4+
5+
* connector::base_connector: fix UB in dealing with boolean flag
6+
7+
### Misc
8+
9+
* Add thread/address/UB sanitizers build to CI
10+
11+
112
## 1.1.10 (2021-08-17)
213

314
### Bug Fixes

CMakeLists.txt

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
22

33
set(STREAMCLIENT_VERSION_MAJOR "1")
44
set(STREAMCLIENT_VERSION_MINOR "1")
5-
set(STREAMCLIENT_VERSION_RELEASE "10")
5+
set(STREAMCLIENT_VERSION_RELEASE "11")
66
set(STREAMCLIENT_SUMMARY "C++ library")
77
set(STREAMCLIENT_REPOSITORY_URL "https://github.com/TinkoffCreditSystems/stream-client")
88
set(STREAMCLIENT_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
@@ -32,6 +32,30 @@ if(NOT CMAKE_BUILD_TYPE)
3232
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
3333
endif()
3434

35+
# ThreadSanitizer
36+
set(CMAKE_CXX_FLAGS_TSAN "-fsanitize=thread -g -O1"
37+
CACHE STRING "Flags used by the C++ compiler during ThreadSanitizer builds."
38+
FORCE
39+
)
40+
# AddressSanitize
41+
set(CMAKE_CXX_FLAGS_ASAN "-fsanitize=address \
42+
-fno-optimize-sibling-calls \
43+
-fsanitize-address-use-after-scope \
44+
-fno-omit-frame-pointer -g -O1"
45+
CACHE STRING "Flags used by the C++ compiler during AddressSanitizer builds."
46+
FORCE
47+
)
48+
# LeakSanitizer
49+
set(CMAKE_CXX_FLAGS_LSAN "-fsanitize=leak -fno-omit-frame-pointer -g -O1"
50+
CACHE STRING "Flags used by the C++ compiler during LeakSanitizer builds."
51+
FORCE
52+
)
53+
# UndefinedBehaviour
54+
set(CMAKE_CXX_FLAGS_UBSAN "-fsanitize=undefined"
55+
CACHE STRING "Flags used by the C++ compiler during UndefinedBehaviourSanitizer builds."
56+
FORCE
57+
)
58+
3559
option(STREAMCLIENT_BUILD_TESTING "Build included unit-tests" OFF)
3660
option(STREAMCLIENT_BUILD_DOCS "Build sphinx generated docs" OFF)
3761
option(STREAMCLIENT_BUILD_EXAMPLES "Build stream-client examples" OFF)
@@ -124,11 +148,13 @@ install(EXPORT ${PROJECT_NAME}-targets
124148
if(STREAMCLIENT_BUILD_TESTING)
125149
include(CTest)
126150

127-
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
128-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
129-
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
130-
if(NOT APPLE)
131-
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -lgcov")
151+
if(CMAKE_BUILD_TYPE STREQUAL Debug)
152+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
153+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
154+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
155+
if(NOT APPLE)
156+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov")
157+
endif()
132158
endif()
133159

134160
add_subdirectory(tests)

include/stream-client/connector/connector.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "stream-client/resolver/resolver.hpp"
44
#include "stream-client/stream/http_socket.hpp"
55

6+
#include <atomic>
67
#include <condition_variable>
78
#include <mutex>
89

@@ -277,17 +278,17 @@ class base_connector
277278
endpoint_container_type endpoints_; ///< Resolved endpoints.
278279
mutable std::mutex endpoints_mutex_; ///< @p endpoints_ mutex.
279280

280-
bool resolving_thread_running_ = true; ///< Flag to stop @p resolving_thread_.
281+
std::atomic_bool resolving_thread_running_{true}; ///< Flag to stop @p resolving_thread_.
281282
std::thread resolving_thread_; ///< Thread to run resolve_routine() in.
282283

283284
boost::system::error_code resolve_error_; ///< Error value propagated from @p resolving_thread_.
284285
mutable std::mutex resolve_error_mutex_; ///< @p resolve_error_ mutex.
285286

286287
/* used to implement waits on update/done events without polling */
287-
bool resolve_needed_ = true; ///< Flag to trigger @p resolving_thread_ to reresolve.
288+
bool resolve_needed_{true}; ///< Flag to trigger @p resolving_thread_ to reresolve.
288289
std::timed_mutex resolve_needed_mutex_; ///< @p resolve_needed_ mutex.
289290
std::condition_variable_any resolve_needed_cv_; ///< @p resolve_needed_ condition variable.
290-
bool resolve_done_ = false; ///< Flag to notify that @p resolving_thread_ has done @p endpoints_ update.
291+
bool resolve_done_{false}; ///< Flag to notify that @p resolving_thread_ has done @p endpoints_ update.
291292
std::timed_mutex resolve_done_mutex_; ///< @p resolve_done_ mutex.
292293
std::condition_variable_any resolve_done_cv_; ///< @p resolve_done_ condition variable.
293294
};

include/stream-client/connector/impl/connector.ipp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ base_connector<Stream>::base_connector(const std::string& host, const std::strin
3131
{
3232
resolve_done_ = false;
3333
resolve_needed_ = true;
34-
resolving_thread_running_ = true;
34+
resolving_thread_running_.store(true, std::memory_order_release);
3535
resolving_thread_ = std::thread([this]() { this->resolve_routine(); });
3636
}
3737

3838
template <typename Stream>
3939
base_connector<Stream>::~base_connector()
4040
{
41-
resolving_thread_running_ = false;
41+
resolving_thread_running_.store(false, std::memory_order_release);
4242
if (resolving_thread_.joinable()) {
4343
resolving_thread_.join();
4444
}
@@ -89,7 +89,7 @@ void base_connector<Stream>::resolve_routine()
8989
{
9090
static const auto lock_timeout = std::chrono::milliseconds(100);
9191

92-
while (resolving_thread_running_) {
92+
while (resolving_thread_running_.load(std::memory_order_acquire)) {
9393
std::unique_lock<std::timed_mutex> resolve_needed_lk(resolve_needed_mutex_, std::defer_lock);
9494
if (!resolve_needed_lk.try_lock_for(lock_timeout) ||
9595
!resolve_needed_cv_.wait_for(resolve_needed_lk, lock_timeout, [this] { return resolve_needed_; })) {

tests/timeout.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ TYPED_TEST(ServerEnv, ConnectZeroTimeout)
1212
boost::asio::error::timed_out);
1313

1414
const auto elapsed = std::chrono::steady_clock::now() - start_t;
15-
EXPECT_TIME_GE(elapsed, std::chrono::milliseconds(0));
16-
EXPECT_TIME_LE(elapsed, std::chrono::milliseconds(20));
15+
EXPECT_TIME_LE(elapsed, std::chrono::milliseconds(50)); // actual time differs with sanitized builds
1716
}
1817

1918
TEST_F(TCPServerEnv, ConnectTimeout)

tests/utils/echo_server.hpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ class echo_session
1717
{
1818
}
1919

20+
echo_session(const echo_session<Socket>& other) = delete;
21+
echo_session<Socket>& operator=(const echo_session<Socket>& other) = delete;
22+
echo_session(echo_session<Socket>&& other) = default;
23+
echo_session<Socket>& operator=(echo_session<Socket>&& other) = default;
24+
2025
virtual ~echo_session() = default;
2126

2227
protected:
@@ -345,12 +350,12 @@ class tcp_base_server: public echo_server<Session>
345350
auto future = promise.get_future();
346351

347352
session_threads_.emplace_back(
348-
[=](std::promise<Session>&& promise) {
349-
std::unique_lock<std::mutex> lk(acceptor_mutex_);
353+
[this](std::promise<Session>&& promise) {
354+
std::unique_lock<std::mutex> lk(this->acceptor_mutex_);
350355

351356
auto sock = std::make_shared<boost::asio::ip::tcp::socket>(*this->io_service_);
352357
this->acceptor_.accept(*sock);
353-
promise.set_value_at_thread_exit(Session(this->io_service_, std::move(sock)));
358+
promise.set_value(Session(this->io_service_, std::move(sock)));
354359
},
355360
std::move(promise));
356361

@@ -422,13 +427,13 @@ class ssl_server: public echo_server<ssl_session>
422427
auto future = promise.get_future();
423428

424429
session_threads_.emplace_back(
425-
[=](std::promise<ssl_session>&& promise) {
426-
std::unique_lock<std::mutex> lk(acceptor_mutex_);
430+
[this](std::promise<ssl_session>&& promise) {
431+
std::unique_lock<std::mutex> lk(this->acceptor_mutex_);
427432

428433
auto session = ssl_session(this->io_service_, context_);
429434
this->acceptor_.accept(session.get_socket());
430435
session.get_ssl_socket().handshake(boost::asio::ssl::stream_base::server);
431-
promise.set_value_at_thread_exit(std::move(session));
436+
promise.set_value(std::move(session));
432437
},
433438
std::move(promise));
434439

@@ -472,8 +477,8 @@ class udp_server: public echo_server<udp_session>
472477
auto future = promise.get_future();
473478

474479
session_threads_.emplace_back(
475-
[=](std::promise<udp_session>&& promise) {
476-
promise.set_value_at_thread_exit(udp_session(this->io_service_, this->socket_));
480+
[this](std::promise<udp_session>&& promise) {
481+
promise.set_value(udp_session(this->io_service_, this->socket_));
477482
},
478483
std::move(promise));
479484

0 commit comments

Comments
 (0)