1 /* -*- c-basic-offset: 2 -*- */ 2 /* 3 Copyright(C) 2009-2016 Brazil 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License version 2.1 as published by the Free Software Foundation. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with this library; if not, write to the Free Software 16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA 17 */ 18 19 #include "grn.h" 20 #include "grn_alloc.h" 21 #include "grn_ctx_impl.h" 22 23 static int alloc_count = 0; 24 25 #ifdef USE_FAIL_MALLOC 26 static int grn_fmalloc_prob = 0; 27 static char *grn_fmalloc_func = NULL; 28 static char *grn_fmalloc_file = NULL; 29 static int grn_fmalloc_line = 0; 30 #endif /* USE_FAIL_MALLOC */ 31 32 #ifdef USE_EXACT_ALLOC_COUNT 33 # define GRN_ADD_ALLOC_COUNT(count) do { \ 34 uint32_t alloced; \ 35 GRN_ATOMIC_ADD_EX(&alloc_count, count, alloced); \ 36 } while (0) 37 #else /* USE_EXACT_ALLOC_COUNT */ 38 # define GRN_ADD_ALLOC_COUNT(count) do { \ 39 alloc_count += count; \ 40 } while (0) 41 #endif 42 43 void 44 grn_alloc_init_from_env(void) 45 { 46 #ifdef USE_FAIL_MALLOC 47 { 48 char grn_fmalloc_prob_env[GRN_ENV_BUFFER_SIZE]; 49 grn_getenv("GRN_FMALLOC_PROB", 50 grn_fmalloc_prob_env, 51 GRN_ENV_BUFFER_SIZE); 52 if (grn_fmalloc_prob_env[0]) { 53 char grn_fmalloc_seed_env[GRN_ENV_BUFFER_SIZE]; 54 grn_fmalloc_prob = strtod(grn_fmalloc_prob_env, 0) * RAND_MAX; 55 grn_getenv("GRN_FMALLOC_SEED", 56 grn_fmalloc_seed_env, 57 GRN_ENV_BUFFER_SIZE); 58 if (grn_fmalloc_seed_env[0]) { 59 srand((unsigned int)atoi(grn_fmalloc_seed_env)); 60 } else { 61 srand((unsigned int)time(NULL)); 62 } 63 } 64 } 65 { 66 static char grn_fmalloc_func_env[GRN_ENV_BUFFER_SIZE]; 67 grn_getenv("GRN_FMALLOC_FUNC", 68 grn_fmalloc_func_env, 69 GRN_ENV_BUFFER_SIZE); 70 if (grn_fmalloc_func_env[0]) { 71 grn_fmalloc_func = grn_fmalloc_func_env; 72 } 73 } 74 { 75 static char grn_fmalloc_file_env[GRN_ENV_BUFFER_SIZE]; 76 grn_getenv("GRN_FMALLOC_FILE", 77 grn_fmalloc_file_env, 78 GRN_ENV_BUFFER_SIZE); 79 if (grn_fmalloc_file_env[0]) { 80 grn_fmalloc_file = grn_fmalloc_file_env; 81 } 82 } 83 { 84 char grn_fmalloc_line_env[GRN_ENV_BUFFER_SIZE]; 85 grn_getenv("GRN_FMALLOC_LINE", 86 grn_fmalloc_line_env, 87 GRN_ENV_BUFFER_SIZE); 88 if (grn_fmalloc_line_env[0]) { 89 grn_fmalloc_line = atoi(grn_fmalloc_line_env); 90 } 91 } 92 #endif /* USE_FAIL_MALLOC */ 93 } 94 95 #ifdef USE_MEMORY_DEBUG 96 static grn_critical_section grn_alloc_info_lock; 97 98 void 99 grn_alloc_info_init(void) 100 { 101 CRITICAL_SECTION_INIT(grn_alloc_info_lock); 102 } 103 104 void 105 grn_alloc_info_fin(void) 106 { 107 CRITICAL_SECTION_FIN(grn_alloc_info_lock); 108 } 109 110 inline static void 111 grn_alloc_info_set_backtrace(char *buffer, size_t size) 112 { 113 # ifdef HAVE_BACKTRACE 114 # define N_TRACE_LEVEL 100 115 static void *trace[N_TRACE_LEVEL]; 116 char **symbols; 117 int i, n, rest; 118 119 rest = size; 120 n = backtrace(trace, N_TRACE_LEVEL); 121 symbols = backtrace_symbols(trace, n); 122 if (symbols) { 123 for (i = 0; i < n; i++) { 124 int symbol_length; 125 126 symbol_length = strlen(symbols[i]); 127 if (symbol_length + 2 > rest) { 128 break; 129 } 130 grn_memcpy(buffer, symbols[i], symbol_length); 131 buffer += symbol_length; 132 rest -= symbol_length; 133 buffer[0] = '\n'; 134 buffer++; 135 rest--; 136 buffer[0] = '\0'; 137 rest--; 138 } 139 free(symbols); 140 } else { 141 buffer[0] = '\0'; 142 } 143 # undef N_TRACE_LEVEL 144 # else /* HAVE_BACKTRACE */ 145 buffer[0] = '\0'; 146 # endif /* HAVE_BACKTRACE */ 147 } 148 149 inline static void 150 grn_alloc_info_add(void *address, size_t size, 151 const char *file, int line, const char *func) 152 { 153 grn_ctx *ctx; 154 grn_alloc_info *new_alloc_info; 155 156 ctx = &grn_gctx; 157 if (!ctx->impl) { return; } 158 159 CRITICAL_SECTION_ENTER(grn_alloc_info_lock); 160 new_alloc_info = malloc(sizeof(grn_alloc_info)); 161 if (new_alloc_info) { 162 new_alloc_info->address = address; 163 new_alloc_info->size = size; 164 new_alloc_info->freed = GRN_FALSE; 165 grn_alloc_info_set_backtrace(new_alloc_info->alloc_backtrace, 166 sizeof(new_alloc_info->alloc_backtrace)); 167 if (file) { 168 new_alloc_info->file = strdup(file); 169 } else { 170 new_alloc_info->file = NULL; 171 } 172 new_alloc_info->line = line; 173 if (func) { 174 new_alloc_info->func = strdup(func); 175 } else { 176 new_alloc_info->func = NULL; 177 } 178 new_alloc_info->next = ctx->impl->alloc_info; 179 ctx->impl->alloc_info = new_alloc_info; 180 } 181 CRITICAL_SECTION_LEAVE(grn_alloc_info_lock); 182 } 183 184 inline static void 185 grn_alloc_info_change(void *old_address, void *new_address, size_t size) 186 { 187 grn_ctx *ctx; 188 grn_alloc_info *alloc_info; 189 190 ctx = &grn_gctx; 191 if (!ctx->impl) { return; } 192 193 CRITICAL_SECTION_ENTER(grn_alloc_info_lock); 194 alloc_info = ctx->impl->alloc_info; 195 for (; alloc_info; alloc_info = alloc_info->next) { 196 if (alloc_info->address == old_address) { 197 alloc_info->address = new_address; 198 alloc_info->size = size; 199 grn_alloc_info_set_backtrace(alloc_info->alloc_backtrace, 200 sizeof(alloc_info->alloc_backtrace)); 201 } 202 } 203 CRITICAL_SECTION_LEAVE(grn_alloc_info_lock); 204 } 205 206 void 207 grn_alloc_info_dump(grn_ctx *ctx) 208 { 209 int i = 0; 210 grn_alloc_info *alloc_info; 211 212 if (!ctx) { return; } 213 if (!ctx->impl) { return; } 214 215 alloc_info = ctx->impl->alloc_info; 216 for (; alloc_info; alloc_info = alloc_info->next) { 217 if (alloc_info->freed) { 218 printf("address[%d][freed]: %p(%" GRN_FMT_SIZE ")\n", 219 i, alloc_info->address, alloc_info->size); 220 } else { 221 printf("address[%d][not-freed]: %p(%" GRN_FMT_SIZE "): %s:%d: %s()\n%s", 222 i, 223 alloc_info->address, 224 alloc_info->size, 225 alloc_info->file ? alloc_info->file : "(unknown)", 226 alloc_info->line, 227 alloc_info->func ? alloc_info->func : "(unknown)", 228 alloc_info->alloc_backtrace); 229 } 230 i++; 231 } 232 } 233 234 inline static void 235 grn_alloc_info_check(grn_ctx *ctx, void *address) 236 { 237 grn_alloc_info *alloc_info; 238 239 if (!grn_gctx.impl) { return; } 240 /* grn_alloc_info_dump(ctx); */ 241 242 CRITICAL_SECTION_ENTER(grn_alloc_info_lock); 243 alloc_info = grn_gctx.impl->alloc_info; 244 for (; alloc_info; alloc_info = alloc_info->next) { 245 if (alloc_info->address == address) { 246 if (alloc_info->freed) { 247 GRN_LOG(ctx, GRN_LOG_WARNING, 248 "double free: %p(%" GRN_FMT_SIZE "):\n" 249 "alloc backtrace:\n" 250 "%sfree backtrace:\n" 251 "%s", 252 alloc_info->address, 253 alloc_info->size, 254 alloc_info->alloc_backtrace, 255 alloc_info->free_backtrace); 256 } else { 257 alloc_info->freed = GRN_TRUE; 258 grn_alloc_info_set_backtrace(alloc_info->free_backtrace, 259 sizeof(alloc_info->free_backtrace)); 260 } 261 break; 262 } 263 } 264 CRITICAL_SECTION_LEAVE(grn_alloc_info_lock); 265 } 266 267 void 268 grn_alloc_info_free(grn_ctx *ctx) 269 { 270 grn_alloc_info *alloc_info; 271 272 if (!ctx) { return; } 273 if (!ctx->impl) { return; } 274 275 alloc_info = ctx->impl->alloc_info; 276 while (alloc_info) { 277 grn_alloc_info *current_alloc_info = alloc_info; 278 alloc_info = alloc_info->next; 279 current_alloc_info->next = NULL; 280 free(current_alloc_info->file); 281 free(current_alloc_info->func); 282 free(current_alloc_info); 283 } 284 ctx->impl->alloc_info = NULL; 285 } 286 287 #else /* USE_MEMORY_DEBUG */ 288 void 289 grn_alloc_info_init(void) 290 { 291 } 292 293 void 294 grn_alloc_info_fin(void) 295 { 296 } 297 298 # define grn_alloc_info_add(address, size, file, line, func) 299 # define grn_alloc_info_change(old_address, new_address, size) 300 # define grn_alloc_info_check(ctx, address) 301 302 void 303 grn_alloc_info_dump(grn_ctx *ctx) 304 { 305 } 306 307 void 308 grn_alloc_info_free(grn_ctx *ctx) 309 { 310 } 311 #endif /* USE_MEMORY_DEBUG */ 312 313 #define GRN_CTX_SEGMENT_SIZE (1<<22) 314 #define GRN_CTX_SEGMENT_MASK (GRN_CTX_SEGMENT_SIZE - 1) 315 316 #define GRN_CTX_SEGMENT_WORD (1<<31) 317 #define GRN_CTX_SEGMENT_VLEN (1<<30) 318 #define GRN_CTX_SEGMENT_LIFO (1<<29) 319 #define GRN_CTX_SEGMENT_DIRTY (1<<28) 320 321 void 322 grn_alloc_init_ctx_impl(grn_ctx *ctx) 323 { 324 #ifdef USE_DYNAMIC_MALLOC_CHANGE 325 # ifdef USE_FAIL_MALLOC 326 ctx->impl->malloc_func = grn_malloc_fail; 327 ctx->impl->calloc_func = grn_calloc_fail; 328 ctx->impl->realloc_func = grn_realloc_fail; 329 ctx->impl->strdup_func = grn_strdup_fail; 330 # else 331 ctx->impl->malloc_func = grn_malloc_default; 332 ctx->impl->calloc_func = grn_calloc_default; 333 ctx->impl->realloc_func = grn_realloc_default; 334 ctx->impl->strdup_func = grn_strdup_default; 335 # endif 336 #endif 337 338 #ifdef USE_MEMORY_DEBUG 339 ctx->impl->alloc_info = NULL; 340 #endif 341 } 342 343 void 344 grn_alloc_fin_ctx_impl(grn_ctx *ctx) 345 { 346 int i; 347 grn_io_mapinfo *mi; 348 for (i = 0, mi = ctx->impl->segs; i < GRN_CTX_N_SEGMENTS; i++, mi++) { 349 if (mi->map) { 350 //GRN_LOG(ctx, GRN_LOG_NOTICE, "unmap in ctx_fin(%d,%d,%d)", i, (mi->count & GRN_CTX_SEGMENT_MASK), mi->nref); 351 if (mi->count & GRN_CTX_SEGMENT_VLEN) { 352 grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize); 353 } else { 354 grn_io_anon_unmap(ctx, mi, GRN_CTX_SEGMENT_SIZE); 355 } 356 } 357 } 358 } 359 360 #define ALIGN_SIZE (1<<3) 361 #define ALIGN_MASK (ALIGN_SIZE-1) 362 #define GRN_CTX_ALLOC_CLEAR 1 363 364 static void * 365 grn_ctx_alloc(grn_ctx *ctx, size_t size, int flags, 366 const char* file, int line, const char *func) 367 { 368 void *res = NULL; 369 if (!ctx) { return res; } 370 if (!ctx->impl) { 371 if (ERRP(ctx, GRN_ERROR)) { return res; } 372 } 373 CRITICAL_SECTION_ENTER(ctx->impl->lock); 374 { 375 int32_t i; 376 int32_t *header; 377 grn_io_mapinfo *mi; 378 size = ((size + ALIGN_MASK) & ~ALIGN_MASK) + ALIGN_SIZE; 379 if (size > GRN_CTX_SEGMENT_SIZE) { 380 uint64_t npages = (size + (grn_pagesize - 1)) / grn_pagesize; 381 size_t aligned_size; 382 if (npages >= (1LL<<32)) { 383 MERR("too long request size=%" GRN_FMT_SIZE, size); 384 goto exit; 385 } 386 for (i = 0, mi = ctx->impl->segs;; i++, mi++) { 387 if (i >= GRN_CTX_N_SEGMENTS) { 388 MERR("all segments are full"); 389 goto exit; 390 } 391 if (!mi->map) { break; } 392 } 393 aligned_size = grn_pagesize * ((size_t)npages); 394 if (!grn_io_anon_map(ctx, mi, aligned_size)) { goto exit; } 395 /* GRN_LOG(ctx, GRN_LOG_NOTICE, "map i=%d (%d)", i, npages * grn_pagesize); */ 396 mi->nref = (uint32_t) npages; 397 mi->count = GRN_CTX_SEGMENT_VLEN; 398 ctx->impl->currseg = -1; 399 header = mi->map; 400 header[0] = i; 401 header[1] = (int32_t) size; 402 } else { 403 i = ctx->impl->currseg; 404 mi = &ctx->impl->segs[i]; 405 if (i < 0 || size + mi->nref > GRN_CTX_SEGMENT_SIZE) { 406 for (i = 0, mi = ctx->impl->segs;; i++, mi++) { 407 if (i >= GRN_CTX_N_SEGMENTS) { 408 MERR("all segments are full"); 409 goto exit; 410 } 411 if (!mi->map) { break; } 412 } 413 if (!grn_io_anon_map(ctx, mi, GRN_CTX_SEGMENT_SIZE)) { goto exit; } 414 /* GRN_LOG(ctx, GRN_LOG_NOTICE, "map i=%d", i); */ 415 mi->nref = 0; 416 mi->count = GRN_CTX_SEGMENT_WORD; 417 ctx->impl->currseg = i; 418 } 419 header = (int32_t *)((byte *)mi->map + mi->nref); 420 mi->nref += size; 421 mi->count++; 422 header[0] = i; 423 header[1] = (int32_t) size; 424 if ((flags & GRN_CTX_ALLOC_CLEAR) && 425 (mi->count & GRN_CTX_SEGMENT_DIRTY) && (size > ALIGN_SIZE)) { 426 memset(&header[2], 0, size - ALIGN_SIZE); 427 } 428 } 429 /* 430 { 431 char g = (ctx == &grn_gctx) ? 'g' : ' '; 432 GRN_LOG(ctx, GRN_LOG_NOTICE, "+%c(%p) %s:%d(%s) (%d:%d)%p mi(%d:%d)", g, ctx, file, line, func, header[0], header[1], &header[2], mi->nref, (mi->count & GRN_CTX_SEGMENT_MASK)); 433 } 434 */ 435 res = &header[2]; 436 } 437 exit : 438 CRITICAL_SECTION_LEAVE(ctx->impl->lock); 439 return res; 440 } 441 442 void * 443 grn_ctx_malloc(grn_ctx *ctx, size_t size, 444 const char* file, int line, const char *func) 445 { 446 return grn_ctx_alloc(ctx, size, 0, file, line, func); 447 } 448 449 void * 450 grn_ctx_calloc(grn_ctx *ctx, size_t size, 451 const char* file, int line, const char *func) 452 { 453 return grn_ctx_alloc(ctx, size, GRN_CTX_ALLOC_CLEAR, file, line, func); 454 } 455 456 void * 457 grn_ctx_realloc(grn_ctx *ctx, void *ptr, size_t size, 458 const char* file, int line, const char *func) 459 { 460 void *res = NULL; 461 if (size) { 462 /* todo : expand if possible */ 463 res = grn_ctx_alloc(ctx, size, 0, file, line, func); 464 if (res && ptr) { 465 int32_t *header = &((int32_t *)ptr)[-2]; 466 size_t size_ = header[1]; 467 grn_memcpy(res, ptr, size_ > size ? size : size_); 468 grn_ctx_free(ctx, ptr, file, line, func); 469 } 470 } else { 471 grn_ctx_free(ctx, ptr, file, line, func); 472 } 473 return res; 474 } 475 476 char * 477 grn_ctx_strdup(grn_ctx *ctx, const char *s, 478 const char* file, int line, const char *func) 479 { 480 void *res = NULL; 481 if (s) { 482 size_t size = strlen(s) + 1; 483 if ((res = grn_ctx_alloc(ctx, size, 0, file, line, func))) { 484 grn_memcpy(res, s, size); 485 } 486 } 487 return res; 488 } 489 490 void 491 grn_ctx_free(grn_ctx *ctx, void *ptr, 492 const char* file, int line, const char *func) 493 { 494 if (!ctx) { return; } 495 if (!ctx->impl) { 496 ERR(GRN_INVALID_ARGUMENT,"ctx without impl passed."); 497 return; 498 } 499 CRITICAL_SECTION_ENTER(ctx->impl->lock); 500 if (ptr) { 501 int32_t *header = &((int32_t *)ptr)[-2]; 502 503 if (header[0] >= GRN_CTX_N_SEGMENTS) { 504 ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed. ptr=%p seg=%d", ptr, *header); 505 goto exit; 506 } 507 /* 508 { 509 int32_t i = header[0]; 510 char c = 'X', g = (ctx == &grn_gctx) ? 'g' : ' '; 511 grn_io_mapinfo *mi = &ctx->impl->segs[i]; 512 if (!(mi->count & GRN_CTX_SEGMENT_VLEN) && 513 mi->map <= (void *)header && (char *)header < ((char *)mi->map + GRN_CTX_SEGMENT_SIZE)) { c = '-'; } 514 GRN_LOG(ctx, GRN_LOG_NOTICE, "%c%c(%p) %s:%d(%s) (%d:%d)%p mi(%d:%d)", c, g, ctx, file, line, func, header[0], header[1], &header[2], mi->nref, (mi->count & GRN_CTX_SEGMENT_MASK)); 515 } 516 */ 517 { 518 int32_t i = header[0]; 519 grn_io_mapinfo *mi = &ctx->impl->segs[i]; 520 if (mi->count & GRN_CTX_SEGMENT_VLEN) { 521 if (mi->map != header) { 522 ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed.. ptr=%p seg=%d", ptr, i); 523 goto exit; 524 } 525 //GRN_LOG(ctx, GRN_LOG_NOTICE, "umap i=%d (%d)", i, mi->nref * grn_pagesize); 526 grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize); 527 mi->map = NULL; 528 } else { 529 if (!mi->map) { 530 ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed... ptr=%p seg=%d", ptr, i); 531 goto exit; 532 } 533 mi->count--; 534 if (!(mi->count & GRN_CTX_SEGMENT_MASK)) { 535 //GRN_LOG(ctx, GRN_LOG_NOTICE, "umap i=%d", i); 536 if (i == ctx->impl->currseg) { 537 mi->count |= GRN_CTX_SEGMENT_DIRTY; 538 mi->nref = 0; 539 } else { 540 grn_io_anon_unmap(ctx, mi, GRN_CTX_SEGMENT_SIZE); 541 mi->map = NULL; 542 } 543 } 544 } 545 } 546 } 547 exit : 548 CRITICAL_SECTION_LEAVE(ctx->impl->lock); 549 } 550 551 void * 552 grn_ctx_alloc_lifo(grn_ctx *ctx, size_t size, 553 const char* file, int line, const char *func) 554 { 555 if (!ctx) { return NULL; } 556 if (!ctx->impl) { 557 if (ERRP(ctx, GRN_ERROR)) { return NULL; } 558 } 559 { 560 int32_t i = ctx->impl->lifoseg; 561 grn_io_mapinfo *mi = &ctx->impl->segs[i]; 562 if (size > GRN_CTX_SEGMENT_SIZE) { 563 uint64_t npages = (size + (grn_pagesize - 1)) / grn_pagesize; 564 size_t aligned_size; 565 if (npages >= (1LL<<32)) { 566 MERR("too long request size=%" GRN_FMT_SIZE, size); 567 return NULL; 568 } 569 for (;;) { 570 if (++i >= GRN_CTX_N_SEGMENTS) { 571 MERR("all segments are full"); 572 return NULL; 573 } 574 mi++; 575 if (!mi->map) { break; } 576 } 577 aligned_size = grn_pagesize * ((size_t)npages); 578 if (!grn_io_anon_map(ctx, mi, aligned_size)) { return NULL; } 579 mi->nref = (uint32_t) npages; 580 mi->count = GRN_CTX_SEGMENT_VLEN|GRN_CTX_SEGMENT_LIFO; 581 ctx->impl->lifoseg = i; 582 return mi->map; 583 } else { 584 size = (size + ALIGN_MASK) & ~ALIGN_MASK; 585 if (i < 0 || (mi->count & GRN_CTX_SEGMENT_VLEN) || size + mi->nref > GRN_CTX_SEGMENT_SIZE) { 586 for (;;) { 587 if (++i >= GRN_CTX_N_SEGMENTS) { 588 MERR("all segments are full"); 589 return NULL; 590 } 591 if (!(++mi)->map) { break; } 592 } 593 if (!grn_io_anon_map(ctx, mi, GRN_CTX_SEGMENT_SIZE)) { return NULL; } 594 mi->nref = 0; 595 mi->count = GRN_CTX_SEGMENT_WORD|GRN_CTX_SEGMENT_LIFO; 596 ctx->impl->lifoseg = i; 597 } 598 { 599 uint32_t u = mi->nref; 600 mi->nref += size; 601 return (byte *)mi->map + u; 602 } 603 } 604 } 605 } 606 607 void 608 grn_ctx_free_lifo(grn_ctx *ctx, void *ptr, 609 const char* file, int line, const char *func) 610 { 611 if (!ctx) { return; } 612 if (!ctx->impl) { 613 ERR(GRN_INVALID_ARGUMENT,"ctx without impl passed."); 614 return; 615 } 616 { 617 int32_t i = ctx->impl->lifoseg, done = 0; 618 grn_io_mapinfo *mi = &ctx->impl->segs[i]; 619 if (i < 0) { 620 ERR(GRN_INVALID_ARGUMENT, "lifo buffer is void"); 621 return; 622 } 623 for (; i >= 0; i--, mi--) { 624 if (!(mi->count & GRN_CTX_SEGMENT_LIFO)) { continue; } 625 if (done) { break; } 626 if (mi->count & GRN_CTX_SEGMENT_VLEN) { 627 if (mi->map == ptr) { done = 1; } 628 grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize); 629 mi->map = NULL; 630 } else { 631 if (mi->map == ptr) { 632 done = 1; 633 } else { 634 if (mi->map < ptr && ptr < (void *)((byte*)mi->map + mi->nref)) { 635 mi->nref = (uint32_t) ((uintptr_t)ptr - (uintptr_t)mi->map); 636 break; 637 } 638 } 639 grn_io_anon_unmap(ctx, mi, GRN_CTX_SEGMENT_SIZE); 640 mi->map = NULL; 641 } 642 } 643 ctx->impl->lifoseg = i; 644 } 645 } 646 647 #if defined(USE_DYNAMIC_MALLOC_CHANGE) 648 grn_malloc_func 649 grn_ctx_get_malloc(grn_ctx *ctx) 650 { 651 if (!ctx || !ctx->impl) { return NULL; } 652 return ctx->impl->malloc_func; 653 } 654 655 void 656 grn_ctx_set_malloc(grn_ctx *ctx, grn_malloc_func malloc_func) 657 { 658 if (!ctx || !ctx->impl) { return; } 659 ctx->impl->malloc_func = malloc_func; 660 } 661 662 grn_calloc_func 663 grn_ctx_get_calloc(grn_ctx *ctx) 664 { 665 if (!ctx || !ctx->impl) { return NULL; } 666 return ctx->impl->calloc_func; 667 } 668 669 void 670 grn_ctx_set_calloc(grn_ctx *ctx, grn_calloc_func calloc_func) 671 { 672 if (!ctx || !ctx->impl) { return; } 673 ctx->impl->calloc_func = calloc_func; 674 } 675 676 grn_realloc_func 677 grn_ctx_get_realloc(grn_ctx *ctx) 678 { 679 if (!ctx || !ctx->impl) { return NULL; } 680 return ctx->impl->realloc_func; 681 } 682 683 void 684 grn_ctx_set_realloc(grn_ctx *ctx, grn_realloc_func realloc_func) 685 { 686 if (!ctx || !ctx->impl) { return; } 687 ctx->impl->realloc_func = realloc_func; 688 } 689 690 grn_strdup_func 691 grn_ctx_get_strdup(grn_ctx *ctx) 692 { 693 if (!ctx || !ctx->impl) { return NULL; } 694 return ctx->impl->strdup_func; 695 } 696 697 void 698 grn_ctx_set_strdup(grn_ctx *ctx, grn_strdup_func strdup_func) 699 { 700 if (!ctx || !ctx->impl) { return; } 701 ctx->impl->strdup_func = strdup_func; 702 } 703 704 grn_free_func 705 grn_ctx_get_free(grn_ctx *ctx) 706 { 707 if (!ctx || !ctx->impl) { return NULL; } 708 return ctx->impl->free_func; 709 } 710 711 void 712 grn_ctx_set_free(grn_ctx *ctx, grn_free_func free_func) 713 { 714 if (!ctx || !ctx->impl) { return; } 715 ctx->impl->free_func = free_func; 716 } 717 718 void * 719 grn_malloc(grn_ctx *ctx, size_t size, 720 const char* file, int line, const char *func) 721 { 722 if (ctx && ctx->impl && ctx->impl->malloc_func) { 723 return ctx->impl->malloc_func(ctx, size, file, line, func); 724 } else { 725 return grn_malloc_default(ctx, size, file, line, func); 726 } 727 } 728 729 void * 730 grn_calloc(grn_ctx *ctx, size_t size, 731 const char* file, int line, const char *func) 732 { 733 if (ctx && ctx->impl && ctx->impl->calloc_func) { 734 return ctx->impl->calloc_func(ctx, size, file, line, func); 735 } else { 736 return grn_calloc_default(ctx, size, file, line, func); 737 } 738 } 739 740 void * 741 grn_realloc(grn_ctx *ctx, void *ptr, size_t size, 742 const char* file, int line, const char *func) 743 { 744 if (ctx && ctx->impl && ctx->impl->realloc_func) { 745 return ctx->impl->realloc_func(ctx, ptr, size, file, line, func); 746 } else { 747 return grn_realloc_default(ctx, ptr, size, file, line, func); 748 } 749 } 750 751 char * 752 grn_strdup(grn_ctx *ctx, const char *string, 753 const char* file, int line, const char *func) 754 { 755 if (ctx && ctx->impl && ctx->impl->strdup_func) { 756 return ctx->impl->strdup_func(ctx, string, file, line, func); 757 } else { 758 return grn_strdup_default(ctx, string, file, line, func); 759 } 760 } 761 762 void 763 grn_free(grn_ctx *ctx, void *ptr, 764 const char* file, int line, const char *func) 765 { 766 if (ctx && ctx->impl && ctx->impl->free_func) { 767 return ctx->impl->free_func(ctx, ptr, file, line, func); 768 } else { 769 return grn_free_default(ctx, ptr, file, line, func); 770 } 771 } 772 #endif 773 774 void * 775 grn_malloc_default(grn_ctx *ctx, size_t size, 776 const char* file, int line, const char *func) 777 { 778 if (!ctx) { return NULL; } 779 { 780 void *res = malloc(size); 781 if (res) { 782 GRN_ADD_ALLOC_COUNT(1); 783 grn_alloc_info_add(res, size, file, line, func); 784 } else { 785 if (!(res = malloc(size))) { 786 MERR("malloc fail (%" GRN_FMT_SIZE ")=%p (%s:%d) <%d>", 787 size, res, file, line, alloc_count); 788 } else { 789 GRN_ADD_ALLOC_COUNT(1); 790 grn_alloc_info_add(res, size, file, line, func); 791 } 792 } 793 return res; 794 } 795 } 796 797 void * 798 grn_calloc_default(grn_ctx *ctx, size_t size, 799 const char* file, int line, const char *func) 800 { 801 if (!ctx) { return NULL; } 802 { 803 void *res = calloc(size, 1); 804 if (res) { 805 GRN_ADD_ALLOC_COUNT(1); 806 grn_alloc_info_add(res, size, file, line, func); 807 } else { 808 if (!(res = calloc(size, 1))) { 809 MERR("calloc fail (%" GRN_FMT_SIZE ")=%p (%s:%d) <%d>", 810 size, res, file, line, alloc_count); 811 } else { 812 GRN_ADD_ALLOC_COUNT(1); 813 grn_alloc_info_add(res, size, file, line, func); 814 } 815 } 816 return res; 817 } 818 } 819 820 void 821 grn_free_default(grn_ctx *ctx, void *ptr, 822 const char* file, int line, const char *func) 823 { 824 if (!ctx) { return; } 825 grn_alloc_info_check(ctx, ptr); 826 { 827 free(ptr); 828 if (ptr) { 829 GRN_ADD_ALLOC_COUNT(-1); 830 } else { 831 GRN_LOG(ctx, GRN_LOG_ALERT, "free fail (%p) (%s:%d) <%d>", 832 ptr, file, line, alloc_count); 833 } 834 } 835 } 836 837 void * 838 grn_realloc_default(grn_ctx *ctx, void *ptr, size_t size, 839 const char* file, int line, const char *func) 840 { 841 void *res; 842 if (!ctx) { return NULL; } 843 if (size) { 844 if (!(res = realloc(ptr, size))) { 845 if (!(res = realloc(ptr, size))) { 846 MERR("realloc fail (%p,%" GRN_FMT_SIZE ")=%p (%s:%d) <%d>", 847 ptr, size, res, file, line, alloc_count); 848 return NULL; 849 } 850 } 851 if (ptr) { 852 grn_alloc_info_change(ptr, res, size); 853 } else { 854 GRN_ADD_ALLOC_COUNT(1); 855 grn_alloc_info_add(res, size, file, line, func); 856 } 857 } else { 858 if (!ptr) { return NULL; } 859 grn_alloc_info_check(ctx, ptr); 860 GRN_ADD_ALLOC_COUNT(-1); 861 free(ptr); 862 res = NULL; 863 } 864 return res; 865 } 866 867 int 868 grn_alloc_count(void) 869 { 870 return alloc_count; 871 } 872 873 char * 874 grn_strdup_default(grn_ctx *ctx, const char *s, 875 const char* file, int line, const char *func) 876 { 877 if (!ctx) { return NULL; } 878 { 879 char *res = grn_strdup_raw(s); 880 if (res) { 881 GRN_ADD_ALLOC_COUNT(1); 882 grn_alloc_info_add(res, strlen(res) + 1, file, line, func); 883 } else { 884 if (!(res = grn_strdup_raw(s))) { 885 MERR("strdup(%p)=%p (%s:%d) <%d>", s, res, file, line, alloc_count); 886 } else { 887 GRN_ADD_ALLOC_COUNT(1); 888 grn_alloc_info_add(res, strlen(res) + 1, file, line, func); 889 } 890 } 891 return res; 892 } 893 } 894 895 #ifdef USE_FAIL_MALLOC 896 int 897 grn_fail_malloc_check(size_t size, 898 const char *file, int line, const char *func) 899 { 900 if ((grn_fmalloc_file && strcmp(file, grn_fmalloc_file)) || 901 (grn_fmalloc_line && line != grn_fmalloc_line) || 902 (grn_fmalloc_func && strcmp(func, grn_fmalloc_func))) { 903 return 1; 904 } 905 if (grn_fmalloc_prob && grn_fmalloc_prob >= rand()) { 906 return 0; 907 } 908 return 1; 909 } 910 911 void * 912 grn_malloc_fail(grn_ctx *ctx, size_t size, 913 const char* file, int line, const char *func) 914 { 915 if (grn_fail_malloc_check(size, file, line, func)) { 916 return grn_malloc_default(ctx, size, file, line, func); 917 } else { 918 MERR("fail_malloc (%" GRN_FMT_SIZE ") (%s:%d@%s) <%d>", 919 size, file, line, func, alloc_count); 920 return NULL; 921 } 922 } 923 924 void * 925 grn_calloc_fail(grn_ctx *ctx, size_t size, 926 const char* file, int line, const char *func) 927 { 928 if (grn_fail_malloc_check(size, file, line, func)) { 929 return grn_calloc_default(ctx, size, file, line, func); 930 } else { 931 MERR("fail_calloc (%" GRN_FMT_SIZE ") (%s:%d@%s) <%d>", 932 size, file, line, func, alloc_count); 933 return NULL; 934 } 935 } 936 937 void * 938 grn_realloc_fail(grn_ctx *ctx, void *ptr, size_t size, 939 const char* file, int line, const char *func) 940 { 941 if (grn_fail_malloc_check(size, file, line, func)) { 942 return grn_realloc_default(ctx, ptr, size, file, line, func); 943 } else { 944 MERR("fail_realloc (%p,%" GRN_FMT_SIZE ") (%s:%d@%s) <%d>", 945 ptr, size, file, line, func, alloc_count); 946 return NULL; 947 } 948 } 949 950 char * 951 grn_strdup_fail(grn_ctx *ctx, const char *s, 952 const char* file, int line, const char *func) 953 { 954 if (grn_fail_malloc_check(strlen(s), file, line, func)) { 955 return grn_strdup_default(ctx, s, file, line, func); 956 } else { 957 MERR("fail_strdup(%p) (%s:%d@%s) <%d>", s, file, line, func, alloc_count); 958 return NULL; 959 } 960 } 961 #endif /* USE_FAIL_MALLOC */ 962