commit 235b06458a4e60a61dced04eccef13dfe62c270e from: Omar Polo via: Thomas Adam date: Sat Oct 28 11:32:53 2023 UTC patch: handle NULs in lines got patch assumes that lines can be encoded as strings, so embedded NUL bytes truncates what got sees of the line. While here, add some minor semplification to the logic by splitting the type out of the line string and change linecmp into lines_eq (name suggested by stsp@) ok stsp@ commit - d50c8991ddc68e92266707a26186b792429d767f commit + 235b06458a4e60a61dced04eccef13dfe62c270e blob - 859db450301302dc99c3de2be338542c3ced2112 blob + 9eefe7a7a92b333c9eb4231c478f26c9255591d7 --- lib/patch.c +++ lib/patch.c @@ -57,6 +57,12 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif +struct got_patch_line { + char mode; + char *line; + size_t len; +}; + struct got_patch_hunk { STAILQ_ENTRY(got_patch_hunk) entries; const struct got_error *err; @@ -70,7 +76,7 @@ struct got_patch_hunk { int new_lines; size_t len; size_t cap; - char **lines; + struct got_patch_line *lines; }; STAILQ_HEAD(got_patch_hunk_head, got_patch_hunk); @@ -126,7 +132,7 @@ patch_free(struct got_patch *p) STAILQ_REMOVE_HEAD(&p->head, entries); for (i = 0; i < h->len; ++i) - free(h->lines[i]); + free(h->lines[i].line); free(h->lines); free(h); } @@ -139,7 +145,7 @@ patch_free(struct got_patch *p) } static const struct got_error * -pushline(struct got_patch_hunk *h, const char *line) +pushline(struct got_patch_hunk *h, const char *line, size_t len) { void *t; size_t newcap; @@ -155,10 +161,14 @@ pushline(struct got_patch_hunk *h, const char *line) h->cap = newcap; } - if ((t = strdup(line)) == NULL) - return got_error_from_errno("strdup"); + if ((t = malloc(len - 1)) == NULL) + return got_error_from_errno("malloc"); + memcpy(t, line + 1, len - 1); /* skip the line type */ - h->lines[h->len++] = t; + h->lines[h->len].mode = *line; + h->lines[h->len].line = t; + h->lines[h->len].len = len - 2; /* line type and trailing NUL */ + h->len++; return NULL; } @@ -299,7 +309,7 @@ recv_patch(struct imsgbuf *ibuf, int *done, struct got } if (*t != '\\') - err = pushline(h, t); + err = pushline(h, t, datalen); else if (lastmode == '-') h->old_nonl = 1; else if (lastmode == '+') @@ -349,10 +359,10 @@ reverse_patch(struct got_patch *p) h->new_nonl = tmp; for (i = 0; i < h->len; ++i) { - if (*h->lines[i] == '+') - *h->lines[i] = '-'; - else if (*h->lines[i] == '-') - *h->lines[i] = '+'; + if (h->lines[i].mode == '+') + h->lines[i].mode = '-'; + else if (h->lines[i].mode == '-') + h->lines[i].mode = '+'; } } } @@ -390,14 +400,15 @@ copy(FILE *tmp, FILE *orig, off_t copypos, off_t pos) return NULL; } -static int linecmp(const char *, const char *, int *); +static int lines_eq(struct got_patch_line *, const char *, size_t, int *); static const struct got_error * locate_hunk(FILE *orig, struct got_patch_hunk *h, off_t *pos, int *lineno) { const struct got_error *err = NULL; + struct got_patch_line *l = &h->lines[0]; char *line = NULL; - char mode = *h->lines[0]; + char mode = l->mode; size_t linesize = 0; ssize_t linelen; off_t match = -1; @@ -412,12 +423,10 @@ locate_hunk(FILE *orig, struct got_patch_hunk *h, off_ err = got_error(GOT_ERR_HUNK_FAILED); break; } - if (line[linelen - 1] == '\n') - line[linelen - 1] = '\0'; (*lineno)++; - if ((mode == ' ' && !linecmp(h->lines[0] + 1, line, &mangled)) || - (mode == '-' && !linecmp(h->lines[0] + 1, line, &mangled)) || + if ((mode == ' ' && lines_eq(l, line, linelen, &mangled)) || + (mode == '-' && lines_eq(l, line, linelen, &mangled)) || (mode == '+' && *lineno == h->old_from)) { match = ftello(orig); if (match == -1) { @@ -447,27 +456,34 @@ locate_hunk(FILE *orig, struct got_patch_hunk *h, off_ } static int -linecmp(const char *a, const char *b, int *mangled) +lines_eq(struct got_patch_line *l, const char *b, size_t len, int *mangled) { - int c; + char *a = l->line; + size_t i, j; + if (len > 00 && b[len - 1] == '\n') + len--; + *mangled = 0; - c = strcmp(a, b); - if (c == 0) - return c; + if (l->len == len && !memcmp(a, b, len)) + return 1; *mangled = 1; + + i = j = 0; for (;;) { - while (*a == '\t' || *a == ' ' || *a == '\f') - a++; - while (*b == '\t' || *b == ' ' || *b == '\f') - b++; - if (*a == '\0' || *a != *b) + while (i < l->len && + (a[i] == '\t' || a[i] == ' ' || a[i] == '\f')) + i++; + while (j < len && + (b[j] == '\t' || b[j] == ' ' || b[j] == '\f')) + j++; + if (i == l->len || j == len || a[i] != b[j]) break; - a++, b++; + i++, j++; } - return *a - *b; + return (i == l->len && j == len); } static const struct got_error * @@ -480,7 +496,7 @@ test_hunk(FILE *orig, struct got_patch_hunk *h) int mangled; for (i = 0; i < h->len; ++i) { - switch (*h->lines[i]) { + switch (h->lines[i].mode) { case '+': continue; case ' ': @@ -494,9 +510,7 @@ test_hunk(FILE *orig, struct got_patch_hunk *h) GOT_ERR_HUNK_FAILED); goto done; } - if (line[linelen - 1] == '\n') - line[linelen - 1] = '\0'; - if (linecmp(h->lines[i] + 1, line, &mangled)) { + if (!lines_eq(&h->lines[i], line, linelen, &mangled)) { err = got_error(GOT_ERR_HUNK_FAILED); goto done; } @@ -520,13 +534,14 @@ apply_hunk(FILE *orig, FILE *tmp, struct got_patch_hun size_t linesize = 0, i, new = 0; char *line = NULL; char mode; + size_t l; ssize_t linelen; if (orig != NULL && fseeko(orig, from, SEEK_SET) == -1) return got_error_from_errno("fseeko"); for (i = 0; i < h->len; ++i) { - switch (mode = *h->lines[i]) { + switch (mode = h->lines[i].mode) { case '-': case ' ': (*lineno)++; @@ -539,18 +554,24 @@ apply_hunk(FILE *orig, FILE *tmp, struct got_patch_hun if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; t = line; - } else - t = h->lines[i] + 1; + l = linelen - 1; + } else { + t = h->lines[i].line; + l = h->lines[i].len; + } if (mode == '-') continue; - if (fprintf(tmp, "%s\n", t) < 0) { + if (fwrite(t, 1, l, tmp) != l || + fputc('\n', tmp) == EOF) { err = got_error_from_errno("fprintf"); goto done; } break; case '+': new++; - if (fprintf(tmp, "%s", h->lines[i] + 1) < 0) { + t = h->lines[i].line; + l = h->lines[i].len; + if (fwrite(t, 1, l, tmp) != l) { err = got_error_from_errno("fprintf"); goto done; } blob - 356a98a6a2717f7b336945d2f9e218faf421ebda blob + 2bd03989ae5d34928f3c1eada815a2c0085adfca --- libexec/got-read-patch/got-read-patch.c +++ libexec/got-read-patch/got-read-patch.c @@ -443,23 +443,29 @@ parse_hdr(char *s, int *done, struct got_imsg_patch_hu } static const struct got_error * -send_line(const char *line) +send_line(const char *line, size_t len) { static const struct got_error *err = NULL; - char *p = NULL; + struct iovec iov[2]; + int iovcnt = 0; + memset(&iov, 0, sizeof(iov)); + if (*line != '+' && *line != '-' && *line != ' ' && *line != '\\') { - if (asprintf(&p, " %s", line) == -1) - return got_error_from_errno("asprintf"); - line = p; + iov[iovcnt].iov_base = (void *)" "; + iov[iovcnt].iov_len = 1; + iovcnt++; } - if (imsg_compose(&ibuf, GOT_IMSG_PATCH_LINE, 0, 0, -1, - line, strlen(line) + 1) == -1) + iov[iovcnt].iov_base = (void *)line; + iov[iovcnt].iov_len = len; + iovcnt++; + + if (imsg_composev(&ibuf, GOT_IMSG_PATCH_LINE, 0, 0, -1, + iov, iovcnt) == -1) err = got_error_from_errno( "imsg_compose GOT_IMSG_PATCH_LINE"); - free(p); return err; } @@ -476,7 +482,7 @@ peek_special_line(FILE *fp) } if (ch == '\\') { - err = send_line("\\"); + err = send_line("\\", 2); if (err) return err; } @@ -566,7 +572,7 @@ parse_hunk(FILE *fp, int *done) goto done; } - err = send_line(line); + err = send_line(line, linelen); if (err) goto done;