Browse Source

branch: segfault fixes and validation

branch_get() can return NULL (so far on detached HEAD only) but some
code paths in builtin/branch.c cannot deal with that and cause
segfaults.

While at there, make sure to bail out when the user gives 2 or more
branches with --set-upstream-to or --unset-upstream, where only the
first branch is processed and the rest silently dropped.

Reported-by: Per Cederqvist <cederp@opera.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Nguyễn Thái Ngọc Duy 12 years ago committed by Junio C Hamano
parent
commit
8efb8899cf
  1. 27
      builtin/branch.c
  2. 21
      t/t3200-branch.sh

27
builtin/branch.c

@ -889,6 +889,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
} else if (new_upstream) { } else if (new_upstream) {
struct branch *branch = branch_get(argv[0]); struct branch *branch = branch_get(argv[0]);


if (argc > 1)
die(_("too many branches to set new upstream"));

if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
die(_("could not set upstream of HEAD to %s when "
"it does not point to any branch."),
new_upstream);
die(_("no such branch '%s'"), argv[0]);
}

if (!ref_exists(branch->refname)) if (!ref_exists(branch->refname))
die(_("branch '%s' does not exist"), branch->name); die(_("branch '%s' does not exist"), branch->name);


@ -901,6 +912,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
struct branch *branch = branch_get(argv[0]); struct branch *branch = branch_get(argv[0]);
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;


if (argc > 1)
die(_("too many branches to unset upstream"));

if (!branch) {
if (!argc || !strcmp(argv[0], "HEAD"))
die(_("could not unset upstream of HEAD when "
"it does not point to any branch."));
die(_("no such branch '%s'"), argv[0]);
}

if (!branch_has_merge_config(branch)) { if (!branch_has_merge_config(branch)) {
die(_("Branch '%s' has no upstream information"), branch->name); die(_("Branch '%s' has no upstream information"), branch->name);
} }
@ -916,6 +937,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int branch_existed = 0, remote_tracking = 0; int branch_existed = 0, remote_tracking = 0;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;


if (!strcmp(argv[0], "HEAD"))
die(_("it does not make sense to create 'HEAD' manually"));

if (!branch)
die(_("no such branch '%s'"), argv[0]);

if (kinds != REF_LOCAL_BRANCH) if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name")); die(_("-a and -r options to 'git branch' do not make sense with a branch name"));



21
t/t3200-branch.sh

@ -42,6 +42,10 @@ test_expect_success \
'git branch a/b/c should create a branch' \ 'git branch a/b/c should create a branch' \
'git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c' 'git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c'


test_expect_success \
'git branch HEAD should fail' \
'test_must_fail git branch HEAD'

cat >expect <<EOF cat >expect <<EOF
$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master $_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
EOF EOF
@ -388,6 +392,14 @@ test_expect_success \
'git tag foobar && 'git tag foobar &&
test_must_fail git branch --track my11 foobar' test_must_fail git branch --track my11 foobar'


test_expect_success '--set-upstream-to fails on multiple branches' \
'test_must_fail git branch --set-upstream-to master a b c'

test_expect_success '--set-upstream-to fails on detached HEAD' \
'git checkout HEAD^{} &&
test_must_fail git branch --set-upstream-to master &&
git checkout -'

test_expect_success 'use --set-upstream-to modify HEAD' \ test_expect_success 'use --set-upstream-to modify HEAD' \
'test_config branch.master.remote foo && 'test_config branch.master.remote foo &&
test_config branch.master.merge foo && test_config branch.master.merge foo &&
@ -417,6 +429,15 @@ test_expect_success 'test --unset-upstream on HEAD' \
test_must_fail git branch --unset-upstream test_must_fail git branch --unset-upstream
' '


test_expect_success '--unset-upstream should fail on multiple branches' \
'test_must_fail git branch --unset-upstream a b c'

test_expect_success '--unset-upstream should fail on detached HEAD' \
'git checkout HEAD^{} &&
test_must_fail git branch --unset-upstream &&
git checkout -
'

test_expect_success 'test --unset-upstream on a particular branch' \ test_expect_success 'test --unset-upstream on a particular branch' \
'git branch my15 'git branch my15
git branch --set-upstream-to master my14 && git branch --set-upstream-to master my14 &&

Loading…
Cancel
Save