Skip to content

Commit fdf5a70

Browse files
abhinavdangetichiyoung
authored andcommitted
Address heap use after free issue in Dcp BackfillManager
21:23:11 WARNING: ThreadSanitizer: heap-use-after-free (pid=8561) 21:23:11 Read of size 8 at 0x7d240000d6a8 by thread T15: 21:23:11 #0 BackfillManager::backfill() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/dcp/backfill-manager.cc:250 (ep.so+0x00000004f35a) 21:23:11 couchbase#1 BackfillManagerTask::run() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/dcp/backfill-manager.cc:43 (ep.so+0x00000004ee6f) 21:23:11 couchbase#2 ExecutorThread::run() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/executorthread.cc:115 (ep.so+0x0000000f1736) 21:23:11 couchbase#3 launch_executor_thread(void*) /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/executorthread.cc:33 (ep.so+0x0000000f12e5) 21:23:11 couchbase#4 platform_thread_wrap(void*) /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/platform/src/cb_pthreads.cc:54 (libplatform.so.0.1.0+0x00000000551b) 21:23:11 21:23:11 Previous write of size 8 at 0x7d240000d6a8 by thread T15: 21:23:11 #0 operator delete(void*) <null> (engine_testapp+0x00000046485b) 21:23:11 couchbase#1 DcpProducer::~DcpProducer() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/dcp/producer.cc:167 (ep.so+0x00000006377b) 21:23:11 couchbase#2 DcpProducer::~DcpProducer() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/dcp/producer.cc:165 (ep.so+0x000000063a45) 21:23:11 couchbase#3 ActiveStream::~ActiveStream() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/atomic.h:272 (ep.so+0x00000006ed6d) 21:23:11 couchbase#4 ActiveStream::~ActiveStream() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/dcp/stream.cc:200 (ep.so+0x00000006f8b5) 21:23:11 couchbase#5 BackfillManager::backfill() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/atomic.h:272 (ep.so+0x00000004f345) 21:23:11 #6 BackfillManagerTask::run() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/dcp/backfill-manager.cc:43 (ep.so+0x00000004ee6f) 21:23:11 #7 ExecutorThread::run() /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/executorthread.cc:115 (ep.so+0x0000000f1736) 21:23:11 #8 launch_executor_thread(void*) /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/ep-engine/src/executorthread.cc:33 (ep.so+0x0000000f12e5) 21:23:11 #9 platform_thread_wrap(void*) /home/couchbase/jenkins/workspace/ep-engine-threadsanitizer-master/platform/src/cb_pthreads.cc:54 (libplatform.so.0.1.0+0x00000000551b) Change-Id: I3c63215791c23de49b5304654115fd4c558a3328 Reviewed-on: http://review.couchbase.org/58619 Tested-by: buildbot <build@couchbase.com> Reviewed-by: Chiyoung Seo <chiyoung@couchbase.com>
1 parent 1d92be0 commit fdf5a70

7 files changed

Lines changed: 49 additions & 23 deletions

File tree

src/connmap.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,7 @@ void DcpConnMap::notifyBackfillManagerTasks() {
12141214
for (; itr != map_.end(); ++itr) {
12151215
DcpProducer* producer = dynamic_cast<DcpProducer*> (itr->second.get());
12161216
if (producer) {
1217-
producer->getBackfillManager()->wakeUpTask();
1217+
producer->notifyBackfillManager();
12181218
}
12191219
}
12201220
}

src/dcp/backfill-manager.cc

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ static const size_t sleepTime = 1;
2626

2727
class BackfillManagerTask : public GlobalTask {
2828
public:
29-
BackfillManagerTask(EventuallyPersistentEngine* e, BackfillManager* mgr,
29+
BackfillManagerTask(EventuallyPersistentEngine* e, backfill_manager_t mgr,
3030
const Priority &p, double sleeptime = 0,
31-
bool shutdown = false)
32-
: GlobalTask(e, p, sleeptime, shutdown), manager(mgr) {}
31+
bool completeBeforeShutdown = false)
32+
: GlobalTask(e, p, sleeptime, completeBeforeShutdown), manager(mgr) {}
3333

3434
bool run();
3535

3636
std::string getDescription();
3737

3838
private:
39-
BackfillManager* manager;
39+
backfill_manager_t manager;
4040
};
4141

4242
bool BackfillManagerTask::run() {
@@ -88,10 +88,6 @@ void BackfillManager::addStats(connection_t conn, ADD_STAT add_stat,
8888
}
8989

9090
BackfillManager::~BackfillManager() {
91-
if (managerTask) {
92-
managerTask->cancel();
93-
}
94-
9591
while (!activeBackfills.empty()) {
9692
DCPBackfill* backfill = activeBackfills.front();
9793
activeBackfills.pop_front();
@@ -116,6 +112,15 @@ BackfillManager::~BackfillManager() {
116112
}
117113
}
118114

115+
void BackfillManager::terminate() {
116+
LockHolder lh(lock);
117+
if (managerTask) {
118+
managerTask->cancel();
119+
managerTask.reset();
120+
}
121+
}
122+
123+
119124
void BackfillManager::schedule(stream_t stream, uint64_t start, uint64_t end) {
120125
LockHolder lh(lock);
121126
if (engine->getDcpConnMap().canAddBackfillToActiveQ()) {

src/dcp/backfill-manager.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727

2828
class EventuallyPersistentEngine;
2929

30-
class BackfillManager {
30+
class BackfillManager : public RCValue {
3131
public:
3232
BackfillManager(EventuallyPersistentEngine* e);
3333

3434
~BackfillManager();
3535

36+
void terminate();
37+
3638
void addStats(connection_t conn, ADD_STAT add_stat, const void *c);
3739

3840
void schedule(stream_t stream, uint64_t start, uint64_t end);

src/dcp/dcp-types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@ typedef SingleThreadedRCPtr<Stream> stream_t;
4040
// Implementation defined in dcp/stream.h
4141
class PassiveStream;
4242
typedef RCPtr<PassiveStream> passive_stream_t;
43+
44+
// Implementation defined in dcp/backfill-manager.h
45+
class BackfillManager;
46+
typedef RCPtr<BackfillManager> backfill_manager_t;

src/dcp/producer.cc

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ DcpProducer::DcpProducer(EventuallyPersistentEngine &e, const void *cookie,
163163
}
164164

165165
DcpProducer::~DcpProducer() {
166+
backfillMgr->terminate();
166167
delete rejectResp;
167-
delete backfillMgr;
168168
}
169169

170170
ENGINE_ERROR_CODE DcpProducer::streamRequest(uint32_t flags,
@@ -652,6 +652,23 @@ ENGINE_ERROR_CODE DcpProducer::closeStream(uint32_t opaque, uint16_t vbucket) {
652652
return ret;
653653
}
654654

655+
void DcpProducer::notifyBackfillManager() {
656+
backfillMgr->wakeUpTask();
657+
}
658+
659+
bool DcpProducer::recordBackfillManagerBytesRead(uint32_t bytes) {
660+
return backfillMgr->bytesRead(bytes);
661+
}
662+
663+
void DcpProducer::recordBackfillManagerBytesSent(uint32_t bytes) {
664+
backfillMgr->bytesSent(bytes);
665+
}
666+
667+
void DcpProducer::scheduleBackfillManager(stream_t s,
668+
uint64_t start, uint64_t end) {
669+
backfillMgr->schedule(s, start, end);
670+
}
671+
655672
void DcpProducer::addStats(ADD_STAT add_stat, const void *c) {
656673
Producer::addStats(add_stat, c);
657674

@@ -671,9 +688,7 @@ void DcpProducer::addStats(ADD_STAT add_stat, const void *c) {
671688
supportsCursorDropping ? "ELIGIBLE" : "NOT_ELIGIBLE",
672689
add_stat, c);
673690

674-
if (backfillMgr) {
675-
backfillMgr->addStats(this, add_stat, c);
676-
}
691+
backfillMgr->addStats(this, add_stat, c);
677692

678693
log.addStats(add_stat, c);
679694

src/dcp/producer.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,10 @@ class DcpProducer : public Producer {
107107

108108
void notifyStreamReady(uint16_t vbucket, bool schedule);
109109

110-
BackfillManager* getBackfillManager() {
111-
return backfillMgr;
112-
}
110+
void notifyBackfillManager();
111+
bool recordBackfillManagerBytesRead(uint32_t bytes);
112+
void recordBackfillManagerBytesSent(uint32_t bytes);
113+
void scheduleBackfillManager(stream_t s, uint64_t start, uint64_t end);
113114

114115
bool isExtMetaDataEnabled () {
115116
return enableExtMetaData;
@@ -230,7 +231,7 @@ class DcpProducer : public Producer {
230231
Couchbase::RelaxedAtomic<rel_time_t> lastSendTime;
231232
BufferLog log;
232233

233-
BackfillManager* backfillMgr;
234+
backfill_manager_t backfillMgr;
234235

235236
// Guards all accesses to streams map. If only reading elements in streams
236237
// (i.e. not adding / removing elements) then can acquire ReadLock, even

src/dcp/stream.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ bool ActiveStream::backfillReceived(Item* itm, backfill_source_t backfill_source
314314
}
315315
LockHolder lh(streamMutex);
316316
if (state_ == STREAM_BACKFILLING) {
317-
if (!producer->getBackfillManager()->bytesRead(itm->size())) {
317+
if (!producer->recordBackfillManagerBytesRead(itm->size())) {
318318
delete itm;
319319
return false;
320320
}
@@ -425,7 +425,7 @@ DcpResponse* ActiveStream::backfillPhase() {
425425
resp->getEvent() == DCP_DELETION ||
426426
resp->getEvent() == DCP_EXPIRATION)) {
427427
MutationResponse* m = static_cast<MutationResponse*>(resp);
428-
producer->getBackfillManager()->bytesSent(m->getItem()->size());
428+
producer->recordBackfillManagerBytesSent(m->getItem()->size());
429429
bufferedBackfill.bytes.fetch_sub(m->getItem()->size());
430430
bufferedBackfill.items--;
431431
if (backfillRemaining.load(std::memory_order_relaxed) > 0) {
@@ -740,7 +740,7 @@ void ActiveStream::endStream(end_stream_status_t reason) {
740740
// If Stream were in Backfilling state, clear out the
741741
// backfilled items to clear up the backfill buffer.
742742
clear_UNLOCKED();
743-
producer->getBackfillManager()->bytesSent(bufferedBackfill.bytes);
743+
producer->recordBackfillManagerBytesSent(bufferedBackfill.bytes);
744744
bufferedBackfill.bytes = 0;
745745
bufferedBackfill.items = 0;
746746
}
@@ -801,8 +801,7 @@ void ActiveStream::scheduleBackfill() {
801801
bool tryBackfill = isFirstItem || flags_ & DCP_ADD_STREAM_FLAG_DISKONLY;
802802

803803
if (backfillStart <= backfillEnd && tryBackfill) {
804-
BackfillManager* backfillMgr = producer->getBackfillManager();
805-
backfillMgr->schedule(this, backfillStart, backfillEnd);
804+
producer->scheduleBackfillManager(this, backfillStart, backfillEnd);
806805
isBackfillTaskRunning.store(true);
807806
} else {
808807
if (flags_ & DCP_ADD_STREAM_FLAG_DISKONLY) {

0 commit comments

Comments
 (0)