From: Stefan Sperling Subject: avoid per tree-entry asprintf/free To: gameoftrees@openbsd.org Date: Mon, 23 Feb 2026 21:41:44 +0100 Avoid doing asprintf/free per tree entry in got_pack_load_tree_entries(). Allocate one path buffer and keep growing it as needed. For directories we still need to copy the path. But blobs can use the path buffer directly. ok? M lib/pack_create.c | 38+ 11- 1 file changed, 38 insertions(+), 11 deletions(-) commit - 23c16b295963fd2cfddf454ef642b1dfb6afa3d1 commit + bf9514555f3e1bcbc972ed5f791d2cf0a9c797e6 blob - 88ae6a7f7857b14079689f7c4e8f26ef6cebdfce blob + 0e3b3d8caf3352ddb1c89e6e64acc9d0897aa079 --- lib/pack_create.c +++ lib/pack_create.c @@ -797,7 +797,7 @@ got_pack_load_tree_entries(struct got_object_id_queue { const struct got_error *err; char *p = NULL; - int i; + int i, ret, psize = _POSIX_PATH_MAX; (*ntrees)++; err = got_pack_report_progress(progress_cb, progress_arg, rl, @@ -805,6 +805,11 @@ got_pack_load_tree_entries(struct got_object_id_queue if (err) return err; + p = malloc(psize); + if (p == NULL) + return got_error_from_errno("malloc"); + p[0] = '\0'; + for (i = 0; i < got_object_tree_get_nentries(tree); i++) { struct got_tree_entry *e = got_object_tree_get_entry(tree, i); struct got_object_id *id = got_tree_entry_get_id(e); @@ -828,20 +833,47 @@ got_pack_load_tree_entries(struct got_object_id_queue if (ids == NULL && S_ISDIR(mode)) continue; - if (asprintf(&p, "%s%s%s", dpath, + ret = snprintf(p, psize, "%s%s%s", dpath, got_path_is_root_dir(dpath) ? "" : "/", - got_tree_entry_get_name(e)) == -1) { - err = got_error_from_errno("asprintf"); + got_tree_entry_get_name(e)); + if (ret == -1) { + err = got_error_from_errno("snprintf"); break; } + if (ret >= psize) { + char *s; + s = realloc(p, ret + 1); + if (s == NULL) { + err = got_error_from_errno("realloc"); + break; + } + p = s; + psize = ret + 1; + + ret = snprintf(p, psize, "%s%s%s", dpath, + got_path_is_root_dir(dpath) ? "" : "/", + got_tree_entry_get_name(e)); + if (ret == -1) { + err = got_error_from_errno("snprintf"); + break; + } + if (ret >= psize) { /* should not happen */ + err = got_error(GOT_ERR_NO_SPACE); + break; + } + } + if (S_ISDIR(mode)) { struct got_object_qid *qid; err = got_object_qid_alloc(&qid, id); if (err) break; - qid->data = p; - p = NULL; + qid->data = strdup(p); + if (qid->data == NULL) { + err = got_error_from_errno("strdup"); + break; + } STAILQ_INSERT_TAIL(ids, qid, entry); } else if (S_ISREG(mode) || S_ISLNK(mode)) { err = got_pack_add_object(want_meta, @@ -851,11 +883,6 @@ got_pack_load_tree_entries(struct got_object_id_queue progress_cb, progress_arg, rl); if (err) break; - free(p); - p = NULL; - } else { - free(p); - p = NULL; } }