Sanitize git_diff_format_email_options' summary parameter It will form part of the subject line and should thus be one line.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
diff --git a/src/diff.c b/src/diff.c
index ba3cd26..cb05a5f 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1544,6 +1544,7 @@ int git_diff_format_email(
const git_diff_format_email_options *opts)
{
git_diff_stats *stats = NULL;
+ char *summary = NULL, *loc = NULL;
bool ignore_marker;
unsigned int format_flags = 0;
int error;
@@ -1565,8 +1566,24 @@ int git_diff_format_email(
}
}
+ /* the summary we receive may not be clean.
+ * it could potentially contain new line characters
+ * or not be set, sanitize, */
+ if ((loc = strpbrk(opts->summary, "\r\n")) != NULL) {
+ size_t offset = 0;
+
+ if ((offset = (loc - opts->summary)) == 0) {
+ giterr_set(GITERR_INVALID, "summary is empty");
+ error = -1;
+ }
+
+ summary = git__calloc(offset + 1, sizeof(char));
+ GITERR_CHECK_ALLOC(summary);
+ strncpy(summary, opts->summary, offset);
+ }
+
error = git_diff_format_email__append_header_tobuf(out,
- opts->id, opts->author, opts->summary,
+ opts->id, opts->author, summary == NULL ? opts->summary : summary,
opts->patch_no, opts->total_patches, ignore_marker);
if (error < 0)
@@ -1583,6 +1600,7 @@ int git_diff_format_email(
error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n");
on_error:
+ git__free(summary);
git_diff_stats_free(stats);
return error;
diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c
index ff0209e..dbd4155 100644
--- a/tests/diff/format_email.c
+++ b/tests/diff/format_email.c
@@ -443,3 +443,71 @@ void test_diff_format_email__rename_add_remove(void)
git_buf_free(&buf);
}
+void test_diff_format_email__multiline_summary(void)
+{
+ git_oid oid;
+ git_commit *commit = NULL;
+ git_diff *diff = NULL;
+ git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
+ git_buf buf = GIT_BUF_INIT;
+
+ const char *email =
+ "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \
+ "From: Jacques Germishuys <jacquesg@striata.com>\n" \
+ "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \
+ "Subject: [PATCH] Modify some content\n" \
+ "\n" \
+ "---\n" \
+ " file1.txt | 8 +++++---\n" \
+ " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \
+ "\n" \
+ "diff --git a/file1.txt b/file1.txt\n" \
+ "index 94aaae8..af8f41d 100644\n" \
+ "--- a/file1.txt\n" \
+ "+++ b/file1.txt\n" \
+ "@@ -1,15 +1,17 @@\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ "+_file1.txt_\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ "+\n" \
+ "+\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ " file1.txt\n" \
+ "-file1.txt\n" \
+ "-file1.txt\n" \
+ "-file1.txt\n" \
+ "+_file1.txt_\n" \
+ "+_file1.txt_\n" \
+ " file1.txt\n" \
+ "--\n" \
+ "libgit2 " LIBGIT2_VERSION "\n" \
+ "\n";
+
+ git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92");
+
+ cl_git_pass(git_commit_lookup(&commit, repo, &oid));
+
+ opts.id = git_commit_id(commit);
+ opts.author = git_commit_author(commit);
+ opts.summary = "Modify some content\nSome extra stuff here";
+
+ cl_git_pass(git_diff__commit(&diff, repo, commit, NULL));
+ cl_git_pass(git_diff_format_email(&buf, diff, &opts));
+ cl_assert(strcmp(git_buf_cstr(&buf), email) == 0);
+
+ git_buf_clear(&buf);
+ cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL));
+ cl_assert(strcmp(git_buf_cstr(&buf), email) == 0);
+
+ git_diff_free(diff);
+ git_commit_free(commit);
+ git_buf_free(&buf);
+}
+