fix: correct off-by-one in SortSlices equal-run check - #402
Open
nileshpatil6 wants to merge 1 commit into
Open
Conversation
sliceSorter.checkSort records the start of a run of mutually equal elements as i, but when !less(v[i-1], v[i]) the run begins at i-1. The loop's own comment says the check covers v[start:i], the whole run, and with start = i a two element run yields the empty slice v[i:i] in the panic message. Two consequences. The guard misses violations whose offending element is first in a run, so a non-transitive less function silently produces an order dependent result from cmp.Equal instead of the documented "incomparable values detected" panic. And when it does fire, the message prints a window missing its leading element. Adds a case where the incomparable element starts the run, which does not panic before this change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
sliceSorter.checkSorttracks the start of a run of mutually "equal" elements:When
!less(v[i-1], v[i])the run begins ati-1, noti, so the first element of every equal run is excluded from the check.The loop's own comment gives it away: it says the check covers
v[start:i], the whole run. Withstart = i, a two-element run producesv.Slice(i, i), an empty slice, in the panic message.Why it matters
checkSortexists to panic withincomparable values detectedwhen the supplied less function is not transitive over the data, because the sorted order and thereforecmp.Equal's answer is otherwise arbitrary. With the off-by-one, a violation whose offending element is first in a run goes undetected, andcmp.Equalquietly returns an order-dependent result instead of telling the caller their option is broken.The everyday case is a float slice containing
NaNwith the obvious less function, which is exactly the misuse this package already has awantPanictest for:Sorted, the run is
[0 NaN 1]andless(0, 1)is true, so it must panic. It does not, becausestartpoints atNaNrather than at0, andNaNcompares "equal" to1in both directions.When the check does fire, the message also prints the wrong window. On the existing test input it reports
[2 2 NaN 3 3 3 3]where the run is[2 2 2 NaN 3 3 3 3].mapSorter.checkSortis unaffected: it requires a total order and checks every adjacent pair, so it has no run-start concept.The change
start = i - 1, plus one case in the existingTestOptionstable where the incomparable element begins the run.Widening the window by one cannot cause a false panic: for a valid strict weak ordering every element of a run is mutually equal, so the added comparison is against an element already known to be equivalent.
Testing
Without the fix the new case fails:
With it,
./cmp/...passes in full.gofmt -l cmp/is clean, andgo vetoutput is byte-identical to the unmodified tree.One user-visible note: this changes the panic message on the existing
wantPaniccase from[2 2 NaN 3 3 3 3]to[2 2 2 NaN 3 3 3 3]. No test asserts that string.