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-1301 USA
17*/
18
19#include "grn.h"
20#include "grn_alloc.h"
21#include "grn_ctx_impl.h"
22
23static int alloc_count = 0;
24
25#ifdef USE_FAIL_MALLOC
26static int grn_fmalloc_prob = 0;
27static char *grn_fmalloc_func = NULL;
28static char *grn_fmalloc_file = NULL;
29static 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
43void
44grn_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
96static grn_critical_section grn_alloc_info_lock;
97
98void
99grn_alloc_info_init(void)
100{
101 CRITICAL_SECTION_INIT(grn_alloc_info_lock);
102}
103
104void
105grn_alloc_info_fin(void)
106{
107 CRITICAL_SECTION_FIN(grn_alloc_info_lock);
108}
109
110inline static void
111grn_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
149inline static void
150grn_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
184inline static void
185grn_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
206void
207grn_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
234inline static void
235grn_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
267void
268grn_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 */
288void
289grn_alloc_info_init(void)
290{
291}
292
293void
294grn_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
302void
303grn_alloc_info_dump(grn_ctx *ctx)
304{
305}
306
307void
308grn_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
321void
322grn_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
343void
344grn_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
364static void *
365grn_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 }
437exit :
438 CRITICAL_SECTION_LEAVE(ctx->impl->lock);
439 return res;
440}
441
442void *
443grn_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
449void *
450grn_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
456void *
457grn_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
476char *
477grn_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
490void
491grn_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 }
547exit :
548 CRITICAL_SECTION_LEAVE(ctx->impl->lock);
549}
550
551void *
552grn_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
607void
608grn_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)
648grn_malloc_func
649grn_ctx_get_malloc(grn_ctx *ctx)
650{
651 if (!ctx || !ctx->impl) { return NULL; }
652 return ctx->impl->malloc_func;
653}
654
655void
656grn_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
662grn_calloc_func
663grn_ctx_get_calloc(grn_ctx *ctx)
664{
665 if (!ctx || !ctx->impl) { return NULL; }
666 return ctx->impl->calloc_func;
667}
668
669void
670grn_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
676grn_realloc_func
677grn_ctx_get_realloc(grn_ctx *ctx)
678{
679 if (!ctx || !ctx->impl) { return NULL; }
680 return ctx->impl->realloc_func;
681}
682
683void
684grn_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
690grn_strdup_func
691grn_ctx_get_strdup(grn_ctx *ctx)
692{
693 if (!ctx || !ctx->impl) { return NULL; }
694 return ctx->impl->strdup_func;
695}
696
697void
698grn_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
704grn_free_func
705grn_ctx_get_free(grn_ctx *ctx)
706{
707 if (!ctx || !ctx->impl) { return NULL; }
708 return ctx->impl->free_func;
709}
710
711void
712grn_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
718void *
719grn_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
729void *
730grn_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
740void *
741grn_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
751char *
752grn_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
762void
763grn_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
774void *
775grn_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
797void *
798grn_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
820void
821grn_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
837void *
838grn_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
867int
868grn_alloc_count(void)
869{
870 return alloc_count;
871}
872
873char *
874grn_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
896int
897grn_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
911void *
912grn_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
924void *
925grn_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
937void *
938grn_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
950char *
951grn_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