Remove component size limit for version comparisons

The VersionCompare() function converted version components to
'unsigned long' prior to comparing them.  Any version components
too large for 'unsigned long' were treated as equal to ULONG_MAX.
This impacted operators like VERSION_GREATER, VERSION_LESS, and
VERSION_EQUAL.  The new code does not limit the length of the
version components for valid comparisons.
This commit is contained in:
David Gobbi
2023-02-20 08:59:11 -07:00
committed by Brad King
parent 7e730d8f7f
commit aa86e8ddfd
2 changed files with 48 additions and 9 deletions

View File

@@ -3197,20 +3197,41 @@ bool VersionCompare(cmSystemTools::CompareOp op, const char* lhss,
{
const char* endl = lhss;
const char* endr = rhss;
unsigned long lhs;
unsigned long rhs;
while (((*endl >= '0') && (*endl <= '9')) ||
((*endr >= '0') && (*endr <= '9'))) {
// Do component-wise comparison.
lhs = strtoul(endl, const_cast<char**>(&endl), 10);
rhs = strtoul(endr, const_cast<char**>(&endr), 10);
// Do component-wise comparison, ignoring leading zeros
// (components are treated as integers, not as mantissas)
while (*endl == '0') {
endl++;
}
while (*endr == '0') {
endr++;
}
if (lhs < rhs) {
const char* beginl = endl;
const char* beginr = endr;
// count significant digits
while ((*endl >= '0') && (*endl <= '9')) {
endl++;
}
while ((*endr >= '0') && (*endr <= '9')) {
endr++;
}
// compare number of digits first
ptrdiff_t r = ((endl - beginl) - (endr - beginr));
if (r == 0) {
// compare the digits if number of digits is equal
r = strncmp(beginl, beginr, endl - beginl);
}
if (r < 0) {
// lhs < rhs, so true if operation is LESS
return (op & cmSystemTools::OP_LESS) != 0;
}
if (lhs > rhs) {
if (r > 0) {
// lhs > rhs, so true if operation is GREATER
return (op & cmSystemTools::OP_GREATER) != 0;
}

View File

@@ -61,8 +61,26 @@ int testSystemTools(int /*unused*/, char* /*unused*/[])
"VersionCompareEqual different length");
cmAssert(cmSystemTools::VersionCompareGreater("6.2.1", "6.2"),
"VersionCompareGreater different length");
cmAssert(cmSystemTools::VersionCompareGreater("3.141592653", "3.14159265"),
"VersionCompareGreater more digits");
cmAssert(
!cmSystemTools::VersionCompareEqual(
"3.14159265358979323846264338327950288419716939937510582097494459230",
"3.14159265358979323846264338327950288419716939937510582097494459231"),
"VersionCompareEqual long number");
cmAssert(
!cmSystemTools::VersionCompareGreater(
"3.14159265358979323846264338327950288419716939937510582097494459230",
"3.14159265358979323846264338327950288419716939937510582097494459231"),
"VersionCompareGreater long number");
cmAssert(
!cmSystemTools::VersionCompareEqual(
"3.141592653589793238462643383279502884197169399375105820974944592307",
"3.14159265358979323846264338327950288419716939937510582097494459231"),
"VersionCompareEqual more digits");
cmAssert(
cmSystemTools::VersionCompareGreater(
"3.141592653589793238462643383279502884197169399375105820974944592307",
"3.14159265358979323846264338327950288419716939937510582097494459231"),
"VersionCompareGreater more digits");
// ----------------------------------------------------------------------
// Test cmSystemTools::strverscmp