From: Omar Polo Subject: reduce the reallocarray() calls in read_fileindex_path() To: gameoftrees@openbsd.org Date: Fri, 28 Jul 2023 10:52:25 +0200 We spend a decent amount of time reading the fileindex in reallocarray(). The fileindex has the path stored (NUL included) with a final padding to the next multiple of eight bytes, so we read 8 bytes per iteration. That's fine. Calling reallocarray() to increase the size of the allocation by 8 byte each iteration however is a waste. Instead, use a local buffer and strdup() on exit. Git paths don't have an implicit length limit, but this is the fileindex of a worktree and AFAIK we can't check-out files whose path is more than PATH_MAX anyway. ok? ----------------------------------------------- commit 1772f04de18f32fe8a4b91869eaf51da7ce85167 from: Omar Polo date: Fri Jul 28 08:48:01 2023 UTC read_fileindex_path: avoid many reallocarray() calls, use local buffer diff c2eedbd13a618c74343a8d8d645acecdfb677b8f 1772f04de18f32fe8a4b91869eaf51da7ce85167 commit - c2eedbd13a618c74343a8d8d645acecdfb677b8f commit + 1772f04de18f32fe8a4b91869eaf51da7ce85167 blob - 1575b0dd69dc7a97d0d393fa46ba56957b8ee0b7 blob + 62f7df1b95d5d56bd0b23c83df32e7d74f3d4b00 --- lib/fileindex.c +++ lib/fileindex.c @@ -579,38 +579,26 @@ read_fileindex_path(char **path, struct got_hash *ctx, static const struct got_error * read_fileindex_path(char **path, struct got_hash *ctx, FILE *infile) { - const struct got_error *err = NULL; const size_t chunk_size = 8; - size_t n, len = 0, totlen = chunk_size; + char p[PATH_MAX]; + size_t n, len = 0; - *path = malloc(totlen); - if (*path == NULL) - return got_error_from_errno("malloc"); - do { - if (len + chunk_size > totlen) { - char *p = reallocarray(*path, totlen + chunk_size, 1); - if (p == NULL) { - err = got_error_from_errno("reallocarray"); - break; - } - totlen += chunk_size; - *path = p; - } - n = fread(*path + len, 1, chunk_size, infile); - if (n != chunk_size) { - err = got_ferror(infile, GOT_ERR_FILEIDX_BAD); - break; - } - got_hash_update(ctx, *path + len, chunk_size); + if (len + chunk_size > sizeof(p)) + return got_error(GOT_ERR_FILEIDX_BAD); + + n = fread(&p[len], 1, chunk_size, infile); + if (n != chunk_size) + return got_ferror(infile, GOT_ERR_FILEIDX_BAD); + + got_hash_update(ctx, &p[len], chunk_size); len += chunk_size; - } while (memchr(*path + len - chunk_size, '\0', chunk_size) == NULL); + } while (memchr(&p[len - chunk_size], '\0', chunk_size) == NULL); - if (err) { - free(*path); - *path = NULL; - } - return err; + *path = strdup(p); + if (*path == NULL) + return got_error_from_errno("strdup"); + return NULL; } static const struct got_error *