Consider protecting Context (pre-)shutdown callback interface against use-after-frees
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 805
- Forks
- 564
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 27
Description
Bug report
Required Info:
- Operating System:
- All
- Installation type:
- All
- Version or commit hash:
- HEAD
- DDS implementation:
- ALl
- Client library (if applicable):
- rclcpp
Steps to reproduce issue
It's possible to create a Context shutdown callback using an std::bind to a class instance. If that instance is freed, the callback
can later fire and seg fault.
Example:
context->add_pre_shutdown_callback(
std::bind(&LifecycleNode::on_rcl_preshutdown, this))
Feature request
Feature description
To be sure, the user should not allow the instance to be freed until the callback is removed. They could e.g. add the cb removal in the destructor.
@SteveMacenski recommended we consider a pattern on the callback side to try preventing segfaults when somebody makes such mistakes, or to make the mistake clear via e.g. an exception. As such, this is a feature request towards that end.
We may be able to make another interface where a different type of cb handle is returned. That new type automatically removes the cb in its destructor. It holds a ptr back to the callback handle we are using today today. Then the user would need to keep the handle around, and it could be removed in the automatic destruction process of an instance containing it (rather than needing to update dtor code to do it, since the user may mistakenly forget). If the user fails to keep the this new type of handle around, the dtor will fire automatically and the cb will never be used (which should be pretty obvious).
A clearer protection may be something like add_pre_shutdown_callback_safe where the user passes a shared_ptr to the ShutdownCallbackType type object instead of us making a new shared_ptr in the Context code (see Context::add_shutdown_callback), and to check the corresponding weak_ptr for expiration. If it expires before we call the callback, we raise an exception or log instead of calling the now-freed thing.
Anyways, consider whether we want to make some segfault protections here somehow.
Expected behavior
No seg faults in the shutdown callback path.
Actual behavior
Context shutdown callback ptr can point to freed thing, causing segfaults.
Additional information
Implementation considerations
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading Context::add_shutdown_callback and the add_pre_shutdown_callback usage with std::bind to understand callback lifetime and removal. Compare the proposed automatic handle and shared_ptr/weak_ptr approaches, then define an agreed interface whose shutdown path cannot call a freed instance and document or test the expected behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100