Coverage Report

Created: 2025-07-23 06:59

/src/libgit2/src/util/pool.c
Line
Count
Source (jump to first uncovered line)
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
#ifndef GIT_DEBUG_POOL
25
26
static size_t system_page_size = 0;
27
28
int git_pool_global_init(void)
29
2
{
30
2
  if (git__page_size(&system_page_size) < 0)
31
0
    system_page_size = 4096;
32
  /* allow space for malloc overhead */
33
2
  system_page_size -= (2 * sizeof(void *)) + sizeof(git_pool_page);
34
2
  return 0;
35
2
}
36
37
int git_pool_init(git_pool *pool, size_t item_size)
38
0
{
39
0
  GIT_ASSERT_ARG(pool);
40
0
  GIT_ASSERT_ARG(item_size >= 1);
41
42
0
  memset(pool, 0, sizeof(git_pool));
43
0
  pool->item_size = item_size;
44
0
  pool->page_size = system_page_size;
45
46
0
  return 0;
47
0
}
48
49
void git_pool_clear(git_pool *pool)
50
0
{
51
0
  git_pool_page *scan, *next;
52
53
0
  for (scan = pool->pages; scan != NULL; scan = next) {
54
0
    next = scan->next;
55
0
    git__free(scan);
56
0
  }
57
58
0
  pool->pages = NULL;
59
0
}
60
61
static void *pool_alloc_page(git_pool *pool, size_t size)
62
0
{
63
0
  git_pool_page *page;
64
0
  const size_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
65
0
  size_t alloc_size;
66
67
0
  if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
68
0
    !(page = git__malloc(alloc_size)))
69
0
    return NULL;
70
71
0
  page->size = new_page_size;
72
0
  page->avail = new_page_size - size;
73
0
  page->next = pool->pages;
74
75
0
  pool->pages = page;
76
77
0
  return page->data;
78
0
}
79
80
static void *pool_alloc(git_pool *pool, size_t size)
81
0
{
82
0
  git_pool_page *page = pool->pages;
83
0
  void *ptr = NULL;
84
85
0
  if (!page || page->avail < size)
86
0
    return pool_alloc_page(pool, size);
87
88
0
  ptr = &page->data[page->size - page->avail];
89
0
  page->avail -= size;
90
91
0
  return ptr;
92
0
}
93
94
uint32_t git_pool__open_pages(git_pool *pool)
95
0
{
96
0
  uint32_t ct = 0;
97
0
  git_pool_page *scan;
98
0
  for (scan = pool->pages; scan != NULL; scan = scan->next) ct++;
99
0
  return ct;
100
0
}
101
102
bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
103
0
{
104
0
  git_pool_page *scan;
105
0
  for (scan = pool->pages; scan != NULL; scan = scan->next)
106
0
    if ((void *)scan->data <= ptr &&
107
0
      (void *)(((char *)scan->data) + scan->size) > ptr)
108
0
      return true;
109
0
  return false;
110
0
}
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_dispose_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
void git_pool_swap(git_pool *a, git_pool *b)
167
0
{
168
0
  git_pool temp;
169
170
0
  if (a == b)
171
0
    return;
172
173
0
  memcpy(&temp, a, sizeof(temp));
174
0
  memcpy(a, b, sizeof(temp));
175
0
  memcpy(b, &temp, sizeof(temp));
176
0
}
177
178
static size_t alloc_size(git_pool *pool, size_t count)
179
0
{
180
0
  const size_t align = sizeof(void *) - 1;
181
182
0
  if (pool->item_size > 1) {
183
0
    const size_t item_size = (pool->item_size + align) & ~align;
184
0
    return item_size * count;
185
0
  }
186
187
0
  return (count + align) & ~align;
188
0
}
189
190
void *git_pool_malloc(git_pool *pool, size_t items)
191
0
{
192
0
  return pool_alloc(pool, alloc_size(pool, items));
193
0
}
194
195
void *git_pool_mallocz(git_pool *pool, size_t items)
196
0
{
197
0
  const size_t size = alloc_size(pool, items);
198
0
  void *ptr = pool_alloc(pool, size);
199
0
  if (ptr)
200
0
    memset(ptr, 0x0, size);
201
0
  return ptr;
202
0
}
203
204
char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
205
0
{
206
0
  char *ptr = NULL;
207
208
0
  GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
209
0
  GIT_ASSERT_ARG_WITH_RETVAL(str, NULL);
210
0
  GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
211
212
0
  if (n == SIZE_MAX)
213
0
    return NULL;
214
215
0
  if ((ptr = git_pool_malloc(pool, (n + 1))) != NULL) {
216
0
    memcpy(ptr, str, n);
217
0
    ptr[n] = '\0';
218
0
  }
219
220
0
  return ptr;
221
0
}
222
223
char *git_pool_strdup(git_pool *pool, const char *str)
224
0
{
225
0
  GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
226
0
  GIT_ASSERT_ARG_WITH_RETVAL(str, NULL);
227
0
  GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
228
229
0
  return git_pool_strndup(pool, str, strlen(str));
230
0
}
231
232
char *git_pool_strdup_safe(git_pool *pool, const char *str)
233
0
{
234
0
  return str ? git_pool_strdup(pool, str) : NULL;
235
0
}
236
237
char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
238
0
{
239
0
  void *ptr;
240
0
  size_t len_a, len_b, total;
241
242
0
  GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
243
0
  GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
244
245
0
  len_a = a ? strlen(a) : 0;
246
0
  len_b = b ? strlen(b) : 0;
247
248
0
  if (GIT_ADD_SIZET_OVERFLOW(&total, len_a, len_b) ||
249
0
    GIT_ADD_SIZET_OVERFLOW(&total, total, 1))
250
0
    return NULL;
251
252
0
  if ((ptr = git_pool_malloc(pool, total)) != NULL) {
253
0
    if (len_a)
254
0
      memcpy(ptr, a, len_a);
255
0
    if (len_b)
256
0
      memcpy(((char *)ptr) + len_a, b, len_b);
257
0
    *(((char *)ptr) + len_a + len_b) = '\0';
258
0
  }
259
0
  return ptr;
260
0
}