Git fork

Merge branch 'ps/leakfixes-part-7'

More leak-fixes.

* ps/leakfixes-part-7: (23 commits)
diffcore-break: fix leaking filespecs when merging broken pairs
revision: fix leaking parents when simplifying commits
builtin/maintenance: fix leak in `get_schedule_cmd()`
builtin/maintenance: fix leaking config string
promisor-remote: fix leaking partial clone filter
grep: fix leaking grep pattern
submodule: fix leaking submodule ODB paths
trace2: destroy context stored in thread-local storage
builtin/difftool: plug several trivial memory leaks
builtin/repack: fix leaking configuration
diffcore-order: fix leaking buffer when parsing orderfiles
parse-options: free previous value of `OPTION_FILENAME`
diff: fix leaking orderfile option
builtin/pull: fix leaking "ff" option
dir: fix off by one errors for ignored and untracked entries
builtin/submodule--helper: fix leaking remote ref on errors
t/helper: fix leaking subrepo in nested submodule config helper
builtin/submodule--helper: fix leaking error buffer
builtin/submodule--helper: clear child process when not running it
submodule: fix leaking update strategy
...

+279 -124
+6
builtin/difftool.c
··· 662 662 if (fp) 663 663 fclose(fp); 664 664 665 + hashmap_clear_and_free(&working_tree_dups, struct working_tree_entry, entry); 666 + hashmap_clear_and_free(&wt_modified, struct path_entry, entry); 667 + hashmap_clear_and_free(&tmp_modified, struct path_entry, entry); 668 + hashmap_clear_and_free(&submodules, struct pair_entry, entry); 669 + hashmap_clear_and_free(&symlinks2, struct pair_entry, entry); 670 + release_index(&wtindex); 665 671 free(lbase_dir); 666 672 free(rbase_dir); 667 673 strbuf_release(&info);
+82 -49
builtin/gc.c
··· 1478 1478 1479 1479 static void initialize_maintenance_strategy(void) 1480 1480 { 1481 - char *config_str; 1481 + const char *config_str; 1482 1482 1483 - if (git_config_get_string("maintenance.strategy", &config_str)) 1483 + if (git_config_get_string_tmp("maintenance.strategy", &config_str)) 1484 1484 return; 1485 1485 1486 1486 if (!strcasecmp(config_str, "incremental")) { ··· 1818 1818 * * If $GIT_TEST_MAINT_SCHEDULER is set, return true. 1819 1819 * In this case, the *cmd value is read as input. 1820 1820 * 1821 - * * if the input value *cmd is the key of one of the comma-separated list 1822 - * item, then *is_available is set to true and *cmd is modified and becomes 1821 + * * if the input value cmd is the key of one of the comma-separated list 1822 + * item, then *is_available is set to true and *out is set to 1823 1823 * the mock command. 1824 1824 * 1825 1825 * * if the input value *cmd isn’t the key of any of the comma-separated list 1826 - * item, then *is_available is set to false. 1826 + * item, then *is_available is set to false and *out is set to the original 1827 + * command. 1827 1828 * 1828 1829 * Ex.: 1829 1830 * GIT_TEST_MAINT_SCHEDULER not set 1830 1831 * +-------+-------------------------------------------------+ 1831 1832 * | Input | Output | 1832 - * | *cmd | return code | *cmd | *is_available | 1833 + * | *cmd | return code | *out | *is_available | 1833 1834 * +-------+-------------+-------------------+---------------+ 1834 - * | "foo" | false | "foo" (unchanged) | (unchanged) | 1835 + * | "foo" | false | NULL | (unchanged) | 1835 1836 * +-------+-------------+-------------------+---------------+ 1836 1837 * 1837 1838 * GIT_TEST_MAINT_SCHEDULER set to “foo:./mock_foo.sh,bar:./mock_bar.sh” 1838 1839 * +-------+-------------------------------------------------+ 1839 1840 * | Input | Output | 1840 - * | *cmd | return code | *cmd | *is_available | 1841 + * | *cmd | return code | *out | *is_available | 1841 1842 * +-------+-------------+-------------------+---------------+ 1842 1843 * | "foo" | true | "./mock.foo.sh" | true | 1843 - * | "qux" | true | "qux" (unchanged) | false | 1844 + * | "qux" | true | "qux" (allocated) | false | 1844 1845 * +-------+-------------+-------------------+---------------+ 1845 1846 */ 1846 - static int get_schedule_cmd(const char **cmd, int *is_available) 1847 + static int get_schedule_cmd(const char *cmd, int *is_available, char **out) 1847 1848 { 1848 1849 char *testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER")); 1849 1850 struct string_list_item *item; ··· 1862 1863 if (string_list_split_in_place(&pair, item->string, ":", 2) != 2) 1863 1864 continue; 1864 1865 1865 - if (!strcmp(*cmd, pair.items[0].string)) { 1866 - *cmd = pair.items[1].string; 1866 + if (!strcmp(cmd, pair.items[0].string)) { 1867 + if (out) 1868 + *out = xstrdup(pair.items[1].string); 1867 1869 if (is_available) 1868 1870 *is_available = 1; 1869 - string_list_clear(&list, 0); 1870 - UNLEAK(testing); 1871 - return 1; 1871 + string_list_clear(&pair, 0); 1872 + goto out; 1872 1873 } 1874 + 1875 + string_list_clear(&pair, 0); 1873 1876 } 1874 1877 1878 + if (out) 1879 + *out = xstrdup(cmd); 1880 + 1881 + out: 1875 1882 string_list_clear(&list, 0); 1876 1883 free(testing); 1877 1884 return 1; ··· 1888 1895 1889 1896 static int is_launchctl_available(void) 1890 1897 { 1891 - const char *cmd = "launchctl"; 1892 1898 int is_available; 1893 - if (get_schedule_cmd(&cmd, &is_available)) 1899 + if (get_schedule_cmd("launchctl", &is_available, NULL)) 1894 1900 return is_available; 1895 1901 1896 1902 #ifdef __APPLE__ ··· 1928 1934 1929 1935 static int launchctl_boot_plist(int enable, const char *filename) 1930 1936 { 1931 - const char *cmd = "launchctl"; 1937 + char *cmd; 1932 1938 int result; 1933 1939 struct child_process child = CHILD_PROCESS_INIT; 1934 1940 char *uid = launchctl_get_uid(); 1935 1941 1936 - get_schedule_cmd(&cmd, NULL); 1942 + get_schedule_cmd("launchctl", NULL, &cmd); 1937 1943 strvec_split(&child.args, cmd); 1938 1944 strvec_pushl(&child.args, enable ? "bootstrap" : "bootout", uid, 1939 1945 filename, NULL); ··· 1946 1952 1947 1953 result = finish_command(&child); 1948 1954 1955 + free(cmd); 1949 1956 free(uid); 1950 1957 return result; 1951 1958 } ··· 1997 2004 static unsigned long lock_file_timeout_ms = ULONG_MAX; 1998 2005 struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT; 1999 2006 struct stat st; 2000 - const char *cmd = "launchctl"; 2007 + char *cmd; 2001 2008 int minute = get_random_minute(); 2002 2009 2003 - get_schedule_cmd(&cmd, NULL); 2010 + get_schedule_cmd("launchctl", NULL, &cmd); 2004 2011 preamble = "<?xml version=\"1.0\"?>\n" 2005 2012 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 2006 2013 "<plist version=\"1.0\">" ··· 2092 2099 2093 2100 free(filename); 2094 2101 free(name); 2102 + free(cmd); 2095 2103 strbuf_release(&plist); 2096 2104 strbuf_release(&plist2); 2097 2105 return 0; ··· 2116 2124 2117 2125 static int is_schtasks_available(void) 2118 2126 { 2119 - const char *cmd = "schtasks"; 2120 2127 int is_available; 2121 - if (get_schedule_cmd(&cmd, &is_available)) 2128 + if (get_schedule_cmd("schtasks", &is_available, NULL)) 2122 2129 return is_available; 2123 2130 2124 2131 #ifdef GIT_WINDOWS_NATIVE ··· 2137 2144 2138 2145 static int schtasks_remove_task(enum schedule_priority schedule) 2139 2146 { 2140 - const char *cmd = "schtasks"; 2147 + char *cmd; 2141 2148 struct child_process child = CHILD_PROCESS_INIT; 2142 2149 const char *frequency = get_frequency(schedule); 2143 2150 char *name = schtasks_task_name(frequency); 2144 2151 2145 - get_schedule_cmd(&cmd, NULL); 2152 + get_schedule_cmd("schtasks", NULL, &cmd); 2146 2153 strvec_split(&child.args, cmd); 2147 2154 strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL); 2148 2155 free(name); 2156 + free(cmd); 2149 2157 2150 2158 return run_command(&child); 2151 2159 } ··· 2159 2167 2160 2168 static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule) 2161 2169 { 2162 - const char *cmd = "schtasks"; 2170 + char *cmd; 2163 2171 int result; 2164 2172 struct child_process child = CHILD_PROCESS_INIT; 2165 2173 const char *xml; ··· 2169 2177 struct strbuf tfilename = STRBUF_INIT; 2170 2178 int minute = get_random_minute(); 2171 2179 2172 - get_schedule_cmd(&cmd, NULL); 2180 + get_schedule_cmd("schtasks", NULL, &cmd); 2173 2181 2174 2182 strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX", 2175 2183 repo_get_common_dir(the_repository), frequency); ··· 2276 2284 2277 2285 delete_tempfile(&tfile); 2278 2286 free(name); 2287 + free(cmd); 2279 2288 return result; 2280 2289 } 2281 2290 ··· 2317 2326 2318 2327 static int is_crontab_available(void) 2319 2328 { 2320 - const char *cmd = "crontab"; 2329 + char *cmd; 2321 2330 int is_available; 2331 + int ret; 2322 2332 2323 - if (get_schedule_cmd(&cmd, &is_available)) 2324 - return is_available; 2333 + if (get_schedule_cmd("crontab", &is_available, &cmd)) { 2334 + ret = is_available; 2335 + goto out; 2336 + } 2325 2337 2326 2338 #ifdef __APPLE__ 2327 2339 /* 2328 2340 * macOS has cron, but it requires special permissions and will 2329 2341 * create a UI alert when attempting to run this command. 2330 2342 */ 2331 - return 0; 2343 + ret = 0; 2332 2344 #else 2333 - return check_crontab_process(cmd); 2345 + ret = check_crontab_process(cmd); 2334 2346 #endif 2347 + 2348 + out: 2349 + free(cmd); 2350 + return ret; 2335 2351 } 2336 2352 2337 2353 #define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE" ··· 2339 2355 2340 2356 static int crontab_update_schedule(int run_maintenance, int fd) 2341 2357 { 2342 - const char *cmd = "crontab"; 2358 + char *cmd; 2343 2359 int result = 0; 2344 2360 int in_old_region = 0; 2345 2361 struct child_process crontab_list = CHILD_PROCESS_INIT; ··· 2349 2365 struct tempfile *tmpedit = NULL; 2350 2366 int minute = get_random_minute(); 2351 2367 2352 - get_schedule_cmd(&cmd, NULL); 2368 + get_schedule_cmd("crontab", NULL, &cmd); 2353 2369 strvec_split(&crontab_list.args, cmd); 2354 2370 strvec_push(&crontab_list.args, "-l"); 2355 2371 crontab_list.in = -1; 2356 2372 crontab_list.out = dup(fd); 2357 2373 crontab_list.git_cmd = 0; 2358 2374 2359 - if (start_command(&crontab_list)) 2360 - return error(_("failed to run 'crontab -l'; your system might not support 'cron'")); 2375 + if (start_command(&crontab_list)) { 2376 + result = error(_("failed to run 'crontab -l'; your system might not support 'cron'")); 2377 + goto out; 2378 + } 2361 2379 2362 2380 /* Ignore exit code, as an empty crontab will return error. */ 2363 2381 finish_command(&crontab_list); ··· 2427 2445 result = error(_("'crontab' died")); 2428 2446 else 2429 2447 fclose(cron_list); 2448 + 2430 2449 out: 2431 2450 delete_tempfile(&tmpedit); 2451 + free(cmd); 2432 2452 return result; 2433 2453 } 2434 2454 ··· 2451 2471 2452 2472 static int is_systemd_timer_available(void) 2453 2473 { 2454 - const char *cmd = "systemctl"; 2455 2474 int is_available; 2456 2475 2457 - if (get_schedule_cmd(&cmd, &is_available)) 2476 + if (get_schedule_cmd("systemctl", &is_available, NULL)) 2458 2477 return is_available; 2459 2478 2460 2479 return real_is_systemd_timer_available(); ··· 2635 2654 enum schedule_priority schedule, 2636 2655 int minute) 2637 2656 { 2638 - const char *cmd = "systemctl"; 2657 + char *cmd = NULL; 2639 2658 struct child_process child = CHILD_PROCESS_INIT; 2640 2659 const char *frequency = get_frequency(schedule); 2660 + int ret; 2641 2661 2642 2662 /* 2643 2663 * Disabling the systemd unit while it is already disabled makes ··· 2648 2668 * On the other hand, enabling a systemd unit which is already enabled 2649 2669 * produces no error. 2650 2670 */ 2651 - if (!enable) 2671 + if (!enable) { 2652 2672 child.no_stderr = 1; 2653 - else if (systemd_timer_write_timer_file(schedule, minute)) 2654 - return -1; 2673 + } else if (systemd_timer_write_timer_file(schedule, minute)) { 2674 + ret = -1; 2675 + goto out; 2676 + } 2655 2677 2656 - get_schedule_cmd(&cmd, NULL); 2678 + get_schedule_cmd("systemctl", NULL, &cmd); 2657 2679 strvec_split(&child.args, cmd); 2658 2680 strvec_pushl(&child.args, "--user", enable ? "enable" : "disable", 2659 2681 "--now", NULL); 2660 2682 strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer"); 2661 2683 2662 - if (start_command(&child)) 2663 - return error(_("failed to start systemctl")); 2664 - if (finish_command(&child)) 2684 + if (start_command(&child)) { 2685 + ret = error(_("failed to start systemctl")); 2686 + goto out; 2687 + } 2688 + 2689 + if (finish_command(&child)) { 2665 2690 /* 2666 2691 * Disabling an already disabled systemd unit makes 2667 2692 * systemctl fail. ··· 2669 2694 * 2670 2695 * Enabling an enabled systemd unit doesn't fail. 2671 2696 */ 2672 - if (enable) 2673 - return error(_("failed to run systemctl")); 2674 - return 0; 2697 + if (enable) { 2698 + ret = error(_("failed to run systemctl")); 2699 + goto out; 2700 + } 2701 + } 2702 + 2703 + ret = 0; 2704 + 2705 + out: 2706 + free(cmd); 2707 + return ret; 2675 2708 } 2676 2709 2677 2710 /*
+9 -7
builtin/help.c
··· 54 54 HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION, 55 55 } cmd_mode; 56 56 57 - static const char *html_path; 57 + static char *html_path; 58 58 static int verbose = 1; 59 59 static enum help_format help_format = HELP_FORMAT_NONE; 60 60 static int exclude_guides; ··· 411 411 if (!strcmp(var, "help.htmlpath")) { 412 412 if (!value) 413 413 return config_error_nonbool(var); 414 + free(html_path); 414 415 html_path = xstrdup(value); 415 416 return 0; 416 417 } ··· 515 516 static void get_html_page_path(struct strbuf *page_path, const char *page) 516 517 { 517 518 struct stat st; 519 + const char *path = html_path; 518 520 char *to_free = NULL; 519 521 520 - if (!html_path) 521 - html_path = to_free = system_path(GIT_HTML_PATH); 522 + if (!path) 523 + path = to_free = system_path(GIT_HTML_PATH); 522 524 523 525 /* 524 526 * Check that the page we're looking for exists. 525 527 */ 526 - if (!strstr(html_path, "://")) { 527 - if (stat(mkpath("%s/%s.html", html_path, page), &st) 528 + if (!strstr(path, "://")) { 529 + if (stat(mkpath("%s/%s.html", path, page), &st) 528 530 || !S_ISREG(st.st_mode)) 529 531 die("'%s/%s.html': documentation file not found.", 530 - html_path, page); 532 + path, page); 531 533 } 532 534 533 535 strbuf_init(page_path, 0); 534 - strbuf_addf(page_path, "%s/%s.html", html_path, page); 536 + strbuf_addf(page_path, "%s/%s.html", path, page); 535 537 free(to_free); 536 538 } 537 539
+7 -4
builtin/pull.c
··· 85 85 static const char *opt_commit; 86 86 static const char *opt_edit; 87 87 static const char *cleanup_arg; 88 - static const char *opt_ff; 88 + static char *opt_ff; 89 89 static const char *opt_verify_signatures; 90 90 static const char *opt_verify; 91 91 static int opt_autostash = -1; ··· 1028 1028 * "--rebase" can override a config setting of 1029 1029 * pull.ff=only. 1030 1030 */ 1031 - if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) 1032 - opt_ff = "--ff"; 1031 + if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) { 1032 + free(opt_ff); 1033 + opt_ff = xstrdup("--ff"); 1034 + } 1033 1035 } 1034 1036 1035 1037 if (opt_rebase < 0) ··· 1139 1141 1140 1142 if (can_ff) { 1141 1143 /* we can fast-forward this without invoking rebase */ 1142 - opt_ff = "--ff-only"; 1144 + free(opt_ff); 1145 + opt_ff = xstrdup("--ff-only"); 1143 1146 ret = run_merge(); 1144 1147 } else { 1145 1148 ret = run_rebase(&newbase, &upstream);
+42 -15
builtin/repack.c
··· 86 86 run_update_server_info = git_config_bool(var, value); 87 87 return 0; 88 88 } 89 - if (!strcmp(var, "repack.cruftwindow")) 89 + if (!strcmp(var, "repack.cruftwindow")) { 90 + free(cruft_po_args->window); 90 91 return git_config_string(&cruft_po_args->window, var, value); 91 - if (!strcmp(var, "repack.cruftwindowmemory")) 92 + } 93 + if (!strcmp(var, "repack.cruftwindowmemory")) { 94 + free(cruft_po_args->window_memory); 92 95 return git_config_string(&cruft_po_args->window_memory, var, value); 93 - if (!strcmp(var, "repack.cruftdepth")) 96 + } 97 + if (!strcmp(var, "repack.cruftdepth")) { 98 + free(cruft_po_args->depth); 94 99 return git_config_string(&cruft_po_args->depth, var, value); 95 - if (!strcmp(var, "repack.cruftthreads")) 100 + } 101 + if (!strcmp(var, "repack.cruftthreads")) { 102 + free(cruft_po_args->threads); 96 103 return git_config_string(&cruft_po_args->threads, var, value); 104 + } 97 105 return git_default_config(var, value, ctx, cb); 106 + } 107 + 108 + static void pack_objects_args_release(struct pack_objects_args *args) 109 + { 110 + free(args->window); 111 + free(args->window_memory); 112 + free(args->depth); 113 + free(args->threads); 114 + list_objects_filter_release(&args->filter_options); 98 115 } 99 116 100 117 struct existing_packs { ··· 1156 1173 const char *unpack_unreachable = NULL; 1157 1174 int keep_unreachable = 0; 1158 1175 struct string_list keep_pack_list = STRING_LIST_INIT_NODUP; 1159 - struct pack_objects_args po_args = {NULL}; 1160 - struct pack_objects_args cruft_po_args = {NULL}; 1176 + struct pack_objects_args po_args = { 0 }; 1177 + struct pack_objects_args cruft_po_args = { 0 }; 1161 1178 int write_midx = 0; 1162 1179 const char *cruft_expiration = NULL; 1163 1180 const char *expire_to = NULL; 1164 1181 const char *filter_to = NULL; 1182 + const char *opt_window = NULL; 1183 + const char *opt_window_memory = NULL; 1184 + const char *opt_depth = NULL; 1185 + const char *opt_threads = NULL; 1165 1186 1166 1187 struct option builtin_repack_options[] = { 1167 1188 OPT_BIT('a', NULL, &pack_everything, ··· 1195 1216 N_("with -A, do not loosen objects older than this")), 1196 1217 OPT_BOOL('k', "keep-unreachable", &keep_unreachable, 1197 1218 N_("with -a, repack unreachable objects")), 1198 - OPT_STRING(0, "window", &po_args.window, N_("n"), 1219 + OPT_STRING(0, "window", &opt_window, N_("n"), 1199 1220 N_("size of the window used for delta compression")), 1200 - OPT_STRING(0, "window-memory", &po_args.window_memory, N_("bytes"), 1221 + OPT_STRING(0, "window-memory", &opt_window_memory, N_("bytes"), 1201 1222 N_("same as the above, but limit memory size instead of entries count")), 1202 - OPT_STRING(0, "depth", &po_args.depth, N_("n"), 1223 + OPT_STRING(0, "depth", &opt_depth, N_("n"), 1203 1224 N_("limits the maximum delta depth")), 1204 - OPT_STRING(0, "threads", &po_args.threads, N_("n"), 1225 + OPT_STRING(0, "threads", &opt_threads, N_("n"), 1205 1226 N_("limits the maximum number of threads")), 1206 1227 OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size, 1207 1228 N_("maximum size of each packfile")), ··· 1228 1249 argc = parse_options(argc, argv, prefix, builtin_repack_options, 1229 1250 git_repack_usage, 0); 1230 1251 1252 + po_args.window = xstrdup_or_null(opt_window); 1253 + po_args.window_memory = xstrdup_or_null(opt_window_memory); 1254 + po_args.depth = xstrdup_or_null(opt_depth); 1255 + po_args.threads = xstrdup_or_null(opt_threads); 1256 + 1231 1257 if (delete_redundant && repository_format_precious_objects) 1232 1258 die(_("cannot delete packs in a precious-objects repo")); 1233 1259 ··· 1393 1419 const char *pack_prefix = find_pack_prefix(packdir, packtmp); 1394 1420 1395 1421 if (!cruft_po_args.window) 1396 - cruft_po_args.window = po_args.window; 1422 + cruft_po_args.window = xstrdup_or_null(po_args.window); 1397 1423 if (!cruft_po_args.window_memory) 1398 - cruft_po_args.window_memory = po_args.window_memory; 1424 + cruft_po_args.window_memory = xstrdup_or_null(po_args.window_memory); 1399 1425 if (!cruft_po_args.depth) 1400 - cruft_po_args.depth = po_args.depth; 1426 + cruft_po_args.depth = xstrdup_or_null(po_args.depth); 1401 1427 if (!cruft_po_args.threads) 1402 - cruft_po_args.threads = po_args.threads; 1428 + cruft_po_args.threads = xstrdup_or_null(po_args.threads); 1403 1429 if (!cruft_po_args.max_pack_size) 1404 1430 cruft_po_args.max_pack_size = po_args.max_pack_size; 1405 1431 ··· 1552 1578 string_list_clear(&names, 1); 1553 1579 existing_packs_release(&existing); 1554 1580 free_pack_geometry(&geometry); 1555 - list_objects_filter_release(&po_args.filter_options); 1581 + pack_objects_args_release(&po_args); 1582 + pack_objects_args_release(&cruft_po_args); 1556 1583 1557 1584 return ret; 1558 1585 }
+19 -7
builtin/submodule--helper.c
··· 364 364 if (!info->quiet) 365 365 printf(_("Entering '%s'\n"), displaypath); 366 366 367 - if (info->argv[0] && run_command(&cp)) 368 - die(_("run_command returned non-zero status for %s\n."), 369 - displaypath); 367 + if (info->argv[0]) { 368 + if (run_command(&cp)) 369 + die(_("run_command returned non-zero status for %s\n."), 370 + displaypath); 371 + } else { 372 + child_process_clear(&cp); 373 + } 370 374 371 375 if (info->recursive) { 372 376 struct child_process cpr = CHILD_PROCESS_INIT; ··· 1622 1626 ; /* nothing */ 1623 1627 } 1624 1628 } 1629 + 1630 + strbuf_release(&err); 1625 1631 strbuf_release(&sb); 1626 1632 } 1627 1633 ··· 2026 2032 static void update_data_release(struct update_data *ud) 2027 2033 { 2028 2034 free(ud->displaypath); 2035 + submodule_update_strategy_release(&ud->update_strategy); 2029 2036 module_list_release(&ud->list); 2030 2037 } 2031 2038 ··· 2646 2653 2647 2654 if (!update_data->nofetch) { 2648 2655 if (fetch_in_submodule(update_data->sm_path, update_data->depth, 2649 - 0, NULL)) 2656 + 0, NULL)) { 2657 + free(remote_ref); 2650 2658 return die_message(_("Unable to fetch in submodule path '%s'"), 2651 2659 update_data->sm_path); 2660 + } 2652 2661 } 2653 2662 2654 2663 if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path, 2655 - remote_ref, &update_data->oid)) 2656 - return die_message(_("Unable to find %s revision in submodule path '%s'"), 2657 - remote_ref, update_data->sm_path); 2664 + remote_ref, &update_data->oid)) { 2665 + ret = die_message(_("Unable to find %s revision in submodule path '%s'"), 2666 + remote_ref, update_data->sm_path); 2667 + free(remote_ref); 2668 + return ret; 2669 + } 2658 2670 2659 2671 free(remote_ref); 2660 2672 }
+1 -2
combine-diff.c
··· 1393 1393 { 1394 1394 struct combine_diff_path *paths = NULL; 1395 1395 int i, num_parent = parents->nr; 1396 - 1397 1396 int output_format = opt->output_format; 1398 - const char *orderfile = opt->orderfile; 1397 + char *orderfile = opt->orderfile; 1399 1398 1400 1399 opt->output_format = DIFF_FORMAT_NO_OUTPUT; 1401 1400 /* tell diff_tree to emit paths in sorted (=tree) order */
+5 -2
diff.c
··· 443 443 } 444 444 if (!strcmp(var, "diff.wordregex")) 445 445 return git_config_string(&diff_word_regex_cfg, var, value); 446 - if (!strcmp(var, "diff.orderfile")) 446 + if (!strcmp(var, "diff.orderfile")) { 447 + FREE_AND_NULL(diff_order_file_cfg); 447 448 return git_config_pathname(&diff_order_file_cfg, var, value); 449 + } 448 450 449 451 if (!strcmp(var, "diff.ignoresubmodules")) { 450 452 if (!value) ··· 4778 4780 if (diff_indent_heuristic) 4779 4781 DIFF_XDL_SET(options, INDENT_HEURISTIC); 4780 4782 4781 - options->orderfile = diff_order_file_cfg; 4783 + options->orderfile = xstrdup_or_null(diff_order_file_cfg); 4782 4784 4783 4785 if (!options->flags.ignore_submodule_set) 4784 4786 options->flags.ignore_untracked_in_submodules = 1; ··· 6730 6732 FREE_AND_NULL(options->objfind); 6731 6733 } 6732 6734 6735 + FREE_AND_NULL(options->orderfile); 6733 6736 for (size_t i = 0; i < options->anchors_nr; i++) 6734 6737 free(options->anchors[i]); 6735 6738 FREE_AND_NULL(options->anchors);
+1 -1
diff.h
··· 235 235 * diffcore library with. 236 236 */ 237 237 struct diff_options { 238 - const char *orderfile; 238 + char *orderfile; 239 239 240 240 /* 241 241 * "--rotate-to=<file>" would start showing at <file> and when
+2 -2
diffcore-break.c
··· 266 266 * in the resulting tree. 267 267 */ 268 268 d->one->rename_used++; 269 - diff_free_filespec_data(d->two); 270 - diff_free_filespec_data(c->one); 269 + free_filespec(d->two); 270 + free_filespec(c->one); 271 271 free(d); 272 272 free(c); 273 273 }
+7 -12
diffcore-order.c
··· 14 14 { 15 15 int cnt, pass; 16 16 struct strbuf sb = STRBUF_INIT; 17 - void *map; 18 - char *cp, *endp; 17 + const char *cp, *endp; 19 18 ssize_t sz; 20 19 21 20 if (order) ··· 24 23 sz = strbuf_read_file(&sb, orderfile, 0); 25 24 if (sz < 0) 26 25 die_errno(_("failed to read orderfile '%s'"), orderfile); 27 - map = strbuf_detach(&sb, NULL); 28 - endp = (char *) map + sz; 26 + endp = sb.buf + sz; 29 27 30 28 for (pass = 0; pass < 2; pass++) { 31 29 cnt = 0; 32 - cp = map; 30 + cp = sb.buf; 33 31 while (cp < endp) { 34 - char *ep; 32 + const char *ep; 35 33 for (ep = cp; ep < endp && *ep != '\n'; ep++) 36 34 ; 37 35 /* cp to ep has one line */ ··· 40 38 else if (pass == 0) 41 39 cnt++; 42 40 else { 43 - if (*ep == '\n') { 44 - *ep = 0; 45 - order[cnt] = cp; 46 - } else { 47 - order[cnt] = xmemdupz(cp, ep - cp); 48 - } 41 + order[cnt] = xmemdupz(cp, ep - cp); 49 42 cnt++; 50 43 } 51 44 if (ep < endp) ··· 57 50 ALLOC_ARRAY(order, cnt); 58 51 } 59 52 } 53 + 54 + strbuf_release(&sb); 60 55 } 61 56 62 57 static int match_order(const char *path)
+2 -4
dir.c
··· 2136 2136 */ 2137 2137 state = path_none; 2138 2138 } else { 2139 - int i; 2140 - for (i = old_ignored_nr + 1; i<dir->ignored_nr; ++i) 2139 + for (int i = old_ignored_nr; i < dir->ignored_nr; i++) 2141 2140 FREE_AND_NULL(dir->ignored[i]); 2142 2141 dir->ignored_nr = old_ignored_nr; 2143 2142 } ··· 2149 2148 */ 2150 2149 if ((dir->flags & DIR_SHOW_IGNORED_TOO) && 2151 2150 !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) { 2152 - int i; 2153 - for (i = old_untracked_nr + 1; i<dir->nr; ++i) 2151 + for (int i = old_untracked_nr; i < dir->nr; i++) 2154 2152 FREE_AND_NULL(dir->entries[i]); 2155 2153 dir->nr = old_untracked_nr; 2156 2154 }
+19 -3
git.c
··· 711 711 static void handle_builtin(int argc, const char **argv) 712 712 { 713 713 struct strvec args = STRVEC_INIT; 714 + const char **argv_copy = NULL; 714 715 const char *cmd; 715 716 struct cmd_struct *builtin; 716 717 ··· 731 732 } 732 733 733 734 argc++; 734 - argv = args.v; 735 + 736 + /* 737 + * `run_builtin()` will modify the argv array, so we need to 738 + * create a shallow copy such that we can free all of its 739 + * strings. 740 + */ 741 + CALLOC_ARRAY(argv_copy, argc + 1); 742 + COPY_ARRAY(argv_copy, args.v, argc); 743 + 744 + argv = argv_copy; 735 745 } 736 746 737 747 builtin = get_builtin(cmd); 738 - if (builtin) 739 - exit(run_builtin(builtin, argc, argv, the_repository)); 748 + if (builtin) { 749 + int ret = run_builtin(builtin, argc, argv, the_repository); 750 + strvec_clear(&args); 751 + free(argv_copy); 752 + exit(ret); 753 + } 754 + 740 755 strvec_clear(&args); 756 + free(argv_copy); 741 757 } 742 758 743 759 static void execv_dashed_external(const char **argv)
+1 -1
grep.c
··· 843 843 free_pcre2_pattern(p); 844 844 else 845 845 regfree(&p->regexp); 846 - free(p->pattern); 847 846 break; 848 847 default: 849 848 break; 850 849 } 850 + free(p->pattern); 851 851 free(p); 852 852 } 853 853 }
+14 -8
parse-options.c
··· 60 60 return 0; 61 61 } 62 62 63 - static void fix_filename(const char *prefix, char **file) 63 + static char *fix_filename(const char *prefix, const char *file) 64 64 { 65 65 if (!file || !*file) 66 - ; /* leave as NULL */ 66 + return NULL; 67 67 else 68 - *file = prefix_filename_except_for_dash(prefix, *file); 68 + return prefix_filename_except_for_dash(prefix, file); 69 69 } 70 70 71 71 static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, ··· 129 129 return 0; 130 130 131 131 case OPTION_FILENAME: 132 + { 133 + const char *value; 134 + 135 + FREE_AND_NULL(*(char **)opt->value); 136 + 132 137 err = 0; 138 + 133 139 if (unset) 134 - *(const char **)opt->value = NULL; 140 + value = NULL; 135 141 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 136 - *(const char **)opt->value = (const char *)opt->defval; 142 + value = (const char *) opt->defval; 137 143 else 138 - err = get_arg(p, opt, flags, (const char **)opt->value); 144 + err = get_arg(p, opt, flags, &value); 139 145 140 146 if (!err) 141 - fix_filename(p->prefix, (char **)opt->value); 147 + *(char **)opt->value = fix_filename(p->prefix, value); 142 148 return err; 143 - 149 + } 144 150 case OPTION_CALLBACK: 145 151 { 146 152 const char *p_arg = NULL;
+2
promisor-remote.c
··· 154 154 if (!r) 155 155 return 0; 156 156 157 + FREE_AND_NULL(r->partial_clone_filter); 157 158 return git_config_string(&r->partial_clone_filter, var, value); 158 159 } 159 160 ··· 189 190 { 190 191 while (config->promisors) { 191 192 struct promisor_remote *r = config->promisors; 193 + free(r->partial_clone_filter); 192 194 config->promisors = config->promisors->next; 193 195 free(r); 194 196 }
+5
revision.c
··· 1071 1071 ts->treesame[nth_parent] = 1; 1072 1072 continue; 1073 1073 } 1074 + 1075 + free_commit_list(parent->next); 1074 1076 parent->next = NULL; 1077 + while (commit->parents != parent) 1078 + pop_commit(&commit->parents); 1075 1079 commit->parents = parent; 1076 1080 1077 1081 /* ··· 1103 1107 die("cannot simplify commit %s (invalid %s)", 1104 1108 oid_to_hex(&commit->object.oid), 1105 1109 oid_to_hex(&p->object.oid)); 1110 + free_commit_list(p->parents); 1106 1111 p->parents = NULL; 1107 1112 } 1108 1113 /* fallthrough */
+1 -1
submodule-config.c
··· 95 95 free((void *) entry->config->branch); 96 96 free((void *) entry->config->url); 97 97 free((void *) entry->config->ignore); 98 - free((void *) entry->config->update_strategy.command); 98 + submodule_update_strategy_release(&entry->config->update_strategy); 99 99 free(entry->config); 100 100 } 101 101
+7 -2
submodule.c
··· 175 175 die(_("staging updated .gitmodules failed")); 176 176 } 177 177 178 - static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_NODUP; 178 + static struct string_list added_submodule_odb_paths = STRING_LIST_INIT_DUP; 179 179 180 180 void add_submodule_odb_by_path(const char *path) 181 181 { 182 - string_list_insert(&added_submodule_odb_paths, xstrdup(path)); 182 + string_list_insert(&added_submodule_odb_paths, path); 183 183 } 184 184 185 185 int register_all_submodule_odb_as_alternates(void) ··· 422 422 dst->command = xstrdup(value + 1); 423 423 424 424 return 0; 425 + } 426 + 427 + void submodule_update_strategy_release(struct submodule_update_strategy *strategy) 428 + { 429 + free((char *) strategy->command); 425 430 } 426 431 427 432 const char *submodule_update_type_to_string(enum submodule_update_type type)
+4 -2
submodule.h
··· 41 41 .type = SM_UPDATE_UNSPECIFIED, \ 42 42 } 43 43 44 + int parse_submodule_update_strategy(const char *value, 45 + struct submodule_update_strategy *dst); 46 + void submodule_update_strategy_release(struct submodule_update_strategy *strategy); 47 + 44 48 int is_gitmodules_unmerged(struct index_state *istate); 45 49 int is_writing_gitmodules_ok(void); 46 50 int is_staging_gitmodules_ok(struct index_state *istate); ··· 70 74 void die_path_inside_submodule(struct index_state *istate, 71 75 const struct pathspec *ps); 72 76 enum submodule_update_type parse_submodule_update_type(const char *value); 73 - int parse_submodule_update_strategy(const char *value, 74 - struct submodule_update_strategy *dst); 75 77 const char *submodule_update_type_to_string(enum submodule_update_type type); 76 78 void handle_ignore_submodules_arg(struct diff_options *, const char *); 77 79 void show_submodule_diff_summary(struct diff_options *o, const char *path,
+1 -1
t/helper/test-submodule-nested-repo-config.c
··· 29 29 print_config_from_gitmodules(&subrepo, argv[2]); 30 30 31 31 submodule_free(the_repository); 32 - 32 + repo_clear(&subrepo); 33 33 return 0; 34 34 }
+1
t/t0012-help.sh
··· 2 2 3 3 test_description='help' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 configure_help () {
+1
t/t1414-reflog-walk.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 'set up some reflog entries' '
+1
t/t3011-common-prefixes-and-directory-traversal.sh
··· 2 2 3 3 test_description='directory traversal handling, especially with common prefixes' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 test_expect_success 'setup' '
+2
t/t4008-diff-break-rewrite.sh
··· 21 21 22 22 Further, with -B and -M together, these should turn into two renames. 23 23 ' 24 + 25 + TEST_PASSES_SANITIZE_LEAK=true 24 26 . ./test-lib.sh 25 27 . "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash 26 28
+1
t/t4022-diff-rewrite.sh
··· 2 2 3 3 test_description='rewrite diff' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 . "$TEST_DIRECTORY"/lib-diff-data.sh 7 8
+1
t/t4023-diff-rename-typechange.sh
··· 2 2 3 3 test_description='typechange rename detection' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 . "$TEST_DIRECTORY"/lib-diff.sh 7 8
+1
t/t4031-diff-rewrite-binary.sh
··· 2 2 3 3 test_description='rewrite diff on binary file' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 # We must be large enough to meet the MINIMUM_BREAK_SIZE
+1
t/t4056-diff-order.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 create_files () {
+1
t/t4204-patch-id.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/t5310-pack-bitmaps.sh
··· 2 2 3 3 test_description='exercise basic bitmap functionality' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 . "$TEST_DIRECTORY"/lib-bitmap.sh 7 8
+2
t/t5326-multi-pack-bitmaps.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='exercise basic multi-pack bitmap functionality' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 . "${TEST_DIRECTORY}/lib-bitmap.sh" 6 8
+2
t/t5329-pack-objects-cruft.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='cruft pack related pack-objects tests' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 6 8 objdir=.git/objects
+1
t/t6004-rev-list-path-optim.sh
··· 16 16 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 17 17 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 18 18 19 + TEST_PASSES_SANITIZE_LEAK=true 19 20 . ./test-lib.sh 20 21 21 22 test_expect_success setup '
+1
t/t6019-rev-list-ancestry-path.sh
··· 29 29 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 30 30 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 31 31 32 + TEST_PASSES_SANITIZE_LEAK=true 32 33 . ./test-lib.sh 33 34 34 35 test_merge () {
+1
t/t6111-rev-list-treesame.sh
··· 16 16 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 17 17 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 18 18 19 + TEST_PASSES_SANITIZE_LEAK=true 19 20 . ./test-lib.sh 20 21 21 22 note () {
+1
t/t7061-wtstatus-ignore.sh
··· 2 2 3 3 test_description='git-status ignored files' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 cat >expected <<\EOF
+1
t/t7406-submodule-update.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
+1
t/t7407-submodule-foreach.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
+2
t/t7408-submodule-reference.sh
··· 4 4 # 5 5 6 6 test_description='test clone --reference' 7 + 8 + TEST_PASSES_SANITIZE_LEAK=true 7 9 . ./test-lib.sh 8 10 9 11 base_dir=$(pwd)
+1
t/t7411-submodule-config.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 15 16 test_expect_success 'setup' '
+1
t/t7420-submodule-set-url.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 15 16 test_expect_success 'setup' '
+1
t/t7521-ignored-mode.sh
··· 2 2 3 3 test_description='git status ignored modes' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 test_expect_success 'setup initial commit and ignore file' '
+2
t/t7524-commit-summary.sh
··· 1 1 #!/bin/sh 2 2 3 3 test_description='git commit summary' 4 + 5 + TEST_PASSES_SANITIZE_LEAK=true 4 6 . ./test-lib.sh 5 7 6 8 test_expect_success 'setup' '
+1
t/t7601-merge-pull-config.sh
··· 4 4 5 5 Testing pull.* configuration parsing and other things.' 6 6 7 + TEST_PASSES_SANITIZE_LEAK=true 7 8 . ./test-lib.sh 8 9 9 10 test_expect_success 'setup' '
+1
t/t7700-repack.sh
··· 2 2 3 3 test_description='git repack works correctly' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 . "${TEST_DIRECTORY}/lib-bitmap.sh" 7 8 . "${TEST_DIRECTORY}/lib-midx.sh"
+1
t/t7800-difftool.sh
··· 11 11 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 12 12 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 13 13 14 + TEST_PASSES_SANITIZE_LEAK=true 14 15 . ./test-lib.sh 15 16 16 17 difftool_test_setup ()
+1
t/t7814-grep-recurse-submodules.sh
··· 7 7 ' 8 8 9 9 TEST_CREATE_REPO_NO_TEMPLATE=1 10 + TEST_PASSES_SANITIZE_LEAK=true 10 11 . ./test-lib.sh 11 12 12 13 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
+1
t/t7900-maintenance.sh
··· 2 2 3 3 test_description='git maintenance builtin' 4 4 5 + TEST_PASSES_SANITIZE_LEAK=true 5 6 . ./test-lib.sh 6 7 7 8 GIT_TEST_COMMIT_GRAPH=0
+9 -1
trace2/tr2_tls.c
··· 152 152 return us - tr2tls_us_start_process; 153 153 } 154 154 155 + static void tr2tls_key_destructor(void *payload) 156 + { 157 + struct tr2tls_thread_ctx *ctx = payload; 158 + free((char *)ctx->thread_name); 159 + free(ctx->array_us_start); 160 + free(ctx); 161 + } 162 + 155 163 void tr2tls_init(void) 156 164 { 157 165 tr2tls_start_process_clock(); 158 166 159 - pthread_key_create(&tr2tls_key, NULL); 167 + pthread_key_create(&tr2tls_key, tr2tls_key_destructor); 160 168 init_recursive_mutex(&tr2tls_mutex); 161 169 162 170 tr2tls_thread_main =