Skip to content

Commit 5e48017

Browse files
avargitster
authored andcommitted
stash: always have the owner of "stash_info" free it
Change the initialization of the "revision" member of "struct stash_info" to be initialized vi a macro, and more importantly that that initializing function be tasked to free it, usually via a "goto cleanup" pattern. Despite the "revision" name (and the topic of the series containing this commit) the "stash info" has nothing to do with the "struct rev_info". I'm making this change because in the subsequent commit when we do want to free the "struct rev_info" via a "goto cleanup" pattern we'd otherwise free() uninitialized memory in some cases, as we only strbuf_init() the string in get_stash_info(). So while it's not the smallest possible change, let's convert all users of this pattern in the file while we're at it. A good follow-up to this change would be to change all the "ret = -1; goto done;" in this file to instead use a "goto cleanup", and initialize "int ret = -1" at the start of the relevant functions. That would allow us to drop a lot of needless brace verbosity on two-line "if" statements, but let's leave that alone for now. To ensure that there's a 1=1 mapping between owners of the "struct stash_info" and free_stash_info() change the assert_stash_ref() function to be a trivial get_stash_info_assert() wrapper. The caller will call free_stash_info(), and by returning -1 we'll eventually (via !!ret) exit with status 1 anyway. Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f196c1e commit 5e48017

File tree

1 file changed

+59
-48
lines changed

1 file changed

+59
-48
lines changed

builtin/stash.c

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ struct stash_info {
116116
int has_u;
117117
};
118118

119+
#define STASH_INFO_INIT { \
120+
.revision = STRBUF_INIT, \
121+
}
122+
119123
static void free_stash_info(struct stash_info *info)
120124
{
121125
strbuf_release(&info->revision);
@@ -157,10 +161,8 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
157161
if (argc == 1)
158162
commit = argv[0];
159163

160-
strbuf_init(&info->revision, 0);
161164
if (!commit) {
162165
if (!ref_exists(ref_stash)) {
163-
free_stash_info(info);
164166
fprintf_ln(stderr, _("No stash entries found."));
165167
return -1;
166168
}
@@ -174,11 +176,8 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
174176

175177
revision = info->revision.buf;
176178

177-
if (get_oid(revision, &info->w_commit)) {
178-
error(_("%s is not a valid reference"), revision);
179-
free_stash_info(info);
180-
return -1;
181-
}
179+
if (get_oid(revision, &info->w_commit))
180+
return error(_("%s is not a valid reference"), revision);
182181

183182
assert_stash_like(info, revision);
184183

@@ -197,7 +196,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
197196
info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
198197
break;
199198
default: /* Invalid or ambiguous */
200-
free_stash_info(info);
199+
break;
201200
}
202201

203202
free(expanded_ref);
@@ -598,10 +597,10 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
598597

599598
static int apply_stash(int argc, const char **argv, const char *prefix)
600599
{
601-
int ret;
600+
int ret = -1;
602601
int quiet = 0;
603602
int index = 0;
604-
struct stash_info info;
603+
struct stash_info info = STASH_INFO_INIT;
605604
struct option options[] = {
606605
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
607606
OPT_BOOL(0, "index", &index,
@@ -613,9 +612,10 @@ static int apply_stash(int argc, const char **argv, const char *prefix)
613612
git_stash_apply_usage, 0);
614613

615614
if (get_stash_info(&info, argc, argv))
616-
return -1;
615+
goto cleanup;
617616

618617
ret = do_apply_stash(prefix, &info, index, quiet);
618+
cleanup:
619619
free_stash_info(&info);
620620
return ret;
621621
}
@@ -651,20 +651,25 @@ static int do_drop_stash(struct stash_info *info, int quiet)
651651
return 0;
652652
}
653653

654-
static void assert_stash_ref(struct stash_info *info)
654+
static int get_stash_info_assert(struct stash_info *info, int argc,
655+
const char **argv)
655656
{
656-
if (!info->is_stash_ref) {
657-
error(_("'%s' is not a stash reference"), info->revision.buf);
658-
free_stash_info(info);
659-
exit(1);
660-
}
657+
int ret = get_stash_info(info, argc, argv);
658+
659+
if (ret < 0)
660+
return ret;
661+
662+
if (!info->is_stash_ref)
663+
return error(_("'%s' is not a stash reference"), info->revision.buf);
664+
665+
return 0;
661666
}
662667

663668
static int drop_stash(int argc, const char **argv, const char *prefix)
664669
{
665-
int ret;
670+
int ret = -1;
666671
int quiet = 0;
667-
struct stash_info info;
672+
struct stash_info info = STASH_INFO_INIT;
668673
struct option options[] = {
669674
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
670675
OPT_END()
@@ -673,22 +678,21 @@ static int drop_stash(int argc, const char **argv, const char *prefix)
673678
argc = parse_options(argc, argv, prefix, options,
674679
git_stash_drop_usage, 0);
675680

676-
if (get_stash_info(&info, argc, argv))
677-
return -1;
678-
679-
assert_stash_ref(&info);
681+
if (get_stash_info_assert(&info, argc, argv))
682+
goto cleanup;
680683

681684
ret = do_drop_stash(&info, quiet);
685+
cleanup:
682686
free_stash_info(&info);
683687
return ret;
684688
}
685689

686690
static int pop_stash(int argc, const char **argv, const char *prefix)
687691
{
688-
int ret;
692+
int ret = -1;
689693
int index = 0;
690694
int quiet = 0;
691-
struct stash_info info;
695+
struct stash_info info = STASH_INFO_INIT;
692696
struct option options[] = {
693697
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
694698
OPT_BOOL(0, "index", &index,
@@ -699,25 +703,25 @@ static int pop_stash(int argc, const char **argv, const char *prefix)
699703
argc = parse_options(argc, argv, prefix, options,
700704
git_stash_pop_usage, 0);
701705

702-
if (get_stash_info(&info, argc, argv))
703-
return -1;
706+
if (get_stash_info_assert(&info, argc, argv))
707+
goto cleanup;
704708

705-
assert_stash_ref(&info);
706709
if ((ret = do_apply_stash(prefix, &info, index, quiet)))
707710
printf_ln(_("The stash entry is kept in case "
708711
"you need it again."));
709712
else
710713
ret = do_drop_stash(&info, quiet);
711714

715+
cleanup:
712716
free_stash_info(&info);
713717
return ret;
714718
}
715719

716720
static int branch_stash(int argc, const char **argv, const char *prefix)
717721
{
718-
int ret;
722+
int ret = -1;
719723
const char *branch = NULL;
720-
struct stash_info info;
724+
struct stash_info info = STASH_INFO_INIT;
721725
struct child_process cp = CHILD_PROCESS_INIT;
722726
struct option options[] = {
723727
OPT_END()
@@ -734,7 +738,7 @@ static int branch_stash(int argc, const char **argv, const char *prefix)
734738
branch = argv[0];
735739

736740
if (get_stash_info(&info, argc - 1, argv + 1))
737-
return -1;
741+
goto cleanup;
738742

739743
cp.git_cmd = 1;
740744
strvec_pushl(&cp.args, "checkout", "-b", NULL);
@@ -746,8 +750,8 @@ static int branch_stash(int argc, const char **argv, const char *prefix)
746750
if (!ret && info.is_stash_ref)
747751
ret = do_drop_stash(&info, 0);
748752

753+
cleanup:
749754
free_stash_info(&info);
750-
751755
return ret;
752756
}
753757

@@ -825,8 +829,8 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op
825829
static int show_stash(int argc, const char **argv, const char *prefix)
826830
{
827831
int i;
828-
int ret = 0;
829-
struct stash_info info;
832+
int ret = -1;
833+
struct stash_info info = STASH_INFO_INIT;
830834
struct rev_info rev;
831835
struct strvec stash_args = STRVEC_INIT;
832836
struct strvec revision_args = STRVEC_INIT;
@@ -844,6 +848,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
844848
UNTRACKED_ONLY, PARSE_OPT_NONEG),
845849
OPT_END()
846850
};
851+
int do_usage = 0;
847852

848853
init_diff_ui_defaults();
849854
git_config(git_diff_ui_config, NULL);
@@ -861,10 +866,8 @@ static int show_stash(int argc, const char **argv, const char *prefix)
861866
strvec_push(&revision_args, argv[i]);
862867
}
863868

864-
ret = get_stash_info(&info, stash_args.nr, stash_args.v);
865-
strvec_clear(&stash_args);
866-
if (ret)
867-
return -1;
869+
if (get_stash_info(&info, stash_args.nr, stash_args.v))
870+
goto cleanup;
868871

869872
/*
870873
* The config settings are applied only if there are not passed
@@ -878,16 +881,14 @@ static int show_stash(int argc, const char **argv, const char *prefix)
878881
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
879882

880883
if (!show_stat && !show_patch) {
881-
free_stash_info(&info);
882-
return 0;
884+
ret = 0;
885+
goto cleanup;
883886
}
884887
}
885888

886889
argc = setup_revisions(revision_args.nr, revision_args.v, &rev, NULL);
887-
if (argc > 1) {
888-
free_stash_info(&info);
889-
usage_with_options(git_stash_show_usage, options);
890-
}
890+
if (argc > 1)
891+
goto usage;
891892
if (!rev.diffopt.output_format) {
892893
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
893894
diff_setup_done(&rev.diffopt);
@@ -912,8 +913,16 @@ static int show_stash(int argc, const char **argv, const char *prefix)
912913
}
913914
log_tree_diff_flush(&rev);
914915

916+
ret = diff_result_code(&rev.diffopt, 0);
917+
cleanup:
918+
strvec_clear(&stash_args);
915919
free_stash_info(&info);
916-
return diff_result_code(&rev.diffopt, 0);
920+
if (do_usage)
921+
usage_with_options(git_stash_show_usage, options);
922+
return ret;
923+
usage:
924+
do_usage = 1;
925+
goto cleanup;
917926
}
918927

919928
static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
@@ -1409,9 +1418,9 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
14091418

14101419
static int create_stash(int argc, const char **argv, const char *prefix)
14111420
{
1412-
int ret = 0;
1421+
int ret;
14131422
struct strbuf stash_msg_buf = STRBUF_INIT;
1414-
struct stash_info info;
1423+
struct stash_info info = STASH_INFO_INIT;
14151424
struct pathspec ps;
14161425

14171426
/* Starting with argv[1], since argv[0] is "create" */
@@ -1426,6 +1435,7 @@ static int create_stash(int argc, const char **argv, const char *prefix)
14261435
if (!ret)
14271436
printf_ln("%s", oid_to_hex(&info.w_commit));
14281437

1438+
free_stash_info(&info);
14291439
strbuf_release(&stash_msg_buf);
14301440
return ret;
14311441
}
@@ -1434,7 +1444,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
14341444
int keep_index, int patch_mode, int include_untracked, int only_staged)
14351445
{
14361446
int ret = 0;
1437-
struct stash_info info;
1447+
struct stash_info info = STASH_INFO_INIT;
14381448
struct strbuf patch = STRBUF_INIT;
14391449
struct strbuf stash_msg_buf = STRBUF_INIT;
14401450
struct strbuf untracked_files = STRBUF_INIT;
@@ -1632,6 +1642,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
16321642
}
16331643

16341644
done:
1645+
free_stash_info(&info);
16351646
strbuf_release(&stash_msg_buf);
16361647
return ret;
16371648
}

0 commit comments

Comments
 (0)