Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit 2abf364

Browse files
authored
Free per-thread Context memory on thread exit. (#417)
* Add test for leaking Context memory.
1 parent a1d84d3 commit 2abf364

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

opencensus/context/context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class Context {
6767

6868
friend class ContextTestPeer;
6969
friend class WithContext;
70+
friend class ContextWrapper;
7071
friend class ::opencensus::tags::ContextPeer;
7172
friend class ::opencensus::tags::WithTagMap;
7273
friend class ::opencensus::trace::ContextPeer;

opencensus/context/internal/context.cc

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "opencensus/context/context.h"
1616

1717
#include <functional>
18+
#include <memory>
1819
#include <utility>
1920

2021
#include "absl/strings/str_cat.h"
@@ -25,6 +26,20 @@
2526
namespace opencensus {
2627
namespace context {
2728

29+
// Wrapper for per-thread Context, frees the Context on thread shutdown.
30+
class ContextWrapper {
31+
public:
32+
ContextWrapper() : ptr_(new Context) {}
33+
Context* get() { return ptr_.get(); }
34+
35+
private:
36+
std::unique_ptr<Context> ptr_;
37+
};
38+
39+
namespace {
40+
thread_local ContextWrapper g_wrapper;
41+
} // namespace
42+
2843
Context::Context()
2944
: tags_(opencensus::tags::TagMap({})),
3045
span_(opencensus::trace::Span::BlankSpan()) {}
@@ -47,11 +62,7 @@ std::string Context::DebugString() const {
4762
}
4863

4964
// static
50-
Context* Context::InternalMutableCurrent() {
51-
static thread_local Context* thread_ctx = nullptr;
52-
if (thread_ctx == nullptr) thread_ctx = new Context;
53-
return thread_ctx;
54-
}
65+
Context* Context::InternalMutableCurrent() { return g_wrapper.get(); }
5566

5667
void swap(Context& a, Context& b) {
5768
using std::swap;

opencensus/context/internal/context_test.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <functional>
1818
#include <iostream>
19+
#include <thread>
1920

2021
#include "gtest/gtest.h"
2122
#include "opencensus/tags/context_util.h"
@@ -87,6 +88,18 @@ TEST(ContextTest, WrapDoesNotLeak) {
8788
span.End();
8889
}
8990

91+
TEST(ContextTest, ThreadDoesNotLeak) {
92+
auto span = opencensus::trace::Span::StartSpan("MySpan");
93+
std::thread t([span]() {
94+
// Leak-sanitizer (part of ASAN) throws an error if this leaks.
95+
opencensus::tags::WithTagMap wt(ExampleTagMap());
96+
opencensus::trace::WithSpan ws(span);
97+
});
98+
t.join();
99+
ExpectEmptyContext();
100+
span.End();
101+
}
102+
90103
TEST(ContextTest, WrappedFnIsCopiable) {
91104
std::function<void()> fn1, fn2;
92105
{

0 commit comments

Comments
 (0)