From a5b837e5d77982aa75cd67915ad5ba200817d2ac Mon Sep 17 00:00:00 2001 From: Guichard Desrosiers Date: Sat, 11 Apr 2026 17:15:33 -0400 Subject: [PATCH] fix: NaN bypasses minInclusive/maxInclusive facets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NaN silently passes bounds validation due to trichotomy failure in compareValues. Root Cause: - boundsCheck assumes trichotomy from compareValues (total order): -1, 0, or 1 - NaN triggers compareSpecial → returns 2 (INDETERMINATE) - Trichotomy broken by 4th value (NaN) - minInclusive: `if (result == -1)` → misses INDETERMINATE(2) - maxInclusive: `if (result == 1)` → misses INDETERMINATE(2) Affected: minInclusive/maxInclusive facets only Unaffected: minExclusive/maxExclusive correctly detect NaN Fix: - minInclusive: reject `(result != 1 && result != 0)` - maxInclusive: reject `(result != -1 && result != 0)` --- src/xercesc/validators/datatype/AbstractNumericValidator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xercesc/validators/datatype/AbstractNumericValidator.cpp b/src/xercesc/validators/datatype/AbstractNumericValidator.cpp index b9a041847..40f68905b 100644 --- a/src/xercesc/validators/datatype/AbstractNumericValidator.cpp +++ b/src/xercesc/validators/datatype/AbstractNumericValidator.cpp @@ -85,7 +85,7 @@ void AbstractNumericValidator::boundsCheck(const XMLNumber* const theDat if ( (thisFacetsDefined & DatatypeValidator::FACET_MAXINCLUSIVE) != 0 ) { result = compareValues(theData, getMaxInclusive()); - if (result == 1) + if (result != -1 && result != 0) { REPORT_VALUE_ERROR(theData , getMaxInclusive() @@ -98,7 +98,7 @@ void AbstractNumericValidator::boundsCheck(const XMLNumber* const theDat if ( (thisFacetsDefined & DatatypeValidator::FACET_MININCLUSIVE) != 0 ) { result = compareValues(theData, getMinInclusive()); - if (result == -1) + if (result != 1 && result != 0) { REPORT_VALUE_ERROR(theData , getMinInclusive()