Skip to content

Commit

Permalink
Fix: ConstString::GetConstCStringAndSetMangledCounterPart() should up…
Browse files Browse the repository at this point in the history
…date the value if the key exists already

Summary:
This issue came up because it caused problems in our unit tests. The StringPool did connect counterparts only once and silently ignored the values passed in subsequent calls.
The simplest solution for the unit tests would be silent overwrite. In practice, however, it seems useful to assert that we never overwrite a different mangled counterpart.
If we ever have mangled counterparts for other languages than C++, this makes it more likely to notice collisions.

I added an assertion that allows the following cases:
* inserting a new value
* overwriting the empty string
* overwriting with an identical value

I fixed the unit tests, which used "random" strings and thus produced collisions.
It would be even better if there was a way to reset or isolate the StringPool, but that's a different story.

Reviewers: jingham, friss, labath

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D50536

llvm-svn: 339669
  • Loading branch information
weliveindetail committed Aug 14, 2018
1 parent c66d480 commit 2397a2b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 18 deletions.
15 changes: 10 additions & 5 deletions lldb/source/Utility/ConstString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,16 @@ class Pool {
const uint8_t h = hash(demangled);
llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);

// Make string pool entry with the mangled counterpart already set
StringPoolEntryType &entry =
*m_string_pools[h]
.m_string_map.insert(std::make_pair(demangled, mangled_ccstr))
.first;
// Make or update string pool entry with the mangled counterpart
StringPool &map = m_string_pools[h].m_string_map;
StringPoolEntryType &entry = *map.try_emplace(demangled).first;

assert((entry.second == nullptr || entry.second == mangled_ccstr ||
strlen(entry.second) == 0) &&
"The demangled string must have a unique counterpart or otherwise "
"it must be empty");

entry.second = mangled_ccstr;

// Extract the const version of the demangled_cstr
demangled_ccstr = entry.getKeyData();
Expand Down
46 changes: 33 additions & 13 deletions lldb/unittests/Utility/ConstStringTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,60 @@ TEST(ConstStringTest, format_provider) {
}

TEST(ConstStringTest, MangledCounterpart) {
ConstString foo("foo");
ConstString uvw("uvw");
ConstString counterpart;
EXPECT_FALSE(foo.GetMangledCounterpart(counterpart));
EXPECT_FALSE(uvw.GetMangledCounterpart(counterpart));
EXPECT_EQ("", counterpart.GetStringRef());

ConstString bar;
bar.SetStringWithMangledCounterpart("bar", foo);
EXPECT_EQ("bar", bar.GetStringRef());
ConstString xyz;
xyz.SetStringWithMangledCounterpart("xyz", uvw);
EXPECT_EQ("xyz", xyz.GetStringRef());

EXPECT_TRUE(bar.GetMangledCounterpart(counterpart));
EXPECT_EQ("foo", counterpart.GetStringRef());
EXPECT_TRUE(xyz.GetMangledCounterpart(counterpart));
EXPECT_EQ("uvw", counterpart.GetStringRef());

EXPECT_TRUE(foo.GetMangledCounterpart(counterpart));
EXPECT_EQ("bar", counterpart.GetStringRef());
EXPECT_TRUE(uvw.GetMangledCounterpart(counterpart));
EXPECT_EQ("xyz", counterpart.GetStringRef());
}

TEST(ConstStringTest, UpdateMangledCounterpart) {
{ // Add counterpart
ConstString some1;
some1.SetStringWithMangledCounterpart("some", ConstString(""));
}
{ // Overwrite empty string
ConstString some2;
some2.SetStringWithMangledCounterpart("some", ConstString("one"));
}
{ // Overwrite with identical value
ConstString some2;
some2.SetStringWithMangledCounterpart("some", ConstString("one"));
}
{ // Check counterpart is set
ConstString counterpart;
EXPECT_TRUE(ConstString("some").GetMangledCounterpart(counterpart));
EXPECT_EQ("one", counterpart.GetStringRef());
}
}

TEST(ConstStringTest, FromMidOfBufferStringRef) {
// StringRef's into bigger buffer: no null termination
const char *buffer = "foobarbaz";
const char *buffer = "abcdefghi";
llvm::StringRef foo_ref(buffer, 3);
llvm::StringRef bar_ref(buffer + 3, 3);

ConstString foo(foo_ref);

ConstString bar;
bar.SetStringWithMangledCounterpart(bar_ref, foo);
EXPECT_EQ("bar", bar.GetStringRef());
EXPECT_EQ("def", bar.GetStringRef());

ConstString counterpart;
EXPECT_TRUE(bar.GetMangledCounterpart(counterpart));
EXPECT_EQ("foo", counterpart.GetStringRef());
EXPECT_EQ("abc", counterpart.GetStringRef());

EXPECT_TRUE(foo.GetMangledCounterpart(counterpart));
EXPECT_EQ("bar", counterpart.GetStringRef());
EXPECT_EQ("def", counterpart.GetStringRef());
}

TEST(ConstStringTest, NullAndEmptyStates) {
Expand Down

0 comments on commit 2397a2b

Please sign in to comment.