Merge branch 'mm/diff-U-takes-no-negative-values'

The command line parser for "git diff" learned a few options take
only non-negative integers.

* mm/diff-U-takes-no-negative-values:
  parse-options: clarify what "negated" means for PARSE_OPT_NONEG
  xdiff: guard against negative context lengths
  diff: reject negative values for -U/--unified
  diff: reject negative values for --inter-hunk-context
main
Junio C Hamano 2026-05-25 09:40:07 +09:00
commit 5830a84a14
6 changed files with 40 additions and 17 deletions

25
diff.c
View File

@ -60,8 +60,8 @@ static int diff_suppress_blank_empty;
static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN;
static int diff_color_moved_default;
static int diff_color_moved_ws_default;
static int diff_context_default = 3;
static int diff_interhunk_context_default;
static unsigned int diff_context_default = 3;
static unsigned int diff_interhunk_context_default;
static char *diff_word_regex_cfg;
static struct external_diff external_diff_cfg;
static char *diff_order_file_cfg;
@ -382,16 +382,17 @@ int git_diff_ui_config(const char *var, const char *value,
return 0;
}
if (!strcmp(var, "diff.context")) {
diff_context_default = git_config_int(var, value, ctx->kvi);
if (diff_context_default < 0)
int val = git_config_int(var, value, ctx->kvi);
if (val < 0)
return -1;
diff_context_default = val;
return 0;
}
if (!strcmp(var, "diff.interhunkcontext")) {
diff_interhunk_context_default = git_config_int(var, value,
ctx->kvi);
if (diff_interhunk_context_default < 0)
int val = git_config_int(var, value, ctx->kvi);
if (val < 0)
return -1;
diff_interhunk_context_default = val;
return 0;
}
if (!strcmp(var, "diff.renames")) {
@ -5946,9 +5947,12 @@ static int diff_opt_unified(const struct option *opt,
BUG_ON_OPT_NEG(unset);

if (arg) {
options->context = strtol(arg, &s, 10);
long val = strtol(arg, &s, 10);
if (*s)
return error(_("%s expects a numerical value"), "--unified");
if (val < 0)
return error(_("%s expects a non-negative integer"), "--unified");
options->context = val;
}
enable_patch_output(&options->output_format);

@ -6133,9 +6137,8 @@ struct option *add_diff_options(const struct option *opts,
OPT_CALLBACK_F(0, "default-prefix", options, NULL,
N_("use default prefixes a/ and b/"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_default_prefix),
OPT_INTEGER_F(0, "inter-hunk-context", &options->interhunkcontext,
N_("show context between diff hunks up to the specified number of lines"),
PARSE_OPT_NONEG),
OPT_UNSIGNED(0, "inter-hunk-context", &options->interhunkcontext,
N_("show context between diff hunks up to the specified number of lines")),
OPT_CALLBACK_F(0, "output-indicator-new",
&options->output_indicators[OUTPUT_INDICATOR_NEW],
N_("<char>"),

4
diff.h
View File

@ -294,9 +294,9 @@ struct diff_options {
enum git_colorbool use_color;

/* Number of context lines to generate in patch output. */
int context;
unsigned int context;

int interhunkcontext;
unsigned int interhunkcontext;

/* Affects the way detection logic for complete rewrites, renames and
* copies.

View File

@ -117,6 +117,7 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
* PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs)
* PARSE_OPT_NOARG: says that this option does not take an argument
* PARSE_OPT_NONEG: says that this option cannot be negated
* (i.e. rejects "--no-<option>")
* PARSE_OPT_HIDDEN: this option is skipped in the default usage, and
* shown only in the full usage.
* PARSE_OPT_LASTARG_DEFAULT: says that this option will take the default

View File

@ -116,4 +116,10 @@ test_expect_success 'diff.interHunkContext invalid' '
test_must_fail git diff
'

test_expect_success '--inter-hunk-context rejects negative value' '
test_unconfig diff.interHunkContext &&
test_must_fail git diff --inter-hunk-context=-1 2>err &&
test_grep "expects a non-negative integer" err
'

test_done

View File

@ -82,6 +82,11 @@ test_expect_success 'negative integer config parsing' '
test_grep "bad config variable" output
'

test_expect_success '-U-1 is rejected' '
test_must_fail git diff -U-1 2>err &&
test_grep "expects a non-negative integer" err
'

test_expect_success '-U0 is valid, so is diff.context=0' '
test_config diff.context 0 &&
git diff >output &&

View File

@ -46,12 +46,20 @@ static long saturating_add(long a, long b)
xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
{
xdchange_t *xch, *xchp, *lxch;
long max_common = saturating_add(saturating_add(xecfg->ctxlen,
xecfg->ctxlen),
xecfg->interhunkctxlen);
long max_ignorable = xecfg->ctxlen;
long max_common;
long max_ignorable;
long ignored = 0; /* number of ignored blank lines */

if (xecfg->ctxlen < 0)
BUG("negative context length: %ld", xecfg->ctxlen);
if (xecfg->interhunkctxlen < 0)
BUG("negative inter-hunk context length: %ld", xecfg->interhunkctxlen);

max_common = saturating_add(saturating_add(xecfg->ctxlen,
xecfg->ctxlen),
xecfg->interhunkctxlen);
max_ignorable = xecfg->ctxlen;

/* remove ignorable changes that are too far before other changes */
for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
xch = xchp->next;