commit: sign commit after mutating buffer
The ensure_utf8 function can mutate the buffer to change its encoding, so we must call it before signing the buffer so that we do not invalidate the signature, which is made over raw bytes. Fix a bug which caused the compatibility code to not convert the compatibility buffer if the main buffer was invalid UTF-8. We expect both buffers to be valid UTF-8 or both invalid, since the only data that would differ between them would be hex object IDs, which are always valid UTF-8. Add a test for this case using 0xfe and 0xff, which are never valid in UTF-8. Reported-by: Kushal Das <kushal@sunet.se> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
brian m. carlson committed
Apr 27, 2026 at 22:18 UTC
7735d7eee3a586181dc397afa5aa8f02e009833b
2 files changed
+21
-4
commit.c
+11
-4
@@ -1726,6 +1726,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
1726
struct repository *r = the_repository;
1727
int result = 0;
1728
int encoding_is_utf8;
1729
+ bool warned = false;
1730
struct strbuf buffer = STRBUF_INIT, compat_buffer = STRBUF_INIT;
1731
struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
1732
struct object_id *parent_buf = NULL, *compat_oid = NULL;
@@ -1747,6 +1748,13 @@ int commit_tree_extended(const char *msg, size_t msg_len,
1748
oidcpy(&parent_buf[i++], &p->item->object.oid);
1749
1750
write_commit_tree(&buffer, msg, msg_len, tree, parent_buf, nparents, author, committer, extra);
1751
+
1752
+ /* And check the encoding. */
1753
+ if (encoding_is_utf8 && !ensure_utf8(&buffer)) {
1754
+ fprintf(stderr, _(commit_utf8_warn));
1755
+ warned = true;
1756
+ }
1757
+
1758
if (sign_commit && sign_buffer(&buffer, &sig, sign_commit,
1759
SIGN_BUFFER_USE_DEFAULT_KEY)) {
1760
result = -1;
@@ -1780,6 +1788,9 @@ int commit_tree_extended(const char *msg, size_t msg_len,
1788
free_commit_extra_headers(compat_extra);
1789
free(mapped_parents);
1790
1791
+ if (encoding_is_utf8 && !ensure_utf8(&compat_buffer) && !warned)
1792
+ fprintf(stderr, _(commit_utf8_warn));
1793
+
1794
if (sign_commit && sign_buffer(&compat_buffer, &compat_sig,
1795
sign_commit,
1796
SIGN_BUFFER_USE_DEFAULT_KEY)) {
@@ -1818,10 +1829,6 @@ int commit_tree_extended(const char *msg, size_t msg_len,
1829
}
1830
}
1831
1821
- /* And check the encoding. */
1822
- if (encoding_is_utf8 && (!ensure_utf8(&buffer) || !ensure_utf8(&compat_buffer)))
1823
- fprintf(stderr, _(commit_utf8_warn));
1824
-
1832
if (r->compat_hash_algo) {
1833
hash_object_file(r->compat_hash_algo, compat_buffer.buf, compat_buffer.len,
1834
OBJ_COMMIT, &compat_oid_buf);
t/t7510-signed-commit.sh
+10
@@ -462,4 +462,14 @@ test_expect_success 'custom `gpg.program`' '
462
git commit -S --allow-empty -m signed-commit
463
'
464
465
+test_expect_success GPG 'commit verifies with non-UTF-8 commit message' '
466
+ printf "I hate\\376\\377UTF-8\\n" >message &&
467
+ echo unusual-message >file &&
468
+ git add file &&
469
+ test_tick && git commit -S -F message 2>err &&
470
+ git verify-commit HEAD &&
471
+ grep "commit message did not conform to UTF-8" err >lines &&
472
+ test_line_count = 1 lines
473
+'
474
+
475
test_done