File Coverage

deps/libgit2/src/util/pool.c
Criterion Covered Total %
statement 84 99 84.8
branch 32 66 48.4
condition n/a
subroutine n/a
pod n/a
total 116 165 70.3


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7              
8             #include "pool.h"
9              
10             #include "posix.h"
11             #ifndef GIT_WIN32
12             #include
13             #endif
14              
15             struct git_pool_page {
16             git_pool_page *next;
17             size_t size;
18             size_t avail;
19             GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8);
20             };
21              
22             static void *pool_alloc_page(git_pool *pool, size_t size);
23              
24             #ifndef GIT_DEBUG_POOL
25              
26             static size_t system_page_size = 0;
27              
28 87           int git_pool_global_init(void)
29             {
30 87 50         if (git__page_size(&system_page_size) < 0)
31 0           system_page_size = 4096;
32             /* allow space for malloc overhead */
33 87           system_page_size -= (2 * sizeof(void *)) + sizeof(git_pool_page);
34 87           return 0;
35             }
36              
37 3902           int git_pool_init(git_pool *pool, size_t item_size)
38             {
39 3902 50         GIT_ASSERT_ARG(pool);
40 3902 50         GIT_ASSERT_ARG(item_size >= 1);
41              
42 3902           memset(pool, 0, sizeof(git_pool));
43 3902           pool->item_size = item_size;
44 3902           pool->page_size = system_page_size;
45              
46 3902           return 0;
47             }
48              
49 4377           void git_pool_clear(git_pool *pool)
50             {
51             git_pool_page *scan, *next;
52              
53 5663 100         for (scan = pool->pages; scan != NULL; scan = next) {
54 1286           next = scan->next;
55 1286           git__free(scan);
56             }
57              
58 4377           pool->pages = NULL;
59 4377           }
60              
61 1286           static void *pool_alloc_page(git_pool *pool, size_t size)
62             {
63             git_pool_page *page;
64 1286           const size_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
65             size_t alloc_size;
66              
67 1286 50         if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
    50          
68 1286           !(page = git__malloc(alloc_size)))
69 0           return NULL;
70              
71 1286           page->size = new_page_size;
72 1286           page->avail = new_page_size - size;
73 1286           page->next = pool->pages;
74              
75 1286           pool->pages = page;
76              
77 1286           return page->data;
78             }
79              
80 4029           static void *pool_alloc(git_pool *pool, size_t size)
81             {
82 4029           git_pool_page *page = pool->pages;
83 4029           void *ptr = NULL;
84              
85 4029 100         if (!page || page->avail < size)
    50          
86 1286           return pool_alloc_page(pool, size);
87              
88 2743           ptr = &page->data[page->size - page->avail];
89 2743           page->avail -= size;
90              
91 2743           return ptr;
92             }
93              
94 0           uint32_t git_pool__open_pages(git_pool *pool)
95             {
96 0           uint32_t ct = 0;
97             git_pool_page *scan;
98 0 0         for (scan = pool->pages; scan != NULL; scan = scan->next) ct++;
99 0           return ct;
100             }
101              
102 0           bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
103             {
104             git_pool_page *scan;
105 0 0         for (scan = pool->pages; scan != NULL; scan = scan->next)
106 0 0         if ((void *)scan->data <= ptr &&
    0          
107 0           (void *)(((char *)scan->data) + scan->size) > ptr)
108 0           return true;
109 0           return false;
110             }
111              
112             #else
113              
114             int git_pool_global_init(void)
115             {
116             return 0;
117             }
118              
119             static int git_pool__ptr_cmp(const void * a, const void * b)
120             {
121             if(a > b) {
122             return 1;
123             }
124             if(a < b) {
125             return -1;
126             }
127             else {
128             return 0;
129             }
130             }
131              
132             int git_pool_init(git_pool *pool, size_t item_size)
133             {
134             GIT_ASSERT_ARG(pool);
135             GIT_ASSERT_ARG(item_size >= 1);
136              
137             memset(pool, 0, sizeof(git_pool));
138             pool->item_size = item_size;
139             pool->page_size = git_pool__system_page_size();
140             git_vector_init(&pool->allocations, 100, git_pool__ptr_cmp);
141              
142             return 0;
143             }
144              
145             void git_pool_clear(git_pool *pool)
146             {
147             git_vector_free_deep(&pool->allocations);
148             }
149              
150             static void *pool_alloc(git_pool *pool, size_t size) {
151             void *ptr = NULL;
152             if((ptr = git__malloc(size)) == NULL) {
153             return NULL;
154             }
155             git_vector_insert_sorted(&pool->allocations, ptr, NULL);
156             return ptr;
157             }
158              
159             bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
160             {
161             size_t pos;
162             return git_vector_bsearch(&pos, &pool->allocations, ptr) != GIT_ENOTFOUND;
163             }
164             #endif
165              
166 4           void git_pool_swap(git_pool *a, git_pool *b)
167             {
168             git_pool temp;
169              
170 4 50         if (a == b)
171 0           return;
172              
173 4           memcpy(&temp, a, sizeof(temp));
174 4           memcpy(a, b, sizeof(temp));
175 4           memcpy(b, &temp, sizeof(temp));
176             }
177              
178 4029           static size_t alloc_size(git_pool *pool, size_t count)
179             {
180 4029           const size_t align = sizeof(void *) - 1;
181              
182 4029 100         if (pool->item_size > 1) {
183 1204           const size_t item_size = (pool->item_size + align) & ~align;
184 1204           return item_size * count;
185             }
186              
187 2825           return (count + align) & ~align;
188             }
189              
190 3527           void *git_pool_malloc(git_pool *pool, size_t items)
191             {
192 3527           return pool_alloc(pool, alloc_size(pool, items));
193             }
194              
195 502           void *git_pool_mallocz(git_pool *pool, size_t items)
196             {
197 502           const size_t size = alloc_size(pool, items);
198 502           void *ptr = pool_alloc(pool, size);
199 502 50         if (ptr)
200 502           memset(ptr, 0x0, size);
201 502           return ptr;
202             }
203              
204 1378           char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
205             {
206 1378           char *ptr = NULL;
207              
208 1378 50         GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
209 1378 50         GIT_ASSERT_ARG_WITH_RETVAL(str, NULL);
210 1378 50         GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
211              
212 1378 50         if (n == SIZE_MAX)
213 0           return NULL;
214              
215 1378 50         if ((ptr = git_pool_malloc(pool, (n + 1))) != NULL) {
216 1378           memcpy(ptr, str, n);
217 1378           ptr[n] = '\0';
218             }
219              
220 1378           return ptr;
221             }
222              
223 596           char *git_pool_strdup(git_pool *pool, const char *str)
224             {
225 596 50         GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
226 596 50         GIT_ASSERT_ARG_WITH_RETVAL(str, NULL);
227 596 50         GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
228              
229 596           return git_pool_strndup(pool, str, strlen(str));
230             }
231              
232 8           char *git_pool_strdup_safe(git_pool *pool, const char *str)
233             {
234 8 50         return str ? git_pool_strdup(pool, str) : NULL;
235             }
236              
237 6           char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
238             {
239             void *ptr;
240             size_t len_a, len_b, total;
241              
242 6 50         GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
243 6 50         GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
244              
245 6 50         len_a = a ? strlen(a) : 0;
246 6 50         len_b = b ? strlen(b) : 0;
247              
248 12 50         if (GIT_ADD_SIZET_OVERFLOW(&total, len_a, len_b) ||
    50          
249 6           GIT_ADD_SIZET_OVERFLOW(&total, total, 1))
250 0           return NULL;
251              
252 6 50         if ((ptr = git_pool_malloc(pool, total)) != NULL) {
253 6 50         if (len_a)
254 6           memcpy(ptr, a, len_a);
255 6 50         if (len_b)
256 6           memcpy(((char *)ptr) + len_a, b, len_b);
257 6           *(((char *)ptr) + len_a + len_b) = '\0';
258             }
259 6           return ptr;
260             }