Skip to content

Commit 2816667

Browse files
committed
lib: rewrite shlib check to avoid excessive allocations
1 parent 4e4e9b2 commit 2816667

File tree

1 file changed

+211
-98
lines changed

1 file changed

+211
-98
lines changed

lib/transaction_check_shlibs.c

Lines changed: 211 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#include <stdbool.h>
2929
#include <errno.h>
3030

31+
#include "uthash.h"
32+
33+
#include "xbps.h"
34+
#include "xbps/xbps_array.h"
35+
#include "xbps/xbps_dictionary.h"
3136
#include "xbps_api_impl.h"
3237

3338
/*
@@ -43,142 +48,250 @@
4348
* Abort transaction if such case is found.
4449
*/
4550

46-
static void
47-
shlib_register(xbps_dictionary_t d, const char *shlib, const char *pkgver)
51+
struct shlib_entry {
52+
const char *name;
53+
UT_hash_handle hh;
54+
};
55+
56+
struct shlib_ctx {
57+
struct xbps_handle *xhp;
58+
struct shlib_entry *entries;
59+
xbps_dictionary_t seen;
60+
xbps_array_t missing;
61+
};
62+
63+
static struct shlib_entry *
64+
shlib_entry_find(struct shlib_entry *head, const char *name)
4865
{
49-
xbps_array_t array;
50-
bool alloc = false;
66+
struct shlib_entry *res = NULL;
67+
HASH_FIND_STR(head, name, res);
68+
return res;
69+
}
5170

52-
if ((array = xbps_dictionary_get(d, shlib)) == NULL) {
53-
alloc = true;
54-
array = xbps_array_create();
55-
xbps_dictionary_set(d, shlib, array);
71+
static struct shlib_entry *
72+
shlib_entry_get(struct shlib_ctx *ctx, const char *name)
73+
{
74+
struct shlib_entry *res = shlib_entry_find(ctx->entries, name);
75+
if (res)
76+
return res;
77+
res = calloc(1, sizeof(*res));
78+
if (!res) {
79+
xbps_error_printf("out of memory\n");
80+
errno = ENOMEM;
81+
return NULL;
5682
}
57-
if (!xbps_match_string_in_array(array, pkgver))
58-
xbps_array_add_cstring_nocopy(array, pkgver);
59-
if (alloc)
60-
xbps_object_release(array);
83+
res->name = name;
84+
HASH_ADD_STR(ctx->entries, name, res);
85+
return res;
6186
}
6287

63-
static xbps_dictionary_t
64-
collect_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, bool req)
88+
static int
89+
collect_shlib_array(struct shlib_ctx *ctx, xbps_array_t array)
90+
{
91+
for (unsigned int i = 0; i < xbps_array_count(array); i++) {
92+
struct shlib_entry *entry;
93+
const char *shlib = NULL;
94+
if (!xbps_array_get_cstring_nocopy(array, i, &shlib))
95+
return -EINVAL;
96+
entry = shlib_entry_get(ctx, shlib);
97+
if (!entry)
98+
return -errno;
99+
}
100+
return 0;
101+
}
102+
103+
static int
104+
collect_shlibs(struct shlib_ctx *ctx, xbps_array_t pkgs)
65105
{
66106
xbps_object_t obj;
67107
xbps_object_iterator_t iter;
68-
xbps_dictionary_t d, pd;
69-
const char *pkgname, *pkgver;
70-
71-
d = xbps_dictionary_create();
72-
assert(d);
73-
74-
/* copy pkgdb to out temporary dictionary */
75-
pd = xbps_dictionary_copy(xhp->pkgdb);
76-
assert(pd);
77-
78-
/*
79-
* copy pkgs from transaction to our dictionary, overriding them
80-
* if they were there from pkgdb.
81-
*/
82-
iter = xbps_array_iterator(pkgs);
83-
assert(iter);
84-
while ((obj = xbps_object_iterator_next(iter))) {
85-
if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname))
86-
continue;
108+
xbps_bool_t placeholder;
109+
110+
// can't set null values to xbps_dictionary so just use one boolean
111+
placeholder = xbps_bool_create(true);
112+
if (!placeholder) {
113+
xbps_error_printf("out of memory\n");
114+
return -ENOMEM;
115+
}
116+
117+
ctx->seen = xbps_dictionary_create();
118+
if (!ctx->seen) {
119+
xbps_error_printf("out of memory\n");
120+
return -ENOMEM;
121+
}
87122

88-
/* ignore shlibs if pkg is on hold mode */
89-
if (xbps_transaction_pkg_type(obj) == XBPS_TRANS_HOLD) {
123+
for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) {
124+
const char *pkgname;
125+
xbps_dictionary_t pkgd = xbps_array_get(pkgs, i);
126+
xbps_array_t array;
127+
128+
if (xbps_transaction_pkg_type(pkgd) == XBPS_TRANS_HOLD)
90129
continue;
130+
if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgname", &pkgname)) {
131+
xbps_error_printf("invalid package: missing `pkgname` property\n");
132+
return -EINVAL;
133+
}
134+
if (!xbps_dictionary_set(ctx->seen, pkgname, placeholder)) {
135+
xbps_error_printf("out of memory\n");
136+
return -ENOMEM;
91137
}
92138

93-
xbps_dictionary_set(pd, pkgname, obj);
139+
if (xbps_transaction_pkg_type(pkgd) == XBPS_TRANS_REMOVE)
140+
continue;
141+
142+
array = xbps_dictionary_get(pkgd, "shlib-provides");
143+
if (array) {
144+
int r = collect_shlib_array(ctx, array);
145+
if (r < 0)
146+
return r;
147+
}
94148
}
95-
xbps_object_iterator_release(iter);
96149

97-
/*
98-
* iterate over our dictionary to collect shlib-{requires,provides}.
99-
*/
100-
iter = xbps_dictionary_iterator(pd);
101-
assert(iter);
150+
iter = xbps_dictionary_iterator(ctx->xhp->pkgdb);
151+
if (!iter) {
152+
xbps_error_printf("out of memory\n");
153+
return -ENOMEM;
154+
}
102155

103156
while ((obj = xbps_object_iterator_next(iter))) {
104-
xbps_array_t shobjs;
157+
xbps_array_t array;
105158
xbps_dictionary_t pkgd;
159+
const char *pkgname = NULL;
106160

107-
pkgd = xbps_dictionary_get_keysym(pd, obj);
108-
if (xbps_transaction_pkg_type(pkgd) == XBPS_TRANS_REMOVE) {
109-
continue;
110-
}
111-
/*
112-
* If pkg does not have the required obj, pass to next one.
113-
*/
114-
xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
115-
shobjs = xbps_dictionary_get(pkgd,
116-
req ? "shlib-requires" : "shlib-provides");
117-
if (shobjs == NULL)
161+
pkgname = xbps_dictionary_keysym_cstring_nocopy(obj);
162+
/* ignore internal objs */
163+
if (strncmp(pkgname, "_XBPS_", 6) == 0)
118164
continue;
119165

120-
for (unsigned int i = 0; i < xbps_array_count(shobjs); i++) {
121-
const char *shlib = NULL;
166+
pkgd = xbps_dictionary_get_keysym(ctx->xhp->pkgdb, obj);
167+
168+
if (xbps_dictionary_get(ctx->seen, pkgname))
169+
continue;
122170

123-
xbps_array_get_cstring_nocopy(shobjs, i, &shlib);
124-
xbps_dbg_printf("%s: registering %s for %s\n",
125-
pkgver, shlib, req ? "shlib-requires" : "shlib-provides");
126-
if (req)
127-
shlib_register(d, shlib, pkgver);
128-
else
129-
xbps_dictionary_set_cstring_nocopy(d, shlib, pkgver);
171+
array = xbps_dictionary_get(pkgd, "shlib-provides");
172+
if (array) {
173+
int r = collect_shlib_array(ctx, array);
174+
if (r < 0)
175+
return r;
130176
}
131177
}
178+
132179
xbps_object_iterator_release(iter);
133-
xbps_object_release(pd);
134-
return d;
180+
return 0;
135181
}
136182

137-
bool HIDDEN
138-
xbps_transaction_check_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs)
183+
static int
184+
check_shlibs(struct shlib_ctx *ctx, xbps_array_t pkgs)
139185
{
140-
xbps_array_t array, mshlibs;
141-
xbps_object_t obj, obj2;
142186
xbps_object_iterator_t iter;
143-
xbps_dictionary_t shrequires, shprovides;
144-
const char *pkgver = NULL, *shlib = NULL;
145-
char *buf;
146-
bool broken = false;
187+
xbps_object_t obj;
147188

148-
shrequires = collect_shlibs(xhp, pkgs, true);
149-
shprovides = collect_shlibs(xhp, pkgs, false);
189+
for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) {
190+
xbps_array_t array;
191+
xbps_dictionary_t pkgd = xbps_array_get(pkgs, i);
192+
xbps_trans_type_t ttype = xbps_transaction_pkg_type(pkgd);
150193

151-
mshlibs = xbps_dictionary_get(xhp->transd, "missing_shlibs");
152-
/* iterate over shlib-requires to find unmatched shlibs */
153-
iter = xbps_dictionary_iterator(shrequires);
154-
assert(iter);
194+
if (ttype == XBPS_TRANS_HOLD || ttype == XBPS_TRANS_REMOVE)
195+
continue;
155196

156-
while ((obj = xbps_object_iterator_next(iter))) {
157-
shlib = xbps_dictionary_keysym_cstring_nocopy(obj);
158-
xbps_dbg_printf("%s: checking for `%s': ", __func__, shlib);
159-
if ((obj2 = xbps_dictionary_get(shprovides, shlib))) {
160-
xbps_dbg_printf_append("provided by `%s'\n",
161-
xbps_string_cstring_nocopy(obj2));
197+
array = xbps_dictionary_get(pkgd, "shlib-requires");
198+
if (!array)
162199
continue;
200+
for (unsigned int j = 0; j < xbps_array_count(array); j++) {
201+
const char *pkgver = NULL;
202+
const char *shlib = NULL;
203+
char *missing;
204+
if (!xbps_array_get_cstring_nocopy(array, j, &shlib))
205+
return -EINVAL;
206+
if (shlib_entry_find(ctx->entries, shlib))
207+
continue;
208+
if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver))
209+
return -EINVAL;
210+
missing = xbps_xasprintf(
211+
"%s: broken, unresolvable shlib `%s'",
212+
pkgver, shlib);
213+
if (!xbps_array_add_cstring_nocopy(ctx->missing, missing)) {
214+
xbps_error_printf("out of memory\n");
215+
return -ENOMEM;
216+
}
163217
}
164-
xbps_dbg_printf_append("not found\n");
218+
}
219+
220+
iter = xbps_dictionary_iterator(ctx->xhp->pkgdb);
221+
if (!iter) {
222+
xbps_error_printf("out of memory\n");
223+
return -ENOMEM;
224+
}
225+
226+
while ((obj = xbps_object_iterator_next(iter))) {
227+
xbps_array_t array;
228+
xbps_dictionary_t pkgd;
229+
const char *pkgname = NULL;
230+
231+
pkgname = xbps_dictionary_keysym_cstring_nocopy(obj);
232+
/* ignore internal objs */
233+
if (strncmp(pkgname, "_XBPS_", 6) == 0)
234+
continue;
235+
236+
pkgd = xbps_dictionary_get_keysym(ctx->xhp->pkgdb, obj);
237+
238+
if (xbps_dictionary_get(ctx->seen, pkgname))
239+
continue;
165240

166-
broken = true;
167-
array = xbps_dictionary_get_keysym(shrequires, obj);
241+
array = xbps_dictionary_get(pkgd, "shlib-requires");
242+
if (!array)
243+
continue;
168244
for (unsigned int i = 0; i < xbps_array_count(array); i++) {
169-
xbps_array_get_cstring_nocopy(array, i, &pkgver);
170-
buf = xbps_xasprintf("%s: broken, unresolvable "
171-
"shlib `%s'", pkgver, shlib);
172-
xbps_array_add_cstring(mshlibs, buf);
173-
free(buf);
245+
const char *pkgver = NULL;
246+
const char *shlib = NULL;
247+
char *missing;
248+
if (!xbps_array_get_cstring_nocopy(array, i, &shlib))
249+
return -EINVAL;
250+
if (shlib_entry_find(ctx->entries, shlib))
251+
continue;
252+
if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver))
253+
return -EINVAL;
254+
missing = xbps_xasprintf(
255+
"%s: broken, unresolvable shlib `%s'", pkgver,
256+
shlib);
257+
if (!xbps_array_add_cstring_nocopy(ctx->missing, missing)) {
258+
xbps_error_printf("out of memory\n");
259+
return -ENOMEM;
260+
}
174261
}
175262
}
263+
176264
xbps_object_iterator_release(iter);
177-
if (!broken) {
265+
return 0;
266+
}
267+
268+
bool HIDDEN
269+
xbps_transaction_check_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs)
270+
{
271+
struct shlib_entry *entry, *tmp;
272+
struct shlib_ctx ctx = { .xhp = xhp };
273+
int r;
274+
275+
ctx.missing = xbps_dictionary_get(xhp->transd, "missing_shlibs");
276+
277+
r = collect_shlibs(&ctx, pkgs);
278+
if (r < 0)
279+
goto err;
280+
281+
r = check_shlibs(&ctx, pkgs);
282+
if (r < 0)
283+
goto err;
284+
285+
if (xbps_array_count(ctx.missing) == 0)
178286
xbps_dictionary_remove(xhp->transd, "missing_shlibs");
179-
}
180-
xbps_object_release(shprovides);
181-
xbps_object_release(shrequires);
182287

183-
return true;
288+
r = 0;
289+
err:
290+
HASH_ITER(hh, ctx.entries, entry, tmp) {
291+
HASH_DEL(ctx.entries, entry);
292+
free(entry);
293+
}
294+
if (ctx.seen)
295+
xbps_object_release(ctx.seen);
296+
return r == 0;
184297
}

0 commit comments

Comments
 (0)