Skip to content

Commit 9f79f40

Browse files
jmachowinskiJanosch Machowinski
andauthored
fix: Use default rcl allocator if allocator is std::allocator (#3058)
* fix: Use default rcl allocator if allocator is std::allocator This fixes a bunch of warnings if using ASAN / valgrind on newer OS versions. It also fixed a real bug, as giving the wrong size on deallocate is undefined behavior according to the C++ standard. This version of the patch keeps the behavior for users that specified an own allocator the same and in therefore back portable. Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com> * feat: Provide a way to suppress the deprecation warning This commit adds the feature, that the user can now specify a method rcl_allocator_t get_rcl_allocator() on the given allocator. This method will be called if present, to get the rcl allocator. If the method is not present, the code will fall back to the old (and faulty) implementation and show a deprecation warning. Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com> --------- Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com> Co-authored-by: Janosch Machowinski <j.machowinski@cellumation.com>
1 parent 6ff4d83 commit 9f79f40

7 files changed

Lines changed: 118 additions & 12 deletions

File tree

rclcpp/include/rclcpp/allocator/allocator_common.hpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,39 @@ namespace rclcpp
2727
namespace allocator
2828
{
2929

30+
template<typename T>
31+
using clean_t = std::remove_cv_t<std::remove_reference_t<T>>;
32+
33+
// Primary template: false
34+
template<typename, typename = std::void_t<>>
35+
struct has_get_rcl_allocator : std::false_type {};
36+
37+
// Specialization: true if expression is valid
38+
template<typename T>
39+
struct has_get_rcl_allocator<T,
40+
std::void_t<
41+
decltype(std::declval<clean_t<T> &>().get_rcl_allocator())
42+
>
43+
>
44+
: std::bool_constant<
45+
std::is_same_v<
46+
decltype(std::declval<clean_t<T> &>().get_rcl_allocator()),
47+
rcl_allocator_t
48+
>
49+
>
50+
{};
51+
52+
// Helper variable template
53+
template<typename T>
54+
inline constexpr bool has_get_rcl_allocator_v =
55+
has_get_rcl_allocator<T>::value;
56+
3057
template<typename T, typename Alloc>
3158
using AllocRebind = typename std::allocator_traits<Alloc>::template rebind_traits<T>;
3259

3360
template<typename Alloc>
61+
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
62+
"can not be determined. This will be remove in future versions of ros.")]]
3463
void * retyped_allocate(size_t size, void * untyped_allocator)
3564
{
3665
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -41,6 +70,8 @@ void * retyped_allocate(size_t size, void * untyped_allocator)
4170
}
4271

4372
template<typename Alloc>
73+
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
74+
"can not be determined. This will be remove in future versions of ros.")]]
4475
void * retyped_zero_allocate(size_t number_of_elem, size_t size_of_elem, void * untyped_allocator)
4576
{
4677
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -57,6 +88,8 @@ void * retyped_zero_allocate(size_t number_of_elem, size_t size_of_elem, void *
5788
}
5889

5990
template<typename T, typename Alloc>
91+
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
92+
"can not be determined. This will be remove in future versions of ros.")]]
6093
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
6194
{
6295
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -68,6 +101,8 @@ void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
68101
}
69102

70103
template<typename T, typename Alloc>
104+
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
105+
"can not be determined. This will be remove in future versions of ros.")]]
71106
void * retyped_reallocate(void * untyped_pointer, size_t size, void * untyped_allocator)
72107
{
73108
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -85,6 +120,9 @@ template<
85120
typename T,
86121
typename Alloc,
87122
typename std::enable_if<!std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>
123+
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
124+
"can not be determined. This will be remove in future versions of ros. To suppress this warning"
125+
"define the method 'rcl_allocator_t get_rcl_allocator()' on your allocator")]]
88126
rcl_allocator_t get_rcl_allocator(Alloc & allocator)
89127
{
90128
rcl_allocator_t rcl_allocator = rcl_get_default_allocator();

rclcpp/include/rclcpp/message_memory_strategy.hpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <memory>
1919
#include <stdexcept>
2020

21+
#include "rcl/allocator.h"
2122
#include "rcl/types.h"
2223

2324
#include "rclcpp/allocator/allocator_common.hpp"
@@ -61,15 +62,33 @@ class MessageMemoryStrategy
6162
message_allocator_ = std::make_shared<MessageAlloc>();
6263
serialized_message_allocator_ = std::make_shared<SerializedMessageAlloc>();
6364
buffer_allocator_ = std::make_shared<BufferAlloc>();
64-
rcutils_allocator_ = allocator::get_rcl_allocator<char, BufferAlloc>(*buffer_allocator_.get());
65+
if constexpr (std::is_same_v<Alloc, std::allocator<void>>) {
66+
rcutils_allocator_ = rcl_get_default_allocator();
67+
} else {
68+
if constexpr (rclcpp::allocator::has_get_rcl_allocator_v<Alloc>) {
69+
rcutils_allocator_ = message_allocator_->get_rcl_allocator();
70+
} else {
71+
rcutils_allocator_ = allocator::get_rcl_allocator<char,
72+
BufferAlloc>(*buffer_allocator_.get());
73+
}
74+
}
6575
}
6676

6777
explicit MessageMemoryStrategy(std::shared_ptr<Alloc> allocator)
6878
{
6979
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
7080
serialized_message_allocator_ = std::make_shared<SerializedMessageAlloc>(*allocator.get());
7181
buffer_allocator_ = std::make_shared<BufferAlloc>(*allocator.get());
72-
rcutils_allocator_ = allocator::get_rcl_allocator<char, BufferAlloc>(*buffer_allocator_.get());
82+
if constexpr (std::is_same_v<Alloc, std::allocator<void>>) {
83+
rcutils_allocator_ = rcl_get_default_allocator();
84+
} else {
85+
if constexpr (rclcpp::allocator::has_get_rcl_allocator_v<Alloc>) {
86+
rcutils_allocator_ = allocator->get_rcl_allocator();
87+
} else {
88+
rcutils_allocator_ = allocator::get_rcl_allocator<char,
89+
BufferAlloc>(*buffer_allocator_.get());
90+
}
91+
}
7392
}
7493

7594
virtual ~MessageMemoryStrategy() = default;

rclcpp/include/rclcpp/publisher_options.hpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,20 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
123123
rcl_allocator_t
124124
get_rcl_allocator() const
125125
{
126-
if (!plain_allocator_storage_) {
127-
plain_allocator_storage_ =
128-
std::make_shared<PlainAllocator>(*this->get_allocator());
126+
if constexpr (std::is_same_v<Allocator, std::allocator<void>>) {
127+
return rcl_get_default_allocator();
128+
} else {
129+
if constexpr (rclcpp::allocator::has_get_rcl_allocator_v<Allocator>) {
130+
return get_allocator()->get_rcl_allocator();
131+
} else {
132+
if (!plain_allocator_storage_) {
133+
plain_allocator_storage_ =
134+
std::make_shared<PlainAllocator>(*this->get_allocator());
135+
}
136+
137+
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
138+
}
129139
}
130-
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
131140
}
132141

133142
// This is a temporal workaround, to make sure that get_allocator()

rclcpp/include/rclcpp/strategies/allocator_memory_strategy.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,11 @@ class AllocatorMemoryStrategy : public memory_strategy::MemoryStrategy
515515

516516
rcl_allocator_t get_allocator() override
517517
{
518-
return rclcpp::allocator::get_rcl_allocator<void *, VoidAlloc>(*allocator_.get());
518+
if constexpr (std::is_same_v<Alloc, std::allocator<void>>) {
519+
return rcl_get_default_allocator();
520+
} else {
521+
return rclcpp::allocator::get_rcl_allocator<void *, VoidAlloc>(*allocator_.get());
522+
}
519523
}
520524

521525
size_t number_of_ready_subscriptions() const override

rclcpp/include/rclcpp/subscription_options.hpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,20 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
167167
rcl_allocator_t
168168
get_rcl_allocator() const
169169
{
170-
if (!plain_allocator_storage_) {
171-
plain_allocator_storage_ =
172-
std::make_shared<PlainAllocator>(*this->get_allocator());
170+
if constexpr (std::is_same_v<Allocator, std::allocator<void>>) {
171+
return rcl_get_default_allocator();
172+
} else {
173+
if constexpr (rclcpp::allocator::has_get_rcl_allocator_v<Allocator>) {
174+
return get_allocator()->get_rcl_allocator();
175+
} else {
176+
if (!plain_allocator_storage_) {
177+
plain_allocator_storage_ =
178+
std::make_shared<PlainAllocator>(*this->get_allocator());
179+
}
180+
181+
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
182+
}
173183
}
174-
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
175184
}
176185

177186
// This is a temporal workaround, to make sure that get_allocator()

rclcpp/test/rclcpp/allocator/test_allocator_common.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@
1616

1717
#include <memory>
1818

19+
#include "rcpputils/compile_warnings.hpp"
20+
21+
RCPPUTILS_DEPRECATION_WARNING_OFF_START
1922
#include "rclcpp/allocator/allocator_common.hpp"
23+
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
2024

21-
TEST(TestAllocatorCommon, retyped_allocate) {
25+
TEST(TestAllocatorCommon, retyped_allocate)
26+
{
2227
std::allocator<int> allocator;
2328
void * untyped_allocator = &allocator;
29+
RCPPUTILS_DEPRECATION_WARNING_OFF_START
2430
void * allocated_mem =
2531
rclcpp::allocator::retyped_allocate<std::allocator<char>>(1u, untyped_allocator);
2632
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
@@ -49,9 +55,12 @@ TEST(TestAllocatorCommon, retyped_allocate) {
4955
reallocated_mem, untyped_allocator);
5056
};
5157
EXPECT_NO_THROW(code2());
58+
59+
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
5260
}
5361

5462
TEST(TestAllocatorCommon, retyped_zero_allocate_basic) {
63+
RCPPUTILS_DEPRECATION_WARNING_OFF_START
5564
std::allocator<int> allocator;
5665
void * untyped_allocator = &allocator;
5766
void * allocated_mem =
@@ -63,9 +72,11 @@ TEST(TestAllocatorCommon, retyped_zero_allocate_basic) {
6372
allocated_mem, untyped_allocator);
6473
};
6574
EXPECT_NO_THROW(code());
75+
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
6676
}
6777

6878
TEST(TestAllocatorCommon, retyped_zero_allocate) {
79+
RCPPUTILS_DEPRECATION_WARNING_OFF_START
6980
std::allocator<int> allocator;
7081
void * untyped_allocator = &allocator;
7182
void * allocated_mem =
@@ -96,19 +107,24 @@ TEST(TestAllocatorCommon, retyped_zero_allocate) {
96107
reallocated_mem, untyped_allocator);
97108
};
98109
EXPECT_NO_THROW(code2());
110+
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
99111
}
100112

101113
TEST(TestAllocatorCommon, get_rcl_allocator) {
114+
RCPPUTILS_DEPRECATION_WARNING_OFF_START
102115
std::allocator<int> allocator;
103116
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator<int>(allocator);
104117
EXPECT_NE(nullptr, rcl_allocator.allocate);
105118
EXPECT_NE(nullptr, rcl_allocator.deallocate);
106119
EXPECT_NE(nullptr, rcl_allocator.reallocate);
107120
EXPECT_NE(nullptr, rcl_allocator.zero_allocate);
108121
// Not testing state as that may or may not be null depending on platform
122+
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
109123
}
110124

111125
TEST(TestAllocatorCommon, get_void_rcl_allocator) {
126+
RCPPUTILS_DEPRECATION_WARNING_OFF_START
127+
112128
std::allocator<void> allocator;
113129
auto rcl_allocator =
114130
rclcpp::allocator::get_rcl_allocator<void, std::allocator<void>>(allocator);
@@ -117,4 +133,5 @@ TEST(TestAllocatorCommon, get_void_rcl_allocator) {
117133
EXPECT_NE(nullptr, rcl_allocator.reallocate);
118134
EXPECT_NE(nullptr, rcl_allocator.zero_allocate);
119135
// Not testing state as that may or may not be null depending on platform
136+
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
120137
}

rclcpp/test/rclcpp/test_intra_process_manager_with_allocators.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ struct MyAllocator
7575
{
7676
typedef MyAllocator<U> other;
7777
};
78+
79+
rcl_allocator_t get_rcl_allocator()
80+
{
81+
return rcl_get_default_allocator();
82+
}
7883
};
7984

8085
// Explicit specialization for void
@@ -102,6 +107,11 @@ struct MyAllocator<void>
102107
{
103108
typedef MyAllocator<U> other;
104109
};
110+
111+
rcl_allocator_t get_rcl_allocator()
112+
{
113+
return rcl_get_default_allocator();
114+
}
105115
};
106116

107117
template<typename T, typename U>

0 commit comments

Comments
 (0)