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

Commit 47553b1

Browse files
authored
Fix invalidation of TagKeys. (#401)
Allocate name strings separately so that references to them are stable even if the underlying storage grows / moves. Add test that fails if this isn't done.
1 parent f4ee744 commit 47553b1

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

opencensus/tags/internal/tag_key.cc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
#include "opencensus/tags/tag_key.h"
1616

1717
#include <cstdint>
18+
#include <memory>
1819
#include <string>
1920
#include <unordered_map>
2021
#include <utility>
2122
#include <vector>
2223

2324
#include "absl/base/thread_annotations.h"
25+
#include "absl/memory/memory.h"
2426
#include "absl/strings/string_view.h"
2527
#include "absl/synchronization/mutex.h"
2628

@@ -38,13 +40,16 @@ class TagKeyRegistry {
3840

3941
const std::string& TagKeyName(TagKey key) const LOCKS_EXCLUDED(mu_) {
4042
absl::ReaderMutexLock l(&mu_);
41-
return registered_tag_keys_[key.id_];
43+
return *registered_tag_keys_[key.id_];
4244
}
4345

4446
private:
4547
mutable absl::Mutex mu_;
46-
// The registered tag keys. Tag key ids are indices into this vector.
47-
std::vector<std::string> registered_tag_keys_ GUARDED_BY(mu_);
48+
// The registered tag keys. Tag key ids are indices into this vector. Strings
49+
// are allocated individually so that they don't move around when the vector
50+
// storage moves due to resize.
51+
std::vector<std::unique_ptr<std::string>> registered_tag_keys_
52+
GUARDED_BY(mu_);
4853
// A map from names to IDs.
4954
// TODO: change to string_view when a suitable hash is available.
5055
std::unordered_map<std::string, uint64_t> id_map_ GUARDED_BY(mu_);
@@ -56,7 +61,7 @@ TagKey TagKeyRegistry::Register(absl::string_view name) {
5661
const auto it = id_map_.find(string_name);
5762
if (it == id_map_.end()) {
5863
const uint64_t id = registered_tag_keys_.size();
59-
registered_tag_keys_.emplace_back(name);
64+
registered_tag_keys_.emplace_back(absl::make_unique<std::string>(name));
6065
id_map_.emplace_hint(it, string_name, id);
6166
return TagKey(id);
6267
}

opencensus/tags/internal/tag_key_test.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "opencensus/tags/tag_key.h"
1616

1717
#include "absl/hash/hash.h"
18+
#include "absl/strings/str_cat.h"
1819
#include "gtest/gtest.h"
1920

2021
namespace opencensus {
@@ -40,6 +41,18 @@ TEST(TagKeyTest, Inequality) {
4041
EXPECT_NE(absl::Hash<TagKey>()(k1), absl::Hash<TagKey>()(k2));
4142
}
4243

44+
// Test that the reference returned by TagKey::name() isn't invalidated when the
45+
// registry's underlying storage grows and moves.
46+
TEST(TagKeyTest, GrowRegistry) {
47+
TagKey k = TagKey::Register("my_key");
48+
const std::string& s = k.name();
49+
ASSERT_EQ("my_key", s);
50+
for (int i = 0; i < 1000; ++i) {
51+
TagKey::Register(absl::StrCat("key_", i));
52+
EXPECT_EQ("my_key", s) << "iteration " << i;
53+
}
54+
}
55+
4356
} // namespace
4457
} // namespace tags
4558
} // namespace opencensus

0 commit comments

Comments
 (0)