diff: reject negative values for --inter-hunk-context

Negative values for --inter-hunk-context produce structurally invalid diff output with overlapping hunks: $ git log -1 -p -U3 --inter-hunk-context=-100 791aeddfa2 \ -- git-compat-util.h | grep '^@@' @@ -110,6 +110,9 @@ @@ -115,6 +118,9 @@ @@ -116,6 +122,7 @@ Hunk 1 covers lines 110-115, hunk 2 starts at 115 (overlap), hunk 3 starts at 116 (overlaps both). The resulting patch cannot be applied. The config variable diff.interHunkContext already rejects negative values, but the command line option does not. Change the type of diff_options.interhunkcontext and its static default from int to unsigned int, and switch the option parser from OPT_INTEGER_F to OPT_UNSIGNED. This rejects negative values at parse time via git_parse_unsigned() and enforces the correct type at compile time via BARF_UNLESS_UNSIGNED. Signed-off-by: Michael Montalbo <mmontalbo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Montalbo committed May 12, 2026 at 18:10 UTC 321f0ea17b3bcb70867fad430e972548281803f0
3 files changed +13 -8
diff.c
+6 -7
@@ -61,7 +61,7 @@ static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN;
61 static int diff_color_moved_default;
62 static int diff_color_moved_ws_default;
63 static int diff_context_default = 3;
64 -static int diff_interhunk_context_default;
64 +static unsigned int diff_interhunk_context_default;
65 static char *diff_word_regex_cfg;
66 static struct external_diff external_diff_cfg;
67 static char *diff_order_file_cfg;
@@ -388,10 +388,10 @@ int git_diff_ui_config(const char *var, const char *value,
388 return 0;
389 }
390 if (!strcmp(var, "diff.interhunkcontext")) {
391 - diff_interhunk_context_default = git_config_int(var, value,
392 - ctx->kvi);
393 - if (diff_interhunk_context_default < 0)
391 + int val = git_config_int(var, value, ctx->kvi);
392 + if (val < 0)
393 return -1;
394 + diff_interhunk_context_default = val;
395 return 0;
396 }
397 if (!strcmp(var, "diff.renames")) {
@@ -6111,9 +6111,8 @@ struct option *add_diff_options(const struct option *opts,
6111 OPT_CALLBACK_F(0, "default-prefix", options, NULL,
6112 N_("use default prefixes a/ and b/"),
6113 PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_default_prefix),
6114 - OPT_INTEGER_F(0, "inter-hunk-context", &options->interhunkcontext,
6115 - N_("show context between diff hunks up to the specified number of lines"),
6116 - PARSE_OPT_NONEG),
6114 + OPT_UNSIGNED(0, "inter-hunk-context", &options->interhunkcontext,
6115 + N_("show context between diff hunks up to the specified number of lines")),
6116 OPT_CALLBACK_F(0, "output-indicator-new",
6117 &options->output_indicators[OUTPUT_INDICATOR_NEW],
6118 N_("<char>"),
diff.h
+1 -1
@@ -296,7 +296,7 @@ struct diff_options {
296 /* Number of context lines to generate in patch output. */
297 int context;
298
299 - int interhunkcontext;
299 + unsigned int interhunkcontext;
300
301 /* Affects the way detection logic for complete rewrites, renames and
302 * copies.
t/t4032-diff-inter-hunk-context.sh
+6
@@ -114,4 +114,10 @@ test_expect_success 'diff.interHunkContext invalid' '
114 test_must_fail git diff
115 '
116
117 +test_expect_success '--inter-hunk-context rejects negative value' '
118 + test_unconfig diff.interHunkContext &&
119 + test_must_fail git diff --inter-hunk-context=-1 2>err &&
120 + test_grep "expects a non-negative integer" err
121 +'
122 +
123 test_done