@@ -359,3 +359,72 @@ TEST_P(BucketTest, DeleteSelectedBucket) {
359359 adminConnection->selectBucket (" bucket" );
360360 deleteBucket (*adminConnection, " bucket" , [](const std::string&) {});
361361}
362+
363+ class MemTrackingBucketTest : public BucketTest {
364+ public:
365+ static void SetUpTestCase () {
366+ // Note: Important to set the env BEFORE starting memcached,
367+ // env vars wouldn't be passed to the memcached process otherwise
368+ // (unless testapp is run in -e (embedded) mode)
369+ ASSERT_FALSE (getenv (" CB_ARENA_MALLOC_VERIFY_DEALLOC_CLIENT" ));
370+ ASSERT_EQ (0 , setenv (" CB_ARENA_MALLOC_VERIFY_DEALLOC_CLIENT" , " 1" , 0 ));
371+ BucketTest::SetUpTestCase ();
372+ }
373+
374+ static void TearDownTestCase () {
375+ EXPECT_EQ (0 , unsetenv (" CB_ARENA_MALLOC_VERIFY_DEALLOC_CLIENT" ));
376+ BucketTest::TearDownTestCase ();
377+ }
378+ };
379+
380+ INSTANTIATE_TEST_SUITE_P (TransportProtocols,
381+ MemTrackingBucketTest,
382+ ::testing::Values (TransportProtocols::McbpSsl),
383+ ::testing::PrintToStringParamName());
384+
385+ TEST_P (MemTrackingBucketTest, MB_68823) {
386+ // Note: Not using adminConnection as the connection in the test is
387+ // forcibly disconnected and we need adminConnection at TearDown.
388+ auto & conn = getConnection ();
389+ conn.authenticate (" @admin" );
390+ conn.selectBucket (bucketName);
391+ conn.setFeature (cb::mcbp::Feature::JSON, true );
392+ conn.setFeature (cb::mcbp::Feature::Collections, true );
393+ conn.dcpOpenProducer (" dcp-conn_invalid-stream-req-filter" );
394+ conn.dcpControl (" enable_noop" , " true" );
395+
396+ // Invalid StreamReq filter (with cid duplicate) throws in Filter::ctor.
397+ // Before the fix the test fails by:
398+ //
399+ // ===ERROR===: JeArenaMalloc deallocation mismatch
400+ // Memory freed by client:100 domain:None which is assigned arena:0,
401+ // but memory was previously allocated from arena:2 (client-specific
402+ // arena).
403+ // Allocation address:0x10b1b1080 size:192
404+ try {
405+ conn.dcpStreamRequest (Vbid (0 ),
406+ cb::mcbp::DcpAddStreamFlag::None,
407+ 0 , // startSeq
408+ ~0 , // endSeq,
409+ 0 , // vbUuid
410+ 0 , // snapStart
411+ 0 , // snapEnd
412+ R"( {"collections":["0", "0"]})" _json); // filter
413+ } catch (const std::exception&) {
414+ const auto timeout =
415+ std::chrono::steady_clock::now () + std::chrono::seconds{10 };
416+ const auto line =
417+ " EventuallyPersistentEngine::stream_req: Exception GSL: "
418+ " Precondition failure: 'emplaced'" ;
419+ const auto expectedLogInstances = 1 ;
420+ do {
421+ if (mcd_env->verifyLogLine (line) == expectedLogInstances) {
422+ return ;
423+ }
424+ std::this_thread::sleep_for (std::chrono::milliseconds{100 });
425+ } while (std::chrono::steady_clock::now () < timeout);
426+
427+ FAIL () << " Timeout before the log line was dumped to the file" ;
428+ }
429+ FAIL () << " StreamRequest should have failed" ;
430+ }
0 commit comments