Fix PIDControllerRunner member destruction order (#1801)

The mutexes in PIDControllerRunner are declared after the Notifier, and
when the PIDControllerRunner object is destructed, the member object
destructors are called in the reverse order in which they are declared.
The mutexes are destructed first, then the Notifier destructor is called
which stops the Notifier.

There's a window between those destructor calls during which the
Notifier can run the callable and attempt to lock a mutex that no longer
exists.

Declaring the Notifier after all the variables its callable uses fixes
this issue, as it ensures the Notifier is destructed first.
This commit is contained in:
Tyler Veness
2019-08-03 14:58:10 -07:00
committed by Peter Johnson
parent c98ca7310f
commit 8e93ce8929
2 changed files with 12 additions and 2 deletions

View File

@@ -55,7 +55,6 @@ class PIDControllerRunner : SendableBase {
void InitSendable(SendableBuilder& builder) override;
private:
Notifier m_notifier{&PIDControllerRunner::Run, this};
frc2::PIDController& m_controller;
std::function<double(void)> m_measurementSource;
std::function<void(double)> m_controllerOutput;
@@ -67,6 +66,12 @@ class PIDControllerRunner : SendableBase {
// Controller::Update() is already running at that time.
mutable wpi::mutex m_outputMutex;
// This is declared after all other member variables so that during
// PIDControllerRunner destruction, the Notifier is stopped before any member
// variables its callable uses are destructed. This avoids use-after-free
// bugs like crashes when locking is attempted on deallocated mutexes.
Notifier m_notifier{&PIDControllerRunner::Run, this};
void Run();
};