Skip to content

Avoid nested unwind_protect() and unsafe string usage #241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

DavisVaughan
Copy link
Member

We have taken a long hard look at manual usage of unwind_protect() in cpp11 and determined that it is unsafe to use it in a "nested" way. Indeed, if you were to put an Rf_error() call (imitating an R error) inside the unwind_protect() call of fill_one_ngram(), then it causes R to crash. So once thing this PR does is remove the outer unwind_protect() call, which wasn't actually impacting performance much.

In r-lib/cpp11#327 we have some new FAQ recommendations that advise against calling unwind_protect() yourself at all if possible, with the one exception of character vector manipulation, as we have here.

It is fairly hard to call unwind_protect() yourself in a safe way, you have to be careful not to violate these rules:

  • You can't use the cpp11 API inside it
  • You can't throw exceptions
  • You can't create objects that have destructors

We actually violated 2 of these here.

  • std::string objects were being created inside the unwind_protect() and those have destructors. If an R error was thrown from inside the unwind-protect, then that destructor would not be run and you'd get a memory leak. I've worked around this by moving the std::string declaration out of the unwind-protect, which should allow its destructor to always run.
  • Secondly, std::string methods like the + method can throw exceptions in rare cases. One way to avoid this is to use pure C here instead, but that is somewhat difficult, so instead I wrapped the places where exceptions were possible in a try/catch, which avoids throwing the exception across a C stack frame (which is undefined behavior). I tried manually adding in throw std::runtime_error("oh no") and it does indeed catch the exception safely.

I am sending in a new update of cpp11 in soon. I don't think it actually breaks textrecipes, but you should probably try to get this release in sooner rather than later just to be on the safe side (since these problems are present regardless of the version of cpp11 you have)

@EmilHvitfeldt
Copy link
Member

Thank you!

@EmilHvitfeldt EmilHvitfeldt merged commit 7afb6dc into tidymodels:main Jul 28, 2023
@github-actions
Copy link

This pull request has been automatically locked. If you believe you have found a related problem, please file a new issue (with a reprex: https://reprex.tidyverse.org) and link to this issue.

@github-actions github-actions bot locked and limited conversation to collaborators Aug 12, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants