Commit 546ea7b1 authored by Dominik Charousset's avatar Dominik Charousset

Merge pull request #1163

parents 81c00c70 1c96d267
......@@ -5,6 +5,7 @@ set -e
# This script expects the CAF source tree under 'sources', builds in 'build' and
# installs to 'bundle'. Additionally, the script expects the CMake pre-load
# script 'cmake-init.txt' in the current working directorys.
BaseDir="$PWD"
InitFile="$PWD/cmake-init.txt"
SourceDir="$PWD/sources"
BuildDir="$PWD/build"
......@@ -23,6 +24,28 @@ else
exit 1
fi
LeakSanCheck="
#include <cstdlib>
int main() {
int* ptr = new int(EXIT_SUCCESS);
return *ptr;
}
"
# Check that LeakSanitizer works if configured for this build.
if [ "${CAF_CHECK_LEAKS}" == "ON" ]; then
mkdir -p "$BaseDir/LeakCheck"
cd "$BaseDir/LeakCheck"
echo "${LeakSanCheck}" > check.cpp
c++ check.cpp -o check -fsanitize=address -fno-omit-frame-pointer
out=`./check 2>&1 | grep -o LeakSanitizer`
if [ "$out" != "LeakSanitizer" ]; then
echo "unable to detected memory leaks on this platform!"
return 1
fi
cd "$BaseDir"
fi
# Make sure all directories exist, then enter build directory.
mkdir -p "$BuildDir"
cd "$BuildDir"
......@@ -34,4 +57,4 @@ if [ -z "$CAF_NUM_CORES" ]; then
else
$CMakeCommand --build . --target install -- -j $CAF_NUM_CORES
fi
$CTestCommand
$CTestCommand --output-on-failure
......@@ -46,6 +46,8 @@ is based on [Keep a Changelog](https://keepachangelog.com).
to reject log messages immediately (before enqueueing it to the logger's
queue) and then applies the filters individually when generating file or
console output.
- Fix memory leaks when deserializing URIs and when detaching the content of
messages (#1160).
## [0.18.0-rc.1] - 2020-09-09
......
......@@ -31,13 +31,11 @@ config = [
numCores: 4,
tags: ['docker'],
builds: ['debug', 'release'],
extraDebugFlags: ['CAF_SANITIZERS:STRING=address,undefined'],
]],
['centos-8', [
numCores: 4,
tags: ['docker'],
builds: ['debug', 'release'],
extraDebugFlags: ['CAF_SANITIZERS:STRING=address,undefined'],
]],
['debian-9', [
numCores: 4,
......@@ -73,6 +71,7 @@ config = [
numCores: 4,
tags: ['docker'],
builds: ['debug', 'release'],
extraDebugFlags: ['CAF_SANITIZERS:STRING=address'],
]],
// One extra debug build with exceptions disabled.
['centos-7', [
......@@ -119,6 +118,10 @@ config = [
],
// Platform-specific environment settings.
buildEnvironments: [
'fedora-32 && debug': [
'CAF_CHECK_LEAKS=ON',
'ASAN_OPTIONS=detect_leaks=1',
],
nop: [], // Dummy value for getting the proper types.
],
// Default CMake flags by build type.
......@@ -164,7 +167,7 @@ pipeline {
environment {
PrettyJobBaseName = env.JOB_BASE_NAME.replace('%2F', '/')
PrettyJobName = "CAF/$PrettyJobBaseName #${env.BUILD_NUMBER}"
ASAN_OPTIONS = 'detect_leaks=0'
ASAN_OPTIONS = 'detect_leaks=1'
}
stages {
stage('Checkout') {
......
......@@ -32,7 +32,7 @@ public:
// nop
}
explicit typed_message_view(message& msg) : ptr_(&msg.data()) {
explicit typed_message_view(message& msg) : ptr_(msg.ptr()) {
// nop
}
......
......@@ -30,6 +30,7 @@
#include "caf/intrusive_cow_ptr.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/ip_address.hpp"
#include "caf/make_counted.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
......@@ -274,7 +275,7 @@ struct inspector_access<uri> : inspector_access_base<uri> {
} else {
if constexpr (Inspector::is_loading)
if (!x.impl_->unique())
x.impl_.reset(new uri::impl_type);
x.impl_.reset(new uri::impl_type, false);
return inspect(f, *x.impl_);
}
}
......@@ -291,7 +292,7 @@ struct inspector_access<uri> : inspector_access_base<uri> {
} else {
if constexpr (Inspector::is_loading)
if (!x.impl_->unique())
x.impl_.reset(new uri::impl_type);
x.impl_.reset(new uri::impl_type, false);
return inspect(f, *x.impl_);
}
}
......
......@@ -120,15 +120,17 @@ void group_tunnel::stop() {
CAF_LOG_TRACE("");
CAF_LOG_DEBUG("stop group tunnel:" << CAF_ARG2("module", module().name())
<< CAF_ARG2("identifier", identifier_));
auto hdl = actor{};
auto worker_hdl = actor{};
auto intermediary_hdl = actor{};
auto subs = subscriber_set{};
auto cache = cached_message_list{};
auto stopped = critical_section([this, &hdl, &subs, &cache] {
auto stopped = critical_section([&, this] {
using std::swap;
if (!stopped_) {
stopped_ = true;
swap(subs, subscribers_);
swap(hdl, worker_);
swap(worker_hdl, worker_);
swap(intermediary_hdl, intermediary_);
swap(cache, cached_messages_);
return true;
} else {
......@@ -136,7 +138,7 @@ void group_tunnel::stop() {
}
});
if (stopped) {
anon_send_exit(hdl, exit_reason::user_shutdown);
anon_send_exit(worker_hdl, exit_reason::user_shutdown);
if (!subs.empty()) {
auto bye = make_message(group_down_msg{group{this}});
for (auto& sub : subs)
......
......@@ -163,7 +163,7 @@ expected<group> local_group_module::get(const std::string& group_name) {
auto ptr = make_counted<impl>(this, group_name);
ptr->intermediary_ = system().spawn<intermediary_actor, hidden>(ptr);
instances_.emplace(group_name, ptr);
return group{ptr.release()};
return group{std::move(ptr)};
}
}
......
......@@ -69,6 +69,7 @@ message_data* message_data::copy() const {
auto& meta = gmos[id];
// TODO: exception handling.
meta.copy_construct(dst, src);
++ptr->constructed_elements_;
src += meta.padded_size;
dst += meta.padded_size;
}
......
......@@ -83,8 +83,9 @@ struct testee_state {
behavior testee_impl(stateful_actor<testee_state>* self) {
return {
[=](put_atom, int x) { self->state.x = x; },
[=](get_atom) { return self->state.x; },
[self](put_atom, int x) { self->state.x = x; },
[self](get_atom) { return self->state.x; },
[self](const group_down_msg&) { self->quit(); },
};
}
......@@ -103,9 +104,11 @@ struct fixture : test_coordinator_fixture<> {
// Groups keep their subscribers alive (on purpose). Since we don't want to
// manually kill all our testee actors, we simply force the group modules to
// stop here.
uut->stop();
for (auto& kvp : uut->instances)
kvp.second->stop();
sys.groups().get_module("local")->stop();
run();
}
void make_unconnected() {
......
......@@ -61,6 +61,24 @@ CAF_TEST(messages allow index - based access) {
CAF_CHECK_EQUAL(msg.cdata().get_reference_count(), 1u);
}
CAF_TEST(message detach their content on mutating access) {
CAF_MESSAGE("Given to messages pointing to the same content.");
auto msg1 = make_message("one", uint32_t{1});
auto msg2 = msg1;
CAF_CHECK_EQUAL(msg1.cdata().get_reference_count(), 2u);
CAF_CHECK_EQUAL(msg1.cptr(), msg2.cptr());
CAF_MESSAGE("When calling a non-const member function of message.");
msg1.ptr();
CAF_MESSAGE("Then the messages point to separate contents but remain equal.");
CAF_CHECK_NOT_EQUAL(msg1.cptr(), msg2.cptr());
CAF_CHECK_EQUAL(msg1.cdata().get_reference_count(), 1u);
CAF_CHECK_EQUAL(msg2.cdata().get_reference_count(), 1u);
CAF_CHECK(msg1.match_elements<std::string, uint32_t>());
CAF_CHECK(msg2.match_elements<std::string, uint32_t>());
CAF_CHECK_EQUAL(msg1.get_as<std::string>(0), msg2.get_as<std::string>(0));
CAF_CHECK_EQUAL(msg1.get_as<uint32_t>(1), msg2.get_as<uint32_t>(1));
}
CAF_TEST(compare_custom_types) {
s2 tmp;
tmp.value[0][1] = 100;
......
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