Skip to content

Commit 5e73d92

Browse files
committed
fix shared_ptr self assignments
see open-telemetry#3713 (comment)
1 parent 4707617 commit 5e73d92

File tree

8 files changed

+89
-36
lines changed

8 files changed

+89
-36
lines changed

api/include/opentelemetry/context/context.h

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#pragma once
55

6-
#include <string>
6+
#include <cstring>
77
#include <utility>
88

99
#include "opentelemetry/context/context_value.h"
@@ -34,18 +34,18 @@ class Context
3434

3535
// Creates a context object from a key and value, this will
3636
// hold a shared_ptr to the head of the DataList linked list
37-
Context(nostd::string_view key, const ContextValue &value) noexcept
37+
Context(nostd::string_view key, ContextValue value) noexcept
3838
: head_{nostd::shared_ptr<DataList>{new DataList(key, value)}}
3939
{}
4040

4141
// Accepts a new iterable and then returns a new context that
4242
// contains the new key and value data. It attaches the
4343
// exisiting list to the end of the new list.
4444
template <class T>
45-
Context SetValues(T &values) const noexcept
45+
Context SetValues(T &values) noexcept
4646
{
47-
Context context(values);
48-
auto last = context.head_;
47+
Context context = Context(values);
48+
nostd::shared_ptr<DataList> last = context.head_;
4949
while (last->next_ != nullptr)
5050
{
5151
last = last->next_;
@@ -57,9 +57,9 @@ class Context
5757
// Accepts a new iterable and then returns a new context that
5858
// contains the new key and value data. It attaches the
5959
// exisiting list to the end of the new list.
60-
Context SetValue(nostd::string_view key, const ContextValue &value) const noexcept
60+
Context SetValue(nostd::string_view key, ContextValue value) noexcept
6161
{
62-
Context context(key, value);
62+
Context context = Context(key, value);
6363
context.head_->next_ = head_;
6464
return context;
6565
}
@@ -69,9 +69,12 @@ class Context
6969
{
7070
for (DataList *data = head_.get(); data != nullptr; data = data->next_.get())
7171
{
72-
if (key == data->key_)
72+
if (key.size() == data->key_length_)
7373
{
74-
return data->value_;
74+
if (std::memcmp(key.data(), data->key_, data->key_length_) == 0)
75+
{
76+
return data->value_;
77+
}
7578
}
7679
}
7780
return ContextValue{};
@@ -89,10 +92,12 @@ class Context
8992
// A linked list to contain the keys and values of this context node
9093
struct DataList
9194
{
92-
std::string key_;
95+
char *key_ = nullptr;
9396

9497
nostd::shared_ptr<DataList> next_{nullptr};
9598

99+
size_t key_length_ = 0UL;
100+
96101
ContextValue value_;
97102

98103
DataList() = default;
@@ -101,23 +106,62 @@ class Context
101106
template <class T>
102107
DataList(const T &keys_and_vals)
103108
{
104-
auto iter = std::begin(keys_and_vals);
105-
if (iter == std::end(keys_and_vals))
106-
return;
109+
bool first = true;
107110
auto *node = this;
108-
*node = DataList(iter->first, iter->second);
109-
for (++iter; iter != std::end(keys_and_vals); ++iter)
111+
for (auto &iter : keys_and_vals)
110112
{
111-
node->next_ = nostd::shared_ptr<DataList>(new DataList(iter->first, iter->second));
112-
node = node->next_.get();
113+
if (first)
114+
{
115+
*node = DataList(iter.first, iter.second);
116+
first = false;
117+
}
118+
else
119+
{
120+
node->next_ = nostd::shared_ptr<DataList>(new DataList(iter.first, iter.second));
121+
node = node->next_.get();
122+
}
113123
}
114124
}
115125

116126
// Builds a data list with just a key and value, so it will just be the head
117127
// and returns that head.
118128
DataList(nostd::string_view key, const ContextValue &value)
119-
: key_(key.begin(), key.end()), value_(value)
120-
{}
129+
{
130+
key_ = new char[key.size()];
131+
key_length_ = key.size();
132+
std::memcpy(key_, key.data(), key.size() * sizeof(char));
133+
next_ = nostd::shared_ptr<DataList>{nullptr};
134+
value_ = value;
135+
}
136+
137+
DataList(const DataList &other)
138+
: key_(new char[other.key_length_]),
139+
next_(other.next_),
140+
key_length_(other.key_length_),
141+
value_(other.value_)
142+
{
143+
std::memcpy(key_, other.key_, other.key_length_ * sizeof(char));
144+
}
145+
146+
DataList &operator=(DataList &&other) noexcept
147+
{
148+
key_length_ = other.key_length_;
149+
value_ = std::move(other.value_);
150+
next_ = std::move(other.next_);
151+
152+
key_ = other.key_;
153+
other.key_ = nullptr;
154+
155+
return *this;
156+
}
157+
158+
~DataList()
159+
{
160+
if (key_ != nullptr)
161+
{
162+
delete[] key_;
163+
}
164+
}
121165
};
122166

123167
// Head of the list which holds the keys and values of this context

api/include/opentelemetry/nostd/shared_ptr.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#endif
1212

1313
#if !defined(OPENTELEMETRY_HAVE_STD_SHARED_PTR)
14+
# include <cstdlib>
1415
# include <memory>
1516
# include <utility>
1617

@@ -31,9 +32,13 @@ class shared_ptr
3132
using pointer = element_type *;
3233

3334
private:
35+
static constexpr size_t kMaxSize = 32;
3436
static constexpr size_t kAlignment = 8;
3537

36-
struct alignas(kAlignment) PlacementBuffer; // fwd.
38+
struct alignas(kAlignment) PlacementBuffer
39+
{
40+
char data[kMaxSize]{};
41+
};
3742

3843
class shared_ptr_wrapper
3944
{
@@ -42,12 +47,14 @@ class shared_ptr
4247

4348
shared_ptr_wrapper(std::shared_ptr<T> &&ptr) noexcept : ptr_{std::move(ptr)} {}
4449

45-
void CopyTo(PlacementBuffer &buffer) const noexcept
50+
virtual ~shared_ptr_wrapper() {}
51+
52+
virtual void CopyTo(PlacementBuffer &buffer) const noexcept
4653
{
4754
new (buffer.data) shared_ptr_wrapper{*this};
4855
}
4956

50-
void MoveTo(PlacementBuffer &buffer) noexcept
57+
virtual void MoveTo(PlacementBuffer &buffer) noexcept
5158
{
5259
new (buffer.data) shared_ptr_wrapper{std::move(this->ptr_)};
5360
}
@@ -60,19 +67,15 @@ class shared_ptr
6067
new (buffer.data) other_shared_ptr_wrapper{std::move(this->ptr_)};
6168
}
6269

63-
pointer Get() const noexcept { return ptr_.get(); }
70+
virtual pointer Get() const noexcept { return ptr_.get(); }
6471

65-
void Reset() noexcept { ptr_.reset(); }
72+
virtual void Reset() noexcept { ptr_.reset(); }
6673

6774
private:
6875
std::shared_ptr<T> ptr_;
6976
};
7077

71-
struct alignas(kAlignment) PlacementBuffer
72-
{
73-
char data[sizeof(shared_ptr_wrapper)]{};
74-
};
75-
78+
static_assert(sizeof(shared_ptr_wrapper) <= kMaxSize, "Placement buffer is too small");
7679
static_assert(alignof(shared_ptr_wrapper) <= kAlignment, "Placement buffer not properly aligned");
7780

7881
public:
@@ -108,7 +111,7 @@ class shared_ptr
108111

109112
shared_ptr(std::unique_ptr<T> &&other) noexcept
110113
{
111-
std::shared_ptr<T> ptr_(std::move(other));
114+
std::shared_ptr<T> ptr_(other.release());
112115
new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)};
113116
}
114117

api/test/nostd/shared_ptr_test.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ TEST(SharedPtrTest, MoveConstructionFromStdSharedPtr)
9999

100100
TEST(SharedPtrTest, MoveConstructionFromNoStdUniquePtr)
101101
{
102-
opentelemetry::v1::nostd::unique_ptr<int> value(new int{123});
102+
opentelemetry::nostd::unique_ptr<int> value(new int{123});
103103
auto p = value.get();
104104
shared_ptr<int> ptr{std::move(value)};
105105
EXPECT_EQ(value.get(), nullptr); // NOLINT
@@ -133,6 +133,12 @@ TEST(SharedPtrTest, Assignment)
133133
std::shared_ptr<int> ptr3(value3);
134134
ptr1 = ptr3;
135135
EXPECT_EQ(ptr1.get(), value3);
136+
137+
ptr1 = ptr1;
138+
EXPECT_EQ(ptr1.get(), ptr1.get());
139+
140+
ptr1 = std::move(ptr1);
141+
EXPECT_EQ(ptr1.get(), ptr1.get());
136142
}
137143

138144
TEST(SharedPtrTest, BoolConversionOpertor)

third_party/benchmark

Submodule benchmark updated 80 files

third_party/googletest

Submodule googletest updated 56 files

third_party/prometheus-cpp

0 commit comments

Comments
 (0)