Description
Page
Abstract
The v0.8.30 solidity docs say that building from source needs at least Boost 1.67 and GCC 11+ on non-Windows systems.
But this part of document is outdated. And there exists a stack overflow bug due to infinite recursion, triggered specifically when an outdated version of G++ and an outdated Boost library are used together to compile Solidity source code.
Let me explain it step by step. Consider the following C++ code, clang++ correctly chooses rational::operator==
according to the C++ standard, but versions of g++ prior to 14 may incorrectly prefer operator==(const rational<>&a, ...)
due to implementation issues.
#include <iostream>
template <typename IntType>
class rational
{
public:
template <class T>
bool operator== (const T& i) const
{
std::cout << "clang++ resolve" << std::endl;
return true;
}
};
template <class Arg, class IntType>
bool operator == (const rational<IntType>& a, const Arg& b)
{
std::cout << "g++ <14 resolve" << std::endl;
return false;
}
int main() {
rational<int> lengthValue;
return lengthValue == 0;
}
Then, C++20 introduced the spaceship operator (operator<=>
). If you define operator==(T1, T2)
, the compiler automatically reverses the arguments for T2 == T1
to reuse that operator. This means that if you replace the above non-member function operator==
with the following code, the program compiled with -std=c++20
through g++<14 will recursively call itself under the C++20 standard (C++17 is not affected):
template <class Arg, class IntType>
bool operator == (const Arg& b, const rational<IntType>& a)
{
return a == b;
}
Unfortunately, this code pattern existed in Boost versions prior to 1.75. You can easily trigger SEGV with following code.
// g++ -std=c++20 main.cpp -o main && ./main
#include <boost/rational.hpp>
int main() {
boost::rational<int> r;
return r == 0;
}
And this code pattern above also exists in solidity, while solidity enabled C++20 standard at 2025.01.28 but did not update the document accordingly.
void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
{
...
if (Expression const* length = _typeName.length())
{
std::optional<rational> lengthValue; // <-------- [0]
if (length->annotation().type && length->annotation().type->category() == Type::Category::RationalNumber)
...
else if (std::optional<ConstantEvaluator::TypedRational> value = ConstantEvaluator::evaluate(m_errorReporter, *length))
lengthValue = value->value; // <------------- [1]
if (!lengthValue)
m_errorReporter.typeError(
5462_error,
length->location(),
"Invalid array length, expected integer literal or constant expression."
);
else if (*lengthValue == 0) // <--------------- [2]
m_errorReporter.typeError(1406_error, length->location(), "Array with zero length specified.");
...
...
}
...
}
Ubuntu 22.04 provides G++ version 11.4.0 and Boost library version 1.74.0 by default. So this solidity bug would be triggered easily under Ubuntu 22.04.