Git fork

Merge branch 'ps/leakfixes-part-3' into ps/leakfixes-part-4

* ps/leakfixes-part-3: (24 commits)
commit-reach: fix trivial memory leak when computing reachability
convert: fix leaking config strings
entry: fix leaking pathnames during delayed checkout
object-name: fix leaking commit list items
t/test-repository: fix leaking repository
builtin/credential-cache: fix trivial leaks
builtin/worktree: fix leaking derived branch names
builtin/shortlog: fix various trivial memory leaks
builtin/rerere: fix various trivial memory leaks
builtin/credential-store: fix leaking credential
builtin/show-branch: fix several memory leaks
builtin/rev-parse: fix memory leak with `--parseopt`
builtin/stash: fix various trivial memory leaks
builtin/remote: fix various trivial memory leaks
builtin/remote: fix leaking strings in `branch_list`
builtin/ls-remote: fix leaking `pattern` strings
builtin/submodule--helper: fix leaking buffer in `is_tip_reachable`
builtin/submodule--helper: fix leaking clone depth parameter
builtin/name-rev: fix various trivial memory leaks
builtin/describe: fix trivial memory leak when describing blob
...

+256 -88
+7 -2
builtin/credential-cache.c
··· 88 88 die_errno("unable to read result code from cache daemon"); 89 89 if (r != 3 || memcmp(buf, "ok\n", 3)) 90 90 die("cache daemon did not start: %.*s", r, buf); 91 + 92 + child_process_clear(&daemon); 91 93 close(daemon.out); 92 94 } 93 95 ··· 137 139 138 140 int cmd_credential_cache(int argc, const char **argv, const char *prefix) 139 141 { 140 - char *socket_path = NULL; 142 + const char *socket_path_arg = NULL; 143 + char *socket_path; 141 144 int timeout = 900; 142 145 const char *op; 143 146 const char * const usage[] = { ··· 147 150 struct option options[] = { 148 151 OPT_INTEGER(0, "timeout", &timeout, 149 152 "number of seconds to cache credentials"), 150 - OPT_STRING(0, "socket", &socket_path, "path", 153 + OPT_STRING(0, "socket", &socket_path_arg, "path", 151 154 "path of cache-daemon socket"), 152 155 OPT_END() 153 156 }; ··· 160 163 if (!have_unix_sockets()) 161 164 die(_("credential-cache unavailable; no unix socket support")); 162 165 166 + socket_path = xstrdup_or_null(socket_path_arg); 163 167 if (!socket_path) 164 168 socket_path = get_socket_path(); 165 169 if (!socket_path) ··· 176 180 else 177 181 ; /* ignore unknown operation */ 178 182 183 + free(socket_path); 179 184 return 0; 180 185 } 181 186
+1
builtin/credential-store.c
··· 218 218 ; /* Ignore unknown operation. */ 219 219 220 220 string_list_clear(&fns, 0); 221 + credential_clear(&c); 221 222 return 0; 222 223 }
+21 -4
builtin/describe.c
··· 529 529 traverse_commit_list(&revs, process_commit, process_object, &pcd); 530 530 reset_revision_walk(); 531 531 release_revisions(&revs); 532 + strvec_clear(&args); 532 533 } 533 534 534 535 static void describe(const char *arg, int last_one) ··· 619 620 if (contains) { 620 621 struct string_list_item *item; 621 622 struct strvec args; 623 + const char **argv_copy; 624 + int ret; 622 625 623 626 strvec_init(&args); 624 627 strvec_pushl(&args, "name-rev", ··· 637 640 strvec_pushv(&args, argv); 638 641 else 639 642 strvec_push(&args, "HEAD"); 640 - return cmd_name_rev(args.nr, args.v, prefix); 643 + 644 + /* 645 + * `cmd_name_rev()` modifies the array, so we'd leak its 646 + * contained strings if we didn't do a copy here. 647 + */ 648 + ALLOC_ARRAY(argv_copy, args.nr + 1); 649 + for (size_t i = 0; i < args.nr; i++) 650 + argv_copy[i] = args.v[i]; 651 + argv_copy[args.nr] = NULL; 652 + 653 + ret = cmd_name_rev(args.nr, argv_copy, prefix); 654 + 655 + strvec_clear(&args); 656 + free(argv_copy); 657 + return ret; 641 658 } 642 659 643 660 hashmap_init(&names, commit_name_neq, NULL, 0); ··· 679 696 } else if (dirty) { 680 697 struct lock_file index_lock = LOCK_INIT; 681 698 struct rev_info revs; 682 - struct strvec args = STRVEC_INIT; 683 699 int fd; 684 700 685 701 setup_work_tree(); ··· 694 710 repo_update_index_if_able(the_repository, &index_lock); 695 711 696 712 repo_init_revisions(the_repository, &revs, prefix); 697 - strvec_pushv(&args, diff_index_args); 698 - if (setup_revisions(args.nr, args.v, &revs, NULL) != 1) 713 + 714 + if (setup_revisions(ARRAY_SIZE(diff_index_args) - 1, 715 + diff_index_args, &revs, NULL) != 1) 699 716 BUG("malformed internal diff-index command line"); 700 717 run_diff_index(&revs, 0); 701 718
+3 -1
builtin/log.c
··· 1434 1434 int need_8bit_cte = 0; 1435 1435 struct pretty_print_context pp = {0}; 1436 1436 struct commit *head = list[0]; 1437 + char *to_free = NULL; 1437 1438 1438 1439 if (!cmit_fmt_is_mail(rev->commit_format)) 1439 1440 die(_("cover letter needs email format")); ··· 1455 1456 } 1456 1457 1457 1458 if (!branch_name) 1458 - branch_name = find_branch_name(rev); 1459 + branch_name = to_free = find_branch_name(rev); 1459 1460 1460 1461 pp.fmt = CMIT_FMT_EMAIL; 1461 1462 pp.date_mode.type = DATE_RFC2822; ··· 1466 1467 encoding, need_8bit_cte, cfg); 1467 1468 fprintf(rev->diffopt.file, "%s\n", sb.buf); 1468 1469 1470 + free(to_free); 1469 1471 free(pp.after_subject); 1470 1472 strbuf_release(&sb); 1471 1473
+10 -14
builtin/ls-remote.c
··· 19 19 * Is there one among the list of patterns that match the tail part 20 20 * of the path? 21 21 */ 22 - static int tail_match(const char **pattern, const char *path) 22 + static int tail_match(const struct strvec *pattern, const char *path) 23 23 { 24 - const char *p; 25 24 char *pathbuf; 26 25 27 - if (!pattern) 26 + if (!pattern->nr) 28 27 return 1; /* no restriction */ 29 28 30 29 pathbuf = xstrfmt("/%s", path); 31 - while ((p = *(pattern++)) != NULL) { 32 - if (!wildmatch(p, pathbuf, 0)) { 30 + for (size_t i = 0; i < pattern->nr; i++) { 31 + if (!wildmatch(pattern->v[i], pathbuf, 0)) { 33 32 free(pathbuf); 34 33 return 1; 35 34 } ··· 47 46 int status = 0; 48 47 int show_symref_target = 0; 49 48 const char *uploadpack = NULL; 50 - const char **pattern = NULL; 49 + struct strvec pattern = STRVEC_INIT; 51 50 struct transport_ls_refs_options transport_options = 52 51 TRANSPORT_LS_REFS_OPTIONS_INIT; 53 52 int i; ··· 93 92 94 93 packet_trace_identity("ls-remote"); 95 94 96 - if (argc > 1) { 97 - int i; 98 - CALLOC_ARRAY(pattern, argc); 99 - for (i = 1; i < argc; i++) { 100 - pattern[i - 1] = xstrfmt("*/%s", argv[i]); 101 - } 102 - } 95 + for (int i = 1; i < argc; i++) 96 + strvec_pushf(&pattern, "*/%s", argv[i]); 103 97 104 98 if (flags & REF_TAGS) 105 99 strvec_push(&transport_options.ref_prefixes, "refs/tags/"); ··· 136 130 struct ref_array_item *item; 137 131 if (!check_ref_type(ref, flags)) 138 132 continue; 139 - if (!tail_match(pattern, ref->name)) 133 + if (!tail_match(&pattern, ref->name)) 140 134 continue; 141 135 item = ref_array_push(&ref_array, ref->name, &ref->old_oid); 142 136 item->symref = xstrdup_or_null(ref->symref); ··· 158 152 if (transport_disconnect(transport)) 159 153 status = 1; 160 154 transport_ls_refs_options_release(&transport_options); 155 + 156 + strvec_clear(&pattern); 161 157 return status; 162 158 }
+4 -2
builtin/name-rev.c
··· 677 677 always, allow_undefined, data.name_only); 678 678 } 679 679 680 - UNLEAK(string_pool); 681 - UNLEAK(revs); 680 + string_list_clear(&data.ref_filters, 0); 681 + string_list_clear(&data.exclude_filters, 0); 682 + mem_pool_discard(&string_pool, 0); 683 + object_array_clear(&revs); 682 684 return 0; 683 685 }
+35 -9
builtin/remote.c
··· 258 258 char *push_remote_name; 259 259 }; 260 260 261 - static struct string_list branch_list = STRING_LIST_INIT_NODUP; 261 + static struct string_list branch_list = STRING_LIST_INIT_DUP; 262 262 263 263 static const char *abbrev_ref(const char *name, const char *prefix) 264 264 { ··· 292 292 type = PUSH_REMOTE; 293 293 else 294 294 return 0; 295 - name = xmemdupz(key, key_len); 296 295 296 + name = xmemdupz(key, key_len); 297 297 item = string_list_insert(&branch_list, name); 298 298 299 299 if (!item->util) ··· 337 337 BUG("unexpected type=%d", type); 338 338 } 339 339 340 + free(name); 340 341 return 0; 341 342 } 342 343 ··· 554 555 refspec.dst = (char *)refname; 555 556 if (remote_find_tracking(branches->remote, &refspec)) 556 557 return 0; 558 + free(refspec.src); 557 559 558 560 /* don't delete a branch if another remote also uses it */ 559 561 for (kr = branches->keep->list; kr; kr = kr->next) { 560 562 memset(&refspec, 0, sizeof(refspec)); 561 563 refspec.dst = (char *)refname; 562 - if (!remote_find_tracking(kr->remote, &refspec)) 564 + if (!remote_find_tracking(kr->remote, &refspec)) { 565 + free(refspec.src); 563 566 return 0; 567 + } 564 568 } 565 569 566 570 /* don't delete non-remote-tracking refs */ ··· 667 671 static void handle_push_default(const char* old_name, const char* new_name) 668 672 { 669 673 struct push_default_info push_default = { 670 - old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 }; 674 + .old_name = old_name, 675 + .scope = CONFIG_SCOPE_UNKNOWN, 676 + .origin = STRBUF_INIT, 677 + .linenr = -1, 678 + }; 671 679 git_config(config_read_push_default, &push_default); 672 680 if (push_default.scope >= CONFIG_SCOPE_COMMAND) 673 681 ; /* pass */ ··· 687 695 push_default.origin.buf, push_default.linenr, 688 696 old_name); 689 697 } 698 + 699 + strbuf_release(&push_default.origin); 690 700 } 691 701 692 702 ··· 784 794 } 785 795 786 796 if (!refspec_updated) 787 - return 0; 797 + goto out; 788 798 789 799 /* 790 800 * First remove symrefs, then rename the rest, finally create ··· 850 860 display_progress(progress, ++refs_renamed_nr); 851 861 } 852 862 stop_progress(&progress); 853 - string_list_clear(&remote_branches, 1); 854 863 855 864 handle_push_default(rename.old_name, rename.new_name); 856 865 866 + out: 867 + string_list_clear(&remote_branches, 1); 868 + strbuf_release(&old_remote_context); 869 + strbuf_release(&buf); 870 + strbuf_release(&buf2); 871 + strbuf_release(&buf3); 857 872 return 0; 858 873 } 859 874 ··· 944 959 945 960 if (!result) { 946 961 strbuf_addf(&buf, "remote.%s", remote->name); 947 - if (git_config_rename_section(buf.buf, NULL) < 1) 948 - return error(_("Could not remove config section '%s'"), buf.buf); 962 + if (git_config_rename_section(buf.buf, NULL) < 1) { 963 + result = error(_("Could not remove config section '%s'"), buf.buf); 964 + goto out; 965 + } 949 966 950 967 handle_push_default(remote->name, NULL); 951 968 } 952 969 970 + out: 971 + for (struct known_remote *r = known_remotes.list; r;) { 972 + struct known_remote *next = r->next; 973 + free(r); 974 + r = next; 975 + } 976 + strbuf_release(&buf); 953 977 return result; 954 978 } 955 979 ··· 982 1006 983 1007 memset(&refspec, 0, sizeof(refspec)); 984 1008 refspec.dst = (char *)refname; 985 - if (!remote_find_tracking(states->remote, &refspec)) 1009 + if (!remote_find_tracking(states->remote, &refspec)) { 986 1010 string_list_append(&states->tracked, abbrev_branch(refspec.src)); 1011 + free(refspec.src); 1012 + } 987 1013 988 1014 return 0; 989 1015 }
+14 -6
builtin/replay.c
··· 151 151 152 152 static void determine_replay_mode(struct rev_cmdline_info *cmd_info, 153 153 const char *onto_name, 154 - const char **advance_name, 154 + char **advance_name, 155 155 struct commit **onto, 156 156 struct strset **update_refs) 157 157 { ··· 174 174 *onto = peel_committish(*advance_name); 175 175 if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name), 176 176 &oid, &fullname, 0) == 1) { 177 + free(*advance_name); 177 178 *advance_name = fullname; 178 179 } else { 179 180 die(_("argument to --advance must be a reference")); ··· 197 198 if (negative_refs_complete) { 198 199 struct hashmap_iter iter; 199 200 struct strmap_entry *entry; 201 + const char *last_key = NULL; 200 202 201 203 if (rinfo.negative_refexprs == 0) 202 204 die(_("all positive revisions given must be references")); ··· 208 210 /* Only one entry, but we have to loop to get it */ 209 211 strset_for_each_entry(&rinfo.negative_refs, 210 212 &iter, entry) { 211 - *advance_name = entry->key; 213 + last_key = entry->key; 212 214 } 215 + 216 + free(*advance_name); 217 + *advance_name = xstrdup_or_null(last_key); 213 218 } else { /* positive_refs_complete */ 214 219 if (rinfo.negative_refexprs > 1) 215 220 die(_("cannot implicitly determine correct base for --onto")); ··· 271 276 272 277 int cmd_replay(int argc, const char **argv, const char *prefix) 273 278 { 274 - const char *advance_name = NULL; 279 + const char *advance_name_opt = NULL; 280 + char *advance_name = NULL; 275 281 struct commit *onto = NULL; 276 282 const char *onto_name = NULL; 277 283 int contained = 0; ··· 292 298 NULL 293 299 }; 294 300 struct option replay_options[] = { 295 - OPT_STRING(0, "advance", &advance_name, 301 + OPT_STRING(0, "advance", &advance_name_opt, 296 302 N_("branch"), 297 303 N_("make replay advance given branch")), 298 304 OPT_STRING(0, "onto", &onto_name, ··· 306 312 argc = parse_options(argc, argv, prefix, replay_options, replay_usage, 307 313 PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT); 308 314 309 - if (!onto_name && !advance_name) { 315 + if (!onto_name && !advance_name_opt) { 310 316 error(_("option --onto or --advance is mandatory")); 311 317 usage_with_options(replay_usage, replay_options); 312 318 } 313 319 314 - if (advance_name && contained) 320 + if (advance_name_opt && contained) 315 321 die(_("options '%s' and '%s' cannot be used together"), 316 322 "--advance", "--contained"); 323 + advance_name = xstrdup_or_null(advance_name_opt); 317 324 318 325 repo_init_revisions(the_repository, &revs, prefix); 319 326 ··· 441 448 442 449 cleanup: 443 450 release_revisions(&revs); 451 + free(advance_name); 444 452 445 453 /* Return */ 446 454 if (ret < 0)
+7 -1
builtin/rerere.c
··· 73 73 74 74 if (!strcmp(argv[0], "forget")) { 75 75 struct pathspec pathspec; 76 + int ret; 77 + 76 78 if (argc < 2) 77 79 warning(_("'git rerere forget' without paths is deprecated")); 78 80 parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, 79 81 prefix, argv + 1); 80 - return rerere_forget(the_repository, &pathspec); 82 + 83 + ret = rerere_forget(the_repository, &pathspec); 84 + 85 + clear_pathspec(&pathspec); 86 + return ret; 81 87 } 82 88 83 89 if (!strcmp(argv[0], "clear")) {
+4 -1
builtin/rev-parse.c
··· 553 553 strbuf_release(&sb); 554 554 strvec_clear(&longnames); 555 555 strvec_clear(&usage); 556 - free((char *) opts->help); 556 + for (size_t i = 0; i < opts_nr; i++) { 557 + free((char *) opts[i].help); 558 + free((char *) opts[i].argh); 559 + } 557 560 free(opts); 558 561 return 0; 559 562 }
+1
builtin/shortlog.c
··· 514 514 string_list_clear(&log->list, 1); 515 515 clear_mailmap(&log->mailmap); 516 516 string_list_clear(&log->format, 0); 517 + string_list_clear(&log->trailers, 0); 517 518 }
+36 -16
builtin/show-branch.c
··· 502 502 return !strcmp(head, name); 503 503 } 504 504 505 - static int show_merge_base(struct commit_list *seen, int num_rev) 505 + static int show_merge_base(const struct commit_list *seen, int num_rev) 506 506 { 507 507 int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1); 508 508 int all_revs = all_mask & ~((1u << REV_SHIFT) - 1); 509 509 int exit_status = 1; 510 510 511 - while (seen) { 512 - struct commit *commit = pop_commit(&seen); 511 + for (const struct commit_list *s = seen; s; s = s->next) { 512 + struct commit *commit = s->item; 513 513 int flags = commit->object.flags & all_mask; 514 514 if (!(flags & UNINTERESTING) && 515 515 ((flags & all_revs) == all_revs)) { ··· 635 635 int cmd_show_branch(int ac, const char **av, const char *prefix) 636 636 { 637 637 struct commit *rev[MAX_REVS], *commit; 638 - char *reflog_msg[MAX_REVS]; 638 + char *reflog_msg[MAX_REVS] = {0}; 639 639 struct commit_list *list = NULL, *seen = NULL; 640 640 unsigned int rev_mask[MAX_REVS]; 641 641 int num_rev, i, extra = 0; ··· 692 692 parse_reflog_param), 693 693 OPT_END() 694 694 }; 695 + const char **args_copy = NULL; 696 + int ret; 695 697 696 698 init_commit_name_slab(&name_slab); 697 699 ··· 699 701 700 702 /* If nothing is specified, try the default first */ 701 703 if (ac == 1 && default_args.nr) { 704 + DUP_ARRAY(args_copy, default_args.v, default_args.nr); 702 705 ac = default_args.nr; 703 - av = default_args.v; 706 + av = args_copy; 704 707 } 705 708 706 709 ac = parse_options(ac, av, prefix, builtin_show_branch_options, ··· 780 783 } 781 784 782 785 for (i = 0; i < reflog; i++) { 783 - char *logmsg; 786 + char *logmsg = NULL; 784 787 char *nth_desc; 785 788 const char *msg; 786 789 char *end; ··· 790 793 if (read_ref_at(get_main_ref_store(the_repository), 791 794 ref, flags, 0, base + i, &oid, &logmsg, 792 795 &timestamp, &tz, NULL)) { 796 + free(logmsg); 793 797 reflog = i; 794 798 break; 795 799 } ··· 842 846 843 847 if (!ref_name_cnt) { 844 848 fprintf(stderr, "No revs to be shown.\n"); 845 - exit(0); 849 + ret = 0; 850 + goto out; 846 851 } 847 852 848 853 for (num_rev = 0; ref_name[num_rev]; num_rev++) { ··· 879 884 880 885 commit_list_sort_by_date(&seen); 881 886 882 - if (merge_base) 883 - return show_merge_base(seen, num_rev); 887 + if (merge_base) { 888 + ret = show_merge_base(seen, num_rev); 889 + goto out; 890 + } 884 891 885 - if (independent) 886 - return show_independent(rev, num_rev, rev_mask); 892 + if (independent) { 893 + ret = show_independent(rev, num_rev, rev_mask); 894 + goto out; 895 + } 887 896 888 897 /* Show list; --more=-1 means list-only */ 889 898 if (1 < num_rev || extra < 0) { ··· 919 928 putchar('\n'); 920 929 } 921 930 } 922 - if (extra < 0) 923 - exit(0); 931 + if (extra < 0) { 932 + ret = 0; 933 + goto out; 934 + } 924 935 925 936 /* Sort topologically */ 926 937 sort_in_topological_order(&seen, sort_order); ··· 932 943 all_mask = ((1u << (REV_SHIFT + num_rev)) - 1); 933 944 all_revs = all_mask & ~((1u << REV_SHIFT) - 1); 934 945 935 - while (seen) { 936 - struct commit *commit = pop_commit(&seen); 946 + for (struct commit_list *l = seen; l; l = l->next) { 947 + struct commit *commit = l->item; 937 948 int this_flag = commit->object.flags; 938 949 int is_merge_point = ((this_flag & all_revs) == all_revs); 939 950 ··· 973 984 if (shown_merge_point && --extra < 0) 974 985 break; 975 986 } 987 + 988 + ret = 0; 989 + 990 + out: 991 + for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++) 992 + free(reflog_msg[i]); 993 + free_commit_list(seen); 994 + free_commit_list(list); 995 + free(args_copy); 976 996 free(head); 977 - return 0; 997 + return ret; 978 998 }
+16 -2
builtin/stash.c
··· 1521 1521 struct strbuf patch = STRBUF_INIT; 1522 1522 struct strbuf stash_msg_buf = STRBUF_INIT; 1523 1523 struct strbuf untracked_files = STRBUF_INIT; 1524 + struct strbuf out = STRBUF_INIT; 1524 1525 1525 1526 if (patch_mode && keep_index == -1) 1526 1527 keep_index = 1; ··· 1626 1627 struct child_process cp_add = CHILD_PROCESS_INIT; 1627 1628 struct child_process cp_diff = CHILD_PROCESS_INIT; 1628 1629 struct child_process cp_apply = CHILD_PROCESS_INIT; 1629 - struct strbuf out = STRBUF_INIT; 1630 1630 1631 1631 cp_add.git_cmd = 1; 1632 1632 strvec_push(&cp_add.args, "add"); ··· 1718 1718 1719 1719 done: 1720 1720 strbuf_release(&patch); 1721 + strbuf_release(&out); 1721 1722 free_stash_info(&info); 1722 1723 strbuf_release(&stash_msg_buf); 1723 1724 strbuf_release(&untracked_files); ··· 1869 1870 OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE), 1870 1871 OPT_END() 1871 1872 }; 1873 + const char **args_copy; 1874 + int ret; 1872 1875 1873 1876 git_config(git_stash_config, NULL); 1874 1877 ··· 1892 1895 /* Assume 'stash push' */ 1893 1896 strvec_push(&args, "push"); 1894 1897 strvec_pushv(&args, argv); 1895 - return !!push_stash(args.nr, args.v, prefix, 1); 1898 + 1899 + /* 1900 + * `push_stash()` ends up modifying the array, which causes memory 1901 + * leaks if we didn't copy the array here. 1902 + */ 1903 + DUP_ARRAY(args_copy, args.v, args.nr); 1904 + 1905 + ret = !!push_stash(args.nr, args_copy, prefix, 1); 1906 + 1907 + strvec_clear(&args); 1908 + free(args_copy); 1909 + return ret; 1896 1910 }
+12 -8
builtin/submodule--helper.c
··· 1530 1530 const char *path; 1531 1531 const char *name; 1532 1532 const char *url; 1533 - const char *depth; 1533 + int depth; 1534 1534 struct list_objects_filter_options *filter_options; 1535 1535 unsigned int quiet: 1; 1536 1536 unsigned int progress: 1; ··· 1729 1729 strvec_push(&cp.args, "--quiet"); 1730 1730 if (clone_data->progress) 1731 1731 strvec_push(&cp.args, "--progress"); 1732 - if (clone_data->depth && *(clone_data->depth)) 1733 - strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL); 1732 + if (clone_data->depth > 0) 1733 + strvec_pushf(&cp.args, "--depth=%d", clone_data->depth); 1734 1734 if (reference->nr) { 1735 1735 struct string_list_item *item; 1736 1736 ··· 1851 1851 N_("reference repository")), 1852 1852 OPT_BOOL(0, "dissociate", &dissociate, 1853 1853 N_("use --reference only while cloning")), 1854 - OPT_STRING(0, "depth", &clone_data.depth, 1855 - N_("string"), 1854 + OPT_INTEGER(0, "depth", &clone_data.depth, 1856 1855 N_("depth for shallow clones")), 1857 1856 OPT__QUIET(&quiet, "suppress output for cloning a submodule"), 1858 1857 OPT_BOOL(0, "progress", &progress, ··· 2269 2268 struct child_process cp = CHILD_PROCESS_INIT; 2270 2269 struct strbuf rev = STRBUF_INIT; 2271 2270 char *hex = oid_to_hex(oid); 2271 + int reachable; 2272 2272 2273 2273 cp.git_cmd = 1; 2274 2274 cp.dir = path; ··· 2278 2278 prepare_submodule_repo_env(&cp.env); 2279 2279 2280 2280 if (capture_command(&cp, &rev, GIT_MAX_HEXSZ + 1) || rev.len) 2281 - return 0; 2281 + reachable = 0; 2282 + else 2283 + reachable = 1; 2282 2284 2283 - return 1; 2285 + strbuf_release(&rev); 2286 + return reachable; 2284 2287 } 2285 2288 2286 2289 static int fetch_in_submodule(const char *module_path, int depth, int quiet, ··· 3200 3203 } 3201 3204 clone_data.dissociate = add_data->dissociate; 3202 3205 if (add_data->depth >= 0) 3203 - clone_data.depth = xstrfmt("%d", add_data->depth); 3206 + clone_data.depth = add_data->depth; 3204 3207 3205 3208 if (clone_submodule(&clone_data, &reference)) 3206 3209 goto cleanup; ··· 3223 3226 die(_("unable to checkout submodule '%s'"), add_data->sm_path); 3224 3227 } 3225 3228 ret = 0; 3229 + 3226 3230 cleanup: 3227 3231 string_list_clear(&reference, 1); 3228 3232 return ret;
+4 -3
builtin/worktree.c
··· 769 769 char *branch_to_free = NULL; 770 770 char *new_branch_to_free = NULL; 771 771 const char *new_branch = NULL; 772 - const char *opt_track = NULL; 772 + char *opt_track = NULL; 773 773 const char *lock_reason = NULL; 774 774 int keep_locked = 0; 775 775 int used_new_branch_options; ··· 846 846 if (opts.orphan && !new_branch) { 847 847 int n; 848 848 const char *s = worktree_basename(path, &n); 849 - new_branch = xstrndup(s, n); 849 + new_branch = new_branch_to_free = xstrndup(s, n); 850 850 } else if (opts.orphan) { 851 851 ; /* no-op */ 852 852 } else if (opts.detach) { ··· 875 875 remote = unique_tracking_name(branch, &oid, NULL); 876 876 if (remote) { 877 877 new_branch = branch; 878 - branch = remote; 878 + branch = new_branch_to_free = remote; 879 879 } 880 880 } 881 881 ··· 923 923 924 924 ret = add_worktree(path, branch, &opts); 925 925 free(path); 926 + free(opt_track); 926 927 free(branch_to_free); 927 928 free(new_branch_to_free); 928 929 return ret;
+1
commit-reach.c
··· 1227 1227 done: 1228 1228 free(commits); 1229 1229 repo_clear_commit_marks(r, SEEN); 1230 + free_commit_list(stack); 1230 1231 }
+10 -4
convert.c
··· 960 960 while ((line = packet_read_line(process->out, NULL))) { 961 961 const char *path; 962 962 if (skip_prefix(line, "pathname=", &path)) 963 - string_list_insert(available_paths, xstrdup(path)); 963 + string_list_insert(available_paths, path); 964 964 else 965 965 ; /* ignore unknown keys */ 966 966 } ··· 1050 1050 * The command-line will not be interpolated in any way. 1051 1051 */ 1052 1052 1053 - if (!strcmp("smudge", key)) 1053 + if (!strcmp("smudge", key)) { 1054 + FREE_AND_NULL(drv->smudge); 1054 1055 return git_config_string(&drv->smudge, var, value); 1056 + } 1055 1057 1056 - if (!strcmp("clean", key)) 1058 + if (!strcmp("clean", key)) { 1059 + FREE_AND_NULL(drv->clean); 1057 1060 return git_config_string(&drv->clean, var, value); 1061 + } 1058 1062 1059 - if (!strcmp("process", key)) 1063 + if (!strcmp("process", key)) { 1064 + FREE_AND_NULL(drv->process); 1060 1065 return git_config_string(&drv->process, var, value); 1066 + } 1061 1067 1062 1068 if (!strcmp("required", key)) { 1063 1069 drv->required = git_config_bool(var, value);
+3 -1
entry.c
··· 191 191 progress = start_delayed_progress(_("Filtering content"), dco->paths.nr); 192 192 while (dco->filters.nr > 0) { 193 193 for_each_string_list_item(filter, &dco->filters) { 194 - struct string_list available_paths = STRING_LIST_INIT_NODUP; 194 + struct string_list available_paths = STRING_LIST_INIT_DUP; 195 195 196 196 if (!async_query_available_blobs(filter->string, &available_paths)) { 197 197 /* Filter reported an error */ ··· 245 245 } else 246 246 errs = 1; 247 247 } 248 + 249 + string_list_clear(&available_paths, 0); 248 250 } 249 251 250 252 filter_string_list(&dco->filters, 0, string_is_not_null, NULL);
+16 -10
object-name.c
··· 27 27 #include "date.h" 28 28 #include "object-file-convert.h" 29 29 30 - static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *); 30 + static int get_oid_oneline(struct repository *r, const char *, struct object_id *, 31 + const struct commit_list *); 31 32 32 33 typedef int (*disambiguate_hint_fn)(struct repository *, const struct object_id *, void *); 33 34 ··· 1254 1255 prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1)); 1255 1256 commit_list_insert((struct commit *)o, &list); 1256 1257 ret = get_oid_oneline(r, prefix, oid, list); 1258 + 1259 + free_commit_list(list); 1257 1260 free(prefix); 1258 1261 return ret; 1259 1262 } ··· 1388 1391 1389 1392 static int get_oid_oneline(struct repository *r, 1390 1393 const char *prefix, struct object_id *oid, 1391 - struct commit_list *list) 1394 + const struct commit_list *list) 1392 1395 { 1393 - struct commit_list *backup = NULL, *l; 1396 + struct commit_list *copy = NULL; 1397 + const struct commit_list *l; 1394 1398 int found = 0; 1395 1399 int negative = 0; 1396 1400 regex_t regex; ··· 1411 1415 1412 1416 for (l = list; l; l = l->next) { 1413 1417 l->item->object.flags |= ONELINE_SEEN; 1414 - commit_list_insert(l->item, &backup); 1418 + commit_list_insert(l->item, &copy); 1415 1419 } 1416 - while (list) { 1420 + while (copy) { 1417 1421 const char *p, *buf; 1418 1422 struct commit *commit; 1419 1423 int matches; 1420 1424 1421 - commit = pop_most_recent_commit(&list, ONELINE_SEEN); 1425 + commit = pop_most_recent_commit(&copy, ONELINE_SEEN); 1422 1426 if (!parse_object(r, &commit->object.oid)) 1423 1427 continue; 1424 1428 buf = repo_get_commit_buffer(r, commit, NULL); ··· 1433 1437 } 1434 1438 } 1435 1439 regfree(&regex); 1436 - free_commit_list(list); 1437 - for (l = backup; l; l = l->next) 1440 + for (l = list; l; l = l->next) 1438 1441 clear_commit_marks(l->item, ONELINE_SEEN); 1439 - free_commit_list(backup); 1442 + free_commit_list(copy); 1440 1443 return found ? 0 : -1; 1441 1444 } 1442 1445 ··· 2024 2027 refs_for_each_ref(get_main_ref_store(repo), handle_one_ref, &cb); 2025 2028 refs_head_ref(get_main_ref_store(repo), handle_one_ref, &cb); 2026 2029 commit_list_sort_by_date(&list); 2027 - return get_oid_oneline(repo, name + 2, oid, list); 2030 + ret = get_oid_oneline(repo, name + 2, oid, list); 2031 + 2032 + free_commit_list(list); 2033 + return ret; 2028 2034 } 2029 2035 if (namelen < 3 || 2030 2036 name[2] != ':' ||
+7 -2
rerere.c
··· 1107 1107 1108 1108 int rerere_forget(struct repository *r, struct pathspec *pathspec) 1109 1109 { 1110 - int i, fd; 1110 + int i, fd, ret; 1111 1111 struct string_list conflict = STRING_LIST_INIT_DUP; 1112 1112 struct string_list merge_rr = STRING_LIST_INIT_DUP; 1113 1113 ··· 1132 1132 continue; 1133 1133 rerere_forget_one_path(r->index, it->string, &merge_rr); 1134 1134 } 1135 - return write_rr(&merge_rr, fd); 1135 + 1136 + ret = write_rr(&merge_rr, fd); 1137 + 1138 + string_list_clear(&conflict, 0); 1139 + string_list_clear(&merge_rr, 1); 1140 + return ret; 1136 1141 } 1137 1142 1138 1143 /*
+2 -2
t/helper/test-repository.c
··· 19 19 20 20 setup_git_env(gitdir); 21 21 22 - memset(the_repository, 0, sizeof(*the_repository)); 22 + repo_clear(the_repository); 23 23 24 24 if (repo_init(&r, gitdir, worktree)) 25 25 die("Couldn't init repo"); ··· 49 49 50 50 setup_git_env(gitdir); 51 51 52 - memset(the_repository, 0, sizeof(*the_repository)); 52 + repo_clear(the_repository); 53 53 54 54 if (repo_init(&r, gitdir, worktree)) 55 55 die("Couldn't init repo");
+1
t/t0021-conversion.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 . "$TEST_DIRECTORY"/lib-terminal.sh 10 11
+2
t/t0301-credential-cache.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='credential-cache tests' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 . "$TEST_DIRECTORY"/lib-credential.sh 6 8
+2
t/t0302-credential-store.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='credential-store tests' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 . "$TEST_DIRECTORY"/lib-credential.sh 6 8
+1
t/t0303-credential-external.sh
··· 29 29 commands. 30 30 ' 31 31 32 + TEST_PASSES_SANITIZE_LEAK=true 32 33 . ./test-lib.sh 33 34 . "$TEST_DIRECTORY"/lib-credential.sh 34 35
+2
t/t1502-rev-parse-parseopt.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='test git rev-parse --parseopt' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 6 8 check_invalid_long_option () {
+1
t/t1511-rev-parse-caret.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 test_expect_success 'setup' '
+1
t/t2030-unresolve-info.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 check_resolve_undo () {
+1
t/t2080-parallel-checkout-basics.sh
··· 8 8 ' 9 9 10 10 TEST_NO_CREATE_REPO=1 11 + TEST_PASSES_SANITIZE_LEAK=true 11 12 . ./test-lib.sh 12 13 . "$TEST_DIRECTORY/lib-parallel-checkout.sh" 13 14
+1
t/t2082-parallel-checkout-attributes.sh
··· 10 10 ' 11 11 12 12 TEST_NO_CREATE_REPO=1 13 + TEST_PASSES_SANITIZE_LEAK=true 13 14 . ./test-lib.sh 14 15 . "$TEST_DIRECTORY/lib-parallel-checkout.sh" 15 16 . "$TEST_DIRECTORY/lib-encoding.sh"
+1
t/t2400-worktree-add.sh
··· 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 8 TEST_CREATE_REPO_NO_TEMPLATE=1 9 + TEST_PASSES_SANITIZE_LEAK=true 9 10 . ./test-lib.sh 10 11 11 12 . "$TEST_DIRECTORY"/lib-rebase.sh
+1
t/t2501-cwd-empty.sh
··· 2 2 3 3 test_description='Test handling of the current working directory becoming empty' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 test_expect_success setup '
+1
t/t3201-branch-contains.sh
··· 2 2 3 3 test_description='branch --contains <commit>, --no-contains <commit> --merged, and --no-merged' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 test_expect_success setup '
+1
t/t3202-show-branch.sh
··· 2 2 3 3 test_description='test show-branch' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 test_expect_success 'error descriptions on empty repository' '
+1
t/t3206-range-diff.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 # Note that because of the range-diff's heuristics, test_commit does more
+1
t/t3650-replay-basics.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 GIT_AUTHOR_NAME=author@name
+1
t/t3903-stash.sh
··· 8 8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 9 9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 10 10 11 + TEST_PASSES_SANITIZE_LEAK=true 11 12 . ./test-lib.sh 12 13 . "$TEST_DIRECTORY"/lib-unique-files.sh 13 14
+2
t/t3904-stash-patch.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='stash -p' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./lib-patch-mode.sh 5 7 6 8 test_expect_success 'setup' '
+1
t/t3905-stash-include-untracked.sh
··· 5 5 6 6 test_description='Test git stash --include-untracked' 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 test_expect_success 'stash save --include-untracked some dirty working directory' '
+1
t/t4200-rerere.sh
··· 25 25 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 26 26 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 27 27 28 + TEST_PASSES_SANITIZE_LEAK=true 28 29 . ./test-lib.sh 29 30 30 31 test_expect_success 'setup' '
+1
t/t4201-shortlog.sh
··· 9 9 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 10 10 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 11 11 12 + TEST_PASSES_SANITIZE_LEAK=true 12 13 . ./test-lib.sh 13 14 14 15 test_expect_success 'setup' '
+2
t/t5318-commit-graph.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='commit graph' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 . "$TEST_DIRECTORY"/lib-chunk.sh 6 8
+1
t/t5512-ls-remote.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 generate_references () {
+1
t/t5514-fetch-multiple.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 setup_repository () {
+1
t/t5520-pull.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 modify () {
+1
t/t5528-push-default.sh
··· 4 4 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 5 5 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 6 6 7 + TEST_PASSES_SANITIZE_LEAK=true 7 8 . ./test-lib.sh 8 9 9 10 test_expect_success 'setup bare remotes' '
+1
t/t5535-fetch-push-symref.sh
··· 2 2 3 3 test_description='avoiding conflicting update through symref aliasing' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 test_expect_success 'setup' '
+1
t/t5543-atomic-push.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 mk_repo_pair () {
+1
t/t5570-git-daemon.sh
··· 4 4 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 5 5 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 6 6 7 + TEST_PASSES_SANITIZE_LEAK=true 7 8 . ./test-lib.sh 8 9 9 10 . "$TEST_DIRECTORY"/lib-git-daemon.sh
+1
t/t6007-rev-list-cherry-pick-file.sh
··· 5 5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6 6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 7 8 + TEST_PASSES_SANITIZE_LEAK=true 8 9 . ./test-lib.sh 9 10 10 11 # A---B---D---F
+1
t/t6010-merge-base.sh
··· 6 6 test_description='Merge base and parent list computation. 7 7 ' 8 8 9 + TEST_PASSES_SANITIZE_LEAK=true 9 10 . ./test-lib.sh 10 11 11 12 M=1130000000
+1
t/t6120-describe.sh
··· 14 14 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 15 15 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 16 16 17 + TEST_PASSES_SANITIZE_LEAK=true 17 18 . ./test-lib.sh 18 19 19 20 check_describe () {
+2
t/t6133-pathspec-rev-dwim.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='test dwim of revs versus pathspecs in revision parser' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 6 8 test_expect_success 'setup' '
+1
t/t7064-wtstatus-pv2.sh
··· 4 4 5 5 This test exercises porcelain V2 output for git status.' 6 6 7 + TEST_PASSES_SANITIZE_LEAK=true 7 8 . ./test-lib.sh 8 9 9 10
+1
t/t7400-submodule-basic.sh
··· 12 12 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 13 13 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 14 14 15 + TEST_PASSES_SANITIZE_LEAK=true 15 16 . ./test-lib.sh 16 17 17 18 test_expect_success 'setup - enable local submodules' '
+1
t/t9902-completion.sh
··· 16 16 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master 17 17 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 18 18 19 + TEST_PASSES_SANITIZE_LEAK=true 19 20 . ./lib-bash.sh 20 21 21 22 complete ()
+1
t/t9903-bash-prompt.sh
··· 8 8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 9 9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 10 10 11 + TEST_PASSES_SANITIZE_LEAK=true 11 12 . ./lib-bash.sh 12 13 13 14 . "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh"