wlav / cppyy

Other
407 stars 42 forks source link

Segfault with std::forward invocation #19

Open saraedum opened 3 years ago

saraedum commented 3 years ago

A segfault showed up for me when upgrading flatsurf from cppyy 1.9.* to 2.1.0.

The problem seems to be related to move semantics and std::forward.

import cppyy

cppyy.include('gmpxx.h')

cppyy.load_library('gmp')
cppyy.load_library('gmpxx')

cppyy.cppdef(r'''
struct V {
    V(mpq_class&& x, mpq_class&& y): x(std::move(x)), y(std::move(y)) {}
    template <typename X, typename Y, std::enable_if_t<!std::is_convertible_v<X, mpq_class> || !std::is_convertible_v<Y, mpq_class>, int> = 0>
    V(X&& x, Y&& y): V(static_cast<mpq_class>(std::forward<X>(x)), static_cast<mpq_class>(std::forward<Y>(y))) {}

    mpq_class x,y;
};
''')

cppyy.cppdef(r'''
V f() {
    return V(0, mpq_class{});
}
''')

print(cppyy.gbl.f()) # works

def f():
    return cppyy.gbl.V(0, cppyy.gbl.mpq_class())

print(f()) # prints, then segfaults.

I might be doing something wrong here somehow but this used to work with older versions of cppyy.

I am seeing the segfault with the latest version of cppyy from conda-forge on Linux.

wlav commented 3 years ago

The Python code picks the second ctor, whereas the C++ call picks the first. To select the first also in Python, cppyy.gbl.V(0, cppyy.gbl.std.move(cppyy.gbl.mpq_class())) does the trick.

The problem appears to be that the template resolves to T*&& args, not T&&.

This is once more the trouble with Cling not providing any details what the template looks like, but only allowing to try guesses. That 0 means that typename X is going to map to int and things go downhill from there. Upstream is working on improving that, but it's going slow.