Unverified Commit 4c2c9871 authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #982

Fix undefined behavior, build with UBSan in Jenkins
parents c6050d9b 1412244d
...@@ -313,10 +313,10 @@ else() ...@@ -313,10 +313,10 @@ else()
endif() endif()
# enable address sanitizer if requested by the user # enable address sanitizer if requested by the user
if(CAF_ENABLE_ADDRESS_SANITIZER AND NOT WIN32) if(CAF_SANITIZERS)
add_compile_options("-fsanitize=address" add_compile_options("-fsanitize=${CAF_SANITIZERS}"
"-fno-omit-frame-pointer") "-fno-omit-frame-pointer")
list(APPEND CAF_EXTRA_LDFLAGS "-fsanitize=address") list(APPEND CAF_EXTRA_LDFLAGS "-fsanitize=${CAF_SANITIZERS}")
endif() endif()
# -pthread is ignored on MacOSX but required on other platforms # -pthread is ignored on MacOSX but required on other platforms
if(NOT APPLE AND NOT WIN32) if(NOT APPLE AND NOT WIN32)
......
...@@ -6,12 +6,11 @@ ...@@ -6,12 +6,11 @@
defaultReleaseBuildFlags = [ defaultReleaseBuildFlags = [
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes', 'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes',
'CAF_NO_OPENCL:BOOL=yes', 'CAF_NO_OPENCL:BOOL=yes',
'CAF_INSTALL_UNIT_TESTS:BOOL=yes',
] ]
// Default CMake flags for debug builds. // Default CMake flags for debug builds.
defaultDebugBuildFlags = defaultReleaseBuildFlags + [ defaultDebugBuildFlags = defaultReleaseBuildFlags + [
'CAF_ENABLE_ADDRESS_SANITIZER:BOOL=yes', 'CAF_SANITIZERS:STRING=address,undefined',
'CAF_LOG_LEVEL:STRING=TRACE', 'CAF_LOG_LEVEL:STRING=TRACE',
'CAF_ENABLE_ACTOR_PROFILER:BOOL=yes', 'CAF_ENABLE_ACTOR_PROFILER:BOOL=yes',
] ]
...@@ -99,7 +98,9 @@ config = [ ...@@ -99,7 +98,9 @@ config = [
], ],
], ],
Windows: [ Windows: [
debug: defaultDebugBuildFlags + [ debug: [
'CAF_LOG_LEVEL:STRING=TRACE',
'CAF_ENABLE_ACTOR_PROFILER:BOOL=yes',
'CAF_BUILD_STATIC_ONLY:BOOL=yes', 'CAF_BUILD_STATIC_ONLY:BOOL=yes',
], ],
release: defaultReleaseBuildFlags + [ release: defaultReleaseBuildFlags + [
......
...@@ -76,16 +76,14 @@ Usage: $0 [OPTION]... [VAR=VALUE]... ...@@ -76,16 +76,14 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
- INFO - INFO
- DEBUG - DEBUG
- TRACE - TRACE
--with-address-sanitizer build with address sanitizer if available --with-sanitizers=LIST build with this list of sanitizers enabled
--with-asan alias for --with-address-sanitier
--enable-asan alias for --with-address-sanitier
--with-gcov build with gcov coverage enabled
--with-actor-profiler enables the (experimental) actor_profiler API --with-actor-profiler enables the (experimental) actor_profiler API
Convenience options: Convenience options:
--dev-mode sets --build-type=debug, --no-examples, --dev-mode sets --build-type=debug, --no-examples,
--no-tools, --with-runtime-checks, --no-tools, --with-runtime-checks,
--log-level=trace, and --enable-asan --log-level=trace, and
--sanitizers=address,undefined
Influential Environment Variables (only on first invocation): Influential Environment Variables (only on first invocation):
CXX C++ compiler command CXX C++ compiler command
...@@ -238,17 +236,8 @@ while [ $# -ne 0 ]; do ...@@ -238,17 +236,8 @@ while [ $# -ne 0 ]; do
--with-runtime-checks) --with-runtime-checks)
append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes
;; ;;
--with-address-sanitizer) --with-sanitizers=*)
append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes append_cache_entry CAF_SANITIZERS STRING "$optarg"
;;
--with-asan)
append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes
;;
--enable-asan)
append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes
;;
--with-gcov)
append_cache_entry CAF_ENABLE_GCOV BOOL yes
;; ;;
--with-actor-profiler) --with-actor-profiler)
append_cache_entry CAF_ENABLE_ACTOR_PROFILER BOOL yes append_cache_entry CAF_ENABLE_ACTOR_PROFILER BOOL yes
...@@ -374,12 +363,12 @@ while [ $# -ne 0 ]; do ...@@ -374,12 +363,12 @@ while [ $# -ne 0 ]; do
done done
;; ;;
--dev-mode) --dev-mode)
append_cache_entry CMAKE_BUILD_TYPE STRING Debug for var in CAF_NO_TOOLS CAF_NO_EXAMPLES CAF_ENABLE_RUNTIME_CHECKS ; do
append_cache_entry CAF_NO_EXAMPLES BOOL yes append_cache_entry $var BOOL yes
append_cache_entry CAF_NO_TOOLS BOOL yes done
append_cache_entry CMAKE_BUILD_TYPE STRING debug
append_cache_entry CAF_LOG_LEVEL STRING TRACE append_cache_entry CAF_LOG_LEVEL STRING TRACE
append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes append_cache_entry CAF_SANITIZERS STRING address,undefined
append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes
;; ;;
*) *)
echo "Invalid option '$1'. Try $0 --help to see available options." echo "Invalid option '$1'. Try $0 --help to see available options."
......
...@@ -55,13 +55,16 @@ protected: ...@@ -55,13 +55,16 @@ protected:
}; };
/// Wraps a user-defined function and gives it a uniform signature. /// Wraps a user-defined function and gives it a uniform signature.
template <class Base, class F, class ArgsPtr, bool ReturnsBehavior, template <class Base, class F, class Tuple, bool ReturnsBehavior,
bool HasSelfPtr> bool HasSelfPtr>
class init_fun_factory_helper final : public init_fun_factory_helper_base { class init_fun_factory_helper final : public init_fun_factory_helper_base {
public: public:
init_fun_factory_helper(F fun, ArgsPtr args) using args_pointer = std::shared_ptr<Tuple>;
: fun_(std::move(fun)),
args_(std::move(args)) { static constexpr bool args_empty = std::tuple_size<Tuple>::value == 0;
init_fun_factory_helper(F fun, args_pointer args)
: fun_(std::move(fun)), args_(std::move(args)) {
// nop // nop
} }
...@@ -72,41 +75,52 @@ public: ...@@ -72,41 +75,52 @@ public:
behavior operator()(local_actor* self) final { behavior operator()(local_actor* self) final {
if (hook_ != nullptr) if (hook_ != nullptr)
hook_(self); hook_(self);
bool_token<ReturnsBehavior> returns_behavior_token; auto dptr = static_cast<Base*>(self);
bool_token<HasSelfPtr> captures_self_token; if constexpr (ReturnsBehavior) {
return apply(returns_behavior_token, captures_self_token, self); auto unbox = [](auto x) -> behavior { return std::move(x.unbox()); };
} if constexpr (args_empty) {
if constexpr (HasSelfPtr) {
private:
// behavior (pointer) // behavior (pointer)
behavior apply(std::true_type, std::true_type, local_actor* ptr) { return unbox(fun_(dptr));
auto res = apply_moved_args_prefixed(fun_, get_indices(*args_), *args_, } else {
static_cast<Base*>(ptr)); // behavior ()
return std::move(res.unbox()); return unbox(fun_());
} }
} else {
// void (pointer) if constexpr (HasSelfPtr) {
behavior apply(std::false_type, std::true_type, local_actor* ptr) { // behavior (pointer, args...)
apply_moved_args_prefixed(fun_, get_indices(*args_), auto res = apply_moved_args_prefixed(fun_, get_indices(*args_),
*args_, static_cast<Base*>(ptr)); *args_, dptr);
return behavior{}; return unbox(std::move(res));
} else {
// behavior (args...)
return unbox(apply_args(fun_, get_indices(*args_), *args_));
} }
// behavior ()
behavior apply(std::true_type, std::false_type, local_actor*) {
auto res = apply_args(fun_, get_indices(*args_), *args_);
return std::move(res.unbox());
} }
} else {
if constexpr (args_empty) {
if constexpr (HasSelfPtr) {
// void (pointer)
fun_(dptr);
} else {
// void () // void ()
behavior apply(std::false_type, std::false_type, local_actor*) { fun_();
}
} else {
if constexpr (HasSelfPtr) {
// void (pointer, args...)
apply_moved_args_prefixed(fun_, get_indices(*args_), *args_, dptr);
} else {
// void (args...)
apply_args(fun_, get_indices(*args_), *args_); apply_args(fun_, get_indices(*args_), *args_);
return behavior{}; }
}
return {};
}
} }
F fun_; F fun_;
ArgsPtr args_; args_pointer args_;
}; };
template <class Base, class F> template <class Base, class F>
...@@ -127,8 +141,7 @@ public: ...@@ -127,8 +141,7 @@ public:
constexpr bool selfptr = std::is_pointer<first_arg>::value; constexpr bool selfptr = std::is_pointer<first_arg>::value;
constexpr bool rets = std::is_convertible<res_type, behavior>::value; constexpr bool rets = std::is_convertible<res_type, behavior>::value;
using tuple_type = decltype(std::make_tuple(detail::spawn_fwd<Ts>(xs)...)); using tuple_type = decltype(std::make_tuple(detail::spawn_fwd<Ts>(xs)...));
using tuple_ptr = std::shared_ptr<tuple_type>; using helper = init_fun_factory_helper<Base, F, tuple_type, rets, selfptr>;
using helper = init_fun_factory_helper<Base, F, tuple_ptr, rets, selfptr>;
return ptr_type{new helper{std::move(f), sizeof...(Ts) > 0 return ptr_type{new helper{std::move(f), sizeof...(Ts) > 0
? std::make_shared<tuple_type>( ? std::make_shared<tuple_type>(
detail::spawn_fwd<Ts>(xs)...) detail::spawn_fwd<Ts>(xs)...)
......
...@@ -84,13 +84,13 @@ public: ...@@ -84,13 +84,13 @@ public:
// -- operators -------------------------------------------------------------- // -- operators --------------------------------------------------------------
forward_iterator& operator++() { forward_iterator& operator++() {
ptr = promote(ptr->next); ptr = ptr->next;
return *this; return *this;
} }
forward_iterator operator++(int) { forward_iterator operator++(int) {
forward_iterator res = *this; forward_iterator res = *this;
ptr = promote(ptr->next); ptr = ptr->next;
return res; return res;
} }
......
...@@ -173,10 +173,8 @@ public: ...@@ -173,10 +173,8 @@ public:
/// @private /// @private
task_size_type next_task_size() const noexcept { task_size_type next_task_size() const noexcept {
if (head_.next == nullptr) auto ptr = head_.next;
return 0; return ptr != &tail_ ? policy_.task_size(*promote(ptr)) : 0;
auto ptr = promote(head_.next);
return policy_.task_size(*ptr);
} }
/// @private /// @private
...@@ -203,16 +201,6 @@ public: ...@@ -203,16 +201,6 @@ public:
// -- iterator access -------------------------------------------------------- // -- iterator access --------------------------------------------------------
/// Returns an iterator to the dummy before the first element.
iterator before_begin() noexcept {
return &head_;
}
/// Returns an iterator to the dummy before the first element.
const_iterator before_begin() const noexcept {
return &head_;
}
/// Returns an iterator to the dummy before the first element. /// Returns an iterator to the dummy before the first element.
iterator begin() noexcept { iterator begin() noexcept {
return head_.next; return head_.next;
...@@ -252,6 +240,7 @@ public: ...@@ -252,6 +240,7 @@ public:
/// Returns a pointer to the last element. /// Returns a pointer to the last element.
pointer back() noexcept { pointer back() noexcept {
CAF_ASSERT(head_.next != &tail_);
return promote(tail_.next); return promote(tail_.next);
} }
...@@ -319,7 +308,7 @@ public: ...@@ -319,7 +308,7 @@ public:
/// @private /// @private
void lifo_append(node_pointer ptr) { void lifo_append(node_pointer ptr) {
if (old_last_ == nullptr) { if (old_last_ == nullptr) {
old_last_ = back(); old_last_ = tail_.next;
push_back(promote(ptr)); push_back(promote(ptr));
} else { } else {
ptr->next = new_head_; ptr->next = new_head_;
......
...@@ -54,7 +54,7 @@ public: ...@@ -54,7 +54,7 @@ public:
// -- overridden functions of monitorable_actor ------------------------------ // -- overridden functions of monitorable_actor ------------------------------
bool cleanup(error&& fail_state, execution_unit* ptr) override { bool cleanup(error&& fail_state, execution_unit* ptr) override {
auto me = dptr()->ctrl(); auto me = this->ctrl();
for (auto& subscription : subscriptions_) for (auto& subscription : subscriptions_)
subscription->unsubscribe(me); subscription->unsubscribe(me);
subscriptions_.clear(); subscriptions_.clear();
...@@ -69,7 +69,7 @@ public: ...@@ -69,7 +69,7 @@ public:
CAF_LOG_TRACE(CAF_ARG(what)); CAF_LOG_TRACE(CAF_ARG(what));
if (what == invalid_group) if (what == invalid_group)
return; return;
if (what->subscribe(dptr()->ctrl())) if (what->subscribe(this->ctrl()))
subscriptions_.emplace(what); subscriptions_.emplace(what);
} }
...@@ -77,7 +77,7 @@ public: ...@@ -77,7 +77,7 @@ public:
void leave(const group& what) { void leave(const group& what) {
CAF_LOG_TRACE(CAF_ARG(what)); CAF_LOG_TRACE(CAF_ARG(what));
if (subscriptions_.erase(what) > 0) if (subscriptions_.erase(what) > 0)
what->unsubscribe(dptr()->ctrl()); what->unsubscribe(this->ctrl());
} }
/// Returns all subscribed groups. /// Returns all subscribed groups.
...@@ -86,10 +86,6 @@ public: ...@@ -86,10 +86,6 @@ public:
} }
private: private:
Subtype* dptr() {
return static_cast<Subtype*>(this);
}
// -- data members ----------------------------------------------------------- // -- data members -----------------------------------------------------------
/// Stores all subscribed groups. /// Stores all subscribed groups.
......
...@@ -100,7 +100,8 @@ bool node_id::default_data::valid() const noexcept { ...@@ -100,7 +100,8 @@ bool node_id::default_data::valid() const noexcept {
size_t node_id::default_data::hash_code() const noexcept { size_t node_id::default_data::hash_code() const noexcept {
// XOR the first few bytes from the node ID and the process ID. // XOR the first few bytes from the node ID and the process ID.
auto x = static_cast<size_t>(pid_); auto x = static_cast<size_t>(pid_);
auto y = *reinterpret_cast<const size_t*>(host_.data()); size_t y;
memcpy(&y, host_.data(), sizeof(size_t));
return x ^ y; return x ^ y;
} }
......
...@@ -87,7 +87,6 @@ CAF_TEST(default_constructed) { ...@@ -87,7 +87,6 @@ CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.peek(), nullptr); CAF_REQUIRE_EQUAL(queue.peek(), nullptr);
CAF_REQUIRE_EQUAL(queue.next(), nullptr); CAF_REQUIRE_EQUAL(queue.next(), nullptr);
CAF_REQUIRE_EQUAL(queue.begin(), queue.end()); CAF_REQUIRE_EQUAL(queue.begin(), queue.end());
CAF_REQUIRE_EQUAL(queue.before_begin()->next, queue.end().ptr);
} }
CAF_TEST(inc_deficit) { CAF_TEST(inc_deficit) {
......
...@@ -83,7 +83,6 @@ CAF_TEST(default_constructed) { ...@@ -83,7 +83,6 @@ CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.total_task_size(), 0); CAF_REQUIRE_EQUAL(queue.total_task_size(), 0);
CAF_REQUIRE_EQUAL(queue.peek(), nullptr); CAF_REQUIRE_EQUAL(queue.peek(), nullptr);
CAF_REQUIRE_EQUAL(queue.begin(), queue.end()); CAF_REQUIRE_EQUAL(queue.begin(), queue.end());
CAF_REQUIRE_EQUAL(queue.before_begin()->next, queue.end().ptr);
} }
CAF_TEST(push_back) { CAF_TEST(push_back) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment