]> git.proxmox.com Git - libgit2.git/blob - src/pool.c
treebuilder: fix memory leaks in `write_with_buffer`
[libgit2.git] / src / pool.c
1 #include "pool.h"
2 #include "posix.h"
3 #ifndef GIT_WIN32
4 #include <unistd.h>
5 #endif
6
7 struct git_pool_page {
8 git_pool_page *next;
9 uint32_t size;
10 uint32_t avail;
11 GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8);
12 };
13
14 static void *pool_alloc_page(git_pool *pool, uint32_t size);
15
16 uint32_t git_pool__system_page_size(void)
17 {
18 static uint32_t size = 0;
19
20 if (!size) {
21 size_t page_size;
22 if (git__page_size(&page_size) < 0)
23 page_size = 4096;
24 /* allow space for malloc overhead */
25 size = page_size - (2 * sizeof(void *)) - sizeof(git_pool_page);
26 }
27
28 return size;
29 }
30
31 #ifndef GIT_DEBUG_POOL
32 void git_pool_init(git_pool *pool, uint32_t item_size)
33 {
34 assert(pool);
35 assert(item_size >= 1);
36
37 memset(pool, 0, sizeof(git_pool));
38 pool->item_size = item_size;
39 pool->page_size = git_pool__system_page_size();
40 }
41
42 void git_pool_clear(git_pool *pool)
43 {
44 git_pool_page *scan, *next;
45
46 for (scan = pool->pages; scan != NULL; scan = next) {
47 next = scan->next;
48 git__free(scan);
49 }
50
51 pool->pages = NULL;
52 }
53
54 static void *pool_alloc_page(git_pool *pool, uint32_t size)
55 {
56 git_pool_page *page;
57 const uint32_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
58 size_t alloc_size;
59
60 if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
61 !(page = git__malloc(alloc_size)))
62 return NULL;
63
64 page->size = new_page_size;
65 page->avail = new_page_size - size;
66 page->next = pool->pages;
67
68 pool->pages = page;
69
70 return page->data;
71 }
72
73 static void *pool_alloc(git_pool *pool, uint32_t size)
74 {
75 git_pool_page *page = pool->pages;
76 void *ptr = NULL;
77
78 if (!page || page->avail < size)
79 return pool_alloc_page(pool, size);
80
81 ptr = &page->data[page->size - page->avail];
82 page->avail -= size;
83
84 return ptr;
85 }
86
87 uint32_t git_pool__open_pages(git_pool *pool)
88 {
89 uint32_t ct = 0;
90 git_pool_page *scan;
91 for (scan = pool->pages; scan != NULL; scan = scan->next) ct++;
92 return ct;
93 }
94
95 bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
96 {
97 git_pool_page *scan;
98 for (scan = pool->pages; scan != NULL; scan = scan->next)
99 if ((void *)scan->data <= ptr &&
100 (void *)(((char *)scan->data) + scan->size) > ptr)
101 return true;
102 return false;
103 }
104
105 #else
106
107 static int git_pool__ptr_cmp(const void * a, const void * b)
108 {
109 if(a > b) {
110 return 1;
111 }
112 if(a < b) {
113 return -1;
114 }
115 else {
116 return 0;
117 }
118 }
119
120 void git_pool_init(git_pool *pool, uint32_t item_size)
121 {
122 assert(pool);
123 assert(item_size >= 1);
124
125 memset(pool, 0, sizeof(git_pool));
126 pool->item_size = item_size;
127 pool->page_size = git_pool__system_page_size();
128 git_vector_init(&pool->allocations, 100, git_pool__ptr_cmp);
129 }
130
131 void git_pool_clear(git_pool *pool)
132 {
133 git_vector_free_deep(&pool->allocations);
134 }
135
136 static void *pool_alloc(git_pool *pool, uint32_t size) {
137 void *ptr = NULL;
138 if((ptr = git__malloc(size)) == NULL) {
139 return NULL;
140 }
141 git_vector_insert_sorted(&pool->allocations, ptr, NULL);
142 return ptr;
143 }
144
145 bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
146 {
147 size_t pos;
148 return git_vector_bsearch(&pos, &pool->allocations, ptr) != GIT_ENOTFOUND;
149 }
150 #endif
151
152 void git_pool_swap(git_pool *a, git_pool *b)
153 {
154 git_pool temp;
155
156 if (a == b)
157 return;
158
159 memcpy(&temp, a, sizeof(temp));
160 memcpy(a, b, sizeof(temp));
161 memcpy(b, &temp, sizeof(temp));
162 }
163
164 static uint32_t alloc_size(git_pool *pool, uint32_t count)
165 {
166 const uint32_t align = sizeof(void *) - 1;
167
168 if (pool->item_size > 1) {
169 const uint32_t item_size = (pool->item_size + align) & ~align;
170 return item_size * count;
171 }
172
173 return (count + align) & ~align;
174 }
175
176 void *git_pool_malloc(git_pool *pool, uint32_t items)
177 {
178 return pool_alloc(pool, alloc_size(pool, items));
179 }
180
181 void *git_pool_mallocz(git_pool *pool, uint32_t items)
182 {
183 const uint32_t size = alloc_size(pool, items);
184 void *ptr = pool_alloc(pool, size);
185 if (ptr)
186 memset(ptr, 0x0, size);
187 return ptr;
188 }
189
190 char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
191 {
192 char *ptr = NULL;
193
194 assert(pool && str && pool->item_size == sizeof(char));
195
196 if ((uint32_t)(n + 1) < n)
197 return NULL;
198
199 if ((ptr = git_pool_malloc(pool, (uint32_t)(n + 1))) != NULL) {
200 memcpy(ptr, str, n);
201 ptr[n] = '\0';
202 }
203
204 return ptr;
205 }
206
207 char *git_pool_strdup(git_pool *pool, const char *str)
208 {
209 assert(pool && str && pool->item_size == sizeof(char));
210 return git_pool_strndup(pool, str, strlen(str));
211 }
212
213 char *git_pool_strdup_safe(git_pool *pool, const char *str)
214 {
215 return str ? git_pool_strdup(pool, str) : NULL;
216 }
217
218 char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
219 {
220 void *ptr;
221 size_t len_a, len_b;
222
223 assert(pool && pool->item_size == sizeof(char));
224
225 len_a = a ? strlen(a) : 0;
226 len_b = b ? strlen(b) : 0;
227
228 if ((ptr = git_pool_malloc(pool, (uint32_t)(len_a + len_b + 1))) != NULL) {
229 if (len_a)
230 memcpy(ptr, a, len_a);
231 if (len_b)
232 memcpy(((char *)ptr) + len_a, b, len_b);
233 *(((char *)ptr) + len_a + len_b) = '\0';
234 }
235 return ptr;
236 }