Skip to content

Outdated document cause in building from source part. #16084

Open
@kiprey-osec

Description

@kiprey-osec

Page

Building from Source

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.

Pull request

#16083

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions