git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCHv6 2/2] pathspec: give better message for submodule related pathspec error

From
Junio C Hamano <gitster@pobox.com>
Date
Jan 9, 2017, 02:39 UTC
Message-ID
<xmqqbmvhyn1m.fsf@gitster.mtv.corp.google.com>
In-Reply-To
<20170105192904.1107-3-sbeller@google.com>
Stefan Beller <sbeller@google.com> writes:
Show 47 quoted lines
> Every once in a while someone complains to the mailing list to have
> run into this weird assertion[1]. The usual response from the mailing
> list is link to old discussions[2], and acknowledging the problem
> stating it is known.
>
> This patch accomplishes two things:
>
>   1. Switch assert() to die("BUG") to give a more readable message.
>
>   2. Take one of the cases where we hit a BUG and turn it into a normal
>      "there was something wrong with the input" message.
>
>      This assertion triggered for cases where there wasn't a programming
>      bug, but just bogus input. In particular, if the user asks for a
>      pathspec that is inside a submodule, we shouldn't assert() or
>      die("BUG"); we should tell the user their request is bogus.
>
>      The only reason we did not check for it, is the expensive nature
>      of such a check, so callers avoid setting the flag
>      PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE. However when we die due
>      to bogus input, the expense of CPU cycles spent outweighs the user
>      wondering what went wrong, so run that check unconditionally before
>      dying with a more generic error message.
>
> Note: There is a case (e.g. "git -C submodule add .") in which we call
> strip_submodule_slash_expensive, as git-add requests it via the flag
> PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE, but the assert used to
> trigger nevertheless, because the flag PATHSPEC_LITERAL was not set,
> such that we executed
>
> 	if (item->nowildcard_len < prefixlen)
> 		item->nowildcard_len = prefixlen;
>
> and prefixlen was not adapted (e.g. it was computed from "submodule/")
> So in the die_inside_submodule_path function we also need handle paths,
> that were stripped before, i.e. are the exact submodule path. This
> is why the conditions in die_inside_submodule_path are slightly
> different than in strip_submodule_slash_expensive.
>
> [1] https://www.google.com/search?q=item-%3Enowildcard_len
> [2] http://git.661346.n2.nabble.com/assert-failed-in-submodule-edge-case-td7628687.html
>     https://www.spinics.net/lists/git/msg249473.html
>
> Helped-by: Jeff King <peff@peff.net>
> Helped-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---

For future reference, do not bury a useful fix behind unproven new things. The main purpose of this two-patch series is this change, and it does not have to wait for the change to allow test_commit to notice "-C" you have in another series.

Just write it in longhand, and when both topics graduate, send in another patch to update "(cd <dir> && test_commit <others>)" to use the new "test_commit -C <dir> <others>".

Thanks.
Show 97 quoted lines
>  pathspec.c                       | 35 +++++++++++++++++++++++++++++++++--
>  t/t6134-pathspec-in-submodule.sh | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 66 insertions(+), 2 deletions(-)
>  create mode 100755 t/t6134-pathspec-in-submodule.sh
>
> diff --git a/pathspec.c b/pathspec.c
> index d4efcf6662..42cd83c235 100644
> --- a/pathspec.c
> +++ b/pathspec.c
> @@ -296,6 +296,27 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)
>  	}
>  }
>  
> +static void die_inside_submodule_path(struct pathspec_item *item)
> +{
> +	int i;
> +
> +	for (i = 0; i < active_nr; i++) {
> +		struct cache_entry *ce = active_cache[i];
> +		int ce_len = ce_namelen(ce);
> +
> +		if (!S_ISGITLINK(ce->ce_mode))
> +			continue;
> +
> +		if (item->len < ce_len ||
> +		    !(item->match[ce_len] == '/' || item->match[ce_len] == '\0') ||
> +		    memcmp(ce->name, item->match, ce_len))
> +			continue;
> +
> +		die(_("Pathspec '%s' is in submodule '%.*s'"),
> +		    item->original, ce_len, ce->name);
> +	}
> +}
> +
>  /*
>   * Perform the initialization of a pathspec_item based on a pathspec element.
>   */
> @@ -391,8 +412,18 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
>  	}
>  
>  	/* sanity checks, pathspec matchers assume these are sane */
> -	assert(item->nowildcard_len <= item->len &&
> -	       item->prefix         <= item->len);
> +	if (item->nowildcard_len > item->len ||
> +	    item->prefix         > item->len) {
> +		/*
> +		 * This case can be triggered by the user pointing us to a
> +		 * pathspec inside a submodule, which is an input error.
> +		 * Detect that here and complain, but fallback in the
> +		 * non-submodule case to a BUG, as we have no idea what
> +		 * would trigger that.
> +		 */
> +		die_inside_submodule_path(item);
> +		die ("BUG: item->nowildcard_len > item->len || item->prefix > item->len)");
> +	}
>  }
>  
>  static int pathspec_item_cmp(const void *a_, const void *b_)
> diff --git a/t/t6134-pathspec-in-submodule.sh b/t/t6134-pathspec-in-submodule.sh
> new file mode 100755
> index 0000000000..2900d8d06e
> --- /dev/null
> +++ b/t/t6134-pathspec-in-submodule.sh
> @@ -0,0 +1,33 @@
> +#!/bin/sh
> +
> +test_description='test case exclude pathspec'
> +
> +TEST_CREATE_SUBMODULE=yes
> +. ./test-lib.sh
> +
> +test_expect_success 'setup a submodule' '
> +	git submodule add ./pretzel.bare sub &&
> +	git commit -a -m "add submodule" &&
> +	git submodule deinit --all
> +'
> +
> +cat <<EOF >expect
> +fatal: Pathspec 'sub/a' is in submodule 'sub'
> +EOF
> +
> +test_expect_success 'error message for path inside submodule' '
> +	echo a >sub/a &&
> +	test_must_fail git add sub/a 2>actual &&
> +	test_cmp expect actual
> +'
> +
> +cat <<EOF >expect
> +fatal: Pathspec '.' is in submodule 'sub'
> +EOF
> +
> +test_expect_success 'error message for path inside submodule from within submodule' '
> +	test_must_fail git -C sub add . 2>actual &&
> +	test_cmp expect actual
> +'
> +
> +test_done
Previous: Stefan BellerNext: Stefan Beller
Message 3 of 7 in “[PATCHv6 0/2] pathspec: give better message for submodule related pathspec error”
  1. Stefan BellerJan 5, 2017
  2. 2/2 pathspec: give better message for submodule related pathspec errorStefan Beller, Jan 5, 2017
  3. Junio C HamanoJan 9, 2017
  4. Stefan BellerJan 9, 2017
  5. 1/2 submodule tests: don't use itself as a submoduleStefan Beller, Jan 5, 2017
  6. Junio C HamanoJan 9, 2017
  7. Stefan BellerJan 9, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.