gpg-interface: fix strip_cr_before_lf to only remove CR before LF

c4adea82c5 (Convert CR/LF to LF in tag signatures, 2008-07-11) introduced CR stripping for GPG output on Windows, but intentionally stripped all CR characters unconditionally to "keep the code simpler", even though only CRLF sequences (Windows line endings) needed to be normalized. Later 2f47eae2a1 (Split GPG interface into its own helper library, 2011-09-07) moved the code into gpg-interface.c, and 29b315778e (ssh signing: add ssh key format and signing code, 2021-09-10) extracted it into the remove_cr_after() helper when adding SSH signing support, while noticing that it unconditionally strips all CRs, leaving a NEEDSWORK comment. Fix the loop to skip CR only when immediately followed by LF, keeping lone trailing CR characters intact. Rename the function to strip_cr_before_lf to reflect its corrected behavior, and update both call sites and their comments accordingly. Signed-off-by: Antonio De Stefani <antonio.destefani08@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Antonio De Stefani committed Jun 24, 2026 at 11:36 UTC 5dea8b690b50a4f4d11ddc8f2f6cd24a816102ad
1 file changed +11 -14
gpg-interface.c
+11 -14
@@ -990,21 +990,18 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
990 return ret;
991 }
992
993 -/*
994 - * Strip CR from the line endings, in case we are on Windows.
995 - * NEEDSWORK: make it trim only CRs before LFs and rename
996 - */
997 -static void remove_cr_after(struct strbuf *buffer, size_t offset)
993 +/* Strip CR before LF from the line endings, in case we are on Windows. */
994 +static void strip_cr_before_lf(struct strbuf *buffer, size_t offset)
995 {
996 size_t i, j;
997
998 for (i = j = offset; i < buffer->len; i++) {
1002 - if (buffer->buf[i] != '\r') {
1003 - if (i != j)
1004 - buffer->buf[j] = buffer->buf[i];
1005 - j++;
1006 - }
999 + if (buffer->buf[i] == '\r' &&
1000 + i + 1 < buffer->len && buffer->buf[i + 1] == '\n')
1001 + continue;
1002 + buffer->buf[j++] = buffer->buf[i];
1003 }
1004 +
1005 strbuf_setlen(buffer, j);
1006 }
1007
@@ -1049,8 +1046,8 @@ static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
1046 }
1047 strbuf_release(&gpg_status);
1048
1052 - /* Strip CR from the line endings, in case we are on Windows. */
1053 - remove_cr_after(signature, bottom);
1049 + /* Strip CR before LF from the line endings, in case we are on Windows. */
1050 + strip_cr_before_lf(signature, bottom);
1051
1052 return 0;
1053 }
@@ -1136,8 +1133,8 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
1133 ssh_signature_filename.buf);
1134 goto out;
1135 }
1139 - /* Strip CR from the line endings, in case we are on Windows. */
1140 - remove_cr_after(signature, bottom);
1136 + /* Strip CR before LF from the line endings, in case we are on Windows. */
1137 + strip_cr_before_lf(signature, bottom);
1138
1139 out:
1140 if (key_file)