mirror of
https://github.com/git/git
synced 2024-08-25 02:35:46 +00:00
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
This commit is contained in:
commit
ea2dab1abb
|
@ -379,7 +379,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||||
repo_init_revisions(the_repository, &revs, prefix);
|
repo_init_revisions(the_repository, &revs, prefix);
|
||||||
revs.abbrev = DEFAULT_ABBREV;
|
revs.abbrev = DEFAULT_ABBREV;
|
||||||
revs.commit_format = CMIT_FMT_UNSPECIFIED;
|
revs.commit_format = CMIT_FMT_UNSPECIFIED;
|
||||||
revs.do_not_die_on_missing_tree = 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the argument list before invoking setup_revisions(), so that we
|
* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_missing_action)
|
||||||
|
revs.do_not_die_on_missing_tree = 1;
|
||||||
|
|
||||||
argc = setup_revisions(argc, argv, &revs, &s_r_opt);
|
argc = setup_revisions(argc, argv, &revs, &s_r_opt);
|
||||||
|
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
6
commit.c
6
commit.c
|
@ -351,10 +351,10 @@ struct tree *repo_get_commit_tree(struct repository *r,
|
||||||
if (commit->maybe_tree || !commit->object.parsed)
|
if (commit->maybe_tree || !commit->object.parsed)
|
||||||
return commit->maybe_tree;
|
return commit->maybe_tree;
|
||||||
|
|
||||||
if (commit->graph_pos == COMMIT_NOT_FROM_GRAPH)
|
if (commit->graph_pos != COMMIT_NOT_FROM_GRAPH)
|
||||||
BUG("commit has NULL tree, but was not loaded from commit-graph");
|
|
||||||
|
|
||||||
return get_commit_tree_in_graph(r, commit);
|
return get_commit_tree_in_graph(r, commit);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct object_id *get_commit_tree_oid(const struct commit *commit)
|
struct object_id *get_commit_tree_oid(const struct commit *commit)
|
||||||
|
|
|
@ -125,6 +125,11 @@ static void process_tree_contents(struct traversal_context *ctx,
|
||||||
|
|
||||||
if (S_ISDIR(entry.mode)) {
|
if (S_ISDIR(entry.mode)) {
|
||||||
struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
|
struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
|
||||||
|
if (!t) {
|
||||||
|
die(_("entry '%s' in tree %s has tree mode, "
|
||||||
|
"but is not a tree"),
|
||||||
|
entry.path, oid_to_hex(&tree->object.oid));
|
||||||
|
}
|
||||||
t->object.flags |= NOT_USER_GIVEN;
|
t->object.flags |= NOT_USER_GIVEN;
|
||||||
process_tree(ctx, t, base, entry.path);
|
process_tree(ctx, t, base, entry.path);
|
||||||
}
|
}
|
||||||
|
@ -133,6 +138,11 @@ static void process_tree_contents(struct traversal_context *ctx,
|
||||||
base, entry.path);
|
base, entry.path);
|
||||||
else {
|
else {
|
||||||
struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
|
struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
|
||||||
|
if (!b) {
|
||||||
|
die(_("entry '%s' in tree %s has blob mode, "
|
||||||
|
"but is not a blob"),
|
||||||
|
entry.path, oid_to_hex(&tree->object.oid));
|
||||||
|
}
|
||||||
b->object.flags |= NOT_USER_GIVEN;
|
b->object.flags |= NOT_USER_GIVEN;
|
||||||
process_blob(ctx, b, base, entry.path);
|
process_blob(ctx, b, base, entry.path);
|
||||||
}
|
}
|
||||||
|
@ -364,6 +374,9 @@ static void do_traverse(struct traversal_context *ctx)
|
||||||
struct tree *tree = get_commit_tree(commit);
|
struct tree *tree = get_commit_tree(commit);
|
||||||
tree->object.flags |= NOT_USER_GIVEN;
|
tree->object.flags |= NOT_USER_GIVEN;
|
||||||
add_pending_tree(ctx->revs, tree);
|
add_pending_tree(ctx->revs, tree);
|
||||||
|
} else if (commit->object.parsed) {
|
||||||
|
die(_("unable to load root tree for commit %s"),
|
||||||
|
oid_to_hex(&commit->object.oid));
|
||||||
}
|
}
|
||||||
ctx->show_commit(commit, ctx->show_data);
|
ctx->show_commit(commit, ctx->show_data);
|
||||||
|
|
||||||
|
|
|
@ -199,10 +199,6 @@ test_expect_success 'too-short tree' '
|
||||||
test_i18ngrep "too-short tree object" err
|
test_i18ngrep "too-short tree object" err
|
||||||
'
|
'
|
||||||
|
|
||||||
hex2oct() {
|
|
||||||
perl -ne 'printf "\\%03o", hex for /../g'
|
|
||||||
}
|
|
||||||
|
|
||||||
test_expect_success 'malformed mode in tree' '
|
test_expect_success 'malformed mode in tree' '
|
||||||
hex_sha1=$(echo foo | git hash-object --stdin -w) &&
|
hex_sha1=$(echo foo | git hash-object --stdin -w) &&
|
||||||
bin_sha1=$(echo $hex_sha1 | hex2oct) &&
|
bin_sha1=$(echo $hex_sha1 | hex2oct) &&
|
||||||
|
|
|
@ -256,10 +256,6 @@ test_expect_success 'unparseable tree object' '
|
||||||
test_i18ngrep ! "fatal: empty filename in tree entry" out
|
test_i18ngrep ! "fatal: empty filename in tree entry" out
|
||||||
'
|
'
|
||||||
|
|
||||||
hex2oct() {
|
|
||||||
perl -ne 'printf "\\%03o", hex for /../g'
|
|
||||||
}
|
|
||||||
|
|
||||||
test_expect_success 'tree entry with type mismatch' '
|
test_expect_success 'tree entry with type mismatch' '
|
||||||
test_when_finished "remove_object \$blob" &&
|
test_when_finished "remove_object \$blob" &&
|
||||||
test_when_finished "remove_object \$tree" &&
|
test_when_finished "remove_object \$tree" &&
|
||||||
|
|
|
@ -611,10 +611,6 @@ test_expect_success 'GIT_TRACE_PACKFILE produces a usable pack' '
|
||||||
git -C replay.git index-pack -v --stdin <tmp.pack
|
git -C replay.git index-pack -v --stdin <tmp.pack
|
||||||
'
|
'
|
||||||
|
|
||||||
hex2oct () {
|
|
||||||
perl -ne 'printf "\\%03o", hex for /../g'
|
|
||||||
}
|
|
||||||
|
|
||||||
test_expect_success 'clone on case-insensitive fs' '
|
test_expect_success 'clone on case-insensitive fs' '
|
||||||
git init icasefs &&
|
git init icasefs &&
|
||||||
(
|
(
|
||||||
|
|
127
t/t6102-rev-list-unexpected-objects.sh
Executable file
127
t/t6102-rev-list-unexpected-objects.sh
Executable file
|
@ -0,0 +1,127 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='git rev-list should handle unexpected object types'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_expect_success 'setup well-formed objects' '
|
||||||
|
blob="$(printf "foo" | git hash-object -w --stdin)" &&
|
||||||
|
tree="$(printf "100644 blob $blob\tfoo" | git mktree)" &&
|
||||||
|
commit="$(git commit-tree $tree -m "first commit")" &&
|
||||||
|
git cat-file commit $commit >good-commit
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup unexpected non-blob entry' '
|
||||||
|
printf "100644 foo\0$(echo $tree | hex2oct)" >broken-tree &&
|
||||||
|
broken_tree="$(git hash-object -w --literally -t tree broken-tree)"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_failure 'traverse unexpected non-blob entry (lone)' '
|
||||||
|
test_must_fail git rev-list --objects $broken_tree
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-blob entry (seen)' '
|
||||||
|
test_must_fail git rev-list --objects $tree $broken_tree >output 2>&1 &&
|
||||||
|
test_i18ngrep "is not a blob" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup unexpected non-tree entry' '
|
||||||
|
printf "40000 foo\0$(echo $blob | hex2oct)" >broken-tree &&
|
||||||
|
broken_tree="$(git hash-object -w --literally -t tree broken-tree)"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-tree entry (lone)' '
|
||||||
|
test_must_fail git rev-list --objects $broken_tree
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-tree entry (seen)' '
|
||||||
|
test_must_fail git rev-list --objects $blob $broken_tree >output 2>&1 &&
|
||||||
|
test_i18ngrep "is not a tree" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup unexpected non-commit parent' '
|
||||||
|
sed "/^author/ { h; s/.*/parent $blob/; G; }" <good-commit \
|
||||||
|
>broken-commit &&
|
||||||
|
broken_commit="$(git hash-object -w --literally -t commit \
|
||||||
|
broken-commit)"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-commit parent (lone)' '
|
||||||
|
test_must_fail git rev-list --objects $broken_commit >output 2>&1 &&
|
||||||
|
test_i18ngrep "not a commit" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-commit parent (seen)' '
|
||||||
|
test_must_fail git rev-list --objects $commit $broken_commit \
|
||||||
|
>output 2>&1 &&
|
||||||
|
test_i18ngrep "not a commit" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup unexpected non-tree root' '
|
||||||
|
sed -e "s/$tree/$blob/" <good-commit >broken-commit &&
|
||||||
|
broken_commit="$(git hash-object -w --literally -t commit \
|
||||||
|
broken-commit)"
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-tree root (lone)' '
|
||||||
|
test_must_fail git rev-list --objects $broken_commit
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-tree root (seen)' '
|
||||||
|
test_must_fail git rev-list --objects $blob $broken_commit \
|
||||||
|
>output 2>&1 &&
|
||||||
|
test_i18ngrep "not a tree" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup unexpected non-commit tag' '
|
||||||
|
git tag -a -m "tagged commit" tag $commit &&
|
||||||
|
git cat-file tag tag >good-tag &&
|
||||||
|
test_when_finished "git tag -d tag" &&
|
||||||
|
sed -e "s/$commit/$blob/" <good-tag >broken-tag &&
|
||||||
|
tag=$(git hash-object -w --literally -t tag broken-tag)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-commit tag (lone)' '
|
||||||
|
test_must_fail git rev-list --objects $tag
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-commit tag (seen)' '
|
||||||
|
test_must_fail git rev-list --objects $blob $tag >output 2>&1 &&
|
||||||
|
test_i18ngrep "not a commit" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup unexpected non-tree tag' '
|
||||||
|
git tag -a -m "tagged tree" tag $tree &&
|
||||||
|
git cat-file tag tag >good-tag &&
|
||||||
|
test_when_finished "git tag -d tag" &&
|
||||||
|
sed -e "s/$tree/$blob/" <good-tag >broken-tag &&
|
||||||
|
tag=$(git hash-object -w --literally -t tag broken-tag)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-tree tag (lone)' '
|
||||||
|
test_must_fail git rev-list --objects $tag
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-tree tag (seen)' '
|
||||||
|
test_must_fail git rev-list --objects $blob $tag >output 2>&1 &&
|
||||||
|
test_i18ngrep "not a tree" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup unexpected non-blob tag' '
|
||||||
|
git tag -a -m "tagged blob" tag $blob &&
|
||||||
|
git cat-file tag tag >good-tag &&
|
||||||
|
test_when_finished "git tag -d tag" &&
|
||||||
|
sed -e "s/$blob/$commit/" <good-tag >broken-tag &&
|
||||||
|
tag=$(git hash-object -w --literally -t tag broken-tag)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_failure 'traverse unexpected non-blob tag (lone)' '
|
||||||
|
test_must_fail git rev-list --objects $tag
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'traverse unexpected non-blob tag (seen)' '
|
||||||
|
test_must_fail git rev-list --objects $commit $tag >output 2>&1 &&
|
||||||
|
test_i18ngrep "not a blob" output
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
|
@ -1239,6 +1239,12 @@ depacketize () {
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Converts base-16 data into base-8. The output is given as a sequence of
|
||||||
|
# escaped octals, suitable for consumption by 'printf'.
|
||||||
|
hex2oct () {
|
||||||
|
perl -ne 'printf "\\%03o", hex for /../g'
|
||||||
|
}
|
||||||
|
|
||||||
# Set the hash algorithm in use to $1. Only useful when testing the testsuite.
|
# Set the hash algorithm in use to $1. Only useful when testing the testsuite.
|
||||||
test_set_hash () {
|
test_set_hash () {
|
||||||
test_hash_algo="$1"
|
test_hash_algo="$1"
|
||||||
|
|
Loading…
Reference in a new issue