Skip to content

Commit bf521fe

Browse files
committed
Fix boost::rational comparison bug with gcc < 14 and C++20
Use explicit .operator==() calls to avoid infinite recursion in rational-to-integer comparisons caused by symmetric operator overload resolution bug
1 parent 1505e57 commit bf521fe

File tree

8 files changed

+15
-14
lines changed

8 files changed

+15
-14
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,10 +1901,10 @@ workflows:
19011901
# build-only
19021902
- b_docs: *requires_nothing
19031903
- b_ubu_ossfuzz: *requires_nothing
1904-
- b_ubu_2204: *requires_nothing
19051904
- b_ubu_2204_clang: *requires_nothing
19061905

1907-
# Ubuntu 22.04 boost::rational bug repro test
1906+
# build and test on ubuntu 22.04
1907+
- b_ubu_2204: *requires_nothing
19081908
- t_ubu_2204_soltest:
19091909
<<: *on_all_tags_and_branches
19101910
requires:

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Compiler Features:
77

88
Bugfixes:
99
* Assembler: Fix not using a fixed-width type for IDs being assigned to subassemblies nested more than one level away, resulting in inconsistent `--asm-json` output between target architectures.
10+
* General: Fix boost::rational comparison bug with gcc < 14 and C++20 that leads to infinite recursion.
1011
* Yul Optimizer: Fix edge case in which invalid Yul code is produced by ExpressionSimplifier due to expressions being substituted that contain out-of-scope variables.
1112

1213
### 0.8.30 (2025-05-07)

libsolidity/analysis/ConstantEvaluator.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
9292
case Token::Sub: return _left - _right;
9393
case Token::Mul: return _left * _right;
9494
case Token::Div:
95-
if (_right == rational(0))
95+
if (_right.operator==(rational(0)))
9696
return std::nullopt;
9797
else
9898
return _left / _right;
9999
case Token::Mod:
100-
if (_right == rational(0))
100+
if (_right.operator==(rational(0)))
101101
return std::nullopt;
102102
else if (fractional)
103103
{
@@ -117,9 +117,9 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
117117
// for 0, 1 and -1 the size of the exponent doesn't have to be restricted
118118
if (exp == 0)
119119
return 1;
120-
else if (_left == 0 || _left == 1)
120+
else if (_left.operator==(0) || _left.operator==(1))
121121
return _left;
122-
else if (_left == -1)
122+
else if (_left.operator==(-1))
123123
{
124124
bigint isOdd = abs(exp) & bigint(1);
125125
return 1 - 2 * isOdd.convert_to<int>();

libsolidity/analysis/DeclarationTypeChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
347347
length->location(),
348348
"Invalid array length, expected integer literal or constant expression."
349349
);
350-
else if (*lengthValue == 0)
350+
else if (lengthValue->operator==(0))
351351
m_errorReporter.typeError(1406_error, length->location(), "Array with zero length specified.");
352352
else if (lengthValue->denominator() != 1)
353353
m_errorReporter.typeError(3208_error, length->location(), "Array with fractional length specified.");

libsolidity/analysis/StaticAnalyzer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ bool StaticAnalyzer::visit(BinaryOperation const& _operation)
317317
ConstantEvaluator::evaluate(m_errorReporter, _operation.leftExpression())
318318
)
319319
if (auto rhs = ConstantEvaluator::evaluate(m_errorReporter, _operation.rightExpression()))
320-
if (rhs->value == 0)
320+
if (rhs->value.operator==(0))
321321
m_errorReporter.typeError(
322322
1211_error,
323323
_operation.location(),
@@ -338,7 +338,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall)
338338
solAssert(_functionCall.arguments().size() == 3, "");
339339
if (*_functionCall.arguments()[2]->annotation().isPure)
340340
if (auto lastArg = ConstantEvaluator::evaluate(m_errorReporter, *(_functionCall.arguments())[2]))
341-
if (lastArg->value == 0)
341+
if (lastArg->value.operator==(0))
342342
m_errorReporter.typeError(
343343
4195_error,
344344
_functionCall.location(),

libsolidity/ast/Types.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ std::tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _li
932932
value = std::get<1>(mantissa);
933933

934934
// 0E... is always zero.
935-
if (value == 0)
935+
if (value.operator==(0))
936936
return std::make_tuple(true, rational(0));
937937

938938
bigint exp = bigint(std::string(expPoint + 1, valueString.end()));
@@ -1033,7 +1033,7 @@ BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo)
10331033
return fitsIntoBits(value.numerator(), targetType.numBits(), targetType.isSigned());
10341034
}
10351035
case Category::FixedBytes:
1036-
return (m_value == rational(0)) || (m_compatibleBytesType && *m_compatibleBytesType == _convertTo);
1036+
return (m_value.operator==(rational(0))) || (m_compatibleBytesType && *m_compatibleBytesType == _convertTo);
10371037
default:
10381038
return false;
10391039
}
@@ -1048,7 +1048,7 @@ BoolResult RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo)
10481048
if (category == Category::FixedBytes)
10491049
return false;
10501050
else if (auto addressType = dynamic_cast<AddressType const*>(&_convertTo))
1051-
return (m_value == 0) ||
1051+
return (m_value.operator==(0)) ||
10521052
((addressType->stateMutability() != StateMutability::Payable) &&
10531053
!isNegative() &&
10541054
!isFractional() &&

libsolidity/ast/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ class RationalNumberType: public Type
627627
bool isNegative() const { return m_value < 0; }
628628

629629
/// @returns true if the value is zero.
630-
bool isZero() const { return m_value == 0; }
630+
bool isZero() const { return m_value.operator==(0); }
631631

632632
/// @returns true if the literal is a valid integer.
633633
static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);

libsolidity/experimental/analysis/TypeInference.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ std::optional<rational> rationalValue(Literal const& _literal)
980980
value = *mantissa;
981981

982982
// 0E... is always zero.
983-
if (value == 0)
983+
if (value.operator==(0))
984984
return std::nullopt;
985985

986986
bigint exp = bigint(std::string(expPoint + 1, valueString.end()));

0 commit comments

Comments
 (0)