Fixes for :(optional) path code
cover Fixes for :(optional) path code
This series has a few fixes from Phillip's review, set up as individual patches. Justification is light, as many are hopefully straightforward?
The most important patch comes first. The rest are probably take-or-leave.
D. Ben Knoble (5):
parseopt: fix :(optional) at command line to only ignore missing files
doc: clarify command equivalence comment
parseopt: use boolean type for a simple flag
config: use boolean type for a simple flag
parseopt: restore const qualifier to parsed filename
Documentation/gitcli.adoc | 2 +- config.c | 2 +- parse-options.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-)
base-commit: a99f379adf116d53eb11957af5bab5214915f91d
Signature · 1 line
2.48.1
PATCH 1/5 parseopt: fix :(optional) at command line to only ignore missing files
Unlike the configuration option magic, the parseopt code also ignores empty files: compare implementations from ccfcaf399f (parseopt: values of pathname type can be prefixed with :(optional), 2025-09-28) and 749d6d166d (config: values of pathname type can be prefixed with :(optional), 2025-09-28).
Unify the 2 by not ignoring empty files, which is less surprising and the intended semantics from the first patch for config.
--- parse-options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
parse-options.c +1 -1
@@ -226,7 +226,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,if (!value) is_optional =0 ; value =fix_filename (p->prefix, value); -if (is_optional &&is_empty_or_missing_file (value)) { +if (is_optional &&is_missing_file (value)) {free ((char *)value); }else {FREE_AND_NULL (*(char **)opt->value);
Signature · 1 line
2.48.1
Re: [PATCH 1/5] parseopt: fix :(optional) at command line to only ignore missing files
Hi Ben
These all look good to me though I agree with Junio's comments on patch 3. It would be nice to get at least the fist patch merged in time for 2.52.0.
Thanks for following up on these
Phillip
Quoted 28 lines · D. Ben Knoble
Unlike the configuration option magic, the parseopt code also ignores empty files: compare implementations from
ccfcaf399f(parseopt: values of pathname type can be prefixed with :(optional), 2025-09-28) and749d6d166d(config: values of pathname type can be prefixed with :(optional), 2025-09-28).Unify the 2 by not ignoring empty files, which is less surprising and the intended semantics from the first patch for config.
Suggested-by Phillip Wood <[email protected]>Signed-off-by D. Ben Knoble <[email protected]>--- parse-options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)parse-options.c +1
-1@@ -226,7 +226,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,if (!value) is_optional =0 ; value =fix_filename (p->prefix, value); -if (is_optional &&is_empty_or_missing_file (value)) { +if (is_optional &&is_missing_file (value)) {free ((char *)value); }else {FREE_AND_NULL (*(char **)opt->value);
Re: [PATCH 1/5] parseopt: fix :(optional) at command line to only ignore missing files
Quoted 5 lines · Phillip Wood
Hi Ben
These all look good to me though I agree with Junio's comments on patch
3. It would be nice to get at least the fist patch merged in time for 2.52.0.
Yup, let me do exactly that ;-)
Thanks, both.
Re: [PATCH 1/5] parseopt: fix :(optional) at command line to only ignore missing files
Quoted 11 lines · Junio C Hamano
Quoted 5 lines · Phillip Wood
Hi Ben
These all look good to me though I agree with Junio's comments on patch
3. It would be nice to get at least the fist patch merged in time for 2.52.0.Yup, let me do exactly that ;-)
Thanks, both.
Let me have this on top of Ben's 5-patch series.
----- >8 -----
Subject: [PATCH] parseopt: remove unreachable code
At this point in the code after running skip_prefix() on the variable and receiving the result in the same variable, the contents of the variable can never be NULL. The function either (1) updates the variable to point at a later part of the string it originally pointed at, or (2) leaves it intact if the string does not have the prefix. (1) will never make the variable NULL, and (2) cannot be the source of NULL, because the variable cannot be NULL before calling skip_prefix(), which would die immediately by dereferencing the NULL pointer in that case.
--- parse-options.c | 2 -- 1 file changed, 2 deletions(-)
parse-options.c +0 -2
@@ -223,8 +223,6 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,return 0 ; is_optional =skip_prefix (value,":(optional)" , &value); -if (!value) - is_optional = false; value =fix_filename (p->prefix, value);if (is_optional &&is_missing_file (value)) {free ((char *)value);
Signature · 1 line
2.52.0-rc0-28-g4cf919bd7b
Re: [PATCH 1/5] parseopt: fix :(optional) at command line to only ignore missing files
Quoted 50 lines · Junio C Hamano
Quoted 11 lines · Junio C Hamano
Quoted 5 lines · Phillip Wood
Hi Ben
These all look good to me though I agree with Junio's comments on patch
3. It would be nice to get at least the fist patch merged in time for 2.52.0.Yup, let me do exactly that ;-)
Thanks, both.
Let me have this on top of Ben's 5-patch series.
----- >8 -----
Subject: [PATCH] parseopt: remove unreachable codeAt this point in the code after running
skip_prefix()on the variable and receiving the result in the same variable, the contents of the variable can never be NULL. The function either (1) updates the variable to point at a later part of the string it originally pointed at, or (2) leaves it intact if the string does not have the prefix. (1) will never make the variable NULL, and (2) cannot be the source of NULL, because the variable cannot be NULL before callingskip_prefix(), which would die immediately by dereferencing the NULL pointer in that case.Helped-by Phillip Wood <[email protected]>Signed-off-by Junio C Hamano <[email protected]>--- parse-options.c | 2 -- 1 file changed, 2 deletions(-)parse-options.c +0
-3@@ -223,8 +223,6 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,return 0 ; is_optional =skip_prefix (value,":(optional)" , &value); -if (!value) - is_optional = false; value =fix_filename (p->prefix, value);if (is_optional &&is_missing_file (value)) {free ((char *)value); --
Quoted 2 lines
2.52.0-rc0-28-g4cf919bd7b
Ah, that's fine, and I won't send a new version unless we need it. Thanks!
I do wonder about Phillip's comment: perhaps it should have been !*value? But then something else has to be fixed because value is no longer ":(optional)" which maybe was intended as a literal filename? IDK.
Re: [PATCH 1/5] parseopt: fix :(optional) at command line to only ignore missing files
In reply to Junio C HamanoQuoted 7 lines · Junio C Hamano
Junio C Hamano <[email protected]> writes:
Let me have this on top of Ben's 5-patch series.
----- >8 -----
Subject: [PATCH] parseopt: remove unreachable code
Quoted 9 lines
At this point in the code after running
skip_prefix()on the variable and receiving the result in the same variable, the contents of the variable can never be NULL. The function either (1) updates the variable to point at a later part of the string it originally pointed at, or (2) leaves it intact if the string does not have the prefix. (1) will never make the variable NULL, and (2) cannot be the source of NULL, because the variable cannot be NULL before callingskip_prefix(), which would die immediately by dereferencing the NULL pointer in that case.
Nicely explained, the changes below look good
Thanks
Phillip
Quoted 19 lines
Helped-by Phillip Wood <[email protected]>Signed-off-by Junio C Hamano <[email protected]>--- parse-options.c | 2 -- 1 file changed, 2 deletions(-)parse-options.c +0
-2@@ -223,8 +223,6 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,return 0 ; is_optional =skip_prefix (value,":(optional)" , &value); -if (!value) - is_optional = false; value =fix_filename (p->prefix, value);if (is_optional &&is_missing_file (value)) {free ((char *)value);
Re: [PATCH 1/5] parseopt: fix :(optional) at command line to only ignore missing files
Quoted 18 lines · Phillip Wood
Quoted 7 lines · Junio C Hamano
Junio C Hamano <[email protected]> writes:
Let me have this on top of Ben's 5-patch series.
----- >8 -----
Subject: [PATCH] parseopt: remove unreachable codeQuoted 9 lines
At this point in the code after running
skip_prefix()on the variable and receiving the result in the same variable, the contents of the variable can never be NULL. The function either (1) updates the variable to point at a later part of the string it originally pointed at, or (2) leaves it intact if the string does not have the prefix. (1) will never make the variable NULL, and (2) cannot be the source of NULL, because the variable cannot be NULL before callingskip_prefix(), which would die immediately by dereferencing the NULL pointer in that case.
Quoted 5 lines
Nicely explained, the changes below look good
Thanks
Phillip
Thanks for a quick review.
Quoted 20 lines
Quoted 20 lines
Helped-by Phillip Wood <[email protected]>Signed-off-by Junio C Hamano <[email protected]>--- parse-options.c | 2 -- 1 file changed, 2 deletions(-)parse-options.c +0
-2@@ -223,8 +223,6 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,return 0 ; is_optional =skip_prefix (value,":(optional)" , &value); -if (!value) - is_optional = false; value =fix_filename (p->prefix, value);if (is_optional &&is_missing_file (value)) {free ((char *)value);
PATCH 2/5 doc: clarify command equivalence comment
In reply to D. Ben KnobleDocumentation of command parsing for :(optional) includes a terse comment; expand it to be clearer to readers.
--- Documentation/gitcli.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/gitcli.adoc +1 -1
@@ -223,7 +223,7 @@ Options that take a filename allow a prefix `:(optional)`. For example: ---------------------------- git commit -F :(optional)COMMIT_EDITMSG -# if COMMIT_EDITMSG does not exist, equivalent to +# if COMMIT_EDITMSG does not exist, the above is equivalent to git commit ----------------------------
Signature · 1 line
2.48.1
PATCH 3/5 parseopt: use boolean type for a simple flag
In reply to D. Ben Knoble--- parse-options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
parse-options.c +2 -2
@@ -208,7 +208,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,case OPTION_FILENAME : {const char *value; -int is_optional; +bool is_optional;if (unset) value =NULL ;
@@ -224,7 +224,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, is_optional =skip_prefix (value,":(optional)" , &value);if (!value) - is_optional =0 ; + is_optional = false; value =fix_filename (p->prefix, value);if (is_optional &&is_missing_file (value)) {free ((char *)value);
Signature · 1 line
2.48.1
Re: [PATCH 3/5] parseopt: use boolean type for a simple flag
Quoted 20 lines · D. Ben Knoble
Suggested-by Phillip Wood <[email protected]>Signed-off-by D. Ben Knoble <[email protected]>--- parse-options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)parse-options.c +1
-1@@ -208,7 +208,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,case OPTION_FILENAME : {const char *value; -int is_optional; +bool is_optional;if (unset) value =NULL ;
parse-options.c static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, · line 227
Quoted 5 lines
parse-options.c +1
-1@@ -224,7 +224,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, is_optional =skip_prefix (value,":(optional)" , &value);if (!value) - is_optional =0 ; + is_optional = false;
Whether it is spelled 0 or false, I do not think this makes any sense. skip_prefix() either touches &value to point at the substring in value that comes after ":(optional)", or it does not touch it at all, so there is no way value can be NULL here (and we know value is not NULL before we call skip_prefix()).
Shouldn't you be removing the entire "if value is NULL, it is not optional" thing instead? That is exactly what Phillip pointed out in his review.
Quoted 3 lines
parse-options.c +0
-0value =fix_filename (p->prefix, value);if (is_optional &&is_missing_file (value)) {free ((char *)value);
Re: [PATCH 3/5] parseopt: use boolean type for a simple flag
Quoted 13 lines · Junio C Hamano
parse-options.c static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, · line 227
Quoted 4 lines · D. Ben Knoble
is_optional = skip_prefix(value, ":(optional)", &value); if (!value)parse-options.c +1
-1- is_optional =0 ; + is_optional = false;Whether it is spelled 0 or false, I do not think this makes any sense.
skip_prefix()either touches &value to point at the substring in value that comes after ":(optional)", or it does not touch it at all, so there is no way value can be NULL here (and we know value is not NULL before we callskip_prefix()).
Quoted 3 lines
Shouldn't you be removing the entire "if value is NULL, it is not optional" thing instead? That is exactly what Phillip pointed out in his review.
Looking at this again I wonder if the intention was to error out if there wasn't a filename after the ":(optional)" prefix which I think would be a reasonable thing to do but that's not what this code actually does.
Thanks
Phillip
Re: [PATCH 3/5] parseopt: use boolean type for a simple flag
Quoted 19 lines · Phillip Wood
Quoted 13 lines · Junio C Hamano
parse-options.c static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, · line 227
Quoted 4 lines · D. Ben Knoble
is_optional = skip_prefix(value, ":(optional)", &value); if (!value)parse-options.c +1
-1- is_optional =0 ; + is_optional = false;Whether it is spelled 0 or false, I do not think this makes any sense.
skip_prefix()either touches &value to point at the substring in value that comes after ":(optional)", or it does not touch it at all, so there is no way value can be NULL here (and we know value is not NULL before we callskip_prefix()).Quoted 3 lines
Shouldn't you be removing the entire "if value is NULL, it is not optional" thing instead? That is exactly what Phillip pointed out in his review.
Quoted 8 lines
Looking at this again I wonder if the intention was to error out if there wasn't a filename after the ":(optional)" prefix which I think would be a reasonable thing to do but that's not what this code actually does.
Thanks
Phillip
Agreed both, will reroll
PATCH 4/5 config: use boolean type for a simple flag
In reply to D. Ben Knoble--- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
config.c +1 -1
@@ -1278,7 +1278,7 @@ int git_config_string(char **dest, const char *var, const char *value)int git_config_pathname (char **dest,const char *var,const char *value) { -int is_optional; +bool is_optional;char *path;if (!value)
Signature · 1 line
2.48.1
PATCH 5/5 parseopt: restore const qualifier to parsed filename
In reply to D. Ben KnobleThis was unintentionally dropped in ccfcaf399f (parseopt: values of pathname type can be prefixed with :(optional), 2025-09-28). Notably, continue dropping the const qualifier when free'ing value; see 4049b9cfc0 (fix const issues with some functions, 2007-10-16) or 83838d5c1b (cast variable in call to free() in builtin/diff.c and submodule.c, 2011-11-06) for more details on why.
--- parse-options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
parse-options.c +1 -1
@@ -213,7 +213,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,if (unset) value =NULL ;else if (opt->flags &PARSE_OPT_OPTARG && !p->opt) - value = (char *)opt->defval; + value = (const char *)opt->defval;else {int err =get_arg (p, opt, flags, &value);if (err)
Signature · 1 line
2.48.1