fix shared state used after free (#11059)

Summary:
Before this pr,  the destruction order is `shared` -> `db_`(StressTest destruction) -> `stress`, but `compaction_filter` of `db_` will hold the `shared` pointer, so `shared` maybe used after free.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11059

Reviewed By: hx235

Differential Revision: D42297366

Pulled By: ajkr

fbshipit-source-id: 17b314635359acacd5ba62f9db5f955f451133f7
oxigraph-8.1.1
ehds 2 years ago committed by Facebook GitHub Bot
parent b965a5a80e
commit 4737e1d41b
  1. 63
      db_stress_tool/db_stress_driver.cc
  2. 3
      db_stress_tool/db_stress_driver.h
  3. 6
      db_stress_tool/db_stress_tool.cc

@ -56,12 +56,11 @@ void ThreadBody(void* v) {
} }
} }
bool RunStressTest(StressTest* stress) { bool RunStressTest(SharedState* shared) {
SystemClock* clock = db_stress_env->GetSystemClock().get(); SystemClock* clock = db_stress_env->GetSystemClock().get();
StressTest* stress = shared->GetStressTest();
SharedState shared(db_stress_env, stress); if (shared->ShouldVerifyAtBeginning() && FLAGS_preserve_unverified_changes) {
if (shared.ShouldVerifyAtBeginning() && FLAGS_preserve_unverified_changes) {
Status s = InitUnverifiedSubdir(FLAGS_db); Status s = InitUnverifiedSubdir(FLAGS_db);
if (s.ok() && !FLAGS_expected_values_dir.empty()) { if (s.ok() && !FLAGS_expected_values_dir.empty()) {
s = InitUnverifiedSubdir(FLAGS_expected_values_dir); s = InitUnverifiedSubdir(FLAGS_expected_values_dir);
@ -73,8 +72,8 @@ bool RunStressTest(StressTest* stress) {
} }
} }
stress->InitDb(&shared); stress->InitDb(shared);
stress->FinishInitDb(&shared); stress->FinishInitDb(shared);
if (FLAGS_sync_fault_injection) { if (FLAGS_sync_fault_injection) {
fault_fs_guard->SetFilesystemDirectWritable(false); fault_fs_guard->SetFilesystemDirectWritable(false);
@ -88,28 +87,28 @@ bool RunStressTest(StressTest* stress) {
fprintf(stdout, "%s Initializing worker threads\n", fprintf(stdout, "%s Initializing worker threads\n",
clock->TimeToString(now / 1000000).c_str()); clock->TimeToString(now / 1000000).c_str());
shared.SetThreads(n); shared->SetThreads(n);
if (FLAGS_compaction_thread_pool_adjust_interval > 0) { if (FLAGS_compaction_thread_pool_adjust_interval > 0) {
shared.IncBgThreads(); shared->IncBgThreads();
} }
if (FLAGS_continuous_verification_interval > 0) { if (FLAGS_continuous_verification_interval > 0) {
shared.IncBgThreads(); shared->IncBgThreads();
} }
std::vector<ThreadState*> threads(n); std::vector<ThreadState*> threads(n);
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
threads[i] = new ThreadState(i, &shared); threads[i] = new ThreadState(i, shared);
db_stress_env->StartThread(ThreadBody, threads[i]); db_stress_env->StartThread(ThreadBody, threads[i]);
} }
ThreadState bg_thread(0, &shared); ThreadState bg_thread(0, shared);
if (FLAGS_compaction_thread_pool_adjust_interval > 0) { if (FLAGS_compaction_thread_pool_adjust_interval > 0) {
db_stress_env->StartThread(PoolSizeChangeThread, &bg_thread); db_stress_env->StartThread(PoolSizeChangeThread, &bg_thread);
} }
ThreadState continuous_verification_thread(0, &shared); ThreadState continuous_verification_thread(0, shared);
if (FLAGS_continuous_verification_interval > 0) { if (FLAGS_continuous_verification_interval > 0) {
db_stress_env->StartThread(DbVerificationThread, db_stress_env->StartThread(DbVerificationThread,
&continuous_verification_thread); &continuous_verification_thread);
@ -120,12 +119,12 @@ bool RunStressTest(StressTest* stress) {
// wait for others to operate -> verify -> done // wait for others to operate -> verify -> done
{ {
MutexLock l(shared.GetMutex()); MutexLock l(shared->GetMutex());
while (!shared.AllInitialized()) { while (!shared->AllInitialized()) {
shared.GetCondVar()->Wait(); shared->GetCondVar()->Wait();
} }
if (shared.ShouldVerifyAtBeginning()) { if (shared->ShouldVerifyAtBeginning()) {
if (shared.HasVerificationFailedYet()) { if (shared->HasVerificationFailedYet()) {
fprintf(stderr, "Crash-recovery verification failed :(\n"); fprintf(stderr, "Crash-recovery verification failed :(\n");
} else { } else {
fprintf(stdout, "Crash-recovery verification passed :)\n"); fprintf(stdout, "Crash-recovery verification passed :)\n");
@ -144,17 +143,17 @@ bool RunStressTest(StressTest* stress) {
// This is after the verification step to avoid making all those `Get()`s // This is after the verification step to avoid making all those `Get()`s
// and `MultiGet()`s contend on the DB-wide trace mutex. // and `MultiGet()`s contend on the DB-wide trace mutex.
if (!FLAGS_expected_values_dir.empty()) { if (!FLAGS_expected_values_dir.empty()) {
stress->TrackExpectedState(&shared); stress->TrackExpectedState(shared);
} }
now = clock->NowMicros(); now = clock->NowMicros();
fprintf(stdout, "%s Starting database operations\n", fprintf(stdout, "%s Starting database operations\n",
clock->TimeToString(now / 1000000).c_str()); clock->TimeToString(now / 1000000).c_str());
shared.SetStart(); shared->SetStart();
shared.GetCondVar()->SignalAll(); shared->GetCondVar()->SignalAll();
while (!shared.AllOperated()) { while (!shared->AllOperated()) {
shared.GetCondVar()->Wait(); shared->GetCondVar()->Wait();
} }
now = clock->NowMicros(); now = clock->NowMicros();
@ -169,10 +168,10 @@ bool RunStressTest(StressTest* stress) {
clock->TimeToString((uint64_t)now / 1000000).c_str()); clock->TimeToString((uint64_t)now / 1000000).c_str());
} }
shared.SetStartVerify(); shared->SetStartVerify();
shared.GetCondVar()->SignalAll(); shared->GetCondVar()->SignalAll();
while (!shared.AllDone()) { while (!shared->AllDone()) {
shared.GetCondVar()->Wait(); shared->GetCondVar()->Wait();
} }
} }
@ -187,7 +186,7 @@ bool RunStressTest(StressTest* stress) {
} }
now = clock->NowMicros(); now = clock->NowMicros();
if (!FLAGS_skip_verifydb && !FLAGS_test_batches_snapshots && if (!FLAGS_skip_verifydb && !FLAGS_test_batches_snapshots &&
!shared.HasVerificationFailedYet()) { !shared->HasVerificationFailedYet()) {
fprintf(stdout, "%s Verification successful\n", fprintf(stdout, "%s Verification successful\n",
clock->TimeToString(now / 1000000).c_str()); clock->TimeToString(now / 1000000).c_str());
} }
@ -195,14 +194,14 @@ bool RunStressTest(StressTest* stress) {
if (FLAGS_compaction_thread_pool_adjust_interval > 0 || if (FLAGS_compaction_thread_pool_adjust_interval > 0 ||
FLAGS_continuous_verification_interval > 0) { FLAGS_continuous_verification_interval > 0) {
MutexLock l(shared.GetMutex()); MutexLock l(shared->GetMutex());
shared.SetShouldStopBgThread(); shared->SetShouldStopBgThread();
while (!shared.BgThreadsFinished()) { while (!shared->BgThreadsFinished()) {
shared.GetCondVar()->Wait(); shared->GetCondVar()->Wait();
} }
} }
if (shared.HasVerificationFailedYet()) { if (shared->HasVerificationFailedYet()) {
fprintf(stderr, "Verification failed :(\n"); fprintf(stderr, "Verification failed :(\n");
return false; return false;
} }

@ -7,11 +7,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors. // found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "db_stress_tool/db_stress_shared_state.h"
#ifdef GFLAGS #ifdef GFLAGS
#pragma once #pragma once
#include "db_stress_tool/db_stress_test_base.h" #include "db_stress_tool/db_stress_test_base.h"
namespace ROCKSDB_NAMESPACE { namespace ROCKSDB_NAMESPACE {
extern void ThreadBody(void* /*thread_state*/); extern void ThreadBody(void* /*thread_state*/);
extern bool RunStressTest(StressTest*); extern bool RunStressTest(SharedState*);
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
#endif // GFLAGS #endif // GFLAGS

@ -20,6 +20,7 @@
// NOTE that if FLAGS_test_batches_snapshots is set, the test will have // NOTE that if FLAGS_test_batches_snapshots is set, the test will have
// different behavior. See comment of the flag for details. // different behavior. See comment of the flag for details.
#include "db_stress_tool/db_stress_shared_state.h"
#ifdef GFLAGS #ifdef GFLAGS
#include "db_stress_tool/db_stress_common.h" #include "db_stress_tool/db_stress_common.h"
#include "db_stress_tool/db_stress_driver.h" #include "db_stress_tool/db_stress_driver.h"
@ -340,7 +341,7 @@ int db_stress_tool(int argc, char** argv) {
key_gen_ctx.weights.emplace_back(key_gen_ctx.window - key_gen_ctx.weights.emplace_back(key_gen_ctx.window -
keys_per_level * (levels - 1)); keys_per_level * (levels - 1));
} }
std::unique_ptr<ROCKSDB_NAMESPACE::SharedState> shared;
std::unique_ptr<ROCKSDB_NAMESPACE::StressTest> stress; std::unique_ptr<ROCKSDB_NAMESPACE::StressTest> stress;
if (FLAGS_test_cf_consistency) { if (FLAGS_test_cf_consistency) {
stress.reset(CreateCfConsistencyStressTest()); stress.reset(CreateCfConsistencyStressTest());
@ -353,7 +354,8 @@ int db_stress_tool(int argc, char** argv) {
} }
// Initialize the Zipfian pre-calculated array // Initialize the Zipfian pre-calculated array
InitializeHotKeyGenerator(FLAGS_hot_key_alpha); InitializeHotKeyGenerator(FLAGS_hot_key_alpha);
if (RunStressTest(stress.get())) { shared.reset(new SharedState(db_stress_env, stress.get()));
if (RunStressTest(shared.get())) {
return 0; return 0;
} else { } else {
return 1; return 1;

Loading…
Cancel
Save