NVMeContext: Rework sensor removal concurrent to polling
Concurrent removal of a sensor's configuration while the sensor list is
being iterated for polling can lead to undefined behaviour via access
through a deleted iterator:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count (__r=..., this=<optimised out>, this=<optimised out>, __r=...)
at /usr/include/c++/11.2.0/bits/stl_list.h:224
224 /usr/include/c++/11.2.0/bits/stl_list.h: No such file or directory.
[Current thread is 1 (LWP 6649)]
#0 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count (__r=..., this=<optimised out>, this=<optimised out>, __r=...)
at /usr/include/c++/11.2.0/bits/stl_list.h:224
#1 std::__shared_ptr<NVMeSensor, (__gnu_cxx::_Lock_policy)2>::__shared_ptr (this=<optimised out>, this=<optimised out>)
at /usr/include/c++/11.2.0/bits/shared_ptr_base.h:1152
#2 std::shared_ptr<NVMeSensor>::shared_ptr (this=<optimised out>, this=<optimised out>) at /usr/include/c++/11.2.0/bits/shared_ptr.h:150
#3 NVMeBasicContext::readAndProcessNVMeSensor (this=0x1ac8a90, iter=non-dereferenceable iterator for std::list) at ../git/src/NVMeBasicContext.cpp:299
#4 0x004dd8b8 in NVMeBasicContext::readAndProcessNVMeSensor (this=0x1ac8a90, iter=non-dereferenceable iterator for std::list) at ../git/src/NVMeBasicContext.cpp:312
#5 0x004dd8b8 in NVMeBasicContext::readAndProcessNVMeSensor (this=0x1ac8a90, iter=std::shared_ptr<NVMeSensor> (use count 26, weak count 28153871) = {get() = 0x1ad8db0})
at ../git/src/NVMeBasicContext.cpp:312
Rework polling and sensor removal to uphold the requirement that the
iterator remains valid.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: I69b005fe3dad7ddf21d1762731f9cdfd2408cae1
diff --git a/src/NVMeBasicContext.cpp b/src/NVMeBasicContext.cpp
index 5708ad8..d0ece2c 100644
--- a/src/NVMeBasicContext.cpp
+++ b/src/NVMeBasicContext.cpp
@@ -246,29 +246,28 @@
thread.detach();
}
-void NVMeBasicContext::readAndProcessNVMeSensor(
- std::list<std::shared_ptr<NVMeSensor>>::iterator iter)
+void NVMeBasicContext::readAndProcessNVMeSensor()
{
- if (iter == sensors.end())
+ if (pollCursor == sensors.end())
{
this->pollNVMeDevices();
return;
}
- std::shared_ptr<NVMeSensor> sensor = *iter++;
+ std::shared_ptr<NVMeSensor> sensor = *pollCursor++;
if (!sensor->readingStateGood())
{
sensor->markAvailable(false);
sensor->updateValue(std::numeric_limits<double>::quiet_NaN());
- readAndProcessNVMeSensor(iter);
+ readAndProcessNVMeSensor();
return;
}
/* Potentially defer sampling the sensor sensor if it is in error */
if (!sensor->sample())
{
- readAndProcessNVMeSensor(iter);
+ readAndProcessNVMeSensor();
return;
}
@@ -326,7 +325,7 @@
response->prepare(len);
return len;
},
- [self{shared_from_this()}, iter, sensor, response](
+ [self{shared_from_this()}, sensor, response](
const boost::system::error_code& ec, std::size_t length) mutable {
if (ec)
{
@@ -350,30 +349,30 @@
self->processResponse(sensor, data.data(), data.size());
/* Enqueue processing of the next sensor */
- self->readAndProcessNVMeSensor(iter);
+ self->readAndProcessNVMeSensor();
});
}
void NVMeBasicContext::pollNVMeDevices()
{
- auto scan = sensors.begin();
+ pollCursor = sensors.begin();
scanTimer.expires_from_now(boost::posix_time::seconds(1));
- scanTimer.async_wait([self{shared_from_this()},
- scan](const boost::system::error_code errorCode) {
- if (errorCode == boost::asio::error::operation_aborted)
- {
- return;
- }
+ scanTimer.async_wait(
+ [self{shared_from_this()}](const boost::system::error_code errorCode) {
+ if (errorCode == boost::asio::error::operation_aborted)
+ {
+ return;
+ }
- if (errorCode)
- {
- std::cerr << errorCode.message() << "\n";
- return;
- }
+ if (errorCode)
+ {
+ std::cerr << errorCode.message() << "\n";
+ return;
+ }
- self->readAndProcessNVMeSensor(scan);
- });
+ self->readAndProcessNVMeSensor();
+ });
}
static double getTemperatureReading(int8_t reading)