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
grn_alloc_init_from_env(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
grn_alloc_info_init(void)99 grn_alloc_info_init(void)
100 {
101   CRITICAL_SECTION_INIT(grn_alloc_info_lock);
102 }
103 
104 void
grn_alloc_info_fin(void)105 grn_alloc_info_fin(void)
106 {
107   CRITICAL_SECTION_FIN(grn_alloc_info_lock);
108 }
109 
110 inline static void
grn_alloc_info_set_backtrace(char * buffer,size_t size)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
grn_alloc_info_add(void * address,size_t size,const char * file,int line,const char * func)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
grn_alloc_info_change(void * old_address,void * new_address,size_t size)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
grn_alloc_info_dump(grn_ctx * ctx)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
grn_alloc_info_check(grn_ctx * ctx,void * address)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
grn_alloc_info_free(grn_ctx * ctx)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
grn_alloc_info_init(void)289 grn_alloc_info_init(void)
290 {
291 }
292 
293 void
grn_alloc_info_fin(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
grn_alloc_info_dump(grn_ctx * ctx)303 grn_alloc_info_dump(grn_ctx *ctx)
304 {
305 }
306 
307 void
grn_alloc_info_free(grn_ctx * ctx)308 grn_alloc_info_free(grn_ctx *ctx)
309 {
310 }
311 #endif /* USE_MEMORY_DEBUG */
312 
313 #define GRN_CTX_SEGMENT_SIZE    (1U <<22)
314 #define GRN_CTX_SEGMENT_MASK    (GRN_CTX_SEGMENT_SIZE - 1)
315 
316 #define GRN_CTX_SEGMENT_WORD    (1U <<31)
317 #define GRN_CTX_SEGMENT_VLEN    (1U <<30)
318 #define GRN_CTX_SEGMENT_LIFO    (1U <<29)
319 #define GRN_CTX_SEGMENT_DIRTY   (1U <<28)
320 
321 void
grn_alloc_init_ctx_impl(grn_ctx * ctx)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
grn_alloc_fin_ctx_impl(grn_ctx * ctx)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 *
grn_ctx_alloc(grn_ctx * ctx,size_t size,int flags,const char * file,int line,const char * func)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       if ((i = ctx->impl->currseg) >= 0)
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 *
grn_ctx_malloc(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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 *
grn_ctx_calloc(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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 *
grn_ctx_realloc(grn_ctx * ctx,void * ptr,size_t size,const char * file,int line,const char * func)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 *
grn_ctx_strdup(grn_ctx * ctx,const char * s,const char * file,int line,const char * func)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
grn_ctx_free(grn_ctx * ctx,void * ptr,const char * file,int line,const char * func)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 *
grn_ctx_alloc_lifo(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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
grn_ctx_free_lifo(grn_ctx * ctx,void * ptr,const char * file,int line,const char * func)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
grn_ctx_get_malloc(grn_ctx * ctx)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
grn_ctx_set_malloc(grn_ctx * ctx,grn_malloc_func malloc_func)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
grn_ctx_get_calloc(grn_ctx * ctx)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
grn_ctx_set_calloc(grn_ctx * ctx,grn_calloc_func calloc_func)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
grn_ctx_get_realloc(grn_ctx * ctx)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
grn_ctx_set_realloc(grn_ctx * ctx,grn_realloc_func realloc_func)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
grn_ctx_get_strdup(grn_ctx * ctx)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
grn_ctx_set_strdup(grn_ctx * ctx,grn_strdup_func strdup_func)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
grn_ctx_get_free(grn_ctx * ctx)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
grn_ctx_set_free(grn_ctx * ctx,grn_free_func free_func)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 *
grn_malloc(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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 *
grn_calloc(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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 *
grn_realloc(grn_ctx * ctx,void * ptr,size_t size,const char * file,int line,const char * func)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 *
grn_strdup(grn_ctx * ctx,const char * string,const char * file,int line,const char * func)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
grn_free(grn_ctx * ctx,void * ptr,const char * file,int line,const char * func)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 *
grn_malloc_default(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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 *
grn_calloc_default(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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
grn_free_default(grn_ctx * ctx,void * ptr,const char * file,int line,const char * func)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 *
grn_realloc_default(grn_ctx * ctx,void * ptr,size_t size,const char * file,int line,const char * func)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
grn_alloc_count(void)868 grn_alloc_count(void)
869 {
870   return alloc_count;
871 }
872 
873 char *
grn_strdup_default(grn_ctx * ctx,const char * s,const char * file,int line,const char * func)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
grn_fail_malloc_check(size_t size,const char * file,int line,const char * func)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 *
grn_malloc_fail(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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 *
grn_calloc_fail(grn_ctx * ctx,size_t size,const char * file,int line,const char * func)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 *
grn_realloc_fail(grn_ctx * ctx,void * ptr,size_t size,const char * file,int line,const char * func)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 *
grn_strdup_fail(grn_ctx * ctx,const char * s,const char * file,int line,const char * func)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