]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cbdata.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / cbdata.cc
CommitLineData
e1ac4723 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
e1ac4723 7 */
8
bbc27441
AJ
9/* DEBUG: section 45 Callback Data Registry */
10
f7f3304a 11#include "squid.h"
aa839030 12#include "cbdata.h"
e2849af8 13#include "Generic.h"
f327361e 14#include "mem/Pool.h"
8822ebee 15#include "mgr/Registration.h"
e6ccf245 16#include "Store.h"
a2172245 17
20148bf2 18#include <climits>
02f5357c 19#include <cstddef>
20148bf2 20
b4bab919 21#if WITH_VALGRIND
fa4f735f 22#include <map>
b4bab919 23#endif
24
20148bf2 25static int cbdataCount = 0;
e48ed433 26
ffc6d4e9
AJ
27/**
28 * Manage a set of registered callback data pointers.
29 * One of the easiest ways to make Squid coredump is to issue a
30 * callback to for some data structure which has previously been
31 * freed. With this class, we register (add) callback data
32 * pointers, lock them just before registering the callback function,
33 * validate them before issuing the callback, and then free them
34 * when finished.
35 */
20148bf2 36class cbdata
62e76326 37{
fa4f735f 38#if !WITH_VALGRIND
741c2986 39public:
ced8def3
AJ
40 void *operator new(size_t, void *where) {return where;}
41 /**
42 * Only ever invoked when placement new throws
43 * an exception. Used to prevent an incorrect free.
44 */
45 void operator delete(void *, void *) {}
741c2986 46#else
c16af8fd 47 MEMPROXY_CLASS(cbdata);
741c2986
AJ
48#endif
49
9837567d 50 /* TODO: examine making cbdata templated on this - so we get type
b4bab919 51 * safe access to data - RBC 20030902 */
43ae1d95 52public:
fa4f735f
AJ
53 cbdata() :
54 valid(0),
20148bf2 55 locks(0),
cc8c4af2 56 type(CBDATA_UNKNOWN),
f1d03995 57 cookie(0),
aee3523a 58 data(nullptr)
fa4f735f 59 {}
f668fcda 60 ~cbdata();
fa4f735f 61
1496bd71 62 static cbdata *FromUserData(const void *);
02f5357c 63
3015e83a 64 int valid;
20148bf2 65 int32_t locks;
f668fcda 66 cbdata_type type;
62e76326 67
43ae1d95 68 /* cookie used while debugging */
69 long cookie;
ced8def3 70 void check(int) const {assert(cookie == ((long)this ^ Cookie));}
b4bab919 71 static const long Cookie;
43ae1d95 72
fa4f735f 73#if !WITH_VALGRIND
43ae1d95 74 size_t dataSize() const { return sizeof(data);}
fa4f735f 75#endif
b4bab919 76 /* MUST be the last per-instance member */
77 void *data;
43ae1d95 78};
79
02f5357c 80static_assert(std::is_standard_layout<cbdata>::value, "the behavior of offsetof(cbdata) is defined");
43ae1d95 81
02f5357c 82const long cbdata::Cookie((long)0xDEADBEEF);
a2172245 83
26ac0430 84struct CBDataIndex {
341876ec 85 Mem::Allocator *pool;
62e76326 86}
aee3523a 87*cbdata_index = nullptr;
63be0a78 88
28c60158 89int cbdata_types = 0;
90
fa4f735f
AJ
91#if WITH_VALGRIND
92static std::map<const void *, cbdata *> cbdata_htable;
b4bab919 93#endif
94
f668fcda 95cbdata::~cbdata()
e48ed433 96{
e57b674b
AR
97#if WITH_VALGRIND
98 void *p = data;
99#else
100 void *p = this;
101#endif
102 cbdata_index[type].pool->freeOne(p);
e48ed433 103}
104
1496bd71
AR
105cbdata *
106cbdata::FromUserData(const void *p) {
107#if WITH_VALGRIND
108 return cbdata_htable.at(p);
109#else
110 const auto t = static_cast<const char *>(p) - offsetof(cbdata, data);
111 return reinterpret_cast<cbdata *>(const_cast<char *>(t));
112#endif
113}
114
bcd05a84
AJ
115cbdata_type
116cbdataInternalAddType(cbdata_type type, const char *name, int size)
a2172245 117{
bcd05a84
AJ
118 if (type)
119 return type;
120
121 type = (cbdata_type)(cbdata_types + 1);
122
28c60158 123 char *label;
aa839030 124 assert (type == cbdata_types + 1);
62e76326 125
aa839030 126 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
127 memset(&cbdata_index[type], 0, sizeof(*cbdata_index));
128 cbdata_types = type;
62e76326 129
e6ccf245 130 label = (char *)xmalloc(strlen(name) + 20);
62e76326 131
28c60158 132 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
62e76326 133
fa4f735f 134#if !WITH_VALGRIND
02f5357c 135 size += offsetof(cbdata, data);
b4bab919 136#endif
62e76326 137
04eb0689 138 cbdata_index[type].pool = memPoolCreate(label, size);
62e76326 139
28c60158 140 return type;
a2172245 141}
142
28c60158 143void *
bcd05a84 144cbdataInternalAlloc(cbdata_type type)
a2172245 145{
b4bab919 146 cbdata *c;
147 void *p;
aa839030 148 assert(type > 0 && type <= cbdata_types);
149 /* placement new: the pool alloc gives us cbdata + user type memory space
150 * and we init it with cbdata at the start of it
151 */
fa4f735f 152#if WITH_VALGRIND
b4bab919 153 c = new cbdata;
154 p = cbdata_index[type].pool->alloc();
fa4f735f
AJ
155 c->data = p;
156 cbdata_htable.emplace(p,c);
b4bab919 157#else
158 c = new (cbdata_index[type].pool->alloc()) cbdata;
159 p = (void *)&c->data;
160#endif
f668fcda 161
b4bab919 162 c->type = type;
163 c->valid = 1;
20148bf2 164 c->locks = 0;
b4bab919 165 c->cookie = (long) c ^ cbdata::Cookie;
d7ae3534 166 ++cbdataCount;
0796f998 167 debugs(45, 9, "Allocating " << p);
b4bab919 168 return p;
b8a2718d 169}
170
8b082ed9 171static void
bcd05a84 172cbdataRealFree(cbdata *c)
a2172245 173{
e57b674b
AR
174#if WITH_VALGRIND
175 void *p = c->data;
176#else
177 void *p = (void *)&c->data;
178#endif
62e76326 179
5e263176 180 --cbdataCount;
e57b674b 181 debugs(45, 9, "Freeing " << p);
62e76326 182
fa4f735f 183#if WITH_VALGRIND
e57b674b 184 cbdata_htable.erase(p);
08650a87
AJ
185 delete c;
186#else
f668fcda 187 /* This is ugly. But: operator delete doesn't get
26ac0430 188 * the type parameter, so we can't use that
f668fcda 189 * to free the memory.
190 * So, we free it ourselves.
26ac0430 191 * Note that this means a non-placement
f668fcda 192 * new would be a seriously bad idea.
193 * Lastly, if we where a templated class,
194 * we could use the normal delete operator
195 * and it would Just Work. RBC 20030902
196 */
b4bab919 197 c->cbdata::~cbdata();
08650a87 198#endif
50e2f4c4
AJ
199}
200
201void *
bcd05a84 202cbdataInternalFree(void *p)
50e2f4c4 203{
02f5357c 204 auto *c = cbdata::FromUserData(p);
50e2f4c4
AJ
205
206 c->check(__LINE__);
207 assert(c->valid);
208 c->valid = 0;
50e2f4c4 209
20148bf2
AJ
210 if (c->locks) {
211 debugs(45, 9, p << " has " << c->locks << " locks, not freeing");
aee3523a 212 return nullptr;
50e2f4c4
AJ
213 }
214
bcd05a84 215 cbdataRealFree(c);
aee3523a 216 return nullptr;
72711e31 217}
218
a2172245 219void
fa80a8ef 220cbdataInternalLock(const void *p)
a2172245 221{
aee3523a 222 if (p == nullptr)
62e76326 223 return;
224
02f5357c 225 auto *c = cbdata::FromUserData(p);
62e76326 226
20148bf2 227 debugs(45, 9, p << "=" << (c ? c->locks + 1 : -1));
62e76326 228
06a5ae20 229 c->check(__LINE__);
62e76326 230
20148bf2
AJ
231 assert(c->locks < INT_MAX);
232
233 ++ c->locks;
a2172245 234}
235
236void
fa80a8ef 237cbdataInternalUnlock(const void *p)
a2172245 238{
aee3523a 239 if (p == nullptr)
62e76326 240 return;
241
02f5357c 242 auto *c = cbdata::FromUserData(p);
62e76326 243
20148bf2 244 debugs(45, 9, p << "=" << (c ? c->locks - 1 : -1));
62e76326 245
06a5ae20 246 c->check(__LINE__);
62e76326 247
aee3523a 248 assert(c != nullptr);
62e76326 249
20148bf2
AJ
250 assert(c->locks > 0);
251
252 -- c->locks;
62e76326 253
20148bf2 254 if (c->locks)
62e76326 255 return;
256
bcd05a84 257 if (c->valid)
bc40792d 258 return;
bc40792d 259
bcd05a84 260 cbdataRealFree(c);
a2172245 261}
262
263int
fa80a8ef 264cbdataReferenceValid(const void *p)
a2172245 265{
aee3523a 266 if (p == nullptr)
f53969cc 267 return 1; /* A NULL pointer cannot become invalid */
62e76326 268
0796f998 269 debugs(45, 9, p);
62e76326 270
02f5357c 271 const auto c = cbdata::FromUserData(p);
62e76326 272
06a5ae20 273 c->check(__LINE__);
62e76326 274
20148bf2 275 assert(c->locks > 0);
62e76326 276
3015e83a 277 return c->valid;
a2172245 278}
279
fa80a8ef 280int
fa80a8ef 281cbdataInternalReferenceDoneValid(void **pp, void **tp)
fa80a8ef 282{
283 void *p = (void *) *pp;
284 int valid = cbdataReferenceValid(p);
aee3523a 285 *pp = nullptr;
62e76326 286
fa80a8ef 287 cbdataInternalUnlock(p);
62e76326 288
fa80a8ef 289 if (valid) {
62e76326 290 *tp = p;
291 return 1;
fa80a8ef 292 } else {
aee3523a 293 *tp = nullptr;
62e76326 294 return 0;
fa80a8ef 295 }
296}
297
fd9c47d1
AR
298CallbackData &
299CallbackData::operator =(const CallbackData &other)
300{
301 if (data_ != other.data_) { // assignment to self and no-op assignments
302 auto old = data_;
303 data_ = cbdataReference(other.data_);
304 cbdataReferenceDone(old);
305 }
306 return *this;
307}
308
aa839030 309CBDATA_CLASS_INIT(generic_cbdata);
310