-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Ethereum capability work loop can be cancelled prematurely #5508
Description
Ethereum capabilities make use of boost deadline timers to schedule their work loop via Host::scheduleExecution - for example:
aleth/libethereum/EthereumCapability.cpp
Lines 413 to 417 in 9e5a853
| void EthereumCapability::onStarting() | |
| { | |
| m_backgroundWorkEnabled = true; | |
| m_host->scheduleExecution(c_backroundWorkPeriodMs, [this]() { doBackgroundWork(); }); | |
| } |
...and in EthereumCapability::doBackgroundWork:
aleth/libethereum/EthereumCapability.cpp
Lines 488 to 490 in 9e5a853
| if (m_backgroundWorkEnabled) | |
| m_host->scheduleExecution(c_backroundWorkPeriodMs, [this]() { doBackgroundWork(); }); | |
| } |
Note that Host's usage of deadline timers is susceptible to a race condition - Host::scheduleExecution creates a new timer, adds it to a list, and performs an async_wait on it. The host then "garbage collects" expired timers in Host::run, and it determines if a timer is expired by checking its expiration time:
Lines 687 to 692 in 9e5a853
| DEV_GUARDED(x_networkTimers) | |
| { | |
| m_networkTimers.remove_if([](unique_ptr<io::deadline_timer> const& t) { | |
| return t->expires_from_now().total_milliseconds() < 0; | |
| }); | |
| } |
However, note that when a timer expires, its handler is put into a queue rather than being executed immediately - this means that there's a race condition where a handler can be executed after the timer has been deleted, resulting in the handler being executed with boost error code operation_aborted, which will result in the handler immediately exiting without executing any of its core logic.