]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/cbdata.cc
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 45 Callback Data Registry */
15 #include "mgr/Registration.h"
25 static int cbdataCount
= 0;
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
40 void *operator new(size_t, void *where
) {return where
;}
42 * Only ever invoked when placement new throws
43 * an exception. Used to prevent an incorrect free.
45 void operator delete(void *, void *) {}
47 MEMPROXY_CLASS(cbdata
);
50 /* TODO: examine making cbdata templated on this - so we get type
51 * safe access to data - RBC 20030902 */
62 static cbdata
*FromUserData(const void *);
68 /* cookie used while debugging */
70 void check(int) const {assert(cookie
== ((long)this ^ Cookie
));}
71 static const long Cookie
;
74 size_t dataSize() const { return sizeof(data
);}
76 /* MUST be the last per-instance member */
80 static_assert(std::is_standard_layout
<cbdata
>::value
, "the behavior of offsetof(cbdata) is defined");
82 const long cbdata::Cookie((long)0xDEADBEEF);
87 *cbdata_index
= nullptr;
92 static std::map
<const void *, cbdata
*> cbdata_htable
;
102 cbdata_index
[type
].pool
->freeOne(p
);
106 cbdata::FromUserData(const void *p
) {
108 return cbdata_htable
.at(p
);
110 const auto t
= static_cast<const char *>(p
) - offsetof(cbdata
, data
);
111 return reinterpret_cast<cbdata
*>(const_cast<char *>(t
));
116 cbdataInternalAddType(cbdata_type type
, const char *name
, int size
)
121 type
= (cbdata_type
)(cbdata_types
+ 1);
124 assert (type
== cbdata_types
+ 1);
126 cbdata_index
= (CBDataIndex
*)xrealloc(cbdata_index
, (type
+ 1) * sizeof(*cbdata_index
));
127 memset(&cbdata_index
[type
], 0, sizeof(*cbdata_index
));
130 label
= (char *)xmalloc(strlen(name
) + 20);
132 snprintf(label
, strlen(name
) + 20, "cbdata %s (%d)", name
, (int) type
);
135 size
+= offsetof(cbdata
, data
);
138 cbdata_index
[type
].pool
= memPoolCreate(label
, size
);
144 cbdataInternalAlloc(cbdata_type type
)
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
154 p
= cbdata_index
[type
].pool
->alloc();
156 cbdata_htable
.emplace(p
,c
);
158 c
= new (cbdata_index
[type
].pool
->alloc()) cbdata
;
159 p
= (void *)&c
->data
;
165 c
->cookie
= (long) c
^ cbdata::Cookie
;
167 debugs(45, 9, "Allocating " << p
);
172 cbdataRealFree(cbdata
*c
)
177 void *p
= (void *)&c
->data
;
181 debugs(45, 9, "Freeing " << p
);
184 cbdata_htable
.erase(p
);
187 /* This is ugly. But: operator delete doesn't get
188 * the type parameter, so we can't use that
189 * to free the memory.
190 * So, we free it ourselves.
191 * Note that this means a non-placement
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
197 c
->cbdata::~cbdata();
202 cbdataInternalFree(void *p
)
204 auto *c
= cbdata::FromUserData(p
);
211 debugs(45, 9, p
<< " has " << c
->locks
<< " locks, not freeing");
220 cbdataInternalLock(const void *p
)
225 auto *c
= cbdata::FromUserData(p
);
227 debugs(45, 9, p
<< "=" << (c
? c
->locks
+ 1 : -1));
231 assert(c
->locks
< INT_MAX
);
237 cbdataInternalUnlock(const void *p
)
242 auto *c
= cbdata::FromUserData(p
);
244 debugs(45, 9, p
<< "=" << (c
? c
->locks
- 1 : -1));
248 assert(c
!= nullptr);
250 assert(c
->locks
> 0);
264 cbdataReferenceValid(const void *p
)
267 return 1; /* A NULL pointer cannot become invalid */
271 const auto c
= cbdata::FromUserData(p
);
275 assert(c
->locks
> 0);
281 cbdataInternalReferenceDoneValid(void **pp
, void **tp
)
283 void *p
= (void *) *pp
;
284 int valid
= cbdataReferenceValid(p
);
287 cbdataInternalUnlock(p
);
299 CallbackData::operator =(const CallbackData
&other
)
301 if (data_
!= other
.data_
) { // assignment to self and no-op assignments
303 data_
= cbdataReference(other
.data_
);
304 cbdataReferenceDone(old
);
309 CBDATA_CLASS_INIT(generic_cbdata
);