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>
This commit is contained in:
brian m. carlson
2026-04-27 22:18:34 +00:00
committed by Junio C Hamano
parent 1ddc0481cf
commit 7735d7eee3
2 changed files with 21 additions and 4 deletions
+11 -4
View File
@@ -1726,6 +1726,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
struct repository *r = the_repository;
int result = 0;
int encoding_is_utf8;
bool warned = false;
struct strbuf buffer = STRBUF_INIT, compat_buffer = STRBUF_INIT;
struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
struct object_id *parent_buf = NULL, *compat_oid = NULL;
@@ -1747,6 +1748,13 @@ int commit_tree_extended(const char *msg, size_t msg_len,
oidcpy(&parent_buf[i++], &p->item->object.oid);
write_commit_tree(&buffer, msg, msg_len, tree, parent_buf, nparents, author, committer, extra);
/* And check the encoding. */
if (encoding_is_utf8 && !ensure_utf8(&buffer)) {
fprintf(stderr, _(commit_utf8_warn));
warned = true;
}
if (sign_commit && sign_buffer(&buffer, &sig, sign_commit,
SIGN_BUFFER_USE_DEFAULT_KEY)) {
result = -1;
@@ -1780,6 +1788,9 @@ int commit_tree_extended(const char *msg, size_t msg_len,
free_commit_extra_headers(compat_extra);
free(mapped_parents);
if (encoding_is_utf8 && !ensure_utf8(&compat_buffer) && !warned)
fprintf(stderr, _(commit_utf8_warn));
if (sign_commit && sign_buffer(&compat_buffer, &compat_sig,
sign_commit,
SIGN_BUFFER_USE_DEFAULT_KEY)) {
@@ -1818,10 +1829,6 @@ int commit_tree_extended(const char *msg, size_t msg_len,
}
}
/* And check the encoding. */
if (encoding_is_utf8 && (!ensure_utf8(&buffer) || !ensure_utf8(&compat_buffer)))
fprintf(stderr, _(commit_utf8_warn));
if (r->compat_hash_algo) {
hash_object_file(r->compat_hash_algo, compat_buffer.buf, compat_buffer.len,
OBJ_COMMIT, &compat_oid_buf);
+10
View File
@@ -462,4 +462,14 @@ test_expect_success 'custom `gpg.program`' '
git commit -S --allow-empty -m signed-commit
'
test_expect_success GPG 'commit verifies with non-UTF-8 commit message' '
printf "I hate\\376\\377UTF-8\\n" >message &&
echo unusual-message >file &&
git add file &&
test_tick && git commit -S -F message 2>err &&
git verify-commit HEAD &&
grep "commit message did not conform to UTF-8" err >lines &&
test_line_count = 1 lines
'
test_done