Browse Source

Potential fix for EthashAux race condition

Some EthashAux functions are protected by mutexes. These mutexes are
normal members of the EthashAux class which itself is a singleton. It
can happen that multiple threads will get inside the singleton creation
`get()` functions when requesting a lock, but the lock will not be
acquired due to the singleton not yet existing.

This leads to multiple threads going in the same code and causing double
free corruption.

Making the mutexes static members of the singleton should hopefully
address the issue
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
04aa9867f5
  1. 17
      libethcore/EthashAux.cpp
  2. 6
      libethcore/EthashAux.h

17
libethcore/EthashAux.cpp

@ -44,6 +44,9 @@ using namespace eth;
const char* DAGChannel::name() { return EthGreen "DAG"; }
EthashAux* dev::eth::EthashAux::s_this = nullptr;
SharedMutex dev::eth::EthashAux::x_lights;
Mutex dev::eth::EthashAux::x_epochs;
Mutex dev::eth::EthashAux::x_fulls;
EthashAux::~EthashAux()
{
@ -62,7 +65,7 @@ uint64_t EthashAux::dataSize(uint64_t _blockNumber)
h256 EthashAux::seedHash(unsigned _number)
{
unsigned epoch = _number / ETHASH_EPOCH_LENGTH;
Guard l(get()->x_epochs);
Guard l(x_epochs);
if (epoch >= get()->m_seedHashes.size())
{
h256 ret;
@ -85,7 +88,7 @@ h256 EthashAux::seedHash(unsigned _number)
uint64_t EthashAux::number(h256 const& _seedHash)
{
Guard l(get()->x_epochs);
Guard l(x_epochs);
unsigned epoch = 0;
auto epochIter = get()->m_epochs.find(_seedHash);
if (epochIter == get()->m_epochs.end())
@ -112,7 +115,7 @@ void EthashAux::killCache(h256 const& _s)
EthashAux::LightType EthashAux::light(h256 const& _seedHash)
{
ReadGuard l(get()->x_lights);
ReadGuard l(x_lights);
LightType ret = get()->m_lights[_seedHash];
return ret ? ret : (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash));
}
@ -170,7 +173,7 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing
FullType ret;
auto l = light(_seedHash);
DEV_GUARDED(get()->x_fulls)
DEV_GUARDED(x_fulls)
if ((ret = get()->m_fulls[_seedHash].lock()))
{
get()->m_lastUsedFull = ret;
@ -184,7 +187,7 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing
ret = make_shared<FullAllocation>(l->light, dagCallbackShim);
// cnote << "Done loading.";
DEV_GUARDED(get()->x_fulls)
DEV_GUARDED(x_fulls)
get()->m_fulls[_seedHash] = get()->m_lastUsedFull = ret;
}
@ -195,7 +198,7 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing
unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
{
Guard l(get()->x_fulls);
Guard l(x_fulls);
uint64_t blockNumber;
DEV_IF_THROWS(blockNumber = EthashAux::number(_seedHash))
@ -248,7 +251,7 @@ Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce)
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
{
DEV_GUARDED(get()->x_fulls)
DEV_GUARDED(x_fulls)
if (FullType dag = get()->m_fulls[_seedHash].lock())
return dag->compute(_headerHash, _nonce);
DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))

6
libethcore/EthashAux.h

@ -91,10 +91,10 @@ private:
static EthashAux* s_this;
SharedMutex x_lights;
static SharedMutex x_lights;
std::unordered_map<h256, std::shared_ptr<LightAllocation>> m_lights;
Mutex x_fulls;
static Mutex x_fulls;
std::condition_variable m_fullsChanged;
std::unordered_map<h256, std::weak_ptr<FullAllocation>> m_fulls;
FullType m_lastUsedFull;
@ -102,7 +102,7 @@ private:
uint64_t m_generatingFullNumber = NotGenerating;
unsigned m_fullProgress;
Mutex x_epochs;
static Mutex x_epochs;
std::unordered_map<h256, unsigned> m_epochs;
h256s m_seedHashes;
};

Loading…
Cancel
Save