run_external_diff: use an argv_array for the command line

We currently generate the command-line for the external command using a fixed-length array of size 10. But if there is a rename, we actually need 11 elements (10 items, plus a NULL), and end up writing a random NULL onto the stack. Rather than bump the limit, let's just use an argv_array, which makes this sort of error impossible. Noticed-by: Max L <infthi.inbox@gmail.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Apr 19, 2014 at 15:17 UTC 82fbf269b9994d172719b2d456db5ef8453b323d
1 file changed +16 -16
diff.c
+16 -16
@@ -16,6 +16,7 @@
16 #include "submodule.h"
17 #include "ll-merge.h"
18 #include "string-list.h"
19 +#include "argv-array.h"
20
21 #ifdef NO_FAST_WORKING_DIRECTORY
22 #define FAST_WORKING_DIRECTORY 0
@@ -2906,9 +2907,8 @@ static void run_external_diff(const char *pgm,
2907 int complete_rewrite,
2908 struct diff_options *o)
2909 {
2909 - const char *spawn_arg[10];
2910 + struct argv_array argv = ARGV_ARRAY_INIT;
2911 int retval;
2911 - const char **arg = &spawn_arg[0];
2912 struct diff_queue_struct *q = &diff_queued_diff;
2913 const char *env[3] = { NULL };
2914 char env_counter[50];
@@ -2919,23 +2919,22 @@ static void run_external_diff(const char *pgm,
2919 const char *othername = (other ? other : name);
2920 temp_one = prepare_temp_file(name, one);
2921 temp_two = prepare_temp_file(othername, two);
2922 - *arg++ = pgm;
2923 - *arg++ = name;
2924 - *arg++ = temp_one->name;
2925 - *arg++ = temp_one->hex;
2926 - *arg++ = temp_one->mode;
2927 - *arg++ = temp_two->name;
2928 - *arg++ = temp_two->hex;
2929 - *arg++ = temp_two->mode;
2922 + argv_array_push(&argv, pgm);
2923 + argv_array_push(&argv, name);
2924 + argv_array_push(&argv, temp_one->name);
2925 + argv_array_push(&argv, temp_one->hex);
2926 + argv_array_push(&argv, temp_one->mode);
2927 + argv_array_push(&argv, temp_two->name);
2928 + argv_array_push(&argv, temp_two->hex);
2929 + argv_array_push(&argv, temp_two->mode);
2930 if (other) {
2931 - *arg++ = other;
2932 - *arg++ = xfrm_msg;
2931 + argv_array_push(&argv, other);
2932 + argv_array_push(&argv, xfrm_msg);
2933 }
2934 } else {
2935 - *arg++ = pgm;
2936 - *arg++ = name;
2935 + argv_array_push(&argv, pgm);
2936 + argv_array_push(&argv, name);
2937 }
2938 - *arg = NULL;
2938 fflush(NULL);
2939
2940 env[0] = env_counter;
@@ -2944,8 +2943,9 @@ static void run_external_diff(const char *pgm,
2943 env[1] = env_total;
2944 snprintf(env_total, sizeof(env_total), "GIT_DIFF_PATH_TOTAL=%d", q->nr);
2945
2947 - retval = run_command_v_opt_cd_env(spawn_arg, RUN_USING_SHELL, NULL, env);
2946 + retval = run_command_v_opt_cd_env(argv.argv, RUN_USING_SHELL, NULL, env);
2947 remove_tempfile();
2948 + argv_array_clear(&argv);
2949 if (retval) {
2950 fprintf(stderr, "external diff died, stopping at %s.\n", name);
2951 exit(1);