Bug Summary

File:tools/lldb/source/Utility/ConstString.cpp
Warning:line 205, column 3
Returning null reference

Annotated Source Code

1//===-- ConstString.cpp -----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Utility/ConstString.h"
11
12#include "lldb/Utility/Stream.h"
13
14#include "llvm/ADT/StringExtras.h"
15#include "llvm/ADT/StringMap.h"
16#include "llvm/ADT/iterator.h" // for iterator_facade_base
17#include "llvm/Support/Allocator.h" // for BumpPtrAllocator
18#include "llvm/Support/FormatProviders.h" // for format_provider
19#include "llvm/Support/RWMutex.h"
20#include "llvm/Support/Threading.h"
21
22#include <algorithm> // for min
23#include <array>
24#include <utility> // for make_pair, pair
25
26#include <inttypes.h> // for PRIu64
27#include <stdint.h> // for uint8_t, uint32_t, uint64_t
28#include <string.h> // for size_t, strlen
29
30using namespace lldb_private;
31
32class Pool {
33public:
34 typedef const char *StringPoolValueType;
35 typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator>
36 StringPool;
37 typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
38
39 static StringPoolEntryType &
40 GetStringMapEntryFromKeyData(const char *keyData) {
41 char *ptr = const_cast<char *>(keyData) - sizeof(StringPoolEntryType);
42 return *reinterpret_cast<StringPoolEntryType *>(ptr);
43 }
44
45 size_t GetConstCStringLength(const char *ccstr) const {
46 if (ccstr != nullptr) {
47 const uint8_t h = hash(llvm::StringRef(ccstr));
48 llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
49 const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
50 return entry.getKey().size();
51 }
52 return 0;
53 }
54
55 StringPoolValueType GetMangledCounterpart(const char *ccstr) const {
56 if (ccstr != nullptr) {
57 const uint8_t h = hash(llvm::StringRef(ccstr));
58 llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
59 return GetStringMapEntryFromKeyData(ccstr).getValue();
60 }
61 return nullptr;
62 }
63
64 bool SetMangledCounterparts(const char *key_ccstr, const char *value_ccstr) {
65 if (key_ccstr != nullptr && value_ccstr != nullptr) {
66 {
67 const uint8_t h = hash(llvm::StringRef(key_ccstr));
68 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
69 GetStringMapEntryFromKeyData(key_ccstr).setValue(value_ccstr);
70 }
71 {
72 const uint8_t h = hash(llvm::StringRef(value_ccstr));
73 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
74 GetStringMapEntryFromKeyData(value_ccstr).setValue(key_ccstr);
75 }
76 return true;
77 }
78 return false;
79 }
80
81 const char *GetConstCString(const char *cstr) {
82 if (cstr != nullptr)
83 return GetConstCStringWithLength(cstr, strlen(cstr));
84 return nullptr;
85 }
86
87 const char *GetConstCStringWithLength(const char *cstr, size_t cstr_len) {
88 if (cstr != nullptr)
89 return GetConstCStringWithStringRef(llvm::StringRef(cstr, cstr_len));
90 return nullptr;
91 }
92
93 const char *GetConstCStringWithStringRef(const llvm::StringRef &string_ref) {
94 if (string_ref.data()) {
95 const uint8_t h = hash(string_ref);
96
97 {
98 llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
99 auto it = m_string_pools[h].m_string_map.find(string_ref);
100 if (it != m_string_pools[h].m_string_map.end())
101 return it->getKeyData();
102 }
103
104 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
105 StringPoolEntryType &entry =
106 *m_string_pools[h]
107 .m_string_map.insert(std::make_pair(string_ref, nullptr))
108 .first;
109 return entry.getKeyData();
110 }
111 return nullptr;
112 }
113
114 const char *
115 GetConstCStringAndSetMangledCounterPart(const char *demangled_cstr,
116 const char *mangled_ccstr) {
117 if (demangled_cstr != nullptr) {
118 const char *demangled_ccstr = nullptr;
119
120 {
121 llvm::StringRef string_ref(demangled_cstr);
122 const uint8_t h = hash(string_ref);
123 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
124
125 // Make string pool entry with the mangled counterpart already set
126 StringPoolEntryType &entry =
127 *m_string_pools[h]
128 .m_string_map.insert(std::make_pair(string_ref, mangled_ccstr))
129 .first;
130
131 // Extract the const version of the demangled_cstr
132 demangled_ccstr = entry.getKeyData();
133 }
134
135 {
136 // Now assign the demangled const string as the counterpart of the
137 // mangled const string...
138 const uint8_t h = hash(llvm::StringRef(mangled_ccstr));
139 llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex);
140 GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr);
141 }
142
143 // Return the constant demangled C string
144 return demangled_ccstr;
145 }
146 return nullptr;
147 }
148
149 const char *GetConstTrimmedCStringWithLength(const char *cstr,
150 size_t cstr_len) {
151 if (cstr != nullptr) {
152 const size_t trimmed_len = std::min<size_t>(strlen(cstr), cstr_len);
153 return GetConstCStringWithLength(cstr, trimmed_len);
154 }
155 return nullptr;
156 }
157
158 //------------------------------------------------------------------
159 // Return the size in bytes that this object and any items in its
160 // collection of uniqued strings + data count values takes in
161 // memory.
162 //------------------------------------------------------------------
163 size_t MemorySize() const {
164 size_t mem_size = sizeof(Pool);
165 for (const auto &pool : m_string_pools) {
166 llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex);
167 for (const auto &entry : pool.m_string_map)
168 mem_size += sizeof(StringPoolEntryType) + entry.getKey().size();
169 }
170 return mem_size;
171 }
172
173protected:
174 uint8_t hash(const llvm::StringRef &s) const {
175 uint32_t h = llvm::HashString(s);
176 return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff;
177 }
178
179 struct PoolEntry {
180 mutable llvm::sys::SmartRWMutex<false> m_mutex;
181 StringPool m_string_map;
182 };
183
184 std::array<PoolEntry, 256> m_string_pools;
185};
186
187//----------------------------------------------------------------------
188// Frameworks and dylibs aren't supposed to have global C++
189// initializers so we hide the string pool in a static function so
190// that it will get initialized on the first call to this static
191// function.
192//
193// Note, for now we make the string pool a pointer to the pool, because
194// we can't guarantee that some objects won't get destroyed after the
195// global destructor chain is run, and trying to make sure no destructors
196// touch ConstStrings is difficult. So we leak the pool instead.
197//----------------------------------------------------------------------
198static Pool &StringPool() {
199 static llvm::once_flag g_pool_initialization_flag;
200 static Pool *g_string_pool = nullptr;
2
'g_string_pool' initialized to a null pointer value
201
202 llvm::call_once(g_pool_initialization_flag,
203 []() { g_string_pool = new Pool(); });
204
205 return *g_string_pool;
3
Returning null reference
206}
207
208ConstString::ConstString(const char *cstr)
209 : m_string(StringPool().GetConstCString(cstr)) {}
210
211ConstString::ConstString(const char *cstr, size_t cstr_len)
212 : m_string(StringPool().GetConstCStringWithLength(cstr, cstr_len)) {}
213
214ConstString::ConstString(const llvm::StringRef &s)
215 : m_string(StringPool().GetConstCStringWithLength(s.data(), s.size())) {}
216
217bool ConstString::operator<(const ConstString &rhs) const {
218 if (m_string == rhs.m_string)
219 return false;
220
221 llvm::StringRef lhs_string_ref(m_string,
222 StringPool().GetConstCStringLength(m_string));
223 llvm::StringRef rhs_string_ref(
224 rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
225
226 // If both have valid C strings, then return the comparison
227 if (lhs_string_ref.data() && rhs_string_ref.data())
228 return lhs_string_ref < rhs_string_ref;
229
230 // Else one of them was nullptr, so if LHS is nullptr then it is less than
231 return lhs_string_ref.data() == nullptr;
232}
233
234Stream &lldb_private::operator<<(Stream &s, const ConstString &str) {
235 const char *cstr = str.GetCString();
236 if (cstr != nullptr)
237 s << cstr;
238
239 return s;
240}
241
242size_t ConstString::GetLength() const {
243 return StringPool().GetConstCStringLength(m_string);
244}
245
246bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs,
247 const bool case_sensitive) {
248 if (lhs.m_string == rhs.m_string)
249 return true;
250
251 // Since the pointers weren't equal, and identical ConstStrings always have
252 // identical pointers,
253 // the result must be false for case sensitive equality test.
254 if (case_sensitive)
255 return false;
256
257 // perform case insensitive equality test
258 llvm::StringRef lhs_string_ref(
259 lhs.m_string, StringPool().GetConstCStringLength(lhs.m_string));
260 llvm::StringRef rhs_string_ref(
261 rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
262 return lhs_string_ref.equals_lower(rhs_string_ref);
263}
264
265int ConstString::Compare(const ConstString &lhs, const ConstString &rhs,
266 const bool case_sensitive) {
267 // If the iterators are the same, this is the same string
268 const char *lhs_cstr = lhs.m_string;
269 const char *rhs_cstr = rhs.m_string;
270 if (lhs_cstr == rhs_cstr)
271 return 0;
272 if (lhs_cstr && rhs_cstr) {
273 llvm::StringRef lhs_string_ref(
274 lhs_cstr, StringPool().GetConstCStringLength(lhs_cstr));
275 llvm::StringRef rhs_string_ref(
276 rhs_cstr, StringPool().GetConstCStringLength(rhs_cstr));
277
278 if (case_sensitive) {
279 return lhs_string_ref.compare(rhs_string_ref);
280 } else {
281 return lhs_string_ref.compare_lower(rhs_string_ref);
282 }
283 }
284
285 if (lhs_cstr)
286 return +1; // LHS isn't nullptr but RHS is
287 else
288 return -1; // LHS is nullptr but RHS isn't
289}
290
291void ConstString::Dump(Stream *s, const char *fail_value) const {
292 if (s != nullptr) {
293 const char *cstr = AsCString(fail_value);
294 if (cstr != nullptr)
295 s->PutCString(cstr);
296 }
297}
298
299void ConstString::DumpDebug(Stream *s) const {
300 const char *cstr = GetCString();
301 size_t cstr_len = GetLength();
302 // Only print the parens if we have a non-nullptr string
303 const char *parens = cstr ? "\"" : "";
304 s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64"l" "u",
305 static_cast<int>(sizeof(void *) * 2),
306 static_cast<const void *>(this), parens, cstr, parens,
307 static_cast<uint64_t>(cstr_len));
308}
309
310void ConstString::SetCString(const char *cstr) {
311 m_string = StringPool().GetConstCString(cstr);
312}
313
314void ConstString::SetString(const llvm::StringRef &s) {
315 m_string = StringPool().GetConstCStringWithLength(s.data(), s.size());
316}
317
318void ConstString::SetCStringWithMangledCounterpart(const char *demangled,
319 const ConstString &mangled) {
320 m_string = StringPool().GetConstCStringAndSetMangledCounterPart(
321 demangled, mangled.m_string);
322}
323
324bool ConstString::GetMangledCounterpart(ConstString &counterpart) const {
325 counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
326 return (bool)counterpart;
327}
328
329void ConstString::SetCStringWithLength(const char *cstr, size_t cstr_len) {
330 m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
331}
332
333void ConstString::SetTrimmedCStringWithLength(const char *cstr,
334 size_t cstr_len) {
335 m_string = StringPool().GetConstTrimmedCStringWithLength(cstr, cstr_len);
336}
337
338size_t ConstString::StaticMemorySize() {
339 // Get the size of the static string pool
340 return StringPool().MemorySize();
1
Calling 'StringPool'
341}
342
343void llvm::format_provider<ConstString>::format(const ConstString &CS,
344 llvm::raw_ostream &OS,
345 llvm::StringRef Options) {
346 format_provider<StringRef>::format(CS.AsCString(), OS, Options);
347}