submodule--helper: fix most "struct pathspec" memory leaks
Call clear_pathspec() at the end of various functions that work with and allocate a "struct pathspec". In some cases the zero-initialization here isn't strictly needed, but as we're moving to a "goto cleanup" pattern let's make sure that it's safe to call clear_pathspec(), we don't want the data to be uninitialized. E.g. for module_foreach() we can see from looking at module_list_compute() that if it returns non-zero that the "pathspec" will always have been initialized. But relying on that both assumes knowledge about parse_pathspec(), and would set up a fragile pattern going forward. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Reviewed-by: Glen Choo <chooglen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Ævar Arnfjörð Bjarmason committed
Sep 1, 2022 at 01:14 UTC
8fb201d4da0e9244f44dabdb1a5f5ea2809b2270
1 file changed
+51
-23
builtin/submodule--helper.c
+51
-23
@@ -379,7 +379,7 @@ cleanup:
379
static int module_foreach(int argc, const char **argv, const char *prefix)
380
{
381
struct foreach_cb info = FOREACH_CB_INIT;
382
- struct pathspec pathspec;
382
+ struct pathspec pathspec = { 0 };
383
struct module_list list = MODULE_LIST_INIT;
384
struct option module_foreach_options[] = {
385
OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
@@ -391,12 +391,13 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
391
N_("git submodule foreach [--quiet] [--recursive] [--] <command>"),
392
NULL
393
};
394
+ int ret = 1;
395
396
argc = parse_options(argc, argv, prefix, module_foreach_options,
397
git_submodule_helper_usage, 0);
398
399
if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)
399
- return 1;
400
+ goto cleanup;
401
402
info.argc = argc;
403
info.argv = argv;
@@ -404,7 +405,10 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
405
406
for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
407
407
- return 0;
408
+ ret = 0;
409
+cleanup:
410
+ clear_pathspec(&pathspec);
411
+ return ret;
412
}
413
414
static int starts_with_dot_slash(const char *const path)
@@ -515,7 +519,7 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
519
static int module_init(int argc, const char **argv, const char *prefix)
520
{
521
struct init_cb info = INIT_CB_INIT;
518
- struct pathspec pathspec;
522
+ struct pathspec pathspec = { 0 };
523
struct module_list list = MODULE_LIST_INIT;
524
int quiet = 0;
525
struct option module_init_options[] = {
@@ -526,12 +530,13 @@ static int module_init(int argc, const char **argv, const char *prefix)
530
N_("git submodule init [<options>] [<path>]"),
531
NULL
532
};
533
+ int ret = 1;
534
535
argc = parse_options(argc, argv, prefix, module_init_options,
536
git_submodule_helper_usage, 0);
537
538
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
534
- return 1;
539
+ goto cleanup;
540
541
/*
542
* If there are no path args and submodule.active is set then,
@@ -546,7 +551,10 @@ static int module_init(int argc, const char **argv, const char *prefix)
551
552
for_each_listed_submodule(&list, init_submodule_cb, &info);
553
549
- return 0;
554
+ ret = 0;
555
+cleanup:
556
+ clear_pathspec(&pathspec);
557
+ return ret;
558
}
559
560
struct status_cb {
@@ -693,7 +701,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
701
static int module_status(int argc, const char **argv, const char *prefix)
702
{
703
struct status_cb info = STATUS_CB_INIT;
696
- struct pathspec pathspec;
704
+ struct pathspec pathspec = { 0 };
705
struct module_list list = MODULE_LIST_INIT;
706
int quiet = 0;
707
struct option module_status_options[] = {
@@ -706,12 +714,13 @@ static int module_status(int argc, const char **argv, const char *prefix)
714
N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
715
NULL
716
};
717
+ int ret = 1;
718
719
argc = parse_options(argc, argv, prefix, module_status_options,
720
git_submodule_helper_usage, 0);
721
722
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
714
- return 1;
723
+ goto cleanup;
724
725
info.prefix = prefix;
726
if (quiet)
@@ -719,7 +728,10 @@ static int module_status(int argc, const char **argv, const char *prefix)
728
729
for_each_listed_submodule(&list, status_submodule_cb, &info);
730
722
- return 0;
731
+ ret = 0;
732
+cleanup:
733
+ clear_pathspec(&pathspec);
734
+ return ret;
735
}
736
737
struct module_cb {
@@ -1258,7 +1270,7 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
1270
static int module_sync(int argc, const char **argv, const char *prefix)
1271
{
1272
struct sync_cb info = SYNC_CB_INIT;
1261
- struct pathspec pathspec;
1273
+ struct pathspec pathspec = { 0 };
1274
struct module_list list = MODULE_LIST_INIT;
1275
int quiet = 0;
1276
int recursive = 0;
@@ -1272,12 +1284,13 @@ static int module_sync(int argc, const char **argv, const char *prefix)
1284
N_("git submodule sync [--quiet] [--recursive] [<path>]"),
1285
NULL
1286
};
1287
+ int ret = 1;
1288
1289
argc = parse_options(argc, argv, prefix, module_sync_options,
1290
git_submodule_helper_usage, 0);
1291
1292
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
1280
- return 1;
1293
+ goto cleanup;
1294
1295
info.prefix = prefix;
1296
if (quiet)
@@ -1287,7 +1300,10 @@ static int module_sync(int argc, const char **argv, const char *prefix)
1300
1301
for_each_listed_submodule(&list, sync_submodule_cb, &info);
1302
1290
- return 0;
1303
+ ret = 0;
1304
+cleanup:
1305
+ clear_pathspec(&pathspec);
1306
+ return ret;
1307
}
1308
1309
struct deinit_cb {
@@ -1396,7 +1412,7 @@ static void deinit_submodule_cb(const struct cache_entry *list_item,
1412
static int module_deinit(int argc, const char **argv, const char *prefix)
1413
{
1414
struct deinit_cb info = DEINIT_CB_INIT;
1399
- struct pathspec pathspec;
1415
+ struct pathspec pathspec = { 0 };
1416
struct module_list list = MODULE_LIST_INIT;
1417
int quiet = 0;
1418
int force = 0;
@@ -1411,6 +1427,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
1427
N_("git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"),
1428
NULL
1429
};
1430
+ int ret = 1;
1431
1432
argc = parse_options(argc, argv, prefix, module_deinit_options,
1433
git_submodule_helper_usage, 0);
@@ -1425,7 +1442,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
1442
die(_("Use '--all' if you really want to deinitialize all submodules"));
1443
1444
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
1428
- return 1;
1445
+ goto cleanup;
1446
1447
info.prefix = prefix;
1448
if (quiet)
@@ -1435,7 +1452,10 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
1452
1453
for_each_listed_submodule(&list, deinit_submodule_cb, &info);
1454
1438
- return 0;
1455
+ ret = 0;
1456
+cleanup:
1457
+ clear_pathspec(&pathspec);
1458
+ return ret;
1459
}
1460
1461
struct module_clone_data {
@@ -2540,7 +2560,7 @@ cleanup:
2560
2561
static int module_update(int argc, const char **argv, const char *prefix)
2562
{
2543
- struct pathspec pathspec;
2563
+ struct pathspec pathspec = { 0 };
2564
struct update_data opt = UPDATE_DATA_INIT;
2565
struct list_objects_filter_options filter_options = { 0 };
2566
int ret;
@@ -2617,8 +2637,8 @@ static int module_update(int argc, const char **argv, const char *prefix)
2637
opt.update_strategy.type = opt.update_default;
2638
2639
if (module_list_compute(argc, argv, prefix, &pathspec, &opt.list) < 0) {
2620
- list_objects_filter_release(&filter_options);
2621
- return 1;
2640
+ ret = 1;
2641
+ goto cleanup;
2642
}
2643
2644
if (pathspec.nr)
@@ -2629,8 +2649,10 @@ static int module_update(int argc, const char **argv, const char *prefix)
2649
struct init_cb info = INIT_CB_INIT;
2650
2651
if (module_list_compute(argc, argv, opt.prefix,
2632
- &pathspec, &list) < 0)
2633
- return 1;
2652
+ &pathspec, &list) < 0) {
2653
+ ret = 1;
2654
+ goto cleanup;
2655
+ }
2656
2657
/*
2658
* If there are no path args and submodule.active is set then,
@@ -2647,7 +2669,9 @@ static int module_update(int argc, const char **argv, const char *prefix)
2669
}
2670
2671
ret = update_submodules(&opt);
2672
+cleanup:
2673
list_objects_filter_release(&filter_options);
2674
+ clear_pathspec(&pathspec);
2675
return ret;
2676
}
2677
@@ -2731,7 +2755,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
2755
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
2756
{
2757
int i;
2734
- struct pathspec pathspec;
2758
+ struct pathspec pathspec = { 0 };
2759
struct module_list list = MODULE_LIST_INIT;
2760
unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;
2761
struct option embed_gitdir_options[] = {
@@ -2746,17 +2770,21 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
2770
N_("git submodule absorbgitdirs [<options>] [<path>...]"),
2771
NULL
2772
};
2773
+ int ret = 1;
2774
2775
argc = parse_options(argc, argv, prefix, embed_gitdir_options,
2776
git_submodule_helper_usage, 0);
2777
2778
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
2754
- return 1;
2779
+ goto cleanup;
2780
2781
for (i = 0; i < list.nr; i++)
2782
absorb_git_dir_into_superproject(list.entries[i]->name, flags);
2783
2759
- return 0;
2784
+ ret = 0;
2785
+cleanup:
2786
+ clear_pathspec(&pathspec);
2787
+ return ret;
2788
}
2789
2790
static int module_config(int argc, const char **argv, const char *prefix)