1 |
commit: cea99ce1b9b6d0c9ebb496dcd2f1e77ab9ab1dcd |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Wed Dec 29 12:17:32 2021 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Wed Dec 29 12:17:32 2021 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=cea99ce1 |
7 |
|
8 |
libq/tree: avoid nasty realloc magic on tree_pkg_meta |
9 |
|
10 |
doing reallocs possibly (hight probability) invalidates previously |
11 |
retrieved pointers, which is really nasty to work with, and error prone, |
12 |
so instead allocate incremental slabs where necessary |
13 |
|
14 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
15 |
|
16 |
libq/tree.c | 206 +++++++++++++++++++++++++++++++----------------------------- |
17 |
libq/tree.h | 11 +++- |
18 |
2 files changed, 116 insertions(+), 101 deletions(-) |
19 |
|
20 |
diff --git a/libq/tree.c b/libq/tree.c |
21 |
index 87df175..114541d 100644 |
22 |
--- a/libq/tree.c |
23 |
+++ b/libq/tree.c |
24 |
@@ -651,6 +651,21 @@ tree_pkg_vdb_eat( |
25 |
return ret; |
26 |
} |
27 |
|
28 |
+#define tree_meta_alloc_storage(M,SIZ) { \ |
29 |
+ struct tree_pkg_meta_ll *blk; \ |
30 |
+ size_t newlen; \ |
31 |
+\ |
32 |
+ /* calculate new block size, ensuring it covers whatever we \ |
33 |
+ * need to write this iteration */ \ |
34 |
+ newlen = ((((SIZ) + 1) / BUFSIZ) + 1) * BUFSIZ; \ |
35 |
+ blk = xmalloc(sizeof(*blk) + newlen); \ |
36 |
+ memset(blk, 0, sizeof(*blk)); \ |
37 |
+ blk->next = M->storage; \ |
38 |
+ blk->ptr = (char *)blk + sizeof(*blk); \ |
39 |
+ blk->len = newlen; \ |
40 |
+ M->storage = blk; \ |
41 |
+} |
42 |
+ |
43 |
static tree_pkg_meta * |
44 |
tree_read_file_pms(tree_pkg_ctx *pkg_ctx) |
45 |
{ |
46 |
@@ -668,8 +683,9 @@ tree_read_file_pms(tree_pkg_ctx *pkg_ctx) |
47 |
goto err; |
48 |
|
49 |
len = sizeof(*ret) + s.st_size + 1; |
50 |
- ret = xzalloc(len); |
51 |
- ptr = (char*)ret + sizeof(*ret); |
52 |
+ ret = xmalloc(len); |
53 |
+ memset(ret, 0, sizeof(*ret)); |
54 |
+ ptr = (char *)ret + sizeof(*ret); |
55 |
if ((off_t)fread(ptr, 1, s.st_size, f) != s.st_size) |
56 |
goto err; |
57 |
ptr[s.st_size] = '\0'; |
58 |
@@ -954,15 +970,15 @@ static void |
59 |
tree_read_file_binpkg_xpak_cb( |
60 |
void *ctx, |
61 |
char *pathname, |
62 |
- int pathname_len, |
63 |
- int data_offset, |
64 |
- int data_len, |
65 |
+ int pathname_len, |
66 |
+ int data_offset, |
67 |
+ int data_len, |
68 |
char *data) |
69 |
{ |
70 |
tree_pkg_meta *m = (tree_pkg_meta *)ctx; |
71 |
- char **key; |
72 |
- size_t pos; |
73 |
- size_t len; |
74 |
+ char **key; |
75 |
+ size_t pos; |
76 |
+ size_t len; |
77 |
|
78 |
#define match_path(K) \ |
79 |
else if (pathname_len == (sizeof(#K) - 1) && strcmp(pathname, #K) == 0) \ |
80 |
@@ -994,37 +1010,28 @@ tree_read_file_binpkg_xpak_cb( |
81 |
return; |
82 |
#undef match_path |
83 |
|
84 |
- /* hijack unused members */ |
85 |
- pos = (size_t)m->Q__eclasses_; |
86 |
- len = (size_t)m->Q__md5_; |
87 |
+ /* get current storage block */ |
88 |
+ if (m->storage != NULL) { |
89 |
+ pos = m->storage->pos; |
90 |
+ len = m->storage->len; |
91 |
+ } else { |
92 |
+ pos = 0; |
93 |
+ len = 0; |
94 |
+ } |
95 |
|
96 |
/* trim whitespace (mostly trailing newline) */ |
97 |
while (isspace((int)data[data_offset + data_len - 1])) |
98 |
data_len--; |
99 |
|
100 |
if (len - pos < (size_t)(data_len + 1)) { |
101 |
- char *old_data = m->Q__data; |
102 |
- len += (((data_len + 1 - (len - pos)) / BUFSIZ) + 1) * BUFSIZ; |
103 |
- m->Q__data = xrealloc(m->Q__data, len); |
104 |
- |
105 |
- /* re-position existing keys */ |
106 |
- if (old_data != NULL && m->Q__data != old_data) { |
107 |
- char **newdata = (char **)m; |
108 |
- int elems = sizeof(tree_pkg_meta) / sizeof(char *); |
109 |
- while (elems-- > 1) /* skip Q__data itself */ |
110 |
- if (newdata[elems] != NULL) |
111 |
- newdata[elems] = m->Q__data + (newdata[elems] - old_data); |
112 |
- } |
113 |
- |
114 |
- /* set after repositioning! */ |
115 |
- m->Q__md5_ = (char *)len; |
116 |
- m->Q__eclasses_ = (char *)pos; |
117 |
+ tree_meta_alloc_storage(m, data_len + 1); |
118 |
+ len = m->storage->len; |
119 |
+ pos = m->storage->pos; |
120 |
} |
121 |
|
122 |
- *key = m->Q__data + pos; |
123 |
+ *key = m->storage->ptr + pos; |
124 |
snprintf(*key, len - pos, "%.*s", data_len, data + data_offset); |
125 |
- pos += data_len + 1; |
126 |
- m->Q__eclasses_ = (char *)pos; |
127 |
+ m->storage->pos += data_len + 1; |
128 |
} |
129 |
|
130 |
static tree_pkg_meta * |
131 |
@@ -1042,33 +1049,23 @@ tree_read_file_binpkg(tree_pkg_ctx *pkg_ctx) |
132 |
if (newfd != -1) { |
133 |
size_t fsize; |
134 |
size_t needlen = 40 + 1 + 19 + 1; |
135 |
- size_t pos = (size_t)m->Q__eclasses_; |
136 |
- size_t len = (size_t)m->Q__md5_; |
137 |
+ size_t pos = 0; |
138 |
+ size_t len = 0; |
139 |
|
140 |
- if (len - pos < needlen) { |
141 |
- char *old_data = m->Q__data; |
142 |
- len += (((needlen - (len - pos)) / BUFSIZ) + 1) * BUFSIZ; |
143 |
- m->Q__data = xrealloc(m->Q__data, len); |
144 |
- |
145 |
- /* re-position existing keys */ |
146 |
- if (old_data != NULL && m->Q__data != old_data) { |
147 |
- char **newdata = (char **)m; |
148 |
- int elems = sizeof(tree_pkg_meta) / sizeof(char *); |
149 |
- while (elems-- > 1) /* skip Q__data itself */ |
150 |
- if (newdata[elems] != NULL) |
151 |
- newdata[elems] = |
152 |
- m->Q__data + (newdata[elems] - old_data); |
153 |
- } |
154 |
+ if (m->storage != NULL) { |
155 |
+ pos = m->storage->pos; |
156 |
+ len = m->storage->len; |
157 |
+ } |
158 |
|
159 |
- /* set after repositioning! */ |
160 |
- m->Q__md5_ = (char *)len; |
161 |
- m->Q__eclasses_ = (char *)pos; |
162 |
+ if (len - pos < needlen) { |
163 |
+ tree_meta_alloc_storage(m, needlen); |
164 |
+ len = m->storage->len; |
165 |
+ pos = m->storage->pos; |
166 |
} |
167 |
|
168 |
- m->Q_SHA1 = m->Q__data + pos; |
169 |
+ m->Q_SHA1 = m->storage->ptr + pos; |
170 |
m->Q_SIZE = m->Q_SHA1 + 40 + 1; |
171 |
- pos += needlen; |
172 |
- m->Q__eclasses_ = (char *)pos; |
173 |
+ m->storage->pos += needlen; |
174 |
|
175 |
lseek(newfd, 0, SEEK_SET); /* reposition at the whole file */ |
176 |
if (hash_multiple_file_fd(newfd, NULL, m->Q_SHA1, NULL, NULL, |
177 |
@@ -1123,13 +1120,48 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx) |
178 |
return ret; |
179 |
} |
180 |
|
181 |
+static tree_pkg_meta * |
182 |
+tree_clone_meta(tree_pkg_meta *m) |
183 |
+{ |
184 |
+ tree_pkg_meta *ret; |
185 |
+ size_t pos = 0; |
186 |
+ size_t len = 0; |
187 |
+ char **ptr; |
188 |
+ char *p; |
189 |
+ |
190 |
+ /* compute necessary space upfront */ |
191 |
+ len = sizeof(*ret); |
192 |
+ for (ptr = &m->Q__data; ptr <= &m->Q__last; ptr++) |
193 |
+ if (*ptr != NULL) |
194 |
+ len += strlen(*ptr); |
195 |
+ |
196 |
+ /* malloc and copy */ |
197 |
+ ret = xzalloc(len); |
198 |
+ p = (char *)ret + sizeof(*ret); |
199 |
+ for (ptr = &m->Q__data; ptr <= &m->Q__last; ptr++, pos++) { |
200 |
+ if (*ptr == NULL) |
201 |
+ continue; |
202 |
+ *(&ret->Q__data + pos) = p; |
203 |
+ len = strlen(*ptr) + 1; |
204 |
+ memcpy(p, *ptr, len); |
205 |
+ p += len; |
206 |
+ } |
207 |
+ |
208 |
+ return ret; |
209 |
+} |
210 |
+ |
211 |
static void |
212 |
tree_close_meta(tree_pkg_meta *cache) |
213 |
{ |
214 |
+ struct tree_pkg_meta_ll *blk; |
215 |
+ |
216 |
if (cache == NULL) |
217 |
errf("Cache is empty !"); |
218 |
- if (cache->Q__data != NULL) |
219 |
- free(cache->Q__data); |
220 |
+ while (cache->storage != NULL) { |
221 |
+ blk = cache->storage->next; |
222 |
+ free(cache->storage); |
223 |
+ cache->storage = blk; |
224 |
+ } |
225 |
free(cache); |
226 |
} |
227 |
|
228 |
@@ -1165,37 +1197,26 @@ tree_pkg_meta_get_int(tree_pkg_ctx *pkg_ctx, size_t offset, const char *keyn) |
229 |
return NULL; |
230 |
} |
231 |
|
232 |
- /* hijack unused members */ |
233 |
- pos = (size_t)m->Q__eclasses_; |
234 |
- len = (size_t)m->Q__md5_; |
235 |
+ if (m->storage != NULL) { |
236 |
+ pos = m->storage->pos; |
237 |
+ len = m->storage->len; |
238 |
+ } else { |
239 |
+ pos = 0; |
240 |
+ len = 0; |
241 |
+ } |
242 |
|
243 |
- /* TODO: this is an exact copy from tree_read_file_binpkg_xpak_cb */ |
244 |
if (len - pos < (size_t)(s.st_size + 1)) { |
245 |
- p = m->Q__data; |
246 |
- len += (((s.st_size + 1 - (len - pos)) / BUFSIZ) + 1) * BUFSIZ; |
247 |
- m->Q__data = xrealloc(m->Q__data, len); |
248 |
- |
249 |
- /* re-position existing keys */ |
250 |
- if (p != NULL && m->Q__data != p) { |
251 |
- char **newdata = (char **)m; |
252 |
- int elems = sizeof(tree_pkg_meta) / sizeof(char *); |
253 |
- while (elems-- > 1) /* skip Q__data itself */ |
254 |
- if (newdata[elems] != NULL) |
255 |
- newdata[elems] = m->Q__data + (newdata[elems] - p); |
256 |
- } |
257 |
- |
258 |
- /* set after repositioning! */ |
259 |
- m->Q__md5_ = (char *)len; |
260 |
- m->Q__eclasses_ = (char *)pos; |
261 |
+ tree_meta_alloc_storage(m, s.st_size + 1); |
262 |
+ pos = m->storage->pos; |
263 |
+ len = m->storage->len; |
264 |
} |
265 |
|
266 |
- p = *key = m->Q__data + pos; |
267 |
+ p = *key = m->storage->ptr + pos; |
268 |
if (read(fd, p, s.st_size) == (ssize_t)s.st_size) { |
269 |
p[s.st_size] = '\0'; |
270 |
while (s.st_size > 0 && isspace((int)p[s.st_size - 1])) |
271 |
p[--s.st_size] = '\0'; |
272 |
- pos += s.st_size + 1; |
273 |
- m->Q__eclasses_ = (char *)pos; |
274 |
+ m->storage->pos += s.st_size + 1; |
275 |
} |
276 |
close(fd); |
277 |
} |
278 |
@@ -1692,29 +1713,14 @@ tree_match_atom_cache_populate_cb(tree_pkg_ctx *ctx, void *priv) |
279 |
pkg->repo = tctx->repo != NULL ? xstrdup(tctx->repo) : NULL; |
280 |
if (meta != NULL) { |
281 |
pkg->fd = -2; /* don't try to read, we fill it in here */ |
282 |
- pkg->meta = xmalloc(sizeof(*pkg->meta)); |
283 |
- memcpy(pkg->meta, meta, sizeof(*pkg->meta)); |
284 |
- if (ctx->cat_ctx->ctx->cachetype == CACHE_PACKAGES) { |
285 |
- pkg->meta->Q__data = NULL; /* avoid free here (just to be sure) */ |
286 |
- } else { /* CACHE_BINPKG */ |
287 |
- char **newdata; |
288 |
- int elems; |
289 |
- size_t datasize = (size_t)meta->Q__eclasses_; |
290 |
- |
291 |
- pkg->meta->Q__data = xmalloc(sizeof(char) * datasize); |
292 |
- memcpy(pkg->meta->Q__data, meta->Q__data, datasize); |
293 |
- |
294 |
- /* re-position keys */ |
295 |
- newdata = (char **)pkg->meta; |
296 |
- elems = sizeof(tree_pkg_meta) / sizeof(char *); |
297 |
- while (elems-- > 1) /* skip Q__data itself */ |
298 |
- if (newdata[elems] != NULL) |
299 |
- newdata[elems] = pkg->meta->Q__data + |
300 |
- (newdata[elems] - meta->Q__data); |
301 |
- |
302 |
- /* drop garbage used for Q__data admin in original case */ |
303 |
- pkg->meta->Q__eclasses_ = NULL; |
304 |
- pkg->meta->Q__md5_ = NULL; |
305 |
+ if (tctx->cachetype == CACHE_PACKAGES) { |
306 |
+ /* need to copy, source is based on temp space in foreach */ |
307 |
+ pkg->meta = tree_clone_meta(meta); |
308 |
+ } else { |
309 |
+ /* BINPKG case, this one is read/allocated separately from |
310 |
+ * xpak archive, so can just take it over */ |
311 |
+ pkg->meta = meta; |
312 |
+ ctx->meta = NULL; /* avoid double free */ |
313 |
} |
314 |
} else { |
315 |
pkg->meta = NULL; |
316 |
|
317 |
diff --git a/libq/tree.h b/libq/tree.h |
318 |
index 052715b..8279281 100644 |
319 |
--- a/libq/tree.h |
320 |
+++ b/libq/tree.h |
321 |
@@ -80,7 +80,7 @@ struct tree_pkg_ctx { |
322 |
|
323 |
/* Ebuild data */ |
324 |
struct tree_pkg_meta { |
325 |
- char *Q__data; |
326 |
+#define Q__data Q_DEPEND /* ptr to first member of the struct */ |
327 |
char *Q_DEPEND; /* line 1 */ |
328 |
char *Q_RDEPEND; |
329 |
char *Q_SLOT; |
330 |
@@ -111,6 +111,15 @@ struct tree_pkg_meta { |
331 |
/* These are MD5-Cache only */ |
332 |
char *Q__eclasses_; |
333 |
char *Q__md5_; |
334 |
+#define Q__last Q__md5_ /* ptr to last data member in struct */ |
335 |
+ |
336 |
+ /* for memory allocations backing the pointers above */ |
337 |
+ struct tree_pkg_meta_ll { |
338 |
+ char *ptr; |
339 |
+ size_t len; |
340 |
+ size_t pos; |
341 |
+ struct tree_pkg_meta_ll *next; |
342 |
+ } *storage; |
343 |
}; |
344 |
|
345 |
/* Metadata.xml */ |