Skip to content

Commit

Permalink
Protect all code against C++ exceptions.
Browse files Browse the repository at this point in the history
  • Loading branch information
cfis committed Nov 27, 2024
1 parent 86fa108 commit 0186461
Showing 1 changed file with 39 additions and 42 deletions.
81 changes: 39 additions & 42 deletions rice/detail/Native.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ namespace Rice::detail
A call from ruby of some_method(1) will exactly match both signatures, but the first one
will be chosen because the parameterMatch will be 1.0 for the first overload but 0.5
for the second. */

Native* native = nullptr;

ID methodId;
Expand All @@ -66,55 +67,51 @@ namespace Rice::detail
rb_raise(rb_eRuntimeError, "Cannot get method id and class for function");
}

const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, methodId);

if (natives.size() == 1)
{
native = natives.front().get();
}
else if (natives.size() == 0)
{
Identifier identifier(methodId);
rb_raise(rb_eArgError, "Could not find method call for %s#%s", rb_class2name(klass), identifier.c_str());
}
else
// Execute the function but make sure to catch any C++ exceptions!
return cpp_protect([&]
{
// Loop over every native to see how well they match the Ruby parameters
std::vector<Resolved> resolves;
std::transform(natives.begin(), natives.end(),
std::back_inserter(resolves),
[&](const std::unique_ptr<Native>& native)
{
return native->matches(argc, argv, self);
});
const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, methodId);

// Now sort from best to worst
std::sort(resolves.begin(), resolves.end(), std::greater{});

// Get the best one
Resolved resolved = resolves.front();

// Did it match?
if (resolved.convertible != Convertible::None)
if (natives.size() == 1)
{
native = resolved.native;
native = natives.front().get();
}
else
else if (natives.size() == 0)
{
Identifier identifier(methodId);
rb_raise(rb_eArgError, "Could not resolve method call for %s#%s", rb_class2name(klass), identifier.c_str());
rb_raise(rb_eArgError, "Could not find method call for %s#%s", rb_class2name(klass), identifier.c_str());
}
}

return native->call(argc, argv, self);
}

inline VALUE Native::call( int argc, VALUE* argv, VALUE self)
{
// Execute the function but make sure to catch any C++ exceptions!
return cpp_protect([&]
else
{
return this->operator()(argc, argv, self);
});
// Loop over every native to see how well they match the Ruby parameters
std::vector<Resolved> resolves;
std::transform(natives.begin(), natives.end(),
std::back_inserter(resolves),
[&](const std::unique_ptr<Native>& native)
{
return native->matches(argc, argv, self);
});

// Now sort from best to worst
std::sort(resolves.begin(), resolves.end(), std::greater{});

// Get the best one
Resolved resolved = resolves.front();

// Did it match?
if (resolved.convertible != Convertible::None)
{
native = resolved.native;
}
else
{
Identifier identifier(methodId);
rb_raise(rb_eArgError, "Could not resolve method call for %s#%s", rb_class2name(klass), identifier.c_str());
}
}

// Call the C++ function
return (*native)(argc, argv, self);
});
}
}

0 comments on commit 0186461

Please sign in to comment.