sol2 icon indicating copy to clipboard operation
sol2 copied to clipboard

usertypes: automatically detected to_string can cause crashes

Open SchweizS opened this issue 4 years ago • 1 comments

Description: if the tostring function is automatically detected, the program crashes if the usertype is printed.

Workarounds:

  • delete the usertype name from the global namespace (haven't run into problems with that in my tests yet)
  • manually define the tostring method and don't define to_string or operator<< or disable the autmatic detection

Error: sol: runtime error: stack index 1, expected userdata, received table: value is not a valid userdata

Other Info:

  • Windows (10.0.19042)
  • C++ ( /std:c++latest)
  • Visual Studio 16.10.0
  • cl Version 19.29.30037

Minimal Example:

#include <sol/sol.hpp>
struct TestStruct {
  std::string to_string() const { return "to_string"; }
};
int main() {
	sol::state s;
	s.open_libraries(sol::lib::base);
	s.new_usertype<TestStruct>("__TEST");
	 s.script("print( __TEST)");
	return 0;
}

Example:

#include <sol/sol.hpp>
#include <ostream>
#include <type_traits>
#include <iostream>

template<int N>
struct TestStruct {
	template<int E = N, std::enable_if_t<E == 1, int> = 0>
	std::string to_string() const { return "to_string"; }

	template<int E = N, std::enable_if_t<E == 2 || E == 3, int> = 0>
	friend std::ostream& operator<<(std::ostream& os, const TestStruct&) { os << "operator<<"; return os; }

	std::string ToString() const { return "ToString"; }
};

template<int N>
void test() {
	sol::state s;
	s.open_libraries(sol::lib::base);

	auto meta = s.new_usertype<TestStruct<N>>("__TEST", sol::no_constructor);
	if constexpr (N == 4) {
		meta["__tostring"] = &TestStruct<N>::ToString;
	}
	if constexpr (N == 3) {
		s["__TEST"] = nullptr;
	}
	s["TEST"] = TestStruct<N>{};

	try {
		std::cout << "\n\n\n";
		auto res = s.script("print('TEST', TEST)print('__TEST', __TEST)");
		if (!res.valid()) {
			sol::error err = res;
			std::cout << N << " " << err.what() << "\n";
		}
		else {
			std::cout << N << " OK!\n";
		}
	}
	catch (const sol::error& err) {
		std::cout << N << " !Exception! " << err.what() << "\n";
	}
}
int main() {
	test<1>();
	test<2>();
	test<3>();
	test<4>();
}

SchweizS avatar Jun 17 '21 02:06 SchweizS

Ah, this looks like it might be calling to_string on the special table itself. Which is wrong. I can see the problem at least in my head, now I gotta fix it..

ThePhD avatar Jun 19 '21 12:06 ThePhD