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()
endif()
# enable address sanitizer if requested by the user
if(CAF_ENABLE_ADDRESS_SANITIZER AND NOT WIN32)
add_compile_options("-fsanitize=address"
if(CAF_SANITIZERS)
add_compile_options("-fsanitize=${CAF_SANITIZERS}"
"-fno-omit-frame-pointer")
list(APPEND CAF_EXTRA_LDFLAGS "-fsanitize=address")
list(APPEND CAF_EXTRA_LDFLAGS "-fsanitize=${CAF_SANITIZERS}")
endif()
# -pthread is ignored on MacOSX but required on other platforms
if(NOT APPLE AND NOT WIN32)
......
......@@ -6,12 +6,11 @@
defaultReleaseBuildFlags = [
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes',
'CAF_NO_OPENCL:BOOL=yes',
'CAF_INSTALL_UNIT_TESTS:BOOL=yes',
]
// Default CMake flags for debug builds.
defaultDebugBuildFlags = defaultReleaseBuildFlags + [
'CAF_ENABLE_ADDRESS_SANITIZER:BOOL=yes',
'CAF_SANITIZERS:STRING=address,undefined',
'CAF_LOG_LEVEL:STRING=TRACE',
'CAF_ENABLE_ACTOR_PROFILER:BOOL=yes',
]
......@@ -99,7 +98,9 @@ config = [
],
],
Windows: [
debug: defaultDebugBuildFlags + [
debug: [
'CAF_LOG_LEVEL:STRING=TRACE',
'CAF_ENABLE_ACTOR_PROFILER:BOOL=yes',
'CAF_BUILD_STATIC_ONLY:BOOL=yes',
],
release: defaultReleaseBuildFlags + [
......
......@@ -76,16 +76,14 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
- INFO
- DEBUG
- TRACE
--with-address-sanitizer build with address sanitizer if available
--with-asan alias for --with-address-sanitier
--enable-asan alias for --with-address-sanitier
--with-gcov build with gcov coverage enabled
--with-sanitizers=LIST build with this list of sanitizers enabled
--with-actor-profiler enables the (experimental) actor_profiler API
Convenience options:
--dev-mode sets --build-type=debug, --no-examples,
--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):
CXX C++ compiler command
......@@ -238,17 +236,8 @@ while [ $# -ne 0 ]; do
--with-runtime-checks)
append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes
;;
--with-address-sanitizer)
append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes
;;
--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-sanitizers=*)
append_cache_entry CAF_SANITIZERS STRING "$optarg"
;;
--with-actor-profiler)
append_cache_entry CAF_ENABLE_ACTOR_PROFILER BOOL yes
......@@ -374,12 +363,12 @@ while [ $# -ne 0 ]; do
done
;;
--dev-mode)
append_cache_entry CMAKE_BUILD_TYPE STRING Debug
append_cache_entry CAF_NO_EXAMPLES BOOL yes
append_cache_entry CAF_NO_TOOLS BOOL yes
for var in CAF_NO_TOOLS CAF_NO_EXAMPLES CAF_ENABLE_RUNTIME_CHECKS ; do
append_cache_entry $var BOOL yes
done
append_cache_entry CMAKE_BUILD_TYPE STRING debug
append_cache_entry CAF_LOG_LEVEL STRING TRACE
append_cache_entry CAF_ENABLE_RUNTIME_CHECKS BOOL yes
append_cache_entry CAF_ENABLE_ADDRESS_SANITIZER BOOL yes
append_cache_entry CAF_SANITIZERS STRING address,undefined
;;
*)
echo "Invalid option '$1'. Try $0 --help to see available options."
......
......@@ -55,13 +55,16 @@ protected:
};
/// 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>
class init_fun_factory_helper final : public init_fun_factory_helper_base {
public:
init_fun_factory_helper(F fun, ArgsPtr args)
: fun_(std::move(fun)),
args_(std::move(args)) {
using args_pointer = std::shared_ptr<Tuple>;
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
}
......@@ -72,41 +75,52 @@ public:
behavior operator()(local_actor* self) final {
if (hook_ != nullptr)
hook_(self);
bool_token<ReturnsBehavior> returns_behavior_token;
bool_token<HasSelfPtr> captures_self_token;
return apply(returns_behavior_token, captures_self_token, self);
}
private:
auto dptr = static_cast<Base*>(self);
if constexpr (ReturnsBehavior) {
auto unbox = [](auto x) -> behavior { return std::move(x.unbox()); };
if constexpr (args_empty) {
if constexpr (HasSelfPtr) {
// behavior (pointer)
behavior apply(std::true_type, std::true_type, local_actor* ptr) {
auto res = apply_moved_args_prefixed(fun_, get_indices(*args_), *args_,
static_cast<Base*>(ptr));
return std::move(res.unbox());
return unbox(fun_(dptr));
} else {
// behavior ()
return unbox(fun_());
}
// void (pointer)
behavior apply(std::false_type, std::true_type, local_actor* ptr) {
apply_moved_args_prefixed(fun_, get_indices(*args_),
*args_, static_cast<Base*>(ptr));
return behavior{};
} else {
if constexpr (HasSelfPtr) {
// behavior (pointer, args...)
auto res = apply_moved_args_prefixed(fun_, get_indices(*args_),
*args_, dptr);
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 ()
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_);
return behavior{};
}
}
return {};
}
}
F fun_;
ArgsPtr args_;
args_pointer args_;
};
template <class Base, class F>
......@@ -127,8 +141,7 @@ public:
constexpr bool selfptr = std::is_pointer<first_arg>::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_ptr = std::shared_ptr<tuple_type>;
using helper = init_fun_factory_helper<Base, F, tuple_ptr, rets, selfptr>;
using helper = init_fun_factory_helper<Base, F, tuple_type, rets, selfptr>;
return ptr_type{new helper{std::move(f), sizeof...(Ts) > 0
? std::make_shared<tuple_type>(
detail::spawn_fwd<Ts>(xs)...)
......
......@@ -84,13 +84,13 @@ public:
// -- operators --------------------------------------------------------------
forward_iterator& operator++() {
ptr = promote(ptr->next);
ptr = ptr->next;
return *this;
}
forward_iterator operator++(int) {
forward_iterator res = *this;
ptr = promote(ptr->next);
ptr = ptr->next;
return res;
}
......
......@@ -173,10 +173,8 @@ public:
/// @private
task_size_type next_task_size() const noexcept {
if (head_.next == nullptr)
return 0;
auto ptr = promote(head_.next);
return policy_.task_size(*ptr);
auto ptr = head_.next;
return ptr != &tail_ ? policy_.task_size(*promote(ptr)) : 0;
}
/// @private
......@@ -203,16 +201,6 @@ public:
// -- 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.
iterator begin() noexcept {
return head_.next;
......@@ -252,6 +240,7 @@ public:
/// Returns a pointer to the last element.
pointer back() noexcept {
CAF_ASSERT(head_.next != &tail_);
return promote(tail_.next);
}
......@@ -319,7 +308,7 @@ public:
/// @private
void lifo_append(node_pointer ptr) {
if (old_last_ == nullptr) {
old_last_ = back();
old_last_ = tail_.next;
push_back(promote(ptr));
} else {
ptr->next = new_head_;
......
......@@ -54,7 +54,7 @@ public:
// -- overridden functions of monitorable_actor ------------------------------
bool cleanup(error&& fail_state, execution_unit* ptr) override {
auto me = dptr()->ctrl();
auto me = this->ctrl();
for (auto& subscription : subscriptions_)
subscription->unsubscribe(me);
subscriptions_.clear();
......@@ -69,7 +69,7 @@ public:
CAF_LOG_TRACE(CAF_ARG(what));
if (what == invalid_group)
return;
if (what->subscribe(dptr()->ctrl()))
if (what->subscribe(this->ctrl()))
subscriptions_.emplace(what);
}
......@@ -77,7 +77,7 @@ public:
void leave(const group& what) {
CAF_LOG_TRACE(CAF_ARG(what));
if (subscriptions_.erase(what) > 0)
what->unsubscribe(dptr()->ctrl());
what->unsubscribe(this->ctrl());
}
/// Returns all subscribed groups.
......@@ -86,10 +86,6 @@ public:
}
private:
Subtype* dptr() {
return static_cast<Subtype*>(this);
}
// -- data members -----------------------------------------------------------
/// Stores all subscribed groups.
......
......@@ -100,7 +100,8 @@ bool node_id::default_data::valid() 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.
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;
}
......
......@@ -87,7 +87,6 @@ CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.peek(), nullptr);
CAF_REQUIRE_EQUAL(queue.next(), nullptr);
CAF_REQUIRE_EQUAL(queue.begin(), queue.end());
CAF_REQUIRE_EQUAL(queue.before_begin()->next, queue.end().ptr);
}
CAF_TEST(inc_deficit) {
......
......@@ -83,7 +83,6 @@ CAF_TEST(default_constructed) {
CAF_REQUIRE_EQUAL(queue.total_task_size(), 0);
CAF_REQUIRE_EQUAL(queue.peek(), nullptr);
CAF_REQUIRE_EQUAL(queue.begin(), queue.end());
CAF_REQUIRE_EQUAL(queue.before_begin()->next, queue.end().ptr);
}
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