commit b9c41b542bba17bb3bcdd1ee0795845e086bcf4b from: Stefan Sperling date: Tue Aug 03 08:08:03 2021 UTC use less memory allocations when formatting log messages Rewrite got_object_commit_get_logmsg() such that only one memory allocation is made when creating a pretty version of a log message. ok naddy@ commit - aa8b5dd032c8cba930e5be67a90069a95e0001b8 commit + b9c41b542bba17bb3bcdd1ee0795845e086bcf4b blob - 011bee15a8060f553f213c02b686ba3734dcbeca blob + 4c0fd4f7fc733881e493f8944da591fe3502b689 --- lib/object_parse.c +++ lib/object_parse.c @@ -439,55 +439,48 @@ const struct got_error * got_object_commit_get_logmsg(char **logmsg, struct got_commit_object *commit) { const struct got_error *err = NULL; - char *msg0, *msg, *line, *s; + const char *src; + char *dst; size_t len; - int headers = 1; - - *logmsg = NULL; - msg0 = strdup(commit->logmsg); - if (msg0 == NULL) - return got_error_from_errno("strdup"); - - /* Copy log message line by line to strip out unusual headers... */ - msg = msg0; - do { - if ((line = strsep(&msg, "\n")) == NULL) - break; + len = strlen(commit->logmsg); + *logmsg = malloc(len + 2); /* leave room for a trailing \n and \0 */ + if (*logmsg == NULL) + return got_error_from_errno("malloc"); - if (headers == 1) { - if (line[0] != '\0' && - strncmp(line, GOT_COMMIT_LABEL_TREE, - strlen(GOT_COMMIT_LABEL_TREE)) != 0 && - strncmp(line, GOT_COMMIT_LABEL_AUTHOR, - strlen(GOT_COMMIT_LABEL_AUTHOR)) != 0 && - strncmp(line, GOT_COMMIT_LABEL_PARENT, - strlen(GOT_COMMIT_LABEL_PARENT)) != 0 && - strncmp(line, GOT_COMMIT_LABEL_COMMITTER, - strlen(GOT_COMMIT_LABEL_COMMITTER)) != 0) - continue; + /* + * Strip out unusual headers. Headers are separated from the commit + * message body by a single empty line. + */ + src = commit->logmsg; + dst = *logmsg; + while (*src != '\0' && *src != '\n') { + int copy_header = 1, eol = 0; + if (strncmp(src, GOT_COMMIT_LABEL_TREE, + strlen(GOT_COMMIT_LABEL_TREE)) != 0 && + strncmp(src, GOT_COMMIT_LABEL_AUTHOR, + strlen(GOT_COMMIT_LABEL_AUTHOR)) != 0 && + strncmp(src, GOT_COMMIT_LABEL_PARENT, + strlen(GOT_COMMIT_LABEL_PARENT)) != 0 && + strncmp(src, GOT_COMMIT_LABEL_COMMITTER, + strlen(GOT_COMMIT_LABEL_COMMITTER)) != 0) + copy_header = 0; - if (line[0] == '\0') - headers = 0; + while (*src != '\0' && !eol) { + if (copy_header) { + *dst = *src; + dst++; + } + if (*src == '\n') + eol = 1; + src++; } - - if (asprintf(&s, "%s%s\n", - *logmsg ? *logmsg : "", line) == -1) { - err = got_error_from_errno("asprintf"); - goto done; - } - free(*logmsg); - *logmsg = s; + } + *dst = '\0'; - } while (line); - - if (*logmsg == NULL) { - /* log message does not contain \n */ - *logmsg = strdup(commit->logmsg); - if (*logmsg == NULL) { - err = got_error_from_errno("strdup"); - goto done; - } + if (strlcat(*logmsg, src, len + 1) >= len + 1) { + err = got_error(GOT_ERR_NO_SPACE); + goto done; } /* Trim redundant trailing whitespace. */ @@ -497,8 +490,13 @@ got_object_commit_get_logmsg(char **logmsg, struct got (*logmsg)[len - 1] = '\0'; len--; } + + /* Append a trailing newline if missing. */ + if (len > 0 && (*logmsg)[len - 1] != '\n') { + (*logmsg)[len] = '\n'; + (*logmsg)[len + 1] = '\0'; + } done: - free(msg0); if (err) { free(*logmsg); *logmsg = NULL;