Skip to content

Commit ea2dab1

Browse files
committed
Merge branch 'tb/unexpected'
Code tightening against a "wrong" object appearing where an object of a different type is expected, instead of blindly assuming that the connection between objects are correctly made. * tb/unexpected: rev-list: detect broken root trees rev-list: let traversal die when --missing is not in use get_commit_tree(): return NULL for broken tree list-objects.c: handle unexpected non-tree entries list-objects.c: handle unexpected non-blob entries t: introduce tests for unexpected object types t: move 'hex2oct' into test-lib-functions.sh
2 parents 0b179f3 + 97dd512 commit ea2dab1

File tree

8 files changed

+152
-16
lines changed

8 files changed

+152
-16
lines changed

builtin/rev-list.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
379379
repo_init_revisions(the_repository, &revs, prefix);
380380
revs.abbrev = DEFAULT_ABBREV;
381381
revs.commit_format = CMIT_FMT_UNSPECIFIED;
382-
revs.do_not_die_on_missing_tree = 1;
383382

384383
/*
385384
* Scan the argument list before invoking setup_revisions(), so that we
@@ -409,6 +408,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
409408
}
410409
}
411410

411+
if (arg_missing_action)
412+
revs.do_not_die_on_missing_tree = 1;
413+
412414
argc = setup_revisions(argc, argv, &revs, &s_r_opt);
413415

414416
memset(&info, 0, sizeof(info));

commit.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,10 @@ struct tree *repo_get_commit_tree(struct repository *r,
351351
if (commit->maybe_tree || !commit->object.parsed)
352352
return commit->maybe_tree;
353353

354-
if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
355-
BUG("commit has NULL tree, but was not loaded from commit-graph");
354+
if (commit->graph_pos != COMMIT_NOT_FROM_GRAPH)
355+
return get_commit_tree_in_graph(r, commit);
356356

357-
return get_commit_tree_in_graph(r, commit);
357+
return NULL;
358358
}
359359

360360
struct object_id *get_commit_tree_oid(const struct commit *commit)

list-objects.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ static void process_tree_contents(struct traversal_context *ctx,
125125

126126
if (S_ISDIR(entry.mode)) {
127127
struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
128+
if (!t) {
129+
die(_("entry '%s' in tree %s has tree mode, "
130+
"but is not a tree"),
131+
entry.path, oid_to_hex(&tree->object.oid));
132+
}
128133
t->object.flags |= NOT_USER_GIVEN;
129134
process_tree(ctx, t, base, entry.path);
130135
}
@@ -133,6 +138,11 @@ static void process_tree_contents(struct traversal_context *ctx,
133138
base, entry.path);
134139
else {
135140
struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
141+
if (!b) {
142+
die(_("entry '%s' in tree %s has blob mode, "
143+
"but is not a blob"),
144+
entry.path, oid_to_hex(&tree->object.oid));
145+
}
136146
b->object.flags |= NOT_USER_GIVEN;
137147
process_blob(ctx, b, base, entry.path);
138148
}
@@ -364,6 +374,9 @@ static void do_traverse(struct traversal_context *ctx)
364374
struct tree *tree = get_commit_tree(commit);
365375
tree->object.flags |= NOT_USER_GIVEN;
366376
add_pending_tree(ctx->revs, tree);
377+
} else if (commit->object.parsed) {
378+
die(_("unable to load root tree for commit %s"),
379+
oid_to_hex(&commit->object.oid));
367380
}
368381
ctx->show_commit(commit, ctx->show_data);
369382

t/t1007-hash-object.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,6 @@ test_expect_success 'too-short tree' '
199199
test_i18ngrep "too-short tree object" err
200200
'
201201

202-
hex2oct() {
203-
perl -ne 'printf "\\%03o", hex for /../g'
204-
}
205-
206202
test_expect_success 'malformed mode in tree' '
207203
hex_sha1=$(echo foo | git hash-object --stdin -w) &&
208204
bin_sha1=$(echo $hex_sha1 | hex2oct) &&

t/t1450-fsck.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,6 @@ test_expect_success 'unparseable tree object' '
256256
test_i18ngrep ! "fatal: empty filename in tree entry" out
257257
'
258258

259-
hex2oct() {
260-
perl -ne 'printf "\\%03o", hex for /../g'
261-
}
262-
263259
test_expect_success 'tree entry with type mismatch' '
264260
test_when_finished "remove_object \$blob" &&
265261
test_when_finished "remove_object \$tree" &&

t/t5601-clone.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,10 +611,6 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
611611
git -C replay.git index-pack -v --stdin <tmp.pack
612612
'
613613

614-
hex2oct () {
615-
perl -ne 'printf "\\%03o", hex for /../g'
616-
}
617-
618614
test_expect_success 'clone on case-insensitive fs' '
619615
git init icasefs &&
620616
(
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/bin/sh
2+
3+
test_description='git rev-list should handle unexpected object types'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'setup well-formed objects' '
8+
blob="$(printf "foo" | git hash-object -w --stdin)" &&
9+
tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
10+
commit="$(git commit-tree $tree -m "first commit")" &&
11+
git cat-file commit $commit >good-commit
12+
'
13+
14+
test_expect_success 'setup unexpected non-blob entry' '
15+
printf "100644 foo\0$(echo $tree | hex2oct)" >broken-tree &&
16+
broken_tree="$(git hash-object -w --literally -t tree broken-tree)"
17+
'
18+
19+
test_expect_failure 'traverse unexpected non-blob entry (lone)' '
20+
test_must_fail git rev-list --objects $broken_tree
21+
'
22+
23+
test_expect_success 'traverse unexpected non-blob entry (seen)' '
24+
test_must_fail git rev-list --objects $tree $broken_tree >output 2>&1 &&
25+
test_i18ngrep "is not a blob" output
26+
'
27+
28+
test_expect_success 'setup unexpected non-tree entry' '
29+
printf "40000 foo\0$(echo $blob | hex2oct)" >broken-tree &&
30+
broken_tree="$(git hash-object -w --literally -t tree broken-tree)"
31+
'
32+
33+
test_expect_success 'traverse unexpected non-tree entry (lone)' '
34+
test_must_fail git rev-list --objects $broken_tree
35+
'
36+
37+
test_expect_success 'traverse unexpected non-tree entry (seen)' '
38+
test_must_fail git rev-list --objects $blob $broken_tree >output 2>&1 &&
39+
test_i18ngrep "is not a tree" output
40+
'
41+
42+
test_expect_success 'setup unexpected non-commit parent' '
43+
sed "/^author/ { h; s/.*/parent $blob/; G; }" <good-commit \
44+
>broken-commit &&
45+
broken_commit="$(git hash-object -w --literally -t commit \
46+
broken-commit)"
47+
'
48+
49+
test_expect_success 'traverse unexpected non-commit parent (lone)' '
50+
test_must_fail git rev-list --objects $broken_commit >output 2>&1 &&
51+
test_i18ngrep "not a commit" output
52+
'
53+
54+
test_expect_success 'traverse unexpected non-commit parent (seen)' '
55+
test_must_fail git rev-list --objects $commit $broken_commit \
56+
>output 2>&1 &&
57+
test_i18ngrep "not a commit" output
58+
'
59+
60+
test_expect_success 'setup unexpected non-tree root' '
61+
sed -e "s/$tree/$blob/" <good-commit >broken-commit &&
62+
broken_commit="$(git hash-object -w --literally -t commit \
63+
broken-commit)"
64+
'
65+
66+
test_expect_success 'traverse unexpected non-tree root (lone)' '
67+
test_must_fail git rev-list --objects $broken_commit
68+
'
69+
70+
test_expect_success 'traverse unexpected non-tree root (seen)' '
71+
test_must_fail git rev-list --objects $blob $broken_commit \
72+
>output 2>&1 &&
73+
test_i18ngrep "not a tree" output
74+
'
75+
76+
test_expect_success 'setup unexpected non-commit tag' '
77+
git tag -a -m "tagged commit" tag $commit &&
78+
git cat-file tag tag >good-tag &&
79+
test_when_finished "git tag -d tag" &&
80+
sed -e "s/$commit/$blob/" <good-tag >broken-tag &&
81+
tag=$(git hash-object -w --literally -t tag broken-tag)
82+
'
83+
84+
test_expect_success 'traverse unexpected non-commit tag (lone)' '
85+
test_must_fail git rev-list --objects $tag
86+
'
87+
88+
test_expect_success 'traverse unexpected non-commit tag (seen)' '
89+
test_must_fail git rev-list --objects $blob $tag >output 2>&1 &&
90+
test_i18ngrep "not a commit" output
91+
'
92+
93+
test_expect_success 'setup unexpected non-tree tag' '
94+
git tag -a -m "tagged tree" tag $tree &&
95+
git cat-file tag tag >good-tag &&
96+
test_when_finished "git tag -d tag" &&
97+
sed -e "s/$tree/$blob/" <good-tag >broken-tag &&
98+
tag=$(git hash-object -w --literally -t tag broken-tag)
99+
'
100+
101+
test_expect_success 'traverse unexpected non-tree tag (lone)' '
102+
test_must_fail git rev-list --objects $tag
103+
'
104+
105+
test_expect_success 'traverse unexpected non-tree tag (seen)' '
106+
test_must_fail git rev-list --objects $blob $tag >output 2>&1 &&
107+
test_i18ngrep "not a tree" output
108+
'
109+
110+
test_expect_success 'setup unexpected non-blob tag' '
111+
git tag -a -m "tagged blob" tag $blob &&
112+
git cat-file tag tag >good-tag &&
113+
test_when_finished "git tag -d tag" &&
114+
sed -e "s/$blob/$commit/" <good-tag >broken-tag &&
115+
tag=$(git hash-object -w --literally -t tag broken-tag)
116+
'
117+
118+
test_expect_failure 'traverse unexpected non-blob tag (lone)' '
119+
test_must_fail git rev-list --objects $tag
120+
'
121+
122+
test_expect_success 'traverse unexpected non-blob tag (seen)' '
123+
test_must_fail git rev-list --objects $commit $tag >output 2>&1 &&
124+
test_i18ngrep "not a blob" output
125+
'
126+
127+
test_done

t/test-lib-functions.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,12 @@ depacketize () {
12391239
'
12401240
}
12411241

1242+
# Converts base-16 data into base-8. The output is given as a sequence of
1243+
# escaped octals, suitable for consumption by 'printf'.
1244+
hex2oct () {
1245+
perl -ne 'printf "\\%03o", hex for /../g'
1246+
}
1247+
12421248
# Set the hash algorithm in use to $1. Only useful when testing the testsuite.
12431249
test_set_hash () {
12441250
test_hash_algo="$1"

0 commit comments

Comments
 (0)