xref: /llvm-project-15.0.7/libcxx/src/debug.cpp (revision beb6efb4)
1 //===-------------------------- debug.cpp ---------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "__config"
10 #include "__debug"
11 #include "functional"
12 #include "algorithm"
13 #include "string"
14 #include "cstdio"
15 #include "__hash_table"
16 #include "mutex"
17 
18 _LIBCPP_BEGIN_NAMESPACE_STD
19 
20 std::string __libcpp_debug_info::what() const {
21   string msg = __file_;
22   msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '";
23   msg += __pred_;
24   msg += "' failed. ";
25   msg += __msg_;
26   return msg;
27 }
28 _LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
29     std::fprintf(stderr, "%s\n", info.what().c_str());
30     std::abort();
31 }
32 
33 _LIBCPP_SAFE_STATIC __libcpp_debug_function_type
34     __libcpp_debug_function = __libcpp_abort_debug_function;
35 
36 bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
37   __libcpp_debug_function = __func;
38   return true;
39 }
40 
41 _LIBCPP_FUNC_VIS
42 __libcpp_db*
43 __get_db()
44 {
45     static __libcpp_db db;
46     return &db;
47 }
48 
49 _LIBCPP_FUNC_VIS
50 const __libcpp_db*
51 __get_const_db()
52 {
53     return __get_db();
54 }
55 
56 namespace
57 {
58 
59 #ifndef _LIBCPP_HAS_NO_THREADS
60 typedef mutex mutex_type;
61 typedef lock_guard<mutex_type> WLock;
62 typedef lock_guard<mutex_type> RLock;
63 
64 mutex_type&
65 mut()
66 {
67     static mutex_type m;
68     return m;
69 }
70 #endif // !_LIBCPP_HAS_NO_THREADS
71 
72 }  // unnamed namespace
73 
74 __i_node::~__i_node()
75 {
76     if (__next_)
77     {
78         __next_->~__i_node();
79         free(__next_);
80     }
81 }
82 
83 __c_node::~__c_node()
84 {
85     free(beg_);
86     if (__next_)
87     {
88         __next_->~__c_node();
89         free(__next_);
90     }
91 }
92 
93 __libcpp_db::__libcpp_db()
94     : __cbeg_(nullptr),
95       __cend_(nullptr),
96       __csz_(0),
97       __ibeg_(nullptr),
98       __iend_(nullptr),
99       __isz_(0)
100 {
101 }
102 
103 __libcpp_db::~__libcpp_db()
104 {
105     if (__cbeg_)
106     {
107         for (__c_node** p = __cbeg_; p != __cend_; ++p)
108         {
109             if (*p != nullptr)
110             {
111                 (*p)->~__c_node();
112                 free(*p);
113             }
114         }
115         free(__cbeg_);
116     }
117     if (__ibeg_)
118     {
119         for (__i_node** p = __ibeg_; p != __iend_; ++p)
120         {
121             if (*p != nullptr)
122             {
123                 (*p)->~__i_node();
124                 free(*p);
125             }
126         }
127         free(__ibeg_);
128     }
129 }
130 
131 void*
132 __libcpp_db::__find_c_from_i(void* __i) const
133 {
134 #ifndef _LIBCPP_HAS_NO_THREADS
135     RLock _(mut());
136 #endif
137     __i_node* i = __find_iterator(__i);
138     _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
139     return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
140 }
141 
142 void
143 __libcpp_db::__insert_ic(void* __i, const void* __c)
144 {
145 #ifndef _LIBCPP_HAS_NO_THREADS
146     WLock _(mut());
147 #endif
148     if (__cbeg_ == __cend_)
149         return;
150     size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
151     __c_node* c = __cbeg_[hc];
152     if (c == nullptr)
153         return;
154     while (c->__c_ != __c)
155     {
156         c = c->__next_;
157         if (c == nullptr)
158             return;
159     }
160     __i_node* i = __insert_iterator(__i);
161     c->__add(i);
162     i->__c_ = c;
163 }
164 
165 void
166 __libcpp_db::__insert_c(void* __c, __libcpp_db::_InsertConstruct *__fn)
167 {
168 #ifndef _LIBCPP_HAS_NO_THREADS
169     WLock _(mut());
170 #endif
171     if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
172     {
173         size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
174         __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(void*)));
175         if (cbeg == nullptr)
176             __throw_bad_alloc();
177 
178         for (__c_node** p = __cbeg_; p != __cend_; ++p)
179         {
180             __c_node* q = *p;
181             while (q != nullptr)
182             {
183                 size_t h = hash<void*>()(q->__c_) % nc;
184                 __c_node* r = q->__next_;
185                 q->__next_ = cbeg[h];
186                 cbeg[h] = q;
187                 q = r;
188             }
189         }
190         free(__cbeg_);
191         __cbeg_ = cbeg;
192         __cend_ = __cbeg_ + nc;
193     }
194     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
195     __c_node* p = __cbeg_[hc];
196     void *buf = malloc(sizeof(__c_node));
197     if (buf == nullptr)
198       __throw_bad_alloc();
199     __cbeg_[hc] = __fn(buf, __c, p);
200 
201     ++__csz_;
202 }
203 
204 void
205 __libcpp_db::__erase_i(void* __i)
206 {
207 #ifndef _LIBCPP_HAS_NO_THREADS
208     WLock _(mut());
209 #endif
210     if (__ibeg_ != __iend_)
211     {
212         size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
213         __i_node* p = __ibeg_[hi];
214         if (p != nullptr)
215         {
216             __i_node* q = nullptr;
217             while (p->__i_ != __i)
218             {
219                 q = p;
220                 p = p->__next_;
221                 if (p == nullptr)
222                     return;
223             }
224             if (q == nullptr)
225                 __ibeg_[hi] = p->__next_;
226             else
227                 q->__next_ = p->__next_;
228             __c_node* c = p->__c_;
229             --__isz_;
230             if (c != nullptr)
231                 c->__remove(p);
232             free(p);
233         }
234     }
235 }
236 
237 void
238 __libcpp_db::__invalidate_all(void* __c)
239 {
240 #ifndef _LIBCPP_HAS_NO_THREADS
241     WLock _(mut());
242 #endif
243     if (__cend_ != __cbeg_)
244     {
245         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
246         __c_node* p = __cbeg_[hc];
247         if (p == nullptr)
248             return;
249         while (p->__c_ != __c)
250         {
251             p = p->__next_;
252             if (p == nullptr)
253                 return;
254         }
255         while (p->end_ != p->beg_)
256         {
257             --p->end_;
258             (*p->end_)->__c_ = nullptr;
259         }
260     }
261 }
262 
263 __c_node*
264 __libcpp_db::__find_c_and_lock(void* __c) const
265 {
266 #ifndef _LIBCPP_HAS_NO_THREADS
267     mut().lock();
268 #endif
269     if (__cend_ == __cbeg_)
270     {
271 #ifndef _LIBCPP_HAS_NO_THREADS
272         mut().unlock();
273 #endif
274         return nullptr;
275     }
276     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
277     __c_node* p = __cbeg_[hc];
278     if (p == nullptr)
279     {
280 #ifndef _LIBCPP_HAS_NO_THREADS
281         mut().unlock();
282 #endif
283         return nullptr;
284     }
285     while (p->__c_ != __c)
286     {
287         p = p->__next_;
288         if (p == nullptr)
289         {
290 #ifndef _LIBCPP_HAS_NO_THREADS
291             mut().unlock();
292 #endif
293             return nullptr;
294         }
295     }
296     return p;
297 }
298 
299 __c_node*
300 __libcpp_db::__find_c(void* __c) const
301 {
302     size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
303     __c_node* p = __cbeg_[hc];
304     _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
305     while (p->__c_ != __c)
306     {
307         p = p->__next_;
308         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
309     }
310     return p;
311 }
312 
313 void
314 __libcpp_db::unlock() const
315 {
316 #ifndef _LIBCPP_HAS_NO_THREADS
317     mut().unlock();
318 #endif
319 }
320 
321 void
322 __libcpp_db::__erase_c(void* __c)
323 {
324 #ifndef _LIBCPP_HAS_NO_THREADS
325     WLock _(mut());
326 #endif
327     if (__cend_ != __cbeg_)
328     {
329         size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
330         __c_node* p = __cbeg_[hc];
331         if (p == nullptr)
332             return;
333         __c_node* q = nullptr;
334         _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
335         while (p->__c_ != __c)
336         {
337             q = p;
338             p = p->__next_;
339             if (p == nullptr)
340                 return;
341             _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
342         }
343         if (q == nullptr)
344             __cbeg_[hc] = p->__next_;
345         else
346             q->__next_ = p->__next_;
347         while (p->end_ != p->beg_)
348         {
349             --p->end_;
350             (*p->end_)->__c_ = nullptr;
351         }
352         free(p->beg_);
353         free(p);
354         --__csz_;
355     }
356 }
357 
358 void
359 __libcpp_db::__iterator_copy(void* __i, const void* __i0)
360 {
361 #ifndef _LIBCPP_HAS_NO_THREADS
362     WLock _(mut());
363 #endif
364     __i_node* i = __find_iterator(__i);
365     __i_node* i0 = __find_iterator(__i0);
366     __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
367     if (i == nullptr && i0 != nullptr)
368         i = __insert_iterator(__i);
369     __c_node* c = i != nullptr ? i->__c_ : nullptr;
370     if (c != c0)
371     {
372         if (c != nullptr)
373             c->__remove(i);
374         if (i != nullptr)
375         {
376             i->__c_ = nullptr;
377             if (c0 != nullptr)
378             {
379                 i->__c_ = c0;
380                 i->__c_->__add(i);
381             }
382         }
383     }
384 }
385 
386 bool
387 __libcpp_db::__dereferenceable(const void* __i) const
388 {
389 #ifndef _LIBCPP_HAS_NO_THREADS
390     RLock _(mut());
391 #endif
392     __i_node* i = __find_iterator(__i);
393     return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
394 }
395 
396 bool
397 __libcpp_db::__decrementable(const void* __i) const
398 {
399 #ifndef _LIBCPP_HAS_NO_THREADS
400     RLock _(mut());
401 #endif
402     __i_node* i = __find_iterator(__i);
403     return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
404 }
405 
406 bool
407 __libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
408 {
409 #ifndef _LIBCPP_HAS_NO_THREADS
410     RLock _(mut());
411 #endif
412     __i_node* i = __find_iterator(__i);
413     return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
414 }
415 
416 bool
417 __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
418 {
419 #ifndef _LIBCPP_HAS_NO_THREADS
420     RLock _(mut());
421 #endif
422     __i_node* i = __find_iterator(__i);
423     return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
424 }
425 
426 bool
427 __libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
428 {
429 #ifndef _LIBCPP_HAS_NO_THREADS
430     RLock _(mut());
431 #endif
432     __i_node* i = __find_iterator(__i);
433     __i_node* j = __find_iterator(__j);
434     __c_node* ci = i != nullptr ? i->__c_ : nullptr;
435     __c_node* cj = j != nullptr ? j->__c_ : nullptr;
436     return ci != nullptr && ci == cj;
437 }
438 
439 void
440 __libcpp_db::swap(void* c1, void* c2)
441 {
442 #ifndef _LIBCPP_HAS_NO_THREADS
443     WLock _(mut());
444 #endif
445     size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
446     __c_node* p1 = __cbeg_[hc];
447     _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
448     while (p1->__c_ != c1)
449     {
450         p1 = p1->__next_;
451         _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
452     }
453     hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
454     __c_node* p2 = __cbeg_[hc];
455     _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
456     while (p2->__c_ != c2)
457     {
458         p2 = p2->__next_;
459         _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
460     }
461     std::swap(p1->beg_, p2->beg_);
462     std::swap(p1->end_, p2->end_);
463     std::swap(p1->cap_, p2->cap_);
464     for (__i_node** p = p1->beg_; p != p1->end_; ++p)
465         (*p)->__c_ = p1;
466     for (__i_node** p = p2->beg_; p != p2->end_; ++p)
467         (*p)->__c_ = p2;
468 }
469 
470 void
471 __libcpp_db::__insert_i(void* __i)
472 {
473 #ifndef _LIBCPP_HAS_NO_THREADS
474     WLock _(mut());
475 #endif
476     __insert_iterator(__i);
477 }
478 
479 void
480 __c_node::__add(__i_node* i)
481 {
482     if (end_ == cap_)
483     {
484         size_t nc = 2*static_cast<size_t>(cap_ - beg_);
485         if (nc == 0)
486             nc = 1;
487         __i_node** beg =
488            static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
489         if (beg == nullptr)
490             __throw_bad_alloc();
491 
492         if (nc > 1)
493             memcpy(beg, beg_, nc/2*sizeof(__i_node*));
494         free(beg_);
495         beg_ = beg;
496         end_ = beg_ + nc/2;
497         cap_ = beg_ + nc;
498     }
499     *end_++ = i;
500 }
501 
502 // private api
503 
504 _LIBCPP_HIDDEN
505 __i_node*
506 __libcpp_db::__insert_iterator(void* __i)
507 {
508     if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
509     {
510         size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
511         __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(void*)));
512         if (ibeg == nullptr)
513             __throw_bad_alloc();
514 
515         for (__i_node** p = __ibeg_; p != __iend_; ++p)
516         {
517             __i_node* q = *p;
518             while (q != nullptr)
519             {
520                 size_t h = hash<void*>()(q->__i_) % nc;
521                 __i_node* r = q->__next_;
522                 q->__next_ = ibeg[h];
523                 ibeg[h] = q;
524                 q = r;
525             }
526         }
527         free(__ibeg_);
528         __ibeg_ = ibeg;
529         __iend_ = __ibeg_ + nc;
530     }
531     size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
532     __i_node* p = __ibeg_[hi];
533     __i_node* r = __ibeg_[hi] =
534       static_cast<__i_node*>(malloc(sizeof(__i_node)));
535     if (r == nullptr)
536         __throw_bad_alloc();
537 
538     ::new(r) __i_node(__i, p, nullptr);
539     ++__isz_;
540     return r;
541 }
542 
543 _LIBCPP_HIDDEN
544 __i_node*
545 __libcpp_db::__find_iterator(const void* __i) const
546 {
547     __i_node* r = nullptr;
548     if (__ibeg_ != __iend_)
549     {
550         size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
551         for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
552         {
553             if (nd->__i_ == __i)
554             {
555                 r = nd;
556                 break;
557             }
558         }
559     }
560     return r;
561 }
562 
563 _LIBCPP_HIDDEN
564 void
565 __c_node::__remove(__i_node* p)
566 {
567     __i_node** r = find(beg_, end_, p);
568     _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
569     if (--end_ != r)
570         memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
571 }
572 
573 _LIBCPP_END_NAMESPACE_STD
574