Skip to content

Commit 7cb5f7c

Browse files
committed
blame: fix object casting regression
Commit 1b0d400 refactored the prepare_final() function so that it could be reused in multiple places. Originally, the loop had two outputs: a commit to stuff into sb->final, and the name of the commit from the rev->pending array. After the refactor, that loop is put in its own function with a single return value: the object_array_entry from the rev->pending array. This contains both the name and the object, but with one important difference: the object is the _original_ object found by the revision parser, not the dereferenced commit. If one feeds a tag to "git blame", we end up casting the tag object to a "struct commit", which causes a segfault. Instead, let's return the commit (properly casted) directly from the function, and take the "name" as an optional out-parameter. This does the right thing, and actually simplifies the callers, who no longer need to cast or dereference the object_array_entry themselves. [test case by Max Kirillov <[email protected]>] Signed-off-by: Jeff King <[email protected]>
1 parent 700fd28 commit 7cb5f7c

File tree

2 files changed

+21
-16
lines changed

2 files changed

+21
-16
lines changed

builtin/blame.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2396,10 +2396,12 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
23962396
return commit;
23972397
}
23982398

2399-
static struct object_array_entry *find_single_final(struct rev_info *revs)
2399+
static struct commit *find_single_final(struct rev_info *revs,
2400+
const char **name_p)
24002401
{
24012402
int i;
2402-
struct object_array_entry *found = NULL;
2403+
struct commit *found = NULL;
2404+
const char *name = NULL;
24032405

24042406
for (i = 0; i < revs->pending.nr; i++) {
24052407
struct object *obj = revs->pending.objects[i].item;
@@ -2411,22 +2413,20 @@ static struct object_array_entry *find_single_final(struct rev_info *revs)
24112413
die("Non commit %s?", revs->pending.objects[i].name);
24122414
if (found)
24132415
die("More than one commit to dig from %s and %s?",
2414-
revs->pending.objects[i].name,
2415-
found->name);
2416-
found = &(revs->pending.objects[i]);
2416+
revs->pending.objects[i].name, name);
2417+
found = (struct commit *)obj;
2418+
name = revs->pending.objects[i].name;
24172419
}
2420+
if (name_p)
2421+
*name_p = name;
24182422
return found;
24192423
}
24202424

24212425
static char *prepare_final(struct scoreboard *sb)
24222426
{
2423-
struct object_array_entry *found = find_single_final(sb->revs);
2424-
if (found) {
2425-
sb->final = (struct commit *) found->item;
2426-
return xstrdup(found->name);
2427-
} else {
2428-
return NULL;
2429-
}
2427+
const char *name;
2428+
sb->final = find_single_final(sb->revs, &name);
2429+
return xstrdup_or_null(name);
24302430
}
24312431

24322432
static char *prepare_initial(struct scoreboard *sb)
@@ -2712,11 +2712,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
27122712
die("Cannot use --contents with final commit object name");
27132713

27142714
if (reverse && revs.first_parent_only) {
2715-
struct object_array_entry *entry = find_single_final(sb.revs);
2716-
if (!entry)
2715+
final_commit = find_single_final(sb.revs, NULL);
2716+
if (!final_commit)
27172717
die("--reverse and --first-parent together require specified latest commit");
2718-
else
2719-
final_commit = (struct commit*) entry->item;
27202718
}
27212719

27222720
/*

t/annotate-tests.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ test_expect_success 'blame 1 author' '
6868
check_count A 2
6969
'
7070

71+
test_expect_success 'blame by tag objects' '
72+
git tag -m "test tag" testTag &&
73+
git tag -m "test tag #2" testTag2 testTag &&
74+
check_count -h testTag A 2 &&
75+
check_count -h testTag2 A 2
76+
'
77+
7178
test_expect_success 'setup B lines' '
7279
echo "2A quick brown fox jumps over the" >>file &&
7380
echo "lazy dog" >>file &&

0 commit comments

Comments
 (0)