Skip to content

Commit 6d16ff8

Browse files
committed
MB-68823: Don't throw EPEngine exception to core in StreamReq path
The exception object would be allocated in the EPE domain and then wrongly released in the NoBucketDomain otherwise. All frontend code paths into EPEngine suffer by that potentially (if any path throws). A wider refactor for addressing that is in progress on the master branch. Note that the extra logging introduced in this patch replaces the connection-details logging (provided at core level) that we lose by catching the exception in EPE. Change-Id: Ifacb6fb9970575c2177bbd3d26d85df226dee3e3 Reviewed-on: https://review.couchbase.org/c/kv_engine/+/234445 Well-Formed: Restriction Checker Reviewed-by: Trond Norbye <[email protected]> Tested-by: Build Bot <[email protected]>
1 parent 01991dc commit 6d16ff8

File tree

5 files changed

+93
-2
lines changed

5 files changed

+93
-2
lines changed

daemon/protocol/mcbp/engine_wrapper.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,9 +903,10 @@ cb::engine_errc dcpStreamReq(Cookie& cookie,
903903
json);
904904
if (ret == cb::engine_errc::disconnect) {
905905
LOG_WARNING(
906-
"{}: {} dcp.stream_req returned cb::engine_errc::disconnect",
906+
"{}: dcp.stream_req returned cb::engine_errc::disconnect - "
907+
"Connection {}",
907908
connection.getId(),
908-
connection.getDescription());
909+
connection.to_json().dump());
909910
connection.setTerminationReason("Engine forced disconnect");
910911
}
911912
return ret;

engines/ep/src/ep_engine.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,10 @@ cb::engine_errc EventuallyPersistentEngine::stream_req(
13411341
} catch (const cb::engine_error& e) {
13421342
EP_LOG_INFO("stream_req engine_error {}", e.what());
13431343
return cb::engine_errc(e.code().value());
1344+
} catch (const std::exception& e) {
1345+
EP_LOG_ERR("EventuallyPersistentEngine::stream_req: Exception {}",
1346+
e.what());
1347+
return cb::engine_errc::disconnect;
13441348
}
13451349
}
13461350

tests/testapp/testapp_bucket.cc

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,3 +420,72 @@ TEST_P(BucketTest, MB58598_Connection_ID_clobbered) {
420420
FAIL() << "Timed out waiting for log messages to appear";
421421
}
422422
}
423+
424+
class MemTrackingBucketTest : public BucketTest {
425+
public:
426+
static void SetUpTestCase() {
427+
// Note: Important to set the env BEFORE starting memcached,
428+
// env vars wouldn't be passed to the memcached process otherwise
429+
// (unless testapp is run in -e (embedded) mode)
430+
ASSERT_FALSE(getenv("CB_ARENA_MALLOC_VERIFY_DEALLOC_CLIENT"));
431+
ASSERT_EQ(0, setenv("CB_ARENA_MALLOC_VERIFY_DEALLOC_CLIENT","1", 0));
432+
BucketTest::SetUpTestCase();
433+
}
434+
435+
static void TearDownTestCase() {
436+
EXPECT_EQ(0, unsetenv("CB_ARENA_MALLOC_VERIFY_DEALLOC_CLIENT"));
437+
BucketTest::TearDownTestCase();
438+
}
439+
};
440+
441+
INSTANTIATE_TEST_SUITE_P(TransportProtocols,
442+
MemTrackingBucketTest,
443+
::testing::Values(TransportProtocols::McbpSsl),
444+
::testing::PrintToStringParamName());
445+
446+
TEST_P(MemTrackingBucketTest, MB_68823) {
447+
// Note: Not using adminConnection as the connection in the test is
448+
// forcibly disconnected and we need adminConnection at TearDown.
449+
auto& conn = getConnection();
450+
conn.authenticate("@admin");
451+
conn.selectBucket(bucketName);
452+
conn.setFeature(cb::mcbp::Feature::JSON, true);
453+
conn.setFeature(cb::mcbp::Feature::Collections, true);
454+
conn.dcpOpenProducer("dcp-conn_invalid-stream-req-filter");
455+
conn.dcpControl("enable_noop", "true");
456+
457+
// Invalid StreamReq filter (with cid duplicate) throws in Filter::ctor.
458+
// Before the fix the test fails by:
459+
//
460+
// ===ERROR===: JeArenaMalloc deallocation mismatch
461+
// Memory freed by client:100 domain:None which is assigned arena:0,
462+
// but memory was previously allocated from arena:2 (client-specific
463+
// arena).
464+
// Allocation address:0x10b1b1080 size:192
465+
try {
466+
conn.dcpStreamRequest(Vbid(0),
467+
0, // flags
468+
0, // startSeq
469+
~0, // endSeq,
470+
0, // vbUuid
471+
0, // snapStart
472+
0, // snapEnd
473+
R"({"collections":["0", "0"]})"_json); // filter
474+
} catch (const std::exception&) {
475+
const auto timeout =
476+
std::chrono::steady_clock::now() + std::chrono::seconds{10};
477+
const auto line =
478+
"EventuallyPersistentEngine::stream_req: Exception GSL: "
479+
"Precondition failure: 'emplaced'";
480+
const auto expectedLogInstances = 1;
481+
do {
482+
if (mcd_env->verifyLogLine(line) == expectedLogInstances) {
483+
return;
484+
}
485+
std::this_thread::sleep_for(std::chrono::milliseconds{100});
486+
} while (std::chrono::steady_clock::now() < timeout);
487+
488+
FAIL() << "Timeout before the log line was dumped to the file";
489+
}
490+
FAIL() << "StreamRequest should have failed";
491+
}

tests/testapp/testapp_environment.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,17 @@ class McdEnvironmentImpl : public McdEnvironment {
633633
}
634634
}
635635

636+
size_t verifyLogLine(std::string_view string) const override {
637+
size_t ret = 0;
638+
mcd_env->iterateLogLines([&string, &ret](auto line) {
639+
if (line.find(string) != std::string_view::npos) {
640+
++ret;
641+
}
642+
return true;
643+
});
644+
return ret;
645+
}
646+
636647
private:
637648
const std::filesystem::path test_directory;
638649
const std::filesystem::path isasl_file_name;

tests/testapp/testapp_environment.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,12 @@ class McdEnvironment {
235235
const std::function<bool(std::string_view line)>& callback)
236236
const = 0;
237237

238+
/**
239+
* @param string to search
240+
* @return The number of instances of string in the memcached log file
241+
*/
242+
virtual size_t verifyLogLine(std::string_view string) const = 0;
243+
238244
virtual std::string getLogFilePattern() const = 0;
239245

240246
/// Do we have support for IPv4 addresses on the machine

0 commit comments

Comments
 (0)