"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
avoid per tree-entry asprintf/free
To:
gameoftrees@openbsd.org
Date:
Mon, 23 Feb 2026 21:41:44 +0100

Download raw body.

Thread
  • Stefan Sperling:

    avoid per tree-entry asprintf/free

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;
 		}
 	}