1 #include <stdlib.h>
2 #include <assert.h>
3 
4 #include "nvim/lib/ringbuf.h"
5 
6 enum { RB_SIZE = 1024 };
7 
8 typedef struct {
9   void *ptr;
10   size_t size;
11 } AllocRecord;
12 
13 RINGBUF_TYPEDEF(AllocRecords, AllocRecord)
14 RINGBUF_INIT(AllocRecords, arecs, AllocRecord, RINGBUF_DUMMY_FREE)
15 RINGBUF_STATIC(static, AllocRecords, AllocRecord, arecs, RB_SIZE)
16 
17 size_t allocated_memory = 0;
18 size_t ever_allocated_memory = 0;
19 
20 size_t allocated_memory_limit = SIZE_MAX;
21 
xmalloc(const size_t size)22 void *xmalloc(const size_t size)
23 {
24   void *ret = malloc(size);
25   allocated_memory += size;
26   ever_allocated_memory += size;
27   assert(allocated_memory <= allocated_memory_limit);
28   assert(arecs_rb_length(&arecs) < RB_SIZE);
29   arecs_rb_push(&arecs, (AllocRecord) {
30     .ptr = ret,
31     .size = size,
32   });
33   return ret;
34 }
35 
xfree(void * const p)36 void xfree(void *const p)
37 {
38   if (p == NULL) {
39     return;
40   }
41   RINGBUF_FORALL(&arecs, AllocRecord, arec) {
42     if (arec->ptr == p) {
43       allocated_memory -= arec->size;
44       arecs_rb_remove(&arecs, arecs_rb_find_idx(&arecs, arec));
45       return;
46     }
47   }
48   abort();
49 }
50 
xrealloc(void * const p,size_t new_size)51 void *xrealloc(void *const p, size_t new_size)
52 {
53   void *ret = realloc(p, new_size);
54   RINGBUF_FORALL(&arecs, AllocRecord, arec) {
55     if (arec->ptr == p) {
56       allocated_memory -= arec->size;
57       allocated_memory += new_size;
58       if (new_size > arec->size) {
59         ever_allocated_memory += (new_size - arec->size);
60       }
61       arec->ptr = ret;
62       arec->size = new_size;
63       return ret;
64     }
65   }
66   abort();
67   return (void *)(intptr_t)1;
68 }
69 
xstrdup(const char * str)70 char *xstrdup(const char *str)
71   FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
72   FUNC_ATTR_NONNULL_ALL
73 {
74   return xmemdupz(str, strlen(str));
75 }
76 
xmallocz(size_t size)77 void *xmallocz(size_t size)
78   FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
79 {
80   size_t total_size = size + 1;
81   assert(total_size > size);
82 
83   void *ret = xmalloc(total_size);
84   ((char *)ret)[size] = 0;
85 
86   return ret;
87 }
88 
xstpcpy(char * restrict dst,const char * restrict src)89 char *xstpcpy(char *restrict dst, const char *restrict src)
90   FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
91 {
92   const size_t len = strlen(src);
93   return (char *)memcpy(dst, src, len + 1) + len;
94 }
95 
xmemdupz(const void * data,size_t len)96 void *xmemdupz(const void *data, size_t len)
97   FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
98   FUNC_ATTR_NONNULL_ALL
99 {
100   return memcpy(xmallocz(len), data, len);
101 }
102