mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-02 16:34:37 +00:00
blame: use size_t for line counts in git_blame_hunk
It is not unreasonable to have versioned files with a line count exceeding 2^16. Upon blaming such files we fail to correctly keep track of the lines as `git_blame_hunk` stores them in `uint16_t` fields. Fix this by converting the line fields of `git_blame_hunk` to `size_t`. Add test to verify behavior.
This commit is contained in:
parent
337b2b08f4
commit
cb1cb24ca9
@ -74,8 +74,8 @@ typedef struct git_blame_options {
|
||||
uint16_t min_match_characters;
|
||||
git_oid newest_commit;
|
||||
git_oid oldest_commit;
|
||||
uint32_t min_line;
|
||||
uint32_t max_line;
|
||||
size_t min_line;
|
||||
size_t max_line;
|
||||
} git_blame_options;
|
||||
|
||||
#define GIT_BLAME_OPTIONS_VERSION 1
|
||||
@ -113,15 +113,15 @@ GIT_EXTERN(int) git_blame_init_options(
|
||||
* root, or the commit specified in git_blame_options.oldest_commit)
|
||||
*/
|
||||
typedef struct git_blame_hunk {
|
||||
uint16_t lines_in_hunk;
|
||||
size_t lines_in_hunk;
|
||||
|
||||
git_oid final_commit_id;
|
||||
uint16_t final_start_line_number;
|
||||
size_t final_start_line_number;
|
||||
git_signature *final_signature;
|
||||
|
||||
git_oid orig_commit_id;
|
||||
const char *orig_path;
|
||||
uint16_t orig_start_line_number;
|
||||
size_t orig_start_line_number;
|
||||
git_signature *orig_signature;
|
||||
|
||||
char boundary;
|
||||
@ -156,7 +156,7 @@ GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byindex(
|
||||
*/
|
||||
GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byline(
|
||||
git_blame *blame,
|
||||
uint32_t lineno);
|
||||
size_t lineno);
|
||||
|
||||
/**
|
||||
* Get the blame for a single file.
|
||||
|
24
src/blame.c
24
src/blame.c
@ -23,8 +23,8 @@ static int hunk_byfinalline_search_cmp(const void *key, const void *entry)
|
||||
git_blame_hunk *hunk = (git_blame_hunk*)entry;
|
||||
|
||||
size_t lineno = *(size_t*)key;
|
||||
size_t lines_in_hunk = (size_t)hunk->lines_in_hunk;
|
||||
size_t final_start_line_number = (size_t)hunk->final_start_line_number;
|
||||
size_t lines_in_hunk = hunk->lines_in_hunk;
|
||||
size_t final_start_line_number = hunk->final_start_line_number;
|
||||
|
||||
if (lineno < final_start_line_number)
|
||||
return -1;
|
||||
@ -44,7 +44,7 @@ static int hunk_cmp(const void *_a, const void *_b)
|
||||
|
||||
static bool hunk_ends_at_or_before_line(git_blame_hunk *hunk, size_t line)
|
||||
{
|
||||
return line >= (size_t)(hunk->final_start_line_number + hunk->lines_in_hunk - 1);
|
||||
return line >= (hunk->final_start_line_number + hunk->lines_in_hunk - 1);
|
||||
}
|
||||
|
||||
static bool hunk_starts_at_or_after_line(git_blame_hunk *hunk, size_t line)
|
||||
@ -53,9 +53,9 @@ static bool hunk_starts_at_or_after_line(git_blame_hunk *hunk, size_t line)
|
||||
}
|
||||
|
||||
static git_blame_hunk* new_hunk(
|
||||
uint16_t start,
|
||||
uint16_t lines,
|
||||
uint16_t orig_start,
|
||||
size_t start,
|
||||
size_t lines,
|
||||
size_t orig_start,
|
||||
const char *path)
|
||||
{
|
||||
git_blame_hunk *hunk = git__calloc(1, sizeof(git_blame_hunk));
|
||||
@ -166,9 +166,9 @@ const git_blame_hunk *git_blame_get_hunk_byindex(git_blame *blame, uint32_t inde
|
||||
return (git_blame_hunk*)git_vector_get(&blame->hunks, index);
|
||||
}
|
||||
|
||||
const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, uint32_t lineno)
|
||||
const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_t lineno)
|
||||
{
|
||||
size_t i, new_lineno = (size_t)lineno;
|
||||
size_t i, new_lineno = lineno;
|
||||
assert(blame);
|
||||
|
||||
if (!git_vector_bsearch2(&i, &blame->hunks, hunk_byfinalline_search_cmp, &new_lineno)) {
|
||||
@ -223,8 +223,8 @@ static git_blame_hunk *split_hunk_in_vector(
|
||||
}
|
||||
|
||||
new_line_count = hunk->lines_in_hunk - rel_line;
|
||||
nh = new_hunk((uint16_t)(hunk->final_start_line_number+rel_line), (uint16_t)new_line_count,
|
||||
(uint16_t)(hunk->orig_start_line_number+rel_line), hunk->orig_path);
|
||||
nh = new_hunk(hunk->final_start_line_number + rel_line, new_line_count,
|
||||
hunk->orig_start_line_number + rel_line, hunk->orig_path);
|
||||
|
||||
if (!nh)
|
||||
return NULL;
|
||||
@ -233,7 +233,7 @@ static git_blame_hunk *split_hunk_in_vector(
|
||||
git_oid_cpy(&nh->orig_commit_id, &hunk->orig_commit_id);
|
||||
|
||||
/* Adjust hunk that was split */
|
||||
hunk->lines_in_hunk -= (uint16_t)new_line_count;
|
||||
hunk->lines_in_hunk -= new_line_count;
|
||||
git_vector_insert_sorted(vec, nh, NULL);
|
||||
{
|
||||
git_blame_hunk *ret = return_new ? nh : hunk;
|
||||
@ -442,7 +442,7 @@ static int buffer_line_cb(
|
||||
} else {
|
||||
/* Create a new buffer-blame hunk with this line */
|
||||
shift_hunks_by(&blame->hunks, blame->current_diff_line, 1);
|
||||
blame->current_hunk = new_hunk((uint16_t)blame->current_diff_line, 1, 0, blame->path);
|
||||
blame->current_hunk = new_hunk(blame->current_diff_line, 1, 0, blame->path);
|
||||
GITERR_CHECK_ALLOC(blame->current_hunk);
|
||||
|
||||
git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL);
|
||||
|
@ -4,7 +4,7 @@ void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
|
||||
printf("Hunk %"PRIuZ" (line %d +%d): ", idx,
|
||||
printf("Hunk %"PRIuZ" (line %"PRIuZ" +%"PRIuZ"): ", idx,
|
||||
hunk->final_start_line_number, hunk->lines_in_hunk-1);
|
||||
|
||||
va_start(arglist, fmt);
|
||||
@ -15,7 +15,7 @@ void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...)
|
||||
}
|
||||
|
||||
void check_blame_hunk_index(git_repository *repo, git_blame *blame, int idx,
|
||||
int start_line, int len, char boundary, const char *commit_id, const char *orig_path)
|
||||
size_t start_line, size_t len, char boundary, const char *commit_id, const char *orig_path)
|
||||
{
|
||||
char expected[GIT_OID_HEXSZ+1] = {0}, actual[GIT_OID_HEXSZ+1] = {0};
|
||||
const git_blame_hunk *hunk = git_blame_get_hunk_byindex(blame, idx);
|
||||
|
@ -7,10 +7,8 @@ void check_blame_hunk_index(
|
||||
git_repository *repo,
|
||||
git_blame *blame,
|
||||
int idx,
|
||||
int start_line,
|
||||
int len,
|
||||
size_t start_line,
|
||||
size_t len,
|
||||
char boundary,
|
||||
const char *commit_id,
|
||||
const char *orig_path);
|
||||
|
||||
|
||||
|
@ -281,6 +281,18 @@ void test_blame_simple__can_restrict_lines_both(void)
|
||||
check_blame_hunk_index(g_repo, g_blame, 2, 6, 2, 0, "63d671eb", "b.txt");
|
||||
}
|
||||
|
||||
void test_blame_simple__can_blame_huge_file(void)
|
||||
{
|
||||
git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
|
||||
|
||||
cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git")));
|
||||
|
||||
cl_git_pass(git_blame_file(&g_blame, g_repo, "huge.txt", &opts));
|
||||
cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame));
|
||||
check_blame_hunk_index(g_repo, g_blame, 0, 1, 65536, 0, "4eecfea", "huge.txt");
|
||||
check_blame_hunk_index(g_repo, g_blame, 1, 65537, 1, 0, "6653ff4", "huge.txt");
|
||||
}
|
||||
|
||||
/*
|
||||
* $ git blame -n branch_file.txt be3563a..HEAD
|
||||
* orig line no final line no
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user