]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cbdata.cc
Validate server certificates without bumping
[thirdparty/squid.git] / src / cbdata.cc
CommitLineData
e1ac4723 1/*
bbc27441 2 * Copyright (C) 1996-2014 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
63be0a78 11/**
12 \defgroup CBDATAInternal Callback Data Allocator Internals
13 \ingroup CBDATAAPI
14 *
e1ac4723 15 * These routines manage a set of registered callback data pointers.
63be0a78 16 * One of the easiest ways to make Squid coredump is to issue a
e1ac4723 17 * callback to for some data structure which has previously been
18 * freed. With these routines, we register (add) callback data
19 * pointers, lock them just before registering the callback function,
20 * validate them before issuing the callback, and then free them
21 * when finished.
e1ac4723 22 */
a2172245 23
f7f3304a 24#include "squid.h"
aa839030 25#include "cbdata.h"
e2849af8 26#include "Generic.h"
8822ebee 27#include "mgr/Registration.h"
e6ccf245 28#include "Store.h"
a2172245 29
074d6a40 30#include <climits>
85b067e3 31#if USE_CBDATA_DEBUG
85b067e3 32#include <algorithm>
074d6a40 33#include <vector>
85b067e3 34#endif
582c2af2 35
b4bab919 36#if WITH_VALGRIND
37#define HASHED_CBDATA 1
38#endif
39
8b9a2d90 40static int cbdataCount = 0;
9a0a18de 41#if USE_CBDATA_DEBUG
fa80a8ef 42dlink_list cbdataEntries;
43#endif
8b9a2d90 44
9a0a18de 45#if USE_CBDATA_DEBUG
62e76326 46
47class CBDataCall
48{
49
e48ed433 50public:
26ac0430 51 CBDataCall (char const *callLabel, char const *aFile, int aLine) : label(callLabel), file(aFile), line(aLine) {}
62e76326 52
e48ed433 53 char const *label;
54 char const *file;
55 int line;
56};
62e76326 57
e48ed433 58#endif
59
63be0a78 60/// \ingroup CBDATAInternal
43ae1d95 61#define OFFSET_OF(TYPE, MEMBER) ((size_t) &(((TYPE) *)0)->(MEMBER))
62
63be0a78 63/// \ingroup CBDATAInternal
43ae1d95 64class cbdata
62e76326 65{
63be0a78 66 /** \todo examine making cbdata templated on this - so we get type
b4bab919 67 * safe access to data - RBC 20030902 */
43ae1d95 68public:
b4bab919 69#if HASHED_CBDATA
70 hash_link hash; // Must be first
71#endif
72
9a0a18de 73#if USE_CBDATA_DEBUG
43ae1d95 74
e48ed433 75 void dump(StoreEntry *)const;
76#endif
62e76326 77
b4bab919 78#if !HASHED_CBDATA
f668fcda 79 void *operator new(size_t size, void *where);
e13b11a5 80 void operator delete(void *where, void *where2);
b4bab919 81#else
82 MEMPROXY_CLASS(cndata);
83#endif
f668fcda 84
85 ~cbdata();
3015e83a 86 int valid;
3ad2eed0 87 int32_t locks;
f668fcda 88 cbdata_type type;
9a0a18de 89#if USE_CBDATA_DEBUG
62e76326 90
7ddfeb80 91 void addHistory(char const *label, char const *aFile, int aLine) {
91caca83 92 if (calls.size() > 1000)
62e76326 93 return;
94
85b067e3 95 calls.push_back(new CBDataCall(label, aFile, aLine));
62e76326 96 }
97
fa80a8ef 98 dlink_node link;
4e3f712d 99 const char *file;
100 int line;
85b067e3 101 std::vector<CBDataCall*> calls; // used as a stack with random access operator
4e3f712d 102#endif
62e76326 103
43ae1d95 104 /* cookie used while debugging */
105 long cookie;
7ddfeb80 106 void check(int aLine) const {assert(cookie == ((long)this ^ Cookie));}
b4bab919 107 static const long Cookie;
43ae1d95 108
b4bab919 109#if !HASHED_CBDATA
43ae1d95 110 size_t dataSize() const { return sizeof(data);}
43ae1d95 111 static long MakeOffset();
112 static const long Offset;
b4bab919 113 /* MUST be the last per-instance member */
114 void *data;
115#endif
116
43ae1d95 117};
118
bf5113eb 119const long cbdata::Cookie((long)0xDEADBEEF);
b4bab919 120#if !HASHED_CBDATA
43ae1d95 121const long cbdata::Offset(MakeOffset());
122
f668fcda 123void *
124cbdata::operator new(size_t size, void *where)
125{
126 // assert (size == sizeof(cbdata));
127 return where;
128}
129
63be0a78 130/**
131 * Only ever invoked when placement new throws
132 * an exception. Used to prevent an incorrect
133 * free.
134 */
f668fcda 135void
136cbdata::operator delete(void *where, void *where2)
cfdb8f88
AJ
137{
138 ; // empty.
f668fcda 139}
140
43ae1d95 141long
142cbdata::MakeOffset()
143{
144 cbdata *zero = (cbdata *)0L;
145 void **dataOffset = &zero->data;
146 return (long)dataOffset;
147}
b4bab919 148#else
cfdb8f88 149MEMPROXY_CLASS_INLINE(cbdata);
b4bab919 150#endif
a2172245 151
db1cd23c 152static OBJH cbdataDump;
9a0a18de 153#if USE_CBDATA_DEBUG
e48ed433 154static OBJH cbdataDumpHistory;
155#endif
a2172245 156
63be0a78 157/// \ingroup CBDATAInternal
26ac0430 158struct CBDataIndex {
b4bab919 159 MemAllocator *pool;
72711e31 160 FREE *free_func;
62e76326 161}
62e76326 162*cbdata_index = NULL;
63be0a78 163
164/// \ingroup CBDATAInternal
28c60158 165int cbdata_types = 0;
166
b4bab919 167#if HASHED_CBDATA
168static hash_table *cbdata_htable = NULL;
169
170static int
171cbdata_cmp(const void *p1, const void *p2)
172{
173 return (char *) p1 - (char *) p2;
174}
175
176static unsigned int
177cbdata_hash(const void *p, unsigned int mod)
178{
179 return ((unsigned long) p >> 8) % mod;
180}
181#endif
182
f668fcda 183cbdata::~cbdata()
e48ed433 184{
9a0a18de 185#if USE_CBDATA_DEBUG
62e76326 186
3aa53107 187 while (!calls.empty()) {
85b067e3
FC
188 delete calls.back();
189 calls.pop_back();
3aa53107 190 }
62e76326 191
e48ed433 192#endif
62e76326 193
e48ed433 194 FREE *free_func = cbdata_index[type].free_func;
62e76326 195
b4bab919 196#if HASHED_CBDATA
197 void *p = hash.key;
198#else
199 void *p = &data;
200#endif
201
e48ed433 202 if (free_func)
b4bab919 203 free_func(p);
e48ed433 204}
205
fa80a8ef 206static void
207cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 208{
28c60158 209 char *label;
aa839030 210 assert (type == cbdata_types + 1);
62e76326 211
aa839030 212 cbdata_index = (CBDataIndex *)xrealloc(cbdata_index, (type + 1) * sizeof(*cbdata_index));
213 memset(&cbdata_index[type], 0, sizeof(*cbdata_index));
214 cbdata_types = type;
62e76326 215
e6ccf245 216 label = (char *)xmalloc(strlen(name) + 20);
62e76326 217
28c60158 218 snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
62e76326 219
b4bab919 220#if !HASHED_CBDATA
43ae1d95 221 assert((size_t)cbdata::Offset == (sizeof(cbdata) - ((cbdata *)NULL)->dataSize()));
b4bab919 222 size += cbdata::Offset;
223#endif
62e76326 224
04eb0689 225 cbdata_index[type].pool = memPoolCreate(label, size);
62e76326 226
72711e31 227 cbdata_index[type].free_func = free_func;
b4bab919 228
229#if HASHED_CBDATA
230 if (!cbdata_htable)
26ac0430 231 cbdata_htable = hash_create(cbdata_cmp, 1 << 12, cbdata_hash);
b4bab919 232#endif
a2172245 233}
234
28c60158 235cbdata_type
fa80a8ef 236cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
a2172245 237{
28c60158 238 if (type)
62e76326 239 return type;
240
aa839030 241 type = (cbdata_type)(cbdata_types + 1);
62e76326 242
fa80a8ef 243 cbdataInternalInitType(type, name, size, free_func);
62e76326 244
28c60158 245 return type;
a2172245 246}
247
62ee09ca 248void
dbeed9ea 249cbdataRegisterWithCacheManager(void)
62ee09ca 250{
8822ebee 251 Mgr::RegisterAction("cbdata",
d9fc6862
A
252 "Callback Data Registry Contents",
253 cbdataDump, 0, 1);
9a0a18de 254#if USE_CBDATA_DEBUG
62ee09ca 255
8822ebee 256 Mgr::RegisterAction("cbdatahistory",
d9fc6862
A
257 "Detailed call history for all current cbdata contents",
258 cbdataDumpHistory, 0, 1);
62ee09ca 259#endif
260}
261
28c60158 262void *
9a0a18de 263#if USE_CBDATA_DEBUG
72711e31 264cbdataInternalAllocDbg(cbdata_type type, const char *file, int line)
4e3f712d 265#else
72711e31 266cbdataInternalAlloc(cbdata_type type)
4e3f712d 267#endif
a2172245 268{
b4bab919 269 cbdata *c;
270 void *p;
aa839030 271 assert(type > 0 && type <= cbdata_types);
272 /* placement new: the pool alloc gives us cbdata + user type memory space
273 * and we init it with cbdata at the start of it
274 */
b4bab919 275#if HASHED_CBDATA
276 c = new cbdata;
277 p = cbdata_index[type].pool->alloc();
278 c->hash.key = p;
279 hash_join(cbdata_htable, &c->hash);
280#else
281 c = new (cbdata_index[type].pool->alloc()) cbdata;
282 p = (void *)&c->data;
283#endif
f668fcda 284
b4bab919 285 c->type = type;
286 c->valid = 1;
287 c->locks = 0;
288 c->cookie = (long) c ^ cbdata::Cookie;
d7ae3534 289 ++cbdataCount;
9a0a18de 290#if USE_CBDATA_DEBUG
62e76326 291
b4bab919 292 c->file = file;
293 c->line = line;
85b067e3 294 c->calls = std::vector<CBDataCall *> ();
b4bab919 295 c->addHistory("Alloc", file, line);
296 dlinkAdd(c, &c->link, &cbdataEntries);
bf8fe701 297 debugs(45, 3, "cbdataAlloc: " << p << " " << file << ":" << line);
c4eab974
AR
298#else
299 debugs(45, 9, "cbdataAlloc: " << p);
fa80a8ef 300#endif
62e76326 301
b4bab919 302 return p;
b8a2718d 303}
304
c29316a4 305void *
9a0a18de 306#if USE_CBDATA_DEBUG
fa80a8ef 307cbdataInternalFreeDbg(void *p, const char *file, int line)
308#else
72711e31 309cbdataInternalFree(void *p)
fa80a8ef 310#endif
a2172245 311{
28c60158 312 cbdata *c;
b4bab919 313#if HASHED_CBDATA
314 c = (cbdata *) hash_lookup(cbdata_htable, p);
315#else
43ae1d95 316 c = (cbdata *) (((char *) p) - cbdata::Offset);
b4bab919 317#endif
9a0a18de 318#if USE_CBDATA_DEBUG
62e76326 319
bf8fe701 320 debugs(45, 3, "cbdataFree: " << p << " " << file << ":" << line);
fa80a8ef 321#else
62e76326 322
bf8fe701 323 debugs(45, 9, "cbdataFree: " << p);
fa80a8ef 324#endif
62e76326 325
06a5ae20 326 c->check(__LINE__);
a2fb868f 327 assert(c->valid);
3015e83a 328 c->valid = 0;
9a0a18de 329#if USE_CBDATA_DEBUG
62e76326 330
e48ed433 331 c->addHistory("Free", file, line);
332#endif
62e76326 333
3015e83a 334 if (c->locks) {
bf8fe701 335 debugs(45, 9, "cbdataFree: " << p << " has " << c->locks << " locks, not freeing");
62e76326 336 return NULL;
3015e83a 337 }
62e76326 338
5e263176 339 --cbdataCount;
bf8fe701 340 debugs(45, 9, "cbdataFree: Freeing " << p);
9a0a18de 341#if USE_CBDATA_DEBUG
62e76326 342
fa80a8ef 343 dlinkDelete(&c->link, &cbdataEntries);
344#endif
62e76326 345
f668fcda 346 /* This is ugly. But: operator delete doesn't get
26ac0430 347 * the type parameter, so we can't use that
f668fcda 348 * to free the memory.
349 * So, we free it ourselves.
26ac0430 350 * Note that this means a non-placement
f668fcda 351 * new would be a seriously bad idea.
352 * Lastly, if we where a templated class,
353 * we could use the normal delete operator
354 * and it would Just Work. RBC 20030902
355 */
b4bab919 356 cbdata_type theType = c->type;
357#if HASHED_CBDATA
358 hash_remove_link(cbdata_htable, &c->hash);
359 delete c;
dc47f531 360 cbdata_index[theType].pool->freeOne((void *)p);
b4bab919 361#else
362 c->cbdata::~cbdata();
dc47f531 363 cbdata_index[theType].pool->freeOne(c);
b4bab919 364#endif
c29316a4 365 return NULL;
72711e31 366}
367
a2172245 368void
9a0a18de 369#if USE_CBDATA_DEBUG
fa80a8ef 370cbdataInternalLockDbg(const void *p, const char *file, int line)
b7e6c377 371#else
fa80a8ef 372cbdataInternalLock(const void *p)
b7e6c377 373#endif
a2172245 374{
3015e83a 375 cbdata *c;
62e76326 376
3015e83a 377 if (p == NULL)
62e76326 378 return;
379
b4bab919 380#if HASHED_CBDATA
381 c = (cbdata *) hash_lookup(cbdata_htable, p);
382#else
43ae1d95 383 c = (cbdata *) (((char *) p) - cbdata::Offset);
b4bab919 384#endif
62e76326 385
9a0a18de 386#if USE_CBDATA_DEBUG
62e76326 387
bf8fe701 388 debugs(45, 3, "cbdataLock: " << p << "=" << (c ? c->locks + 1 : -1) << " " << file << ":" << line);
62e76326 389
e48ed433 390 c->addHistory("Reference", file, line);
62e76326 391
fa80a8ef 392#else
62e76326 393
bf8fe701 394 debugs(45, 9, "cbdataLock: " << p << "=" << (c ? c->locks + 1 : -1));
62e76326 395
b7e6c377 396#endif
62e76326 397
06a5ae20 398 c->check(__LINE__);
62e76326 399
3ad2eed0 400 assert(c->locks < INT_MAX);
62e76326 401
d7ae3534 402 ++ c->locks;
a2172245 403}
404
405void
9a0a18de 406#if USE_CBDATA_DEBUG
fa80a8ef 407cbdataInternalUnlockDbg(const void *p, const char *file, int line)
b7e6c377 408#else
fa80a8ef 409cbdataInternalUnlock(const void *p)
b7e6c377 410#endif
a2172245 411{
3015e83a 412 cbdata *c;
62e76326 413
3015e83a 414 if (p == NULL)
62e76326 415 return;
416
b4bab919 417#if HASHED_CBDATA
418 c = (cbdata *) hash_lookup(cbdata_htable, p);
419#else
43ae1d95 420 c = (cbdata *) (((char *) p) - cbdata::Offset);
b4bab919 421#endif
62e76326 422
9a0a18de 423#if USE_CBDATA_DEBUG
62e76326 424
bf8fe701 425 debugs(45, 3, "cbdataUnlock: " << p << "=" << (c ? c->locks - 1 : -1) << " " << file << ":" << line);
62e76326 426
e48ed433 427 c->addHistory("Dereference", file, line);
62e76326 428
fa80a8ef 429#else
62e76326 430
bf8fe701 431 debugs(45, 9, "cbdataUnlock: " << p << "=" << (c ? c->locks - 1 : -1));
62e76326 432
fa80a8ef 433#endif
62e76326 434
06a5ae20 435 c->check(__LINE__);
62e76326 436
3015e83a 437 assert(c != NULL);
62e76326 438
3015e83a 439 assert(c->locks > 0);
62e76326 440
5e263176 441 -- c->locks;
62e76326 442
aab9676e 443 if (c->valid || c->locks)
62e76326 444 return;
445
5e263176 446 --cbdataCount;
62e76326 447
bf8fe701 448 debugs(45, 9, "cbdataUnlock: Freeing " << p);
62e76326 449
9a0a18de 450#if USE_CBDATA_DEBUG
62e76326 451
fa80a8ef 452 dlinkDelete(&c->link, &cbdataEntries);
62e76326 453
fa80a8ef 454#endif
62e76326 455
f668fcda 456 /* This is ugly. But: operator delete doesn't get
26ac0430 457 * the type parameter, so we can't use that
f668fcda 458 * to free the memory.
459 * So, we free it ourselves.
26ac0430 460 * Note that this means a non-placement
f668fcda 461 * new would be a seriously bad idea.
462 * Lastly, if we where a templated class,
463 * we could use the normal delete operator
464 * and it would Just Work. RBC 20030902
465 */
b4bab919 466 cbdata_type theType = c->type;
467#if HASHED_CBDATA
468 hash_remove_link(cbdata_htable, &c->hash);
469 delete c;
dc47f531 470 cbdata_index[theType].pool->freeOne((void *)p);
b4bab919 471#else
472 c->cbdata::~cbdata();
dc47f531 473 cbdata_index[theType].pool->freeOne(c);
b4bab919 474#endif
a2172245 475}
476
477int
fa80a8ef 478cbdataReferenceValid(const void *p)
a2172245 479{
3015e83a 480 cbdata *c;
62e76326 481
3015e83a 482 if (p == NULL)
62e76326 483 return 1; /* A NULL pointer cannot become invalid */
484
bf8fe701 485 debugs(45, 9, "cbdataReferenceValid: " << p);
62e76326 486
b4bab919 487#if HASHED_CBDATA
488 c = (cbdata *) hash_lookup(cbdata_htable, p);
489#else
43ae1d95 490 c = (cbdata *) (((char *) p) - cbdata::Offset);
b4bab919 491#endif
62e76326 492
06a5ae20 493 c->check(__LINE__);
62e76326 494
3015e83a 495 assert(c->locks > 0);
62e76326 496
3015e83a 497 return c->valid;
a2172245 498}
499
fa80a8ef 500int
9a0a18de 501#if USE_CBDATA_DEBUG
fa80a8ef 502cbdataInternalReferenceDoneValidDbg(void **pp, void **tp, const char *file, int line)
503#else
504cbdataInternalReferenceDoneValid(void **pp, void **tp)
505#endif
506{
507 void *p = (void *) *pp;
508 int valid = cbdataReferenceValid(p);
509 *pp = NULL;
9a0a18de 510#if USE_CBDATA_DEBUG
62e76326 511
fa80a8ef 512 cbdataInternalUnlockDbg(p, file, line);
513#else
62e76326 514
fa80a8ef 515 cbdataInternalUnlock(p);
516#endif
62e76326 517
fa80a8ef 518 if (valid) {
62e76326 519 *tp = p;
520 return 1;
fa80a8ef 521 } else {
62e76326 522 *tp = NULL;
523 return 0;
fa80a8ef 524 }
525}
526
9a0a18de 527#if USE_CBDATA_DEBUG
e48ed433 528void
43ae1d95 529cbdata::dump(StoreEntry *sentry) const
e48ed433 530{
b4bab919 531#if HASHED_CBDATA
c692f6b0 532 void *p = (void *)hash.key;
b4bab919 533#else
c692f6b0 534 void *p = (void *)&data;
b4bab919 535#endif
e48ed433 536 storeAppendPrintf(sentry, "%c%p\t%d\t%d\t%20s:%-5d\n", valid ? ' ' :
b4bab919 537 '!', p, type, locks, file, line);
e48ed433 538}
539
26ac0430
AJ
540struct CBDataDumper : public unary_function<cbdata, void> {
541 CBDataDumper(StoreEntry *anEntry):where(anEntry) {}
62e76326 542
26ac0430 543 void operator()(cbdata const &x) {
62e76326 544 x.dump(where);
e48ed433 545 }
62e76326 546
e48ed433 547 StoreEntry *where;
548};
62e76326 549
e48ed433 550#endif
fa80a8ef 551
db1cd23c 552static void
3015e83a 553cbdataDump(StoreEntry * sentry)
a2172245 554{
8b9a2d90 555 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
9a0a18de 556#if USE_CBDATA_DEBUG
62e76326 557
fa80a8ef 558 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
e48ed433 559 CBDataDumper dumper(sentry);
560 for_each (cbdataEntries, dumper);
fa80a8ef 561 storeAppendPrintf(sentry, "\n");
562 storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
62e76326 563
d7ae3534 564 for (int i = 1; i < cbdata_types; ++i) {
b4bab919 565 MemAllocator *pool = cbdata_index[i].pool;
62e76326 566
567 if (pool) {
b4bab919 568#if HASHED_CBDATA
569 int obj_size = pool->objectSize();
570#else
b001e822 571 int obj_size = pool->objectSize() - cbdata::Offset;
b4bab919 572#endif
06a0702b 573 storeAppendPrintf(sentry, "%s\t%d\t%ld\t%ld\n", pool->objectType() + 7, obj_size, (long int)pool->getMeter().inuse.level, (long int)obj_size * pool->getMeter().inuse.level);
62e76326 574 }
fa80a8ef 575 }
62e76326 576
fa80a8ef 577#else
9a0a18de 578 storeAppendPrintf(sentry, "detailed allocation information only available when compiled with --enable-debug-cbdata\n");
62e76326 579
fa80a8ef 580#endif
62e76326 581
fa80a8ef 582 storeAppendPrintf(sentry, "\nsee also \"Memory utilization\" for detailed per type statistics\n");
a2172245 583}
e48ed433 584
aa839030 585CBDATA_CLASS_INIT(generic_cbdata);
586
9a0a18de 587#if USE_CBDATA_DEBUG
e48ed433 588
26ac0430
AJ
589struct CBDataCallDumper : public unary_function<CBDataCall, void> {
590 CBDataCallDumper (StoreEntry *anEntry):where(anEntry) {}
62e76326 591
85b067e3
FC
592 void operator()(CBDataCall * const &x) {
593 storeAppendPrintf(where, "%s\t%s\t%d\n", x->label, x->file, x->line);
e48ed433 594 }
62e76326 595
e48ed433 596 StoreEntry *where;
597};
598
26ac0430
AJ
599struct CBDataHistoryDumper : public CBDataDumper {
600 CBDataHistoryDumper(StoreEntry *anEntry):CBDataDumper(anEntry),where(anEntry), callDumper(anEntry) {}
62e76326 601
26ac0430 602 void operator()(cbdata const &x) {
62e76326 603 CBDataDumper::operator()(x);
604 storeAppendPrintf(where, "\n");
605 storeAppendPrintf(where, "Action\tFile\tLine\n");
85b067e3 606 std::for_each (x.calls.begin(), x.calls.end(), callDumper);
62e76326 607 storeAppendPrintf(where, "\n");
e48ed433 608 }
62e76326 609
e48ed433 610 StoreEntry *where;
611 CBDataCallDumper callDumper;
612};
613
614void
615cbdataDumpHistory(StoreEntry *sentry)
616{
617 storeAppendPrintf(sentry, "%d cbdata entries\n", cbdataCount);
618 storeAppendPrintf(sentry, "Pointer\tType\tLocks\tAllocated by\n");
619 CBDataHistoryDumper dumper(sentry);
620 for_each (cbdataEntries, dumper);
621}
62e76326 622
e48ed433 623#endif