Fix use-after-free on implicit temporary FileOptions (#8571)
Summary: FileOptions has an implicit conversion from EnvOptions and some internal APIs take `const FileOptions&` and save the reference, which is counter to Google C++ guidelines, > Avoid defining functions that require a const reference parameter to outlive the call, because const reference parameters bind to temporaries. Instead, find a way to eliminate the lifetime requirement (for example, by copying the parameter), or pass it by const pointer and document the lifetime and non-null requirements. This is at least a problem for repair.cc, which passes an EnvOptions to TableCache(), which would save a reference to the temporary copy as FileOptions. This was unfortunately only caught as a side effect of changes in https://github.com/facebook/rocksdb/issues/8544. This change fixes the repair.cc case and updates the involved internal APIs that save a reference to use `const FileOptions*` instead. Unfortunately, I don't know how to get any of our sanitizers to reliably report bugs like this, so I can't rule out more existing in our codebase. Pull Request resolved: https://github.com/facebook/rocksdb/pull/8571 Test Plan: Test that issues seen with https://github.com/facebook/rocksdb/issues/8544 are fixed (can reproduce on AWS EC2) Reviewed By: ajkr Differential Revision: D29943890 Pulled By: pdillinger fbshipit-source-id: 95f9c5251548777b4dc994c1a083dd2add5799c9
This commit is contained in:
parent
e352bd5742
commit
74b7c0d249
@ -505,7 +505,7 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
uint32_t id, const std::string& name, Version* _dummy_versions,
|
||||
Cache* _table_cache, WriteBufferManager* write_buffer_manager,
|
||||
const ColumnFamilyOptions& cf_options, const ImmutableDBOptions& db_options,
|
||||
const FileOptions& file_options, ColumnFamilySet* column_family_set,
|
||||
const FileOptions* file_options, ColumnFamilySet* column_family_set,
|
||||
BlockCacheTracer* const block_cache_tracer,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
const std::string& db_session_id)
|
||||
@ -1459,14 +1459,14 @@ ColumnFamilySet::ColumnFamilySet(const std::string& dbname,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
const std::string& db_session_id)
|
||||
: max_column_family_(0),
|
||||
file_options_(file_options),
|
||||
dummy_cfd_(new ColumnFamilyData(
|
||||
ColumnFamilyData::kDummyColumnFamilyDataId, "", nullptr, nullptr,
|
||||
nullptr, ColumnFamilyOptions(), *db_options, file_options, nullptr,
|
||||
nullptr, ColumnFamilyOptions(), *db_options, &file_options_, nullptr,
|
||||
block_cache_tracer, io_tracer, db_session_id)),
|
||||
default_cfd_cache_(nullptr),
|
||||
db_name_(dbname),
|
||||
db_options_(db_options),
|
||||
file_options_(file_options),
|
||||
table_cache_(table_cache),
|
||||
write_buffer_manager_(_write_buffer_manager),
|
||||
write_controller_(_write_controller),
|
||||
@ -1538,7 +1538,7 @@ ColumnFamilyData* ColumnFamilySet::CreateColumnFamily(
|
||||
assert(column_families_.find(name) == column_families_.end());
|
||||
ColumnFamilyData* new_cfd = new ColumnFamilyData(
|
||||
id, name, dummy_versions, table_cache_, write_buffer_manager_, options,
|
||||
*db_options_, file_options_, this, block_cache_tracer_, io_tracer_,
|
||||
*db_options_, &file_options_, this, block_cache_tracer_, io_tracer_,
|
||||
db_session_id_);
|
||||
column_families_.insert({name, id});
|
||||
column_family_data_.insert({id, new_cfd});
|
||||
|
@ -530,7 +530,7 @@ class ColumnFamilyData {
|
||||
WriteBufferManager* write_buffer_manager,
|
||||
const ColumnFamilyOptions& options,
|
||||
const ImmutableDBOptions& db_options,
|
||||
const FileOptions& file_options,
|
||||
const FileOptions* file_options,
|
||||
ColumnFamilySet* column_family_set,
|
||||
BlockCacheTracer* const block_cache_tracer,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
@ -721,6 +721,8 @@ class ColumnFamilySet {
|
||||
std::unordered_map<uint32_t, ColumnFamilyData*> column_family_data_;
|
||||
|
||||
uint32_t max_column_family_;
|
||||
const FileOptions file_options_;
|
||||
|
||||
ColumnFamilyData* dummy_cfd_;
|
||||
// We don't hold the refcount here, since default column family always exists
|
||||
// We are also not responsible for cleaning up default_cfd_cache_. This is
|
||||
@ -730,7 +732,6 @@ class ColumnFamilySet {
|
||||
|
||||
const std::string db_name_;
|
||||
const ImmutableDBOptions* const db_options_;
|
||||
const FileOptions file_options_;
|
||||
Cache* table_cache_;
|
||||
WriteBufferManager* write_buffer_manager_;
|
||||
WriteController* write_controller_;
|
||||
|
19
db/repair.cc
19
db/repair.cc
@ -94,7 +94,7 @@ class Repairer {
|
||||
const ColumnFamilyOptions& unknown_cf_opts, bool create_unknown_cfs)
|
||||
: dbname_(dbname),
|
||||
env_(db_options.env),
|
||||
env_options_(),
|
||||
file_options_(),
|
||||
db_options_(SanitizeOptions(dbname_, db_options)),
|
||||
immutable_db_options_(ImmutableDBOptions(db_options_)),
|
||||
icmp_(default_cf_opts.comparator),
|
||||
@ -112,14 +112,15 @@ class Repairer {
|
||||
table_cache_(
|
||||
// TODO: db_session_id for TableCache should be initialized after
|
||||
// db_session_id_ is set.
|
||||
new TableCache(default_iopts_, env_options_, raw_table_cache_.get(),
|
||||
new TableCache(default_iopts_, &file_options_,
|
||||
raw_table_cache_.get(),
|
||||
/*block_cache_tracer=*/nullptr,
|
||||
/*io_tracer=*/nullptr, /*db_session_id*/ "")),
|
||||
wb_(db_options_.db_write_buffer_size),
|
||||
wc_(db_options_.delayed_write_rate),
|
||||
// TODO: db_session_id for VersionSet should be initialized after
|
||||
// db_session_id_ is set and use it for initialization.
|
||||
vset_(dbname_, &immutable_db_options_, env_options_,
|
||||
vset_(dbname_, &immutable_db_options_, file_options_,
|
||||
raw_table_cache_.get(), &wb_, &wc_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_session_id*/ ""),
|
||||
@ -249,7 +250,7 @@ class Repairer {
|
||||
std::string const dbname_;
|
||||
std::string db_session_id_;
|
||||
Env* const env_;
|
||||
const EnvOptions env_options_;
|
||||
const FileOptions file_options_;
|
||||
const DBOptions db_options_;
|
||||
const ImmutableDBOptions immutable_db_options_;
|
||||
const InternalKeyComparator icmp_;
|
||||
@ -366,7 +367,7 @@ class Repairer {
|
||||
const auto& fs = env_->GetFileSystem();
|
||||
std::unique_ptr<SequentialFileReader> lfile_reader;
|
||||
Status status = SequentialFileReader::Create(
|
||||
fs, logname, fs->OptimizeForLogRead(env_options_), &lfile_reader,
|
||||
fs, logname, fs->OptimizeForLogRead(file_options_), &lfile_reader,
|
||||
nullptr);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
@ -458,7 +459,7 @@ class Repairer {
|
||||
meta.fd.GetNumber());
|
||||
status = BuildTable(
|
||||
dbname_, /* versions */ nullptr, immutable_db_options_, tboptions,
|
||||
env_options_, table_cache_.get(), iter.get(),
|
||||
file_options_, table_cache_.get(), iter.get(),
|
||||
std::move(range_del_iters), &meta, nullptr /* blob_file_additions */,
|
||||
{}, kMaxSequenceNumber, snapshot_checker,
|
||||
false /* paranoid_file_checks*/, nullptr /* internal_stats */, &io_s,
|
||||
@ -510,8 +511,8 @@ class Repairer {
|
||||
file_size);
|
||||
std::shared_ptr<const TableProperties> props;
|
||||
if (status.ok()) {
|
||||
status = table_cache_->GetTableProperties(env_options_, icmp_, t->meta.fd,
|
||||
&props);
|
||||
status = table_cache_->GetTableProperties(file_options_, icmp_,
|
||||
t->meta.fd, &props);
|
||||
}
|
||||
if (status.ok()) {
|
||||
t->column_family_id = static_cast<uint32_t>(props->column_family_id);
|
||||
@ -551,7 +552,7 @@ class Repairer {
|
||||
ReadOptions ropts;
|
||||
ropts.total_order_seek = true;
|
||||
InternalIterator* iter = table_cache_->NewIterator(
|
||||
ropts, env_options_, cfd->internal_comparator(), t->meta,
|
||||
ropts, file_options_, cfd->internal_comparator(), t->meta,
|
||||
nullptr /* range_del_agg */,
|
||||
cfd->GetLatestMutableCFOptions()->prefix_extractor.get(),
|
||||
/*table_reader_ptr=*/nullptr, /*file_read_hist=*/nullptr,
|
||||
|
@ -66,12 +66,12 @@ void AppendVarint64(IterKey* key, uint64_t v) {
|
||||
const int kLoadConcurency = 128;
|
||||
|
||||
TableCache::TableCache(const ImmutableOptions& ioptions,
|
||||
const FileOptions& file_options, Cache* const cache,
|
||||
const FileOptions* file_options, Cache* const cache,
|
||||
BlockCacheTracer* const block_cache_tracer,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
const std::string& db_session_id)
|
||||
: ioptions_(ioptions),
|
||||
file_options_(file_options),
|
||||
file_options_(*file_options),
|
||||
cache_(cache),
|
||||
immortal_tables_(false),
|
||||
block_cache_tracer_(block_cache_tracer),
|
||||
|
@ -49,7 +49,7 @@ class HistogramImpl;
|
||||
class TableCache {
|
||||
public:
|
||||
TableCache(const ImmutableOptions& ioptions,
|
||||
const FileOptions& storage_options, Cache* cache,
|
||||
const FileOptions* storage_options, Cache* cache,
|
||||
BlockCacheTracer* const block_cache_tracer,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
const std::string& db_session_id);
|
||||
|
Loading…
Reference in New Issue
Block a user