Merge branch 'jk/commit-buffer-length'
Move "commit->buffer" out of the in-core commit object and keep track of their lengths. Use this to optimize the code paths to validate GPG signatures in commit objects. * jk/commit-buffer-length: reuse cached commit buffer when parsing signatures commit: record buffer length in cache commit: convert commit->buffer to a slab commit-slab: provide a static initializer use get_commit_buffer everywhere convert logmsg_reencode to get_commit_buffer use get_commit_buffer to avoid duplicate code use get_cached_commit_buffer where appropriate provide helpers to access the commit buffer provide a helper to set the commit buffer provide a helper to free commit buffer sequencer: use logmsg_reencode in get_message logmsg_reencode: return const buffer do not create "struct commit" with xcalloc commit: push commit_index update into alloc_commit_node alloc: include any-object allocations in alloc_report replace dangerous uses of strbuf_attach commit_tree: take a pointer/len pair rather than a const strbuf
This commit is contained in:
131
commit.c
131
commit.c
@ -17,7 +17,6 @@ static struct commit_extra_header *read_commit_extra_header_lines(const char *bu
|
||||
int save_commit_buffer = 1;
|
||||
|
||||
const char *commit_type = "commit";
|
||||
static int commit_count;
|
||||
|
||||
static struct commit *check_commit(struct object *obj,
|
||||
const unsigned char *sha1,
|
||||
@ -64,7 +63,6 @@ struct commit *lookup_commit(const unsigned char *sha1)
|
||||
struct object *obj = lookup_object(sha1);
|
||||
if (!obj) {
|
||||
struct commit *c = alloc_commit_node();
|
||||
c->index = commit_count++;
|
||||
return create_object(sha1, OBJ_COMMIT, c);
|
||||
}
|
||||
if (!obj->type)
|
||||
@ -247,6 +245,76 @@ int unregister_shallow(const unsigned char *sha1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct commit_buffer {
|
||||
void *buffer;
|
||||
unsigned long size;
|
||||
};
|
||||
define_commit_slab(buffer_slab, struct commit_buffer);
|
||||
static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab);
|
||||
|
||||
void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size)
|
||||
{
|
||||
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
|
||||
v->buffer = buffer;
|
||||
v->size = size;
|
||||
}
|
||||
|
||||
const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep)
|
||||
{
|
||||
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
|
||||
if (sizep)
|
||||
*sizep = v->size;
|
||||
return v->buffer;
|
||||
}
|
||||
|
||||
const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
|
||||
{
|
||||
const void *ret = get_cached_commit_buffer(commit, sizep);
|
||||
if (!ret) {
|
||||
enum object_type type;
|
||||
unsigned long size;
|
||||
ret = read_sha1_file(commit->object.sha1, &type, &size);
|
||||
if (!ret)
|
||||
die("cannot read commit object %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
if (type != OBJ_COMMIT)
|
||||
die("expected commit for %s, got %s",
|
||||
sha1_to_hex(commit->object.sha1), typename(type));
|
||||
if (sizep)
|
||||
*sizep = size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void unuse_commit_buffer(const struct commit *commit, const void *buffer)
|
||||
{
|
||||
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
|
||||
if (v->buffer != buffer)
|
||||
free((void *)buffer);
|
||||
}
|
||||
|
||||
void free_commit_buffer(struct commit *commit)
|
||||
{
|
||||
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
|
||||
free(v->buffer);
|
||||
v->buffer = NULL;
|
||||
v->size = 0;
|
||||
}
|
||||
|
||||
const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
|
||||
{
|
||||
struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
|
||||
void *ret;
|
||||
|
||||
ret = v->buffer;
|
||||
if (sizep)
|
||||
*sizep = v->size;
|
||||
|
||||
v->buffer = NULL;
|
||||
v->size = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
|
||||
{
|
||||
const char *tail = buffer;
|
||||
@ -324,7 +392,7 @@ int parse_commit(struct commit *item)
|
||||
}
|
||||
ret = parse_commit_buffer(item, buffer, size);
|
||||
if (save_commit_buffer && !ret) {
|
||||
item->buffer = buffer;
|
||||
set_commit_buffer(item, buffer, size);
|
||||
return 0;
|
||||
}
|
||||
free(buffer);
|
||||
@ -539,22 +607,12 @@ static void record_author_date(struct author_date_slab *author_date,
|
||||
struct commit *commit)
|
||||
{
|
||||
const char *buf, *line_end, *ident_line;
|
||||
char *buffer = NULL;
|
||||
const char *buffer = get_commit_buffer(commit, NULL);
|
||||
struct ident_split ident;
|
||||
char *date_end;
|
||||
unsigned long date;
|
||||
|
||||
if (!commit->buffer) {
|
||||
unsigned long size;
|
||||
enum object_type type;
|
||||
buffer = read_sha1_file(commit->object.sha1, &type, &size);
|
||||
if (!buffer)
|
||||
return;
|
||||
}
|
||||
|
||||
for (buf = commit->buffer ? commit->buffer : buffer;
|
||||
buf;
|
||||
buf = line_end + 1) {
|
||||
for (buf = buffer; buf; buf = line_end + 1) {
|
||||
line_end = strchrnul(buf, '\n');
|
||||
ident_line = skip_prefix(buf, "author ");
|
||||
if (!ident_line) {
|
||||
@ -575,7 +633,7 @@ static void record_author_date(struct author_date_slab *author_date,
|
||||
*(author_date_slab_at(author_date, commit)) = date;
|
||||
|
||||
fail_exit:
|
||||
free(buffer);
|
||||
unuse_commit_buffer(commit, buffer);
|
||||
}
|
||||
|
||||
static int compare_commits_by_author_date(const void *a_, const void *b_,
|
||||
@ -1080,17 +1138,14 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_signed_commit(const unsigned char *sha1,
|
||||
int parse_signed_commit(const struct commit *commit,
|
||||
struct strbuf *payload, struct strbuf *signature)
|
||||
{
|
||||
unsigned long size;
|
||||
enum object_type type;
|
||||
char *buffer = read_sha1_file(sha1, &type, &size);
|
||||
int in_signature, saw_signature = -1;
|
||||
char *line, *tail;
|
||||
|
||||
if (!buffer || type != OBJ_COMMIT)
|
||||
goto cleanup;
|
||||
unsigned long size;
|
||||
const char *buffer = get_commit_buffer(commit, &size);
|
||||
int in_signature, saw_signature = -1;
|
||||
const char *line, *tail;
|
||||
|
||||
line = buffer;
|
||||
tail = buffer + size;
|
||||
@ -1098,7 +1153,7 @@ int parse_signed_commit(const unsigned char *sha1,
|
||||
saw_signature = 0;
|
||||
while (line < tail) {
|
||||
const char *sig = NULL;
|
||||
char *next = memchr(line, '\n', tail - line);
|
||||
const char *next = memchr(line, '\n', tail - line);
|
||||
|
||||
next = next ? next + 1 : tail;
|
||||
if (in_signature && line[0] == ' ')
|
||||
@ -1119,8 +1174,7 @@ int parse_signed_commit(const unsigned char *sha1,
|
||||
}
|
||||
line = next;
|
||||
}
|
||||
cleanup:
|
||||
free(buffer);
|
||||
unuse_commit_buffer(commit, buffer);
|
||||
return saw_signature;
|
||||
}
|
||||
|
||||
@ -1211,8 +1265,7 @@ void check_commit_signature(const struct commit* commit, struct signature_check
|
||||
|
||||
sigc->result = 'N';
|
||||
|
||||
if (parse_signed_commit(commit->object.sha1,
|
||||
&payload, &signature) <= 0)
|
||||
if (parse_signed_commit(commit, &payload, &signature) <= 0)
|
||||
goto out;
|
||||
status = verify_signed_buffer(payload.buf, payload.len,
|
||||
signature.buf, signature.len,
|
||||
@ -1257,11 +1310,9 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
|
||||
{
|
||||
struct commit_extra_header *extra = NULL;
|
||||
unsigned long size;
|
||||
enum object_type type;
|
||||
char *buffer = read_sha1_file(commit->object.sha1, &type, &size);
|
||||
if (buffer && type == OBJ_COMMIT)
|
||||
extra = read_commit_extra_header_lines(buffer, size, exclude);
|
||||
free(buffer);
|
||||
const char *buffer = get_commit_buffer(commit, &size);
|
||||
extra = read_commit_extra_header_lines(buffer, size, exclude);
|
||||
unuse_commit_buffer(commit, buffer);
|
||||
return extra;
|
||||
}
|
||||
|
||||
@ -1344,7 +1395,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
|
||||
}
|
||||
}
|
||||
|
||||
int commit_tree(const struct strbuf *msg, const unsigned char *tree,
|
||||
int commit_tree(const char *msg, size_t msg_len,
|
||||
const unsigned char *tree,
|
||||
struct commit_list *parents, unsigned char *ret,
|
||||
const char *author, const char *sign_commit)
|
||||
{
|
||||
@ -1352,7 +1404,7 @@ int commit_tree(const struct strbuf *msg, const unsigned char *tree,
|
||||
int result;
|
||||
|
||||
append_merge_tag_headers(parents, &tail);
|
||||
result = commit_tree_extended(msg, tree, parents, ret,
|
||||
result = commit_tree_extended(msg, msg_len, tree, parents, ret,
|
||||
author, sign_commit, extra);
|
||||
free_commit_extra_headers(extra);
|
||||
return result;
|
||||
@ -1473,7 +1525,8 @@ static const char commit_utf8_warn[] =
|
||||
"You may want to amend it after fixing the message, or set the config\n"
|
||||
"variable i18n.commitencoding to the encoding your project uses.\n";
|
||||
|
||||
int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
|
||||
int commit_tree_extended(const char *msg, size_t msg_len,
|
||||
const unsigned char *tree,
|
||||
struct commit_list *parents, unsigned char *ret,
|
||||
const char *author, const char *sign_commit,
|
||||
struct commit_extra_header *extra)
|
||||
@ -1484,7 +1537,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
|
||||
|
||||
assert_sha1_type(tree, OBJ_TREE);
|
||||
|
||||
if (memchr(msg->buf, '\0', msg->len))
|
||||
if (memchr(msg, '\0', msg_len))
|
||||
return error("a NUL byte in commit log message not allowed.");
|
||||
|
||||
/* Not having i18n.commitencoding is the same as having utf-8 */
|
||||
@ -1523,7 +1576,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
|
||||
strbuf_addch(&buffer, '\n');
|
||||
|
||||
/* And add the comment */
|
||||
strbuf_addbuf(&buffer, msg);
|
||||
strbuf_add(&buffer, msg, msg_len);
|
||||
|
||||
/* And check the encoding */
|
||||
if (encoding_is_utf8 && !verify_utf8(&buffer))
|
||||
|
||||
Reference in New Issue
Block a user