Uh oh!
There was an error while loading. Please reload this page.
fix: reject an inverted range when the comparer returns a negative other than -1 - #2370
Open
dualfroz wants to merge 1 commit into
Open
Conversation
RangeValidator's constructor guarded against an inverted range with
comparer.Compare(to, from) == -1. The IComparer<T>/IComparable<T> contract
only guarantees the sign of the result, not the magnitude, so the guard
silently failed for comparers returning other negatives, e.g. char.CompareTo
('a'.CompareTo('c') == -2) or custom comparers that return x - y. This let
InclusiveBetween('c', 'a') build a validator that can never pass instead of
throwing, unlike the int case which happens to return -1.
Compare against < 0 to honor the comparer contract. Add char-bound throw
tests to the inclusive and exclusive between suites.dualfrozforce-pushed
the
fix/range-validator-inverted-range-guard
branch
from
September 5, 2026 23:20
ae467a8 to
00e7987Compare
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 freeto 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.
Problem
RangeValidator<T, TProperty>(used byInclusiveBetween/ExclusiveBetween) guardsagainst an inverted range in its constructor:
The check compares the result against the literal
-1. However, theIComparer<T>.Compare/IComparable<T>.CompareTocontract only guarantees the signof the result: any value less than zero means "less than". It does not guarantee
-1.As a result the guard silently fails for legitimate comparers that return other negative
magnitudes:
charbounds.char.CompareToreturns the arithmetic difference, e.g.'a'.CompareTo('c') == -2. SoInclusiveBetween('c', 'a')(an inverted range) isaccepted instead of throwing, producing a validator that can never pass.
IComparer<T>implementations passed to theInclusiveBetween/ExclusiveBetweenoverloads. Returningx - y(a very common pattern) yieldsmagnitudes other than 1.
stringcomparisons can also return magnitudes other than 1.This is inconsistent with the existing behaviour for
int(InclusiveBetween(10, 1)throws, because
int.CompareTohappens to return-1) and defeats the guard's statedintent of rejecting
to < from.Fix
Compare against
< 0instead of== -1, matching the documented comparer contract.src/FluentValidation/Validators/RangeValidator.csTests
Added
char-bound counterparts to the existing "to is smaller than from should throw"tests in both
InclusiveBetweenValidatorTestsandExclusiveBetweenValidatorTests.Before the fix both new tests fail (no exception thrown); after the fix they pass. All
45 tests across the two between-validator suites pass, with no regressions.
Build / test gate
global.jsonroll-forward), library TFMnet8.0.dotnet build src/FluentValidation/FluentValidation.csproj -c Release-> 0 errors.dotnet test ... --filter "FullyQualifiedName~should_throw_for_chars":fails (2/2) before the fix, passes (2/2) after.
dotnet test ... --filter "FullyQualifiedName~BetweenValidatorTests"-> 45 passed.