libbio
Loading...
Searching...
No Matches
PointerSafety.h
Go to the documentation of this file.
1/*
2 * This file is a part of the Biology project by eons LLC.
3 * Biology (aka Develop Biology) is a framework for approaching software
4 * development from a natural sciences perspective.
5 *
6 * Copyright (C) 2026 Séon O'Shannon & eons LLC
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#pragma once
23
25
52//@formatter:off
53#if defined(BIO_POINTER_SAFETY) && BIO_CPP_VERSION >= 11
54 #include <unordered_set>
55 #include <mutex>
56 #include <cstdio>
57 #include <cstdlib>
58 #include <type_traits>
59#endif
60//@formatter:on
61
62namespace bio {
63namespace pointer_safety {
64
65//@formatter:off
66#if defined(BIO_POINTER_SAFETY) && BIO_CPP_VERSION >= 11
67//@formatter:on
68
69namespace detail {
70
71struct RetiredPointer
72{
74 const void* address,
75 const void* type
76 )
77 :
79 mType(type)
80 {
81 }
82
83 bool operator==(const RetiredPointer& other) const
84 {
85 return mAddress == other.mAddress && mType == other.mType;
86 }
87
88 const void* mAddress;
89 const void* mType;
90};
91
93{
94 ::std::size_t operator()(const RetiredPointer& key) const
95 {
96 const ::std::size_t addressHash = ::std::hash< const void* >()(key.mAddress);
97 const ::std::size_t typeHash = ::std::hash< const void* >()(key.mType);
98 return addressHash ^ (typeHash + 0x9e3779b97f4a7c15ULL + (addressHash << 6) + (addressHash >> 2));
99 }
100};
101
103{
104 ::std::unordered_set< RetiredPointer, RetiredPointerHash > mRetired;
105 ::std::mutex mLock;
106};
107
108template < typename T >
109inline const void* TypeToken()
110{
111 typedef typename ::std::remove_cv< T >::type BareT;
112 static const char sToken = 0;
113 (void)sizeof(BareT*);
114 return &sToken;
115}
116
117template < typename T >
118inline RetiredPointer Key(
119 const void* p
120)
121{
123}
124
126 const void* p
127)
128{
129 return Key< void >(p);
130}
131
139{
141 return *sRegistry;
142}
143
149[[noreturn]] inline void OnRetiredDeref(const void* p, const char* file, int line)
150{
151 ::std::fprintf(stderr,
152 "BIO_POINTER_SAFETY: dereference of retired (freed) pointer %p at %s:%d\n",
153 p, file, line);
154 ::std::abort();
155}
156
157} // namespace detail
158
165template < typename T >
166inline void MarkLive(const void* p)
167{
168 if (!p) { return; }
169 detail::PointerSafetyRegistry& reg = detail::Registry();
170 ::std::lock_guard< ::std::mutex > guard(reg.mLock);
171 reg.mRetired.erase(detail::Key< T >(p));
172 reg.mRetired.erase(detail::UntypedKey(p));
173}
174
178inline void MarkLive(const void* p)
179{
181}
182
188template < typename T >
189inline void MarkRetired(const void* p)
190{
191 if (!p) { return; }
192 detail::PointerSafetyRegistry& reg = detail::Registry();
193 ::std::lock_guard< ::std::mutex > guard(reg.mLock);
194 reg.mRetired.insert(detail::Key< T >(p));
195}
196
200inline void MarkRetired(const void* p)
201{
203}
204
210template < typename T >
211inline bool IsLive(const void* p)
212{
213 if (!p) { return true; }
214 detail::PointerSafetyRegistry& reg = detail::Registry();
215 ::std::lock_guard< ::std::mutex > guard(reg.mLock);
216 if (reg.mRetired.find(detail::Key< T >(p)) != reg.mRetired.end())
217 {
218 return false;
219 }
220 const detail::RetiredPointer untyped = detail::UntypedKey(p);
221 if (untyped.mType != detail::TypeToken< T >()
222 && reg.mRetired.find(untyped) != reg.mRetired.end())
223 {
224 return false;
225 }
226 return true;
227}
228
232inline bool IsLive(const void* p)
233{
234 return IsLive< void >(p);
235}
236
237template < typename T >
238inline void AssertLive(
239 const void* p,
240 const char* file,
241 int line
242)
243{
244 if (!IsLive< T >(p))
245 {
246 detail::OnRetiredDeref(p, file, line);
247 }
248}
249
250inline void AssertLive(
251 const void* p,
252 const char* file,
253 int line
254)
255{
256 if (!IsLive(p))
257 {
258 detail::OnRetiredDeref(p, file, line);
259 }
260}
261
262//@formatter:off
263#else // feature off (prod) or cpp98: every entry point is a removed no-op.
264//@formatter:on
265
266template < typename T >
267inline void MarkLive(const void*) {}
268inline void MarkLive(const void*) {}
269template < typename T >
270inline void MarkRetired(const void*) {}
271inline void MarkRetired(const void*) {}
272template < typename T >
273inline bool IsLive(const void*) { return true; }
274inline bool IsLive(const void*) { return true; }
275template < typename T >
276inline void AssertLive(const void*, const char*, int) {}
277inline void AssertLive(const void*, const char*, int) {}
278
279//@formatter:off
280#endif
281//@formatter:on
282
283} // namespace pointer_safety
284} // namespace bio
285
286//@formatter:off
287#if defined(BIO_POINTER_SAFETY) && BIO_CPP_VERSION >= 11
288 // Deref guard used inside Pointer< T >::operator-> / operator*. Aborts on a deref of
289 // a retired (freed) address whenever BIO_POINTER_SAFETY is on -- NOT NDEBUG-gated, so
290 // a Release+BIO_POINTER_SAFETY build catches too. No-op (references nothing) when off.
291 #define BIO_POINTER_SAFETY_CHECK(ptr) \
292 do { ::bio::pointer_safety::AssertLive((const void*)(ptr), __FILE__, __LINE__); } while (0)
293#else
294 #define BIO_POINTER_SAFETY_CHECK(ptr) ((void)0)
295#endif
296//@formatter:on
Definition Pointer.h:115
void MarkLive(const void *)
Definition PointerSafety.h:267
bool IsLive(const void *)
Definition PointerSafety.h:273
void AssertLive(const void *, const char *, int)
Definition PointerSafety.h:276
void MarkRetired(const void *)
Definition PointerSafety.h:270
Definition FinalCell.h:29
bool operator==(T *raw, const Pointer< T > &wrapped)
Definition Pointer.h:394