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