| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 Samba Unix SMB/CIFS implementation. | |
| 3 | |
| 4 Samba trivial allocation library - new interface | |
| 5 | |
| 6 NOTE: Please read talloc_guide.txt for full documentation | |
| 7 | |
| 8 Copyright (C) Andrew Tridgell 2004 | |
| 9 Copyright (C) Stefan Metzmacher 2006 | |
| 10 | |
| 11 ** NOTE! The following LGPL license applies to the talloc | |
| 12 ** library. This does NOT imply that all of Samba is released | |
| 13 ** under the LGPL | |
| 14 | |
| 15 This library is free software; you can redistribute it and/or | |
| 16 modify it under the terms of the GNU Lesser General Public | |
| 17 License as published by the Free Software Foundation; either | |
| 18 version 3 of the License, or (at your option) any later version. | |
| 19 | |
| 20 This library is distributed in the hope that it will be useful, | |
| 21 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 23 Lesser General Public License for more details. | |
| 24 | |
| 25 You should have received a copy of the GNU Lesser General Public | |
| 26 License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
| 27 */ | |
| 28 | |
| 29 /* | |
| 30 inspired by http://swapped.cc/halloc/ | |
| 31 */ | |
| 32 | |
| 33 /* Commented out for building within Chromium */ | |
| 34 /* #include "replace.h" */ | |
| 35 #include "talloc.h" | |
| 36 | |
| 37 #ifdef TALLOC_BUILD_VERSION_MAJOR | |
| 38 #if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR) | |
| 39 #error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR" | |
| 40 #endif | |
| 41 #endif | |
| 42 | |
| 43 #ifdef TALLOC_BUILD_VERSION_MINOR | |
| 44 #if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR) | |
| 45 #error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR" | |
| 46 #endif | |
| 47 #endif | |
| 48 | |
| 49 /* use this to force every realloc to change the pointer, to stress test | |
| 50 code that might not cope */ | |
| 51 #define ALWAYS_REALLOC 0 | |
| 52 | |
| 53 | |
| 54 #define MAX_TALLOC_SIZE 0x10000000 | |
| 55 #define TALLOC_MAGIC_BASE 0xe814ec70 | |
| 56 #define TALLOC_MAGIC ( \ | |
| 57 TALLOC_MAGIC_BASE + \ | |
| 58 (TALLOC_VERSION_MAJOR << 12) + \ | |
| 59 (TALLOC_VERSION_MINOR << 4) \ | |
| 60 ) | |
| 61 | |
| 62 #define TALLOC_FLAG_FREE 0x01 | |
| 63 #define TALLOC_FLAG_LOOP 0x02 | |
| 64 #define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ | |
| 65 #define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ | |
| 66 #define TALLOC_MAGIC_REFERENCE ((const char *)1) | |
| 67 | |
| 68 /* by default we abort when given a bad pointer (such as when talloc_free() is c
alled | |
| 69 on a pointer that came from malloc() */ | |
| 70 #ifndef TALLOC_ABORT | |
| 71 #define TALLOC_ABORT(reason) abort() | |
| 72 #endif | |
| 73 | |
| 74 #ifndef discard_const_p | |
| 75 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) | |
| 76 # define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) | |
| 77 #else | |
| 78 # define discard_const_p(type, ptr) ((type *)(ptr)) | |
| 79 #endif | |
| 80 #endif | |
| 81 | |
| 82 /* these macros gain us a few percent of speed on gcc */ | |
| 83 #if (__GNUC__ >= 3) | |
| 84 /* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 | |
| 85 as its first argument */ | |
| 86 #ifndef likely | |
| 87 #define likely(x) __builtin_expect(!!(x), 1) | |
| 88 #endif | |
| 89 #ifndef unlikely | |
| 90 #define unlikely(x) __builtin_expect(!!(x), 0) | |
| 91 #endif | |
| 92 #else | |
| 93 #ifndef likely | |
| 94 #define likely(x) (x) | |
| 95 #endif | |
| 96 #ifndef unlikely | |
| 97 #define unlikely(x) (x) | |
| 98 #endif | |
| 99 #endif | |
| 100 | |
| 101 /* inline isn't supported in C files in Visual Studio 2008 on Windows */ | |
| 102 #ifdef _MSC_VER | |
| 103 #define INLINE | |
| 104 #else | |
| 105 #define INLINE inline | |
| 106 #endif | |
| 107 | |
| 108 /* this null_context is only used if talloc_enable_leak_report() or | |
| 109 talloc_enable_leak_report_full() is called, otherwise it remains | |
| 110 NULL | |
| 111 */ | |
| 112 static void *null_context; | |
| 113 static void *autofree_context; | |
| 114 | |
| 115 struct talloc_reference_handle { | |
| 116 struct talloc_reference_handle *next, *prev; | |
| 117 void *ptr; | |
| 118 const char *location; | |
| 119 }; | |
| 120 | |
| 121 typedef int (*talloc_destructor_t)(void *); | |
| 122 | |
| 123 struct talloc_chunk { | |
| 124 struct talloc_chunk *next, *prev; | |
| 125 struct talloc_chunk *parent, *child; | |
| 126 struct talloc_reference_handle *refs; | |
| 127 talloc_destructor_t destructor; | |
| 128 const char *name; | |
| 129 size_t size; | |
| 130 unsigned flags; | |
| 131 | |
| 132 /* | |
| 133 * "pool" has dual use: | |
| 134 * | |
| 135 * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool" | |
| 136 * marks the end of the currently allocated area. | |
| 137 * | |
| 138 * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" | |
| 139 * is a pointer to the struct talloc_chunk of the pool that it was | |
| 140 * allocated from. This way children can quickly find the pool to chew | |
| 141 * from. | |
| 142 */ | |
| 143 void *pool; | |
| 144 }; | |
| 145 | |
| 146 /* 16 byte alignment seems to keep everyone happy */ | |
| 147 #define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15) | |
| 148 #define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) | |
| 149 | |
| 150 int talloc_version_major(void) | |
| 151 { | |
| 152 return TALLOC_VERSION_MAJOR; | |
| 153 } | |
| 154 | |
| 155 int talloc_version_minor(void) | |
| 156 { | |
| 157 return TALLOC_VERSION_MINOR; | |
| 158 } | |
| 159 | |
| 160 static void (*talloc_log_fn)(const char *message); | |
| 161 | |
| 162 void talloc_set_log_fn(void (*log_fn)(const char *message)) | |
| 163 { | |
| 164 talloc_log_fn = log_fn; | |
| 165 } | |
| 166 | |
| 167 static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); | |
| 168 static void talloc_log(const char *fmt, ...) | |
| 169 { | |
| 170 va_list ap; | |
| 171 char *message; | |
| 172 | |
| 173 if (!talloc_log_fn) { | |
| 174 return; | |
| 175 } | |
| 176 | |
| 177 va_start(ap, fmt); | |
| 178 message = talloc_vasprintf(NULL, fmt, ap); | |
| 179 va_end(ap); | |
| 180 | |
| 181 talloc_log_fn(message); | |
| 182 talloc_free(message); | |
| 183 } | |
| 184 | |
| 185 static void talloc_log_stderr(const char *message) | |
| 186 { | |
| 187 fprintf(stderr, "%s", message); | |
| 188 } | |
| 189 | |
| 190 void talloc_set_log_stderr(void) | |
| 191 { | |
| 192 talloc_set_log_fn(talloc_log_stderr); | |
| 193 } | |
| 194 | |
| 195 static void (*talloc_abort_fn)(const char *reason); | |
| 196 | |
| 197 void talloc_set_abort_fn(void (*abort_fn)(const char *reason)) | |
| 198 { | |
| 199 talloc_abort_fn = abort_fn; | |
| 200 } | |
| 201 | |
| 202 static void talloc_abort(const char *reason) | |
| 203 { | |
| 204 talloc_log("%s\n", reason); | |
| 205 | |
| 206 if (!talloc_abort_fn) { | |
| 207 TALLOC_ABORT(reason); | |
| 208 } | |
| 209 | |
| 210 talloc_abort_fn(reason); | |
| 211 } | |
| 212 | |
| 213 static void talloc_abort_magic(unsigned magic) | |
| 214 { | |
| 215 unsigned striped = magic - TALLOC_MAGIC_BASE; | |
| 216 unsigned major = (striped & 0xFFFFF000) >> 12; | |
| 217 unsigned minor = (striped & 0x00000FF0) >> 4; | |
| 218 talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n", | |
| 219 magic, major, minor, | |
| 220 TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR); | |
| 221 talloc_abort("Bad talloc magic value - wrong talloc version used/mixed")
; | |
| 222 } | |
| 223 | |
| 224 static void talloc_abort_double_free(void) | |
| 225 { | |
| 226 talloc_abort("Bad talloc magic value - double free"); | |
| 227 } | |
| 228 | |
| 229 static void talloc_abort_unknown_value(void) | |
| 230 { | |
| 231 talloc_abort("Bad talloc magic value - unknown value"); | |
| 232 } | |
| 233 | |
| 234 /* panic if we get a bad magic value */ | |
| 235 static INLINE struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) | |
| 236 { | |
| 237 const char *pp = (const char *)ptr; | |
| 238 struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_H
DR_SIZE); | |
| 239 if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
| |
| 240 if ((tc->flags & (~0xFFF)) == TALLOC_MAGIC_BASE) { | |
| 241 talloc_abort_magic(tc->flags & (~0xF)); | |
| 242 return NULL; | |
| 243 } | |
| 244 | |
| 245 if (tc->flags & TALLOC_FLAG_FREE) { | |
| 246 talloc_log("talloc: double free error - first free may b
e at %s\n", tc->name); | |
| 247 talloc_abort_double_free(); | |
| 248 return NULL; | |
| 249 } else { | |
| 250 talloc_abort_unknown_value(); | |
| 251 return NULL; | |
| 252 } | |
| 253 } | |
| 254 return tc; | |
| 255 } | |
| 256 | |
| 257 /* hook into the front of the list */ | |
| 258 #define _TLIST_ADD(list, p) \ | |
| 259 do { \ | |
| 260 if (!(list)) { \ | |
| 261 (list) = (p); \ | |
| 262 (p)->next = (p)->prev = NULL; \ | |
| 263 } else { \ | |
| 264 (list)->prev = (p); \ | |
| 265 (p)->next = (list); \ | |
| 266 (p)->prev = NULL; \ | |
| 267 (list) = (p); \ | |
| 268 }\ | |
| 269 } while (0) | |
| 270 | |
| 271 /* remove an element from a list - element doesn't have to be in list. */ | |
| 272 #define _TLIST_REMOVE(list, p) \ | |
| 273 do { \ | |
| 274 if ((p) == (list)) { \ | |
| 275 (list) = (p)->next; \ | |
| 276 if (list) (list)->prev = NULL; \ | |
| 277 } else { \ | |
| 278 if ((p)->prev) (p)->prev->next = (p)->next; \ | |
| 279 if ((p)->next) (p)->next->prev = (p)->prev; \ | |
| 280 } \ | |
| 281 if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ | |
| 282 } while (0) | |
| 283 | |
| 284 | |
| 285 /* | |
| 286 return the parent chunk of a pointer | |
| 287 */ | |
| 288 static INLINE struct talloc_chunk *talloc_parent_chunk(const void *ptr) | |
| 289 { | |
| 290 struct talloc_chunk *tc; | |
| 291 | |
| 292 if (unlikely(ptr == NULL)) { | |
| 293 return NULL; | |
| 294 } | |
| 295 | |
| 296 tc = talloc_chunk_from_ptr(ptr); | |
| 297 while (tc->prev) tc=tc->prev; | |
| 298 | |
| 299 return tc->parent; | |
| 300 } | |
| 301 | |
| 302 void *talloc_parent(const void *ptr) | |
| 303 { | |
| 304 struct talloc_chunk *tc = talloc_parent_chunk(ptr); | |
| 305 return tc? TC_PTR_FROM_CHUNK(tc) : NULL; | |
| 306 } | |
| 307 | |
| 308 /* | |
| 309 find parents name | |
| 310 */ | |
| 311 const char *talloc_parent_name(const void *ptr) | |
| 312 { | |
| 313 struct talloc_chunk *tc = talloc_parent_chunk(ptr); | |
| 314 return tc? tc->name : NULL; | |
| 315 } | |
| 316 | |
| 317 /* | |
| 318 A pool carries an in-pool object count count in the first 16 bytes. | |
| 319 bytes. This is done to support talloc_steal() to a parent outside of the | |
| 320 pool. The count includes the pool itself, so a talloc_free() on a pool will | |
| 321 only destroy the pool if the count has dropped to zero. A talloc_free() of a | |
| 322 pool member will reduce the count, and eventually also call free(3) on the | |
| 323 pool memory. | |
| 324 | |
| 325 The object count is not put into "struct talloc_chunk" because it is only | |
| 326 relevant for talloc pools and the alignment to 16 bytes would increase the | |
| 327 memory footprint of each talloc chunk by those 16 bytes. | |
| 328 */ | |
| 329 | |
| 330 #define TALLOC_POOL_HDR_SIZE 16 | |
| 331 | |
| 332 static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc) | |
| 333 { | |
| 334 return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk)); | |
| 335 } | |
| 336 | |
| 337 /* | |
| 338 Allocate from a pool | |
| 339 */ | |
| 340 | |
| 341 static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, | |
| 342 size_t size) | |
| 343 { | |
| 344 struct talloc_chunk *pool_ctx = NULL; | |
| 345 size_t space_left; | |
| 346 struct talloc_chunk *result; | |
| 347 size_t chunk_size; | |
| 348 | |
| 349 if (parent == NULL) { | |
| 350 return NULL; | |
| 351 } | |
| 352 | |
| 353 if (parent->flags & TALLOC_FLAG_POOL) { | |
| 354 pool_ctx = parent; | |
| 355 } | |
| 356 else if (parent->flags & TALLOC_FLAG_POOLMEM) { | |
| 357 pool_ctx = (struct talloc_chunk *)parent->pool; | |
| 358 } | |
| 359 | |
| 360 if (pool_ctx == NULL) { | |
| 361 return NULL; | |
| 362 } | |
| 363 | |
| 364 space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size) | |
| 365 - ((char *)pool_ctx->pool); | |
| 366 | |
| 367 /* | |
| 368 * Align size to 16 bytes | |
| 369 */ | |
| 370 chunk_size = ((size + 15) & ~15); | |
| 371 | |
| 372 if (space_left < chunk_size) { | |
| 373 return NULL; | |
| 374 } | |
| 375 | |
| 376 result = (struct talloc_chunk *)pool_ctx->pool; | |
| 377 | |
| 378 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) | |
| 379 VALGRIND_MAKE_MEM_UNDEFINED(result, size); | |
| 380 #endif | |
| 381 | |
| 382 pool_ctx->pool = (void *)((char *)result + chunk_size); | |
| 383 | |
| 384 result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM; | |
| 385 result->pool = pool_ctx; | |
| 386 | |
| 387 *talloc_pool_objectcount(pool_ctx) += 1; | |
| 388 | |
| 389 return result; | |
| 390 } | |
| 391 | |
| 392 /* | |
| 393 Allocate a bit of memory as a child of an existing pointer | |
| 394 */ | |
| 395 static INLINE void *__talloc(const void *context, size_t size) | |
| 396 { | |
| 397 struct talloc_chunk *tc = NULL; | |
| 398 | |
| 399 if (unlikely(context == NULL)) { | |
| 400 context = null_context; | |
| 401 } | |
| 402 | |
| 403 if (unlikely(size >= MAX_TALLOC_SIZE)) { | |
| 404 return NULL; | |
| 405 } | |
| 406 | |
| 407 if (context != NULL) { | |
| 408 tc = talloc_alloc_pool(talloc_chunk_from_ptr(context), | |
| 409 TC_HDR_SIZE+size); | |
| 410 } | |
| 411 | |
| 412 if (tc == NULL) { | |
| 413 tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); | |
| 414 if (unlikely(tc == NULL)) return NULL; | |
| 415 tc->flags = TALLOC_MAGIC; | |
| 416 tc->pool = NULL; | |
| 417 } | |
| 418 | |
| 419 tc->size = size; | |
| 420 tc->destructor = NULL; | |
| 421 tc->child = NULL; | |
| 422 tc->name = NULL; | |
| 423 tc->refs = NULL; | |
| 424 | |
| 425 if (likely(context)) { | |
| 426 struct talloc_chunk *parent = talloc_chunk_from_ptr(context); | |
| 427 | |
| 428 if (parent->child) { | |
| 429 parent->child->parent = NULL; | |
| 430 tc->next = parent->child; | |
| 431 tc->next->prev = tc; | |
| 432 } else { | |
| 433 tc->next = NULL; | |
| 434 } | |
| 435 tc->parent = parent; | |
| 436 tc->prev = NULL; | |
| 437 parent->child = tc; | |
| 438 } else { | |
| 439 tc->next = tc->prev = tc->parent = NULL; | |
| 440 } | |
| 441 | |
| 442 return TC_PTR_FROM_CHUNK(tc); | |
| 443 } | |
| 444 | |
| 445 /* | |
| 446 * Create a talloc pool | |
| 447 */ | |
| 448 | |
| 449 void *talloc_pool(const void *context, size_t size) | |
| 450 { | |
| 451 void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE); | |
| 452 struct talloc_chunk *tc; | |
| 453 | |
| 454 if (unlikely(result == NULL)) { | |
| 455 return NULL; | |
| 456 } | |
| 457 | |
| 458 tc = talloc_chunk_from_ptr(result); | |
| 459 | |
| 460 tc->flags |= TALLOC_FLAG_POOL; | |
| 461 tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE; | |
| 462 | |
| 463 *talloc_pool_objectcount(tc) = 1; | |
| 464 | |
| 465 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) | |
| 466 VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size); | |
| 467 #endif | |
| 468 | |
| 469 return result; | |
| 470 } | |
| 471 | |
| 472 /* | |
| 473 setup a destructor to be called on free of a pointer | |
| 474 the destructor should return 0 on success, or -1 on failure. | |
| 475 if the destructor fails then the free is failed, and the memory can | |
| 476 be continued to be used | |
| 477 */ | |
| 478 void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) | |
| 479 { | |
| 480 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); | |
| 481 tc->destructor = destructor; | |
| 482 } | |
| 483 | |
| 484 /* | |
| 485 increase the reference count on a piece of memory. | |
| 486 */ | |
| 487 int talloc_increase_ref_count(const void *ptr) | |
| 488 { | |
| 489 if (unlikely(!talloc_reference(null_context, ptr))) { | |
| 490 return -1; | |
| 491 } | |
| 492 return 0; | |
| 493 } | |
| 494 | |
| 495 /* | |
| 496 helper for talloc_reference() | |
| 497 | |
| 498 this is referenced by a function pointer and should not be inline | |
| 499 */ | |
| 500 static int talloc_reference_destructor(struct talloc_reference_handle *handle) | |
| 501 { | |
| 502 struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr); | |
| 503 _TLIST_REMOVE(ptr_tc->refs, handle); | |
| 504 return 0; | |
| 505 } | |
| 506 | |
| 507 /* | |
| 508 more efficient way to add a name to a pointer - the name must point to a | |
| 509 true string constant | |
| 510 */ | |
| 511 static INLINE void _talloc_set_name_const(const void *ptr, const char *name) | |
| 512 { | |
| 513 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); | |
| 514 tc->name = name; | |
| 515 } | |
| 516 | |
| 517 /* | |
| 518 internal talloc_named_const() | |
| 519 */ | |
| 520 static INLINE void *_talloc_named_const(const void *context, size_t size, const
char *name) | |
| 521 { | |
| 522 void *ptr; | |
| 523 | |
| 524 ptr = __talloc(context, size); | |
| 525 if (unlikely(ptr == NULL)) { | |
| 526 return NULL; | |
| 527 } | |
| 528 | |
| 529 _talloc_set_name_const(ptr, name); | |
| 530 | |
| 531 return ptr; | |
| 532 } | |
| 533 | |
| 534 /* | |
| 535 make a secondary reference to a pointer, hanging off the given context. | |
| 536 the pointer remains valid until both the original caller and this given | |
| 537 context are freed. | |
| 538 | |
| 539 the major use for this is when two different structures need to reference the | |
| 540 same underlying data, and you want to be able to free the two instances separa
tely, | |
| 541 and in either order | |
| 542 */ | |
| 543 void *_talloc_reference_loc(const void *context, const void *ptr, const char *lo
cation) | |
| 544 { | |
| 545 struct talloc_chunk *tc; | |
| 546 struct talloc_reference_handle *handle; | |
| 547 if (unlikely(ptr == NULL)) return NULL; | |
| 548 | |
| 549 tc = talloc_chunk_from_ptr(ptr); | |
| 550 handle = (struct talloc_reference_handle *)_talloc_named_const(context, | |
| 551 sizeof(struct talloc_referenc
e_handle), | |
| 552 TALLOC_MAGIC_REFERENCE); | |
| 553 if (unlikely(handle == NULL)) return NULL; | |
| 554 | |
| 555 /* note that we hang the destructor off the handle, not the | |
| 556 main context as that allows the caller to still setup their | |
| 557 own destructor on the context if they want to */ | |
| 558 talloc_set_destructor(handle, talloc_reference_destructor); | |
| 559 handle->ptr = discard_const_p(void, ptr); | |
| 560 handle->location = location; | |
| 561 _TLIST_ADD(tc->refs, handle); | |
| 562 return handle->ptr; | |
| 563 } | |
| 564 | |
| 565 static void *_talloc_steal_internal(const void *new_ctx, const void *ptr); | |
| 566 | |
| 567 /* | |
| 568 internal talloc_free call | |
| 569 */ | |
| 570 static INLINE int _talloc_free_internal(void *ptr, const char *location) | |
| 571 { | |
| 572 struct talloc_chunk *tc; | |
| 573 | |
| 574 if (unlikely(ptr == NULL)) { | |
| 575 return -1; | |
| 576 } | |
| 577 | |
| 578 tc = talloc_chunk_from_ptr(ptr); | |
| 579 | |
| 580 if (unlikely(tc->refs)) { | |
| 581 int is_child; | |
| 582 /* check this is a reference from a child or grantchild | |
| 583 * back to it's parent or grantparent | |
| 584 * | |
| 585 * in that case we need to remove the reference and | |
| 586 * call another instance of talloc_free() on the current | |
| 587 * pointer. | |
| 588 */ | |
| 589 is_child = talloc_is_parent(tc->refs, ptr); | |
| 590 _talloc_free_internal(tc->refs, location); | |
| 591 if (is_child) { | |
| 592 return _talloc_free_internal(ptr, location); | |
| 593 } | |
| 594 return -1; | |
| 595 } | |
| 596 | |
| 597 if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) { | |
| 598 /* we have a free loop - stop looping */ | |
| 599 return 0; | |
| 600 } | |
| 601 | |
| 602 if (unlikely(tc->destructor)) { | |
| 603 talloc_destructor_t d = tc->destructor; | |
| 604 if (d == (talloc_destructor_t)-1) { | |
| 605 return -1; | |
| 606 } | |
| 607 tc->destructor = (talloc_destructor_t)-1; | |
| 608 if (d(ptr) == -1) { | |
| 609 tc->destructor = d; | |
| 610 return -1; | |
| 611 } | |
| 612 tc->destructor = NULL; | |
| 613 } | |
| 614 | |
| 615 if (tc->parent) { | |
| 616 _TLIST_REMOVE(tc->parent->child, tc); | |
| 617 if (tc->parent->child) { | |
| 618 tc->parent->child->parent = tc->parent; | |
| 619 } | |
| 620 } else { | |
| 621 if (tc->prev) tc->prev->next = tc->next; | |
| 622 if (tc->next) tc->next->prev = tc->prev; | |
| 623 } | |
| 624 | |
| 625 tc->flags |= TALLOC_FLAG_LOOP; | |
| 626 | |
| 627 while (tc->child) { | |
| 628 /* we need to work out who will own an abandoned child | |
| 629 if it cannot be freed. In priority order, the first | |
| 630 choice is owner of any remaining reference to this | |
| 631 pointer, the second choice is our parent, and the | |
| 632 final choice is the null context. */ | |
| 633 void *child = TC_PTR_FROM_CHUNK(tc->child); | |
| 634 const void *new_parent = null_context; | |
| 635 if (unlikely(tc->child->refs)) { | |
| 636 struct talloc_chunk *p = talloc_parent_chunk(tc->child->
refs); | |
| 637 if (p) new_parent = TC_PTR_FROM_CHUNK(p); | |
| 638 } | |
| 639 if (unlikely(_talloc_free_internal(child, location) == -1)) { | |
| 640 if (new_parent == null_context) { | |
| 641 struct talloc_chunk *p = talloc_parent_chunk(ptr
); | |
| 642 if (p) new_parent = TC_PTR_FROM_CHUNK(p); | |
| 643 } | |
| 644 _talloc_steal_internal(new_parent, child); | |
| 645 } | |
| 646 } | |
| 647 | |
| 648 tc->flags |= TALLOC_FLAG_FREE; | |
| 649 | |
| 650 /* we mark the freed memory with where we called the free | |
| 651 * from. This means on a double free error we can report where | |
| 652 * the first free came from | |
| 653 */ | |
| 654 tc->name = location; | |
| 655 | |
| 656 if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) { | |
| 657 struct talloc_chunk *pool; | |
| 658 unsigned int *pool_object_count; | |
| 659 | |
| 660 pool = (tc->flags & TALLOC_FLAG_POOL) | |
| 661 ? tc : (struct talloc_chunk *)tc->pool; | |
| 662 | |
| 663 pool_object_count = talloc_pool_objectcount(pool); | |
| 664 | |
| 665 if (*pool_object_count == 0) { | |
| 666 talloc_abort("Pool object count zero!"); | |
| 667 return 0; | |
| 668 } | |
| 669 | |
| 670 *pool_object_count -= 1; | |
| 671 | |
| 672 if (*pool_object_count == 0) { | |
| 673 free(pool); | |
| 674 } | |
| 675 } | |
| 676 else { | |
| 677 free(tc); | |
| 678 } | |
| 679 return 0; | |
| 680 } | |
| 681 | |
| 682 /* | |
| 683 move a lump of memory from one talloc context to another return the | |
| 684 ptr on success, or NULL if it could not be transferred. | |
| 685 passing NULL as ptr will always return NULL with no side effects. | |
| 686 */ | |
| 687 static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) | |
| 688 { | |
| 689 struct talloc_chunk *tc, *new_tc; | |
| 690 | |
| 691 if (unlikely(!ptr)) { | |
| 692 return NULL; | |
| 693 } | |
| 694 | |
| 695 if (unlikely(new_ctx == NULL)) { | |
| 696 new_ctx = null_context; | |
| 697 } | |
| 698 | |
| 699 tc = talloc_chunk_from_ptr(ptr); | |
| 700 | |
| 701 if (unlikely(new_ctx == NULL)) { | |
| 702 if (tc->parent) { | |
| 703 _TLIST_REMOVE(tc->parent->child, tc); | |
| 704 if (tc->parent->child) { | |
| 705 tc->parent->child->parent = tc->parent; | |
| 706 } | |
| 707 } else { | |
| 708 if (tc->prev) tc->prev->next = tc->next; | |
| 709 if (tc->next) tc->next->prev = tc->prev; | |
| 710 } | |
| 711 | |
| 712 tc->parent = tc->next = tc->prev = NULL; | |
| 713 return discard_const_p(void, ptr); | |
| 714 } | |
| 715 | |
| 716 new_tc = talloc_chunk_from_ptr(new_ctx); | |
| 717 | |
| 718 if (unlikely(tc == new_tc || tc->parent == new_tc)) { | |
| 719 return discard_const_p(void, ptr); | |
| 720 } | |
| 721 | |
| 722 if (tc->parent) { | |
| 723 _TLIST_REMOVE(tc->parent->child, tc); | |
| 724 if (tc->parent->child) { | |
| 725 tc->parent->child->parent = tc->parent; | |
| 726 } | |
| 727 } else { | |
| 728 if (tc->prev) tc->prev->next = tc->next; | |
| 729 if (tc->next) tc->next->prev = tc->prev; | |
| 730 } | |
| 731 | |
| 732 tc->parent = new_tc; | |
| 733 if (new_tc->child) new_tc->child->parent = NULL; | |
| 734 _TLIST_ADD(new_tc->child, tc); | |
| 735 | |
| 736 return discard_const_p(void, ptr); | |
| 737 } | |
| 738 | |
| 739 /* | |
| 740 move a lump of memory from one talloc context to another return the | |
| 741 ptr on success, or NULL if it could not be transferred. | |
| 742 passing NULL as ptr will always return NULL with no side effects. | |
| 743 */ | |
| 744 void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *locati
on) | |
| 745 { | |
| 746 struct talloc_chunk *tc; | |
| 747 | |
| 748 if (unlikely(ptr == NULL)) { | |
| 749 return NULL; | |
| 750 } | |
| 751 | |
| 752 tc = talloc_chunk_from_ptr(ptr); | |
| 753 | |
| 754 if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) { | |
| 755 struct talloc_reference_handle *h; | |
| 756 | |
| 757 talloc_log("WARNING: talloc_steal with references at %s\n", | |
| 758 location); | |
| 759 | |
| 760 for (h=tc->refs; h; h=h->next) { | |
| 761 talloc_log("\treference at %s\n", | |
| 762 h->location); | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 return _talloc_steal_internal(new_ctx, ptr); | |
| 767 } | |
| 768 | |
| 769 /* | |
| 770 this is like a talloc_steal(), but you must supply the old | |
| 771 parent. This resolves the ambiguity in a talloc_steal() which is | |
| 772 called on a context that has more than one parent (via references) | |
| 773 | |
| 774 The old parent can be either a reference or a parent | |
| 775 */ | |
| 776 void *talloc_reparent(const void *old_parent, const void *new_parent, const void
*ptr) | |
| 777 { | |
| 778 struct talloc_chunk *tc; | |
| 779 struct talloc_reference_handle *h; | |
| 780 | |
| 781 if (unlikely(ptr == NULL)) { | |
| 782 return NULL; | |
| 783 } | |
| 784 | |
| 785 if (old_parent == talloc_parent(ptr)) { | |
| 786 return _talloc_steal_internal(new_parent, ptr); | |
| 787 } | |
| 788 | |
| 789 tc = talloc_chunk_from_ptr(ptr); | |
| 790 for (h=tc->refs;h;h=h->next) { | |
| 791 if (talloc_parent(h) == old_parent) { | |
| 792 if (_talloc_steal_internal(new_parent, h) != h) { | |
| 793 return NULL; | |
| 794 } | |
| 795 return discard_const_p(void, ptr); | |
| 796 } | |
| 797 } | |
| 798 | |
| 799 /* it wasn't a parent */ | |
| 800 return NULL; | |
| 801 } | |
| 802 | |
| 803 /* | |
| 804 remove a secondary reference to a pointer. This undo's what | |
| 805 talloc_reference() has done. The context and pointer arguments | |
| 806 must match those given to a talloc_reference() | |
| 807 */ | |
| 808 static INLINE int talloc_unreference(const void *context, const void *ptr) | |
| 809 { | |
| 810 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); | |
| 811 struct talloc_reference_handle *h; | |
| 812 | |
| 813 if (unlikely(context == NULL)) { | |
| 814 context = null_context; | |
| 815 } | |
| 816 | |
| 817 for (h=tc->refs;h;h=h->next) { | |
| 818 struct talloc_chunk *p = talloc_parent_chunk(h); | |
| 819 if (p == NULL) { | |
| 820 if (context == NULL) break; | |
| 821 } else if (TC_PTR_FROM_CHUNK(p) == context) { | |
| 822 break; | |
| 823 } | |
| 824 } | |
| 825 if (h == NULL) { | |
| 826 return -1; | |
| 827 } | |
| 828 | |
| 829 return _talloc_free_internal(h, __location__); | |
| 830 } | |
| 831 | |
| 832 /* | |
| 833 remove a specific parent context from a pointer. This is a more | |
| 834 controlled varient of talloc_free() | |
| 835 */ | |
| 836 int talloc_unlink(const void *context, void *ptr) | |
| 837 { | |
| 838 struct talloc_chunk *tc_p, *new_p; | |
| 839 void *new_parent; | |
| 840 | |
| 841 if (ptr == NULL) { | |
| 842 return -1; | |
| 843 } | |
| 844 | |
| 845 if (context == NULL) { | |
| 846 context = null_context; | |
| 847 } | |
| 848 | |
| 849 if (talloc_unreference(context, ptr) == 0) { | |
| 850 return 0; | |
| 851 } | |
| 852 | |
| 853 if (context == NULL) { | |
| 854 if (talloc_parent_chunk(ptr) != NULL) { | |
| 855 return -1; | |
| 856 } | |
| 857 } else { | |
| 858 if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr))
{ | |
| 859 return -1; | |
| 860 } | |
| 861 } | |
| 862 | |
| 863 tc_p = talloc_chunk_from_ptr(ptr); | |
| 864 | |
| 865 if (tc_p->refs == NULL) { | |
| 866 return _talloc_free_internal(ptr, __location__); | |
| 867 } | |
| 868 | |
| 869 new_p = talloc_parent_chunk(tc_p->refs); | |
| 870 if (new_p) { | |
| 871 new_parent = TC_PTR_FROM_CHUNK(new_p); | |
| 872 } else { | |
| 873 new_parent = NULL; | |
| 874 } | |
| 875 | |
| 876 if (talloc_unreference(new_parent, ptr) != 0) { | |
| 877 return -1; | |
| 878 } | |
| 879 | |
| 880 _talloc_steal_internal(new_parent, ptr); | |
| 881 | |
| 882 return 0; | |
| 883 } | |
| 884 | |
| 885 /* | |
| 886 add a name to an existing pointer - va_list version | |
| 887 */ | |
| 888 static INLINE const char *talloc_set_name_v(const void *ptr, const char *fmt, va
_list ap) PRINTF_ATTRIBUTE(2,0); | |
| 889 | |
| 890 static INLINE const char *talloc_set_name_v(const void *ptr, const char *fmt, va
_list ap) | |
| 891 { | |
| 892 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); | |
| 893 tc->name = talloc_vasprintf(ptr, fmt, ap); | |
| 894 if (likely(tc->name)) { | |
| 895 _talloc_set_name_const(tc->name, ".name"); | |
| 896 } | |
| 897 return tc->name; | |
| 898 } | |
| 899 | |
| 900 /* | |
| 901 add a name to an existing pointer | |
| 902 */ | |
| 903 const char *talloc_set_name(const void *ptr, const char *fmt, ...) | |
| 904 { | |
| 905 const char *name; | |
| 906 va_list ap; | |
| 907 va_start(ap, fmt); | |
| 908 name = talloc_set_name_v(ptr, fmt, ap); | |
| 909 va_end(ap); | |
| 910 return name; | |
| 911 } | |
| 912 | |
| 913 | |
| 914 /* | |
| 915 create a named talloc pointer. Any talloc pointer can be named, and | |
| 916 talloc_named() operates just like talloc() except that it allows you | |
| 917 to name the pointer. | |
| 918 */ | |
| 919 void *talloc_named(const void *context, size_t size, const char *fmt, ...) | |
| 920 { | |
| 921 va_list ap; | |
| 922 void *ptr; | |
| 923 const char *name; | |
| 924 | |
| 925 ptr = __talloc(context, size); | |
| 926 if (unlikely(ptr == NULL)) return NULL; | |
| 927 | |
| 928 va_start(ap, fmt); | |
| 929 name = talloc_set_name_v(ptr, fmt, ap); | |
| 930 va_end(ap); | |
| 931 | |
| 932 if (unlikely(name == NULL)) { | |
| 933 _talloc_free_internal(ptr, __location__); | |
| 934 return NULL; | |
| 935 } | |
| 936 | |
| 937 return ptr; | |
| 938 } | |
| 939 | |
| 940 /* | |
| 941 return the name of a talloc ptr, or "UNNAMED" | |
| 942 */ | |
| 943 const char *talloc_get_name(const void *ptr) | |
| 944 { | |
| 945 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); | |
| 946 if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) { | |
| 947 return ".reference"; | |
| 948 } | |
| 949 if (likely(tc->name)) { | |
| 950 return tc->name; | |
| 951 } | |
| 952 return "UNNAMED"; | |
| 953 } | |
| 954 | |
| 955 | |
| 956 /* | |
| 957 check if a pointer has the given name. If it does, return the pointer, | |
| 958 otherwise return NULL | |
| 959 */ | |
| 960 void *talloc_check_name(const void *ptr, const char *name) | |
| 961 { | |
| 962 const char *pname; | |
| 963 if (unlikely(ptr == NULL)) return NULL; | |
| 964 pname = talloc_get_name(ptr); | |
| 965 if (likely(pname == name || strcmp(pname, name) == 0)) { | |
| 966 return discard_const_p(void, ptr); | |
| 967 } | |
| 968 return NULL; | |
| 969 } | |
| 970 | |
| 971 static void talloc_abort_type_missmatch(const char *location, | |
| 972 const char *name, | |
| 973 const char *expected) | |
| 974 { | |
| 975 const char *reason; | |
| 976 | |
| 977 reason = talloc_asprintf(NULL, | |
| 978 "%s: Type mismatch: name[%s] expected[%s]", | |
| 979 location, | |
| 980 name?name:"NULL", | |
| 981 expected); | |
| 982 if (!reason) { | |
| 983 reason = "Type mismatch"; | |
| 984 } | |
| 985 | |
| 986 talloc_abort(reason); | |
| 987 } | |
| 988 | |
| 989 void *_talloc_get_type_abort(const void *ptr, const char *name, const char *loca
tion) | |
| 990 { | |
| 991 const char *pname; | |
| 992 | |
| 993 if (unlikely(ptr == NULL)) { | |
| 994 talloc_abort_type_missmatch(location, NULL, name); | |
| 995 return NULL; | |
| 996 } | |
| 997 | |
| 998 pname = talloc_get_name(ptr); | |
| 999 if (likely(pname == name || strcmp(pname, name) == 0)) { | |
| 1000 return discard_const_p(void, ptr); | |
| 1001 } | |
| 1002 | |
| 1003 talloc_abort_type_missmatch(location, pname, name); | |
| 1004 return NULL; | |
| 1005 } | |
| 1006 | |
| 1007 /* | |
| 1008 this is for compatibility with older versions of talloc | |
| 1009 */ | |
| 1010 void *talloc_init(const char *fmt, ...) | |
| 1011 { | |
| 1012 va_list ap; | |
| 1013 void *ptr; | |
| 1014 const char *name; | |
| 1015 | |
| 1016 /* | |
| 1017 * samba3 expects talloc_report_depth_cb(NULL, ...) | |
| 1018 * reports all talloc'ed memory, so we need to enable | |
| 1019 * null_tracking | |
| 1020 */ | |
| 1021 talloc_enable_null_tracking(); | |
| 1022 | |
| 1023 ptr = __talloc(NULL, 0); | |
| 1024 if (unlikely(ptr == NULL)) return NULL; | |
| 1025 | |
| 1026 va_start(ap, fmt); | |
| 1027 name = talloc_set_name_v(ptr, fmt, ap); | |
| 1028 va_end(ap); | |
| 1029 | |
| 1030 if (unlikely(name == NULL)) { | |
| 1031 _talloc_free_internal(ptr, __location__); | |
| 1032 return NULL; | |
| 1033 } | |
| 1034 | |
| 1035 return ptr; | |
| 1036 } | |
| 1037 | |
| 1038 /* | |
| 1039 this is a replacement for the Samba3 talloc_destroy_pool functionality. It | |
| 1040 should probably not be used in new code. It's in here to keep the talloc | |
| 1041 code consistent across Samba 3 and 4. | |
| 1042 */ | |
| 1043 void talloc_free_children(void *ptr) | |
| 1044 { | |
| 1045 struct talloc_chunk *tc; | |
| 1046 | |
| 1047 if (unlikely(ptr == NULL)) { | |
| 1048 return; | |
| 1049 } | |
| 1050 | |
| 1051 tc = talloc_chunk_from_ptr(ptr); | |
| 1052 | |
| 1053 while (tc->child) { | |
| 1054 /* we need to work out who will own an abandoned child | |
| 1055 if it cannot be freed. In priority order, the first | |
| 1056 choice is owner of any remaining reference to this | |
| 1057 pointer, the second choice is our parent, and the | |
| 1058 final choice is the null context. */ | |
| 1059 void *child = TC_PTR_FROM_CHUNK(tc->child); | |
| 1060 const void *new_parent = null_context; | |
| 1061 if (unlikely(tc->child->refs)) { | |
| 1062 struct talloc_chunk *p = talloc_parent_chunk(tc->child->
refs); | |
| 1063 if (p) new_parent = TC_PTR_FROM_CHUNK(p); | |
| 1064 } | |
| 1065 if (unlikely(talloc_free(child) == -1)) { | |
| 1066 if (new_parent == null_context) { | |
| 1067 struct talloc_chunk *p = talloc_parent_chunk(ptr
); | |
| 1068 if (p) new_parent = TC_PTR_FROM_CHUNK(p); | |
| 1069 } | |
| 1070 _talloc_steal_internal(new_parent, child); | |
| 1071 } | |
| 1072 } | |
| 1073 | |
| 1074 if ((tc->flags & TALLOC_FLAG_POOL) | |
| 1075 && (*talloc_pool_objectcount(tc) == 1)) { | |
| 1076 tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE); | |
| 1077 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) | |
| 1078 VALGRIND_MAKE_MEM_NOACCESS( | |
| 1079 tc->pool, tc->size - TALLOC_POOL_HDR_SIZE); | |
| 1080 #endif | |
| 1081 } | |
| 1082 } | |
| 1083 | |
| 1084 /* | |
| 1085 Allocate a bit of memory as a child of an existing pointer | |
| 1086 */ | |
| 1087 void *_talloc(const void *context, size_t size) | |
| 1088 { | |
| 1089 return __talloc(context, size); | |
| 1090 } | |
| 1091 | |
| 1092 /* | |
| 1093 externally callable talloc_set_name_const() | |
| 1094 */ | |
| 1095 void talloc_set_name_const(const void *ptr, const char *name) | |
| 1096 { | |
| 1097 _talloc_set_name_const(ptr, name); | |
| 1098 } | |
| 1099 | |
| 1100 /* | |
| 1101 create a named talloc pointer. Any talloc pointer can be named, and | |
| 1102 talloc_named() operates just like talloc() except that it allows you | |
| 1103 to name the pointer. | |
| 1104 */ | |
| 1105 void *talloc_named_const(const void *context, size_t size, const char *name) | |
| 1106 { | |
| 1107 return _talloc_named_const(context, size, name); | |
| 1108 } | |
| 1109 | |
| 1110 /* | |
| 1111 free a talloc pointer. This also frees all child pointers of this | |
| 1112 pointer recursively | |
| 1113 | |
| 1114 return 0 if the memory is actually freed, otherwise -1. The memory | |
| 1115 will not be freed if the ref_count is > 1 or the destructor (if | |
| 1116 any) returns non-zero | |
| 1117 */ | |
| 1118 int _talloc_free(void *ptr, const char *location) | |
| 1119 { | |
| 1120 struct talloc_chunk *tc; | |
| 1121 | |
| 1122 if (unlikely(ptr == NULL)) { | |
| 1123 return -1; | |
| 1124 } | |
| 1125 | |
| 1126 tc = talloc_chunk_from_ptr(ptr); | |
| 1127 | |
| 1128 if (unlikely(tc->refs != NULL)) { | |
| 1129 struct talloc_reference_handle *h; | |
| 1130 | |
| 1131 talloc_log("ERROR: talloc_free with references at %s\n", | |
| 1132 location); | |
| 1133 | |
| 1134 for (h=tc->refs; h; h=h->next) { | |
| 1135 talloc_log("\treference at %s\n", | |
| 1136 h->location); | |
| 1137 } | |
| 1138 return -1; | |
| 1139 } | |
| 1140 | |
| 1141 return _talloc_free_internal(ptr, location); | |
| 1142 } | |
| 1143 | |
| 1144 | |
| 1145 static INLINE size_t min_size(size_t a, size_t b) | |
| 1146 { | |
| 1147 return a > b ? b : a; | |
| 1148 } | |
| 1149 | |
| 1150 /* | |
| 1151 A talloc version of realloc. The context argument is only used if | |
| 1152 ptr is NULL | |
| 1153 */ | |
| 1154 void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
ame) | |
| 1155 { | |
| 1156 struct talloc_chunk *tc; | |
| 1157 void *new_ptr; | |
| 1158 int malloced = 0; | |
| 1159 | |
| 1160 /* size zero is equivalent to free() */ | |
| 1161 if (unlikely(size == 0)) { | |
| 1162 talloc_unlink(context, ptr); | |
| 1163 return NULL; | |
| 1164 } | |
| 1165 | |
| 1166 if (unlikely(size >= MAX_TALLOC_SIZE)) { | |
| 1167 return NULL; | |
| 1168 } | |
| 1169 | |
| 1170 /* realloc(NULL) is equivalent to malloc() */ | |
| 1171 if (ptr == NULL) { | |
| 1172 return _talloc_named_const(context, size, name); | |
| 1173 } | |
| 1174 | |
| 1175 tc = talloc_chunk_from_ptr(ptr); | |
| 1176 | |
| 1177 /* don't allow realloc on referenced pointers */ | |
| 1178 if (unlikely(tc->refs)) { | |
| 1179 return NULL; | |
| 1180 } | |
| 1181 | |
| 1182 /* don't let anybody try to realloc a talloc_pool */ | |
| 1183 if (unlikely(tc->flags & TALLOC_FLAG_POOL)) { | |
| 1184 return NULL; | |
| 1185 } | |
| 1186 | |
| 1187 /* don't shrink if we have less than 1k to gain */ | |
| 1188 if ((size < tc->size) && ((tc->size - size) < 1024)) { | |
| 1189 tc->size = size; | |
| 1190 return ptr; | |
| 1191 } | |
| 1192 | |
| 1193 /* by resetting magic we catch users of the old memory */ | |
| 1194 tc->flags |= TALLOC_FLAG_FREE; | |
| 1195 | |
| 1196 #if ALWAYS_REALLOC | |
| 1197 new_ptr = malloc(size + TC_HDR_SIZE); | |
| 1198 if (new_ptr) { | |
| 1199 memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE); | |
| 1200 free(tc); | |
| 1201 } | |
| 1202 #else | |
| 1203 if (tc->flags & TALLOC_FLAG_POOLMEM) { | |
| 1204 | |
| 1205 new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE); | |
| 1206 *talloc_pool_objectcount((struct talloc_chunk *) | |
| 1207 (tc->pool)) -= 1; | |
| 1208 | |
| 1209 if (new_ptr == NULL) { | |
| 1210 new_ptr = malloc(TC_HDR_SIZE+size); | |
| 1211 malloced = 1; | |
| 1212 } | |
| 1213 | |
| 1214 if (new_ptr) { | |
| 1215 memcpy(new_ptr, tc, min_size(tc->size,size) + TC_HDR_SIZ
E); | |
| 1216 } | |
| 1217 } | |
| 1218 else { | |
| 1219 new_ptr = realloc(tc, size + TC_HDR_SIZE); | |
| 1220 } | |
| 1221 #endif | |
| 1222 if (unlikely(!new_ptr)) { | |
| 1223 tc->flags &= ~TALLOC_FLAG_FREE; | |
| 1224 return NULL; | |
| 1225 } | |
| 1226 | |
| 1227 tc = (struct talloc_chunk *)new_ptr; | |
| 1228 tc->flags &= ~TALLOC_FLAG_FREE; | |
| 1229 if (malloced) { | |
| 1230 tc->flags &= ~TALLOC_FLAG_POOLMEM; | |
| 1231 } | |
| 1232 if (tc->parent) { | |
| 1233 tc->parent->child = tc; | |
| 1234 } | |
| 1235 if (tc->child) { | |
| 1236 tc->child->parent = tc; | |
| 1237 } | |
| 1238 | |
| 1239 if (tc->prev) { | |
| 1240 tc->prev->next = tc; | |
| 1241 } | |
| 1242 if (tc->next) { | |
| 1243 tc->next->prev = tc; | |
| 1244 } | |
| 1245 | |
| 1246 tc->size = size; | |
| 1247 _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); | |
| 1248 | |
| 1249 return TC_PTR_FROM_CHUNK(tc); | |
| 1250 } | |
| 1251 | |
| 1252 /* | |
| 1253 a wrapper around talloc_steal() for situations where you are moving a pointer | |
| 1254 between two structures, and want the old pointer to be set to NULL | |
| 1255 */ | |
| 1256 void *_talloc_move(const void *new_ctx, const void *_pptr) | |
| 1257 { | |
| 1258 const void **pptr = discard_const_p(const void *,_pptr); | |
| 1259 void *ret = talloc_steal(new_ctx, discard_const_p(void, *pptr)); | |
| 1260 (*pptr) = NULL; | |
| 1261 return ret; | |
| 1262 } | |
| 1263 | |
| 1264 /* | |
| 1265 return the total size of a talloc pool (subtree) | |
| 1266 */ | |
| 1267 size_t talloc_total_size(const void *ptr) | |
| 1268 { | |
| 1269 size_t total = 0; | |
| 1270 struct talloc_chunk *c, *tc; | |
| 1271 | |
| 1272 if (ptr == NULL) { | |
| 1273 ptr = null_context; | |
| 1274 } | |
| 1275 if (ptr == NULL) { | |
| 1276 return 0; | |
| 1277 } | |
| 1278 | |
| 1279 tc = talloc_chunk_from_ptr(ptr); | |
| 1280 | |
| 1281 if (tc->flags & TALLOC_FLAG_LOOP) { | |
| 1282 return 0; | |
| 1283 } | |
| 1284 | |
| 1285 tc->flags |= TALLOC_FLAG_LOOP; | |
| 1286 | |
| 1287 if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { | |
| 1288 total = tc->size; | |
| 1289 } | |
| 1290 for (c=tc->child;c;c=c->next) { | |
| 1291 total += talloc_total_size(TC_PTR_FROM_CHUNK(c)); | |
| 1292 } | |
| 1293 | |
| 1294 tc->flags &= ~TALLOC_FLAG_LOOP; | |
| 1295 | |
| 1296 return total; | |
| 1297 } | |
| 1298 | |
| 1299 /* | |
| 1300 return the total number of blocks in a talloc pool (subtree) | |
| 1301 */ | |
| 1302 size_t talloc_total_blocks(const void *ptr) | |
| 1303 { | |
| 1304 size_t total = 0; | |
| 1305 struct talloc_chunk *c, *tc; | |
| 1306 | |
| 1307 if (ptr == NULL) { | |
| 1308 ptr = null_context; | |
| 1309 } | |
| 1310 if (ptr == NULL) { | |
| 1311 return 0; | |
| 1312 } | |
| 1313 | |
| 1314 tc = talloc_chunk_from_ptr(ptr); | |
| 1315 | |
| 1316 if (tc->flags & TALLOC_FLAG_LOOP) { | |
| 1317 return 0; | |
| 1318 } | |
| 1319 | |
| 1320 tc->flags |= TALLOC_FLAG_LOOP; | |
| 1321 | |
| 1322 total++; | |
| 1323 for (c=tc->child;c;c=c->next) { | |
| 1324 total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c)); | |
| 1325 } | |
| 1326 | |
| 1327 tc->flags &= ~TALLOC_FLAG_LOOP; | |
| 1328 | |
| 1329 return total; | |
| 1330 } | |
| 1331 | |
| 1332 /* | |
| 1333 return the number of external references to a pointer | |
| 1334 */ | |
| 1335 size_t talloc_reference_count(const void *ptr) | |
| 1336 { | |
| 1337 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); | |
| 1338 struct talloc_reference_handle *h; | |
| 1339 size_t ret = 0; | |
| 1340 | |
| 1341 for (h=tc->refs;h;h=h->next) { | |
| 1342 ret++; | |
| 1343 } | |
| 1344 return ret; | |
| 1345 } | |
| 1346 | |
| 1347 /* | |
| 1348 report on memory usage by all children of a pointer, giving a full tree view | |
| 1349 */ | |
| 1350 void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, | |
| 1351 void (*callback)(const void *ptr, | |
| 1352 int depth, int max_depth, | |
| 1353 int is_ref, | |
| 1354 void *private_data), | |
| 1355 void *private_data) | |
| 1356 { | |
| 1357 struct talloc_chunk *c, *tc; | |
| 1358 | |
| 1359 if (ptr == NULL) { | |
| 1360 ptr = null_context; | |
| 1361 } | |
| 1362 if (ptr == NULL) return; | |
| 1363 | |
| 1364 tc = talloc_chunk_from_ptr(ptr); | |
| 1365 | |
| 1366 if (tc->flags & TALLOC_FLAG_LOOP) { | |
| 1367 return; | |
| 1368 } | |
| 1369 | |
| 1370 callback(ptr, depth, max_depth, 0, private_data); | |
| 1371 | |
| 1372 if (max_depth >= 0 && depth >= max_depth) { | |
| 1373 return; | |
| 1374 } | |
| 1375 | |
| 1376 tc->flags |= TALLOC_FLAG_LOOP; | |
| 1377 for (c=tc->child;c;c=c->next) { | |
| 1378 if (c->name == TALLOC_MAGIC_REFERENCE) { | |
| 1379 struct talloc_reference_handle *h = (struct talloc_refer
ence_handle *)TC_PTR_FROM_CHUNK(c); | |
| 1380 callback(h->ptr, depth + 1, max_depth, 1, private_data); | |
| 1381 } else { | |
| 1382 talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1,
max_depth, callback, private_data); | |
| 1383 } | |
| 1384 } | |
| 1385 tc->flags &= ~TALLOC_FLAG_LOOP; | |
| 1386 } | |
| 1387 | |
| 1388 static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_
depth, int is_ref, void *_f) | |
| 1389 { | |
| 1390 const char *name = talloc_get_name(ptr); | |
| 1391 FILE *f = (FILE *)_f; | |
| 1392 | |
| 1393 if (is_ref) { | |
| 1394 fprintf(f, "%*sreference to: %s\n", depth*4, "", name); | |
| 1395 return; | |
| 1396 } | |
| 1397 | |
| 1398 if (depth == 0) { | |
| 1399 fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blo
cks)\n", | |
| 1400 (max_depth < 0 ? "full " :""), name, | |
| 1401 (unsigned long)talloc_total_size(ptr), | |
| 1402 (unsigned long)talloc_total_blocks(ptr)); | |
| 1403 return; | |
| 1404 } | |
| 1405 | |
| 1406 fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", | |
| 1407 depth*4, "", | |
| 1408 name, | |
| 1409 (unsigned long)talloc_total_size(ptr), | |
| 1410 (unsigned long)talloc_total_blocks(ptr), | |
| 1411 (int)talloc_reference_count(ptr), ptr); | |
| 1412 | |
| 1413 #if 0 | |
| 1414 fprintf(f, "content: "); | |
| 1415 if (talloc_total_size(ptr)) { | |
| 1416 int tot = talloc_total_size(ptr); | |
| 1417 int i; | |
| 1418 | |
| 1419 for (i = 0; i < tot; i++) { | |
| 1420 if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126))
{ | |
| 1421 fprintf(f, "%c", ((char *)ptr)[i]); | |
| 1422 } else { | |
| 1423 fprintf(f, "~%02x", ((char *)ptr)[i]); | |
| 1424 } | |
| 1425 } | |
| 1426 } | |
| 1427 fprintf(f, "\n"); | |
| 1428 #endif | |
| 1429 } | |
| 1430 | |
| 1431 /* | |
| 1432 report on memory usage by all children of a pointer, giving a full tree view | |
| 1433 */ | |
| 1434 void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f
) | |
| 1435 { | |
| 1436 if (f) { | |
| 1437 talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_dept
h_FILE_helper, f); | |
| 1438 fflush(f); | |
| 1439 } | |
| 1440 } | |
| 1441 | |
| 1442 /* | |
| 1443 report on memory usage by all children of a pointer, giving a full tree view | |
| 1444 */ | |
| 1445 void talloc_report_full(const void *ptr, FILE *f) | |
| 1446 { | |
| 1447 talloc_report_depth_file(ptr, 0, -1, f); | |
| 1448 } | |
| 1449 | |
| 1450 /* | |
| 1451 report on memory usage by all children of a pointer | |
| 1452 */ | |
| 1453 void talloc_report(const void *ptr, FILE *f) | |
| 1454 { | |
| 1455 talloc_report_depth_file(ptr, 0, 1, f); | |
| 1456 } | |
| 1457 | |
| 1458 /* | |
| 1459 report on any memory hanging off the null context | |
| 1460 */ | |
| 1461 static void talloc_report_null(void) | |
| 1462 { | |
| 1463 if (talloc_total_size(null_context) != 0) { | |
| 1464 talloc_report(null_context, stderr); | |
| 1465 } | |
| 1466 } | |
| 1467 | |
| 1468 /* | |
| 1469 report on any memory hanging off the null context | |
| 1470 */ | |
| 1471 static void talloc_report_null_full(void) | |
| 1472 { | |
| 1473 if (talloc_total_size(null_context) != 0) { | |
| 1474 talloc_report_full(null_context, stderr); | |
| 1475 } | |
| 1476 } | |
| 1477 | |
| 1478 /* | |
| 1479 enable tracking of the NULL context | |
| 1480 */ | |
| 1481 void talloc_enable_null_tracking(void) | |
| 1482 { | |
| 1483 if (null_context == NULL) { | |
| 1484 null_context = _talloc_named_const(NULL, 0, "null_context"); | |
| 1485 if (autofree_context != NULL) { | |
| 1486 talloc_reparent(NULL, null_context, autofree_context); | |
| 1487 } | |
| 1488 } | |
| 1489 } | |
| 1490 | |
| 1491 /* | |
| 1492 enable tracking of the NULL context, not moving the autofree context | |
| 1493 into the NULL context. This is needed for the talloc testsuite | |
| 1494 */ | |
| 1495 void talloc_enable_null_tracking_no_autofree(void) | |
| 1496 { | |
| 1497 if (null_context == NULL) { | |
| 1498 null_context = _talloc_named_const(NULL, 0, "null_context"); | |
| 1499 } | |
| 1500 } | |
| 1501 | |
| 1502 /* | |
| 1503 disable tracking of the NULL context | |
| 1504 */ | |
| 1505 void talloc_disable_null_tracking(void) | |
| 1506 { | |
| 1507 if (null_context != NULL) { | |
| 1508 /* we have to move any children onto the real NULL | |
| 1509 context */ | |
| 1510 struct talloc_chunk *tc, *tc2; | |
| 1511 tc = talloc_chunk_from_ptr(null_context); | |
| 1512 for (tc2 = tc->child; tc2; tc2=tc2->next) { | |
| 1513 if (tc2->parent == tc) tc2->parent = NULL; | |
| 1514 if (tc2->prev == tc) tc2->prev = NULL; | |
| 1515 } | |
| 1516 for (tc2 = tc->next; tc2; tc2=tc2->next) { | |
| 1517 if (tc2->parent == tc) tc2->parent = NULL; | |
| 1518 if (tc2->prev == tc) tc2->prev = NULL; | |
| 1519 } | |
| 1520 tc->child = NULL; | |
| 1521 tc->next = NULL; | |
| 1522 } | |
| 1523 talloc_free(null_context); | |
| 1524 null_context = NULL; | |
| 1525 } | |
| 1526 | |
| 1527 /* | |
| 1528 enable leak reporting on exit | |
| 1529 */ | |
| 1530 void talloc_enable_leak_report(void) | |
| 1531 { | |
| 1532 talloc_enable_null_tracking(); | |
| 1533 atexit(talloc_report_null); | |
| 1534 } | |
| 1535 | |
| 1536 /* | |
| 1537 enable full leak reporting on exit | |
| 1538 */ | |
| 1539 void talloc_enable_leak_report_full(void) | |
| 1540 { | |
| 1541 talloc_enable_null_tracking(); | |
| 1542 atexit(talloc_report_null_full); | |
| 1543 } | |
| 1544 | |
| 1545 /* | |
| 1546 talloc and zero memory. | |
| 1547 */ | |
| 1548 void *_talloc_zero(const void *ctx, size_t size, const char *name) | |
| 1549 { | |
| 1550 void *p = _talloc_named_const(ctx, size, name); | |
| 1551 | |
| 1552 if (p) { | |
| 1553 memset(p, '\0', size); | |
| 1554 } | |
| 1555 | |
| 1556 return p; | |
| 1557 } | |
| 1558 | |
| 1559 /* | |
| 1560 memdup with a talloc. | |
| 1561 */ | |
| 1562 void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name
) | |
| 1563 { | |
| 1564 void *newp = _talloc_named_const(t, size, name); | |
| 1565 | |
| 1566 if (likely(newp)) { | |
| 1567 memcpy(newp, p, size); | |
| 1568 } | |
| 1569 | |
| 1570 return newp; | |
| 1571 } | |
| 1572 | |
| 1573 static INLINE char *__talloc_strlendup(const void *t, const char *p, size_t len) | |
| 1574 { | |
| 1575 char *ret; | |
| 1576 | |
| 1577 ret = (char *)__talloc(t, len + 1); | |
| 1578 if (unlikely(!ret)) return NULL; | |
| 1579 | |
| 1580 memcpy(ret, p, len); | |
| 1581 ret[len] = 0; | |
| 1582 | |
| 1583 _talloc_set_name_const(ret, ret); | |
| 1584 return ret; | |
| 1585 } | |
| 1586 | |
| 1587 /* | |
| 1588 strdup with a talloc | |
| 1589 */ | |
| 1590 char *talloc_strdup(const void *t, const char *p) | |
| 1591 { | |
| 1592 if (unlikely(!p)) return NULL; | |
| 1593 return __talloc_strlendup(t, p, strlen(p)); | |
| 1594 } | |
| 1595 | |
| 1596 #ifndef HAVE_STRNLEN | |
| 1597 #define strnlen rep_strnlen | |
| 1598 static size_t rep_strnlen(const char* s, size_t n) | |
| 1599 { | |
| 1600 if (unlikely(!s)) return 0; | |
| 1601 int i = 0; | |
| 1602 while (i < n && *s++ != '\0') | |
| 1603 ++i; | |
| 1604 return i; | |
| 1605 } | |
| 1606 #endif | |
| 1607 | |
| 1608 /* | |
| 1609 strndup with a talloc | |
| 1610 */ | |
| 1611 char *talloc_strndup(const void *t, const char *p, size_t n) | |
| 1612 { | |
| 1613 if (unlikely(!p)) return NULL; | |
| 1614 return __talloc_strlendup(t, p, strnlen(p, n)); | |
| 1615 } | |
| 1616 | |
| 1617 static INLINE char *__talloc_strlendup_append(char *s, size_t slen, | |
| 1618 const char *a, size_t alen) | |
| 1619 { | |
| 1620 char *ret; | |
| 1621 | |
| 1622 ret = talloc_realloc(NULL, s, char, slen + alen + 1); | |
| 1623 if (unlikely(!ret)) return NULL; | |
| 1624 | |
| 1625 /* append the string and the trailing \0 */ | |
| 1626 memcpy(&ret[slen], a, alen); | |
| 1627 ret[slen+alen] = 0; | |
| 1628 | |
| 1629 _talloc_set_name_const(ret, ret); | |
| 1630 return ret; | |
| 1631 } | |
| 1632 | |
| 1633 /* | |
| 1634 * Appends at the end of the string. | |
| 1635 */ | |
| 1636 char *talloc_strdup_append(char *s, const char *a) | |
| 1637 { | |
| 1638 if (unlikely(!s)) { | |
| 1639 return talloc_strdup(NULL, a); | |
| 1640 } | |
| 1641 | |
| 1642 if (unlikely(!a)) { | |
| 1643 return s; | |
| 1644 } | |
| 1645 | |
| 1646 return __talloc_strlendup_append(s, strlen(s), a, strlen(a)); | |
| 1647 } | |
| 1648 | |
| 1649 /* | |
| 1650 * Appends at the end of the talloc'ed buffer, | |
| 1651 * not the end of the string. | |
| 1652 */ | |
| 1653 char *talloc_strdup_append_buffer(char *s, const char *a) | |
| 1654 { | |
| 1655 size_t slen; | |
| 1656 | |
| 1657 if (unlikely(!s)) { | |
| 1658 return talloc_strdup(NULL, a); | |
| 1659 } | |
| 1660 | |
| 1661 if (unlikely(!a)) { | |
| 1662 return s; | |
| 1663 } | |
| 1664 | |
| 1665 slen = talloc_get_size(s); | |
| 1666 if (likely(slen > 0)) { | |
| 1667 slen--; | |
| 1668 } | |
| 1669 | |
| 1670 return __talloc_strlendup_append(s, slen, a, strlen(a)); | |
| 1671 } | |
| 1672 | |
| 1673 /* | |
| 1674 * Appends at the end of the string. | |
| 1675 */ | |
| 1676 char *talloc_strndup_append(char *s, const char *a, size_t n) | |
| 1677 { | |
| 1678 if (unlikely(!s)) { | |
| 1679 return talloc_strdup(NULL, a); | |
| 1680 } | |
| 1681 | |
| 1682 if (unlikely(!a)) { | |
| 1683 return s; | |
| 1684 } | |
| 1685 | |
| 1686 return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n)); | |
| 1687 } | |
| 1688 | |
| 1689 /* | |
| 1690 * Appends at the end of the talloc'ed buffer, | |
| 1691 * not the end of the string. | |
| 1692 */ | |
| 1693 char *talloc_strndup_append_buffer(char *s, const char *a, size_t n) | |
| 1694 { | |
| 1695 size_t slen; | |
| 1696 | |
| 1697 if (unlikely(!s)) { | |
| 1698 return talloc_strdup(NULL, a); | |
| 1699 } | |
| 1700 | |
| 1701 if (unlikely(!a)) { | |
| 1702 return s; | |
| 1703 } | |
| 1704 | |
| 1705 slen = talloc_get_size(s); | |
| 1706 if (likely(slen > 0)) { | |
| 1707 slen--; | |
| 1708 } | |
| 1709 | |
| 1710 return __talloc_strlendup_append(s, slen, a, strnlen(a, n)); | |
| 1711 } | |
| 1712 | |
| 1713 #ifndef HAVE_VA_COPY | |
| 1714 #ifdef HAVE___VA_COPY | |
| 1715 #define va_copy(dest, src) __va_copy(dest, src) | |
| 1716 #else | |
| 1717 #define va_copy(dest, src) (dest) = (src) | |
| 1718 #endif | |
| 1719 #endif | |
| 1720 | |
| 1721 char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) | |
| 1722 { | |
| 1723 int len; | |
| 1724 char *ret; | |
| 1725 va_list ap2; | |
| 1726 | |
| 1727 va_copy(ap2, ap); | |
| 1728 len = vsnprintf(NULL, 0, fmt, ap2); | |
| 1729 va_end(ap2); | |
| 1730 if (unlikely(len < 0)) { | |
| 1731 return NULL; | |
| 1732 } | |
| 1733 | |
| 1734 ret = (char *)__talloc(t, len+1); | |
| 1735 if (unlikely(!ret)) return NULL; | |
| 1736 | |
| 1737 va_copy(ap2, ap); | |
| 1738 vsnprintf(ret, len+1, fmt, ap2); | |
| 1739 va_end(ap2); | |
| 1740 | |
| 1741 _talloc_set_name_const(ret, ret); | |
| 1742 return ret; | |
| 1743 } | |
| 1744 | |
| 1745 | |
| 1746 /* | |
| 1747 Perform string formatting, and return a pointer to newly allocated | |
| 1748 memory holding the result, inside a memory pool. | |
| 1749 */ | |
| 1750 char *talloc_asprintf(const void *t, const char *fmt, ...) | |
| 1751 { | |
| 1752 va_list ap; | |
| 1753 char *ret; | |
| 1754 | |
| 1755 va_start(ap, fmt); | |
| 1756 ret = talloc_vasprintf(t, fmt, ap); | |
| 1757 va_end(ap); | |
| 1758 return ret; | |
| 1759 } | |
| 1760 | |
| 1761 static INLINE char *__talloc_vaslenprintf_append(char *s, size_t slen, | |
| 1762 const char *fmt, va_list ap) | |
| 1763 PRINTF_ATTRIBUTE(3,0); | |
| 1764 | |
| 1765 static INLINE char *__talloc_vaslenprintf_append(char *s, size_t slen, | |
| 1766 const char *fmt, va_list ap) | |
| 1767 { | |
| 1768 /* ssize_t isn't present on Windows. */ | |
| 1769 #ifndef _MSC_VER | |
| 1770 ssize_t alen; | |
| 1771 #else | |
| 1772 size_t alen; | |
| 1773 #endif | |
| 1774 va_list ap2; | |
| 1775 | |
| 1776 va_copy(ap2, ap); | |
| 1777 alen = vsnprintf(NULL, 0, fmt, ap2); | |
| 1778 va_end(ap2); | |
| 1779 | |
| 1780 if (alen <= 0) { | |
| 1781 /* Either the vsnprintf failed or the format resulted in | |
| 1782 * no characters being formatted. In the former case, we | |
| 1783 * ought to return NULL, in the latter we ought to return | |
| 1784 * the original string. Most current callers of this | |
| 1785 * function expect it to never return NULL. | |
| 1786 */ | |
| 1787 return s; | |
| 1788 } | |
| 1789 | |
| 1790 s = talloc_realloc(NULL, s, char, slen + alen + 1); | |
| 1791 if (!s) return NULL; | |
| 1792 | |
| 1793 va_copy(ap2, ap); | |
| 1794 vsnprintf(s + slen, alen + 1, fmt, ap2); | |
| 1795 va_end(ap2); | |
| 1796 | |
| 1797 _talloc_set_name_const(s, s); | |
| 1798 return s; | |
| 1799 } | |
| 1800 | |
| 1801 /** | |
| 1802 * Realloc @p s to append the formatted result of @p fmt and @p ap, | |
| 1803 * and return @p s, which may have moved. Good for gradually | |
| 1804 * accumulating output into a string buffer. Appends at the end | |
| 1805 * of the string. | |
| 1806 **/ | |
| 1807 char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) | |
| 1808 { | |
| 1809 if (unlikely(!s)) { | |
| 1810 return talloc_vasprintf(NULL, fmt, ap); | |
| 1811 } | |
| 1812 | |
| 1813 return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap); | |
| 1814 } | |
| 1815 | |
| 1816 /** | |
| 1817 * Realloc @p s to append the formatted result of @p fmt and @p ap, | |
| 1818 * and return @p s, which may have moved. Always appends at the | |
| 1819 * end of the talloc'ed buffer, not the end of the string. | |
| 1820 **/ | |
| 1821 char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) | |
| 1822 { | |
| 1823 size_t slen; | |
| 1824 | |
| 1825 if (unlikely(!s)) { | |
| 1826 return talloc_vasprintf(NULL, fmt, ap); | |
| 1827 } | |
| 1828 | |
| 1829 slen = talloc_get_size(s); | |
| 1830 if (likely(slen > 0)) { | |
| 1831 slen--; | |
| 1832 } | |
| 1833 | |
| 1834 return __talloc_vaslenprintf_append(s, slen, fmt, ap); | |
| 1835 } | |
| 1836 | |
| 1837 /* | |
| 1838 Realloc @p s to append the formatted result of @p fmt and return @p | |
| 1839 s, which may have moved. Good for gradually accumulating output | |
| 1840 into a string buffer. | |
| 1841 */ | |
| 1842 char *talloc_asprintf_append(char *s, const char *fmt, ...) | |
| 1843 { | |
| 1844 va_list ap; | |
| 1845 | |
| 1846 va_start(ap, fmt); | |
| 1847 s = talloc_vasprintf_append(s, fmt, ap); | |
| 1848 va_end(ap); | |
| 1849 return s; | |
| 1850 } | |
| 1851 | |
| 1852 /* | |
| 1853 Realloc @p s to append the formatted result of @p fmt and return @p | |
| 1854 s, which may have moved. Good for gradually accumulating output | |
| 1855 into a buffer. | |
| 1856 */ | |
| 1857 char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) | |
| 1858 { | |
| 1859 va_list ap; | |
| 1860 | |
| 1861 va_start(ap, fmt); | |
| 1862 s = talloc_vasprintf_append_buffer(s, fmt, ap); | |
| 1863 va_end(ap); | |
| 1864 return s; | |
| 1865 } | |
| 1866 | |
| 1867 /* | |
| 1868 alloc an array, checking for integer overflow in the array size | |
| 1869 */ | |
| 1870 void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char
*name) | |
| 1871 { | |
| 1872 if (count >= MAX_TALLOC_SIZE/el_size) { | |
| 1873 return NULL; | |
| 1874 } | |
| 1875 return _talloc_named_const(ctx, el_size * count, name); | |
| 1876 } | |
| 1877 | |
| 1878 /* | |
| 1879 alloc an zero array, checking for integer overflow in the array size | |
| 1880 */ | |
| 1881 void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const
char *name) | |
| 1882 { | |
| 1883 if (count >= MAX_TALLOC_SIZE/el_size) { | |
| 1884 return NULL; | |
| 1885 } | |
| 1886 return _talloc_zero(ctx, el_size * count, name); | |
| 1887 } | |
| 1888 | |
| 1889 /* | |
| 1890 realloc an array, checking for integer overflow in the array size | |
| 1891 */ | |
| 1892 void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned
count, const char *name) | |
| 1893 { | |
| 1894 if (count >= MAX_TALLOC_SIZE/el_size) { | |
| 1895 return NULL; | |
| 1896 } | |
| 1897 return _talloc_realloc(ctx, ptr, el_size * count, name); | |
| 1898 } | |
| 1899 | |
| 1900 /* | |
| 1901 a function version of talloc_realloc(), so it can be passed as a function poin
ter | |
| 1902 to libraries that want a realloc function (a realloc function encapsulates | |
| 1903 all the basic capabilities of an allocation library, which is why this is usef
ul) | |
| 1904 */ | |
| 1905 void *talloc_realloc_fn(const void *context, void *ptr, size_t size) | |
| 1906 { | |
| 1907 return _talloc_realloc(context, ptr, size, NULL); | |
| 1908 } | |
| 1909 | |
| 1910 | |
| 1911 static int talloc_autofree_destructor(void *ptr) | |
| 1912 { | |
| 1913 autofree_context = NULL; | |
| 1914 return 0; | |
| 1915 } | |
| 1916 | |
| 1917 static void talloc_autofree(void) | |
| 1918 { | |
| 1919 talloc_free(autofree_context); | |
| 1920 } | |
| 1921 | |
| 1922 /* | |
| 1923 return a context which will be auto-freed on exit | |
| 1924 this is useful for reducing the noise in leak reports | |
| 1925 */ | |
| 1926 void *talloc_autofree_context(void) | |
| 1927 { | |
| 1928 if (autofree_context == NULL) { | |
| 1929 autofree_context = _talloc_named_const(NULL, 0, "autofree_contex
t"); | |
| 1930 talloc_set_destructor(autofree_context, talloc_autofree_destruct
or); | |
| 1931 atexit(talloc_autofree); | |
| 1932 } | |
| 1933 return autofree_context; | |
| 1934 } | |
| 1935 | |
| 1936 size_t talloc_get_size(const void *context) | |
| 1937 { | |
| 1938 struct talloc_chunk *tc; | |
| 1939 | |
| 1940 if (context == NULL) { | |
| 1941 context = null_context; | |
| 1942 } | |
| 1943 if (context == NULL) { | |
| 1944 return 0; | |
| 1945 } | |
| 1946 | |
| 1947 tc = talloc_chunk_from_ptr(context); | |
| 1948 | |
| 1949 return tc->size; | |
| 1950 } | |
| 1951 | |
| 1952 /* | |
| 1953 find a parent of this context that has the given name, if any | |
| 1954 */ | |
| 1955 void *talloc_find_parent_byname(const void *context, const char *name) | |
| 1956 { | |
| 1957 struct talloc_chunk *tc; | |
| 1958 | |
| 1959 if (context == NULL) { | |
| 1960 return NULL; | |
| 1961 } | |
| 1962 | |
| 1963 tc = talloc_chunk_from_ptr(context); | |
| 1964 while (tc) { | |
| 1965 if (tc->name && strcmp(tc->name, name) == 0) { | |
| 1966 return TC_PTR_FROM_CHUNK(tc); | |
| 1967 } | |
| 1968 while (tc && tc->prev) tc = tc->prev; | |
| 1969 if (tc) { | |
| 1970 tc = tc->parent; | |
| 1971 } | |
| 1972 } | |
| 1973 return NULL; | |
| 1974 } | |
| 1975 | |
| 1976 /* | |
| 1977 show the parentage of a context | |
| 1978 */ | |
| 1979 void talloc_show_parents(const void *context, FILE *file) | |
| 1980 { | |
| 1981 struct talloc_chunk *tc; | |
| 1982 | |
| 1983 if (context == NULL) { | |
| 1984 fprintf(file, "talloc no parents for NULL\n"); | |
| 1985 return; | |
| 1986 } | |
| 1987 | |
| 1988 tc = talloc_chunk_from_ptr(context); | |
| 1989 fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context)); | |
| 1990 while (tc) { | |
| 1991 fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc))
); | |
| 1992 while (tc && tc->prev) tc = tc->prev; | |
| 1993 if (tc) { | |
| 1994 tc = tc->parent; | |
| 1995 } | |
| 1996 } | |
| 1997 fflush(file); | |
| 1998 } | |
| 1999 | |
| 2000 /* | |
| 2001 return 1 if ptr is a parent of context | |
| 2002 */ | |
| 2003 int talloc_is_parent(const void *context, const void *ptr) | |
| 2004 { | |
| 2005 struct talloc_chunk *tc; | |
| 2006 | |
| 2007 if (context == NULL) { | |
| 2008 return 0; | |
| 2009 } | |
| 2010 | |
| 2011 tc = talloc_chunk_from_ptr(context); | |
| 2012 while (tc) { | |
| 2013 if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; | |
| 2014 while (tc && tc->prev) tc = tc->prev; | |
| 2015 if (tc) { | |
| 2016 tc = tc->parent; | |
| 2017 } | |
| 2018 } | |
| 2019 return 0; | |
| 2020 } | |
| OLD | NEW |