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

Re: [PATCH] linear-assignment: fix potential out of bounds memory access

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 12, 2018, 20:11 UTC
Message-ID
<xmqqy3c6jx1m.fsf@gitster-ct.c.googlers.com>
In-Reply-To
<20180912190108.GE4865@hank.intra.tgummerer.com>
Thomas Gummerer <t.gummerer@gmail.com> writes:
Show 10 quoted lines
>> > I'm looking into why that fails.  Also adding Dscho to Cc here as the
>> > author of this code.
>> 
>> The diff below seems to fix it.  Not submitting this as a proper
>> patch [...]
>
> I found the time to actually have a look at the paper, so here's a
> proper patch:
>
> I'm still not entirely sure what the initial code tried to do here,

It looks to me an attempt to optimize (instead of starting from a value that is too big to be minimum, pick the first value and start from there, and all the "found even smaller one, so let's replace" later would work the same way) that went wrong (just that the "first one" was written incorrectly), but it is not absolutely necessary to find out why the code was written in a particular way that happened to be buggy.

> but I think staying as close as possible to the original is probably
> our best option here, also for future readers of this code.
Thanks for digging.
Show 11 quoted lines
> --- >8 ---
>
> Subject: [PATCH] linear-assignment: fix potential out of bounds memory access
>
> Currently the 'compute_assignment()' function can may read memory out
> of bounds, even if used correctly.  Namely this happens when we only
> have one column.  In that case we try to calculate the initial
> minimum cost using '!j1' as column in the reduction transfer code.
> That in turn causes us to try and get the cost from column 1 in the
> cost matrix, which does not exist, and thus results in an out of
> bounds memory read.
This nicely explains what goes wrong.
> Instead of trying to intialize the minimum cost from another column,
> just set it to INT_MAX.  This also matches what the example code in the
> original paper for the algorithm [1] does (it initializes the value to
> inf, for which INT_MAX is the closest match in C).

Yeah, if we really want to avoid INT_MAX we could use another "have we found any value yet?" boolean variable, but the caller in get_correspondences() does not even worry about integer overflows when stuffing diffsize to the cost[] array, and the other possible value that can go to cost[] array is COST_MAX that is mere 65k, so it would be OK to use INT_MAX as sentinel here, I guess.

Show 50 quoted lines
> Note that the test only fails under valgrind on Linux, but the same
> command has been reported to segfault on Mac OS.
>
> Also start from 0 in the loop, which matches what the example code in
> the original paper does as well.  Starting from 1 means we'd ignore
> the first column during the reduction transfer phase.  Note that in
> the original paper the loop does start from 1, but the implementation
> is in Pascal, where arrays are 1 indexed.
>
> [1]: Jonker, R., & Volgenant, A. (1987). A shortest augmenting path
>      algorithm for dense and sparse linear assignment
>      problems. Computing, 38(4), 325–340.
>
> Reported-by: ryenus <ryenus@gmail.com>
> Helped-by: Derrick Stolee <stolee@gmail.com>
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---
>  linear-assignment.c   | 4 ++--
>  t/t3206-range-diff.sh | 5 +++++
>  2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/linear-assignment.c b/linear-assignment.c
> index 9b3e56e283..7700b80eeb 100644
> --- a/linear-assignment.c
> +++ b/linear-assignment.c
> @@ -51,8 +51,8 @@ void compute_assignment(int column_count, int row_count, int *cost,
>  		else if (j1 < -1)
>  			row2column[i] = -2 - j1;
>  		else {
> -			int min = COST(!j1, i) - v[!j1];
> -			for (j = 1; j < column_count; j++)
> +			int min = INT_MAX;
> +			for (j = 0; j < column_count; j++)
>  				if (j != j1 && min > COST(j, i) - v[j])
>  					min = COST(j, i) - v[j];
>  			v[j1] -= min;
> diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
> index 2237c7f4af..fb4c13a84a 100755
> --- a/t/t3206-range-diff.sh
> +++ b/t/t3206-range-diff.sh
> @@ -142,4 +142,9 @@ test_expect_success 'changed message' '
>  	test_cmp expected actual
>  '
>  
> +test_expect_success 'no commits on one side' '
> +	git commit --amend -m "new message" &&
> +	git range-diff master HEAD@{1} HEAD
> +'
> +
>  test_done
Previous: Thomas GummererNext: Thomas Gummerer
Message 8 of 19 in “Git 2.19 Segmentation fault 11 on macOS”
  1. ryenusSep 11, 2018
  2. Derrick StoleeSep 11, 2018
  3. Derrick StoleeSep 11, 2018
  4. Derrick StoleeSep 11, 2018
  5. Thomas GummererSep 11, 2018
  6. Thomas GummererSep 11, 2018
  7. linear-assignment: fix potential out of bounds memory access (was: Re: Git 2.19 Segmentation fault 11 on macOS)Thomas Gummerer, Sep 12, 2018
  8. Junio C HamanoSep 12, 2018
  9. Thomas GummererSep 12, 2018
  10. Johannes SchindelinSep 13, 2018
  11. Thomas GummererSep 13, 2018
  12. Eric SunshineSep 13, 2018
  13. linear-assignment: fix potential out of bounds memory accessThomas Gummerer, Sep 13, 2018
  14. Jonathan NiederSep 17, 2018
  15. Junio C HamanoSep 11, 2018
  16. Elijah NewrenSep 11, 2018
  17. Thomas GummererSep 11, 2018
  18. ryenusSep 11, 2018
  19. Elijah NewrenSep 11, 2018

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.