rocksdb: Fix scan-build memory warning in table/block_based_table_reader.cc

Summary:
scan-build is reporting two memory leak bugs in `table/block_based_table_reader.cc`. They are both false positives. In both cases we allocate memory in `ReadBlockFromFile` if `s.ok()`. Then after the function `ReadBlockFromFile` returns we check for the same variable if `s.ok()` and then use the memory that was allocated. The bugs reported by scan-build is if `ReadBlockFromFile` allocates memory and returns, but for some reason status `s` is not the same and `s.ok() != true`.

In this case scan-build is concerned that memory owner transfer is not explicit. I modified `ReadBlockFromFile` to accept `std::unique_ptr<Block>*` as a parameter, instead of raw pointer.

scan-build reports:
http://home.fburl.com/~sugak/latest2/report-a4b3fa.html#EndPath
http://home.fburl.com/~sugak/latest2/report-29adbf.html#EndPath

Test Plan:
Make sure scan-build does not report these bugs and all tests are passing.
```lang=bash
% make check
% make analyze
```

Reviewers: sdong, lgalanis, meyering, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D33681
This commit is contained in:
Igor Sugak 2015-02-19 14:07:38 -08:00
parent a42324e370
commit 98870c7b9c

View File

@ -64,12 +64,13 @@ const size_t kMaxCacheKeyPrefixSize __attribute__((unused)) =
// On success fill *result and return OK - caller owns *result
Status ReadBlockFromFile(RandomAccessFile* file, const Footer& footer,
const ReadOptions& options, const BlockHandle& handle,
Block** result, Env* env, bool do_uncompress = true) {
std::unique_ptr<Block>* result, Env* env,
bool do_uncompress = true) {
BlockContents contents;
Status s = ReadBlockContents(file, footer, options, handle, &contents, env,
do_uncompress);
if (s.ok()) {
*result = new Block(std::move(contents));
result->reset(new Block(std::move(contents)));
}
return s;
@ -168,12 +169,13 @@ class BinarySearchIndexReader : public IndexReader {
const BlockHandle& index_handle, Env* env,
const Comparator* comparator,
IndexReader** index_reader) {
Block* index_block = nullptr;
std::unique_ptr<Block> index_block;
auto s = ReadBlockFromFile(file, footer, ReadOptions(), index_handle,
&index_block, env);
if (s.ok()) {
*index_reader = new BinarySearchIndexReader(comparator, index_block);
*index_reader =
new BinarySearchIndexReader(comparator, std::move(index_block));
}
return s;
@ -192,8 +194,9 @@ class BinarySearchIndexReader : public IndexReader {
}
private:
BinarySearchIndexReader(const Comparator* comparator, Block* index_block)
: IndexReader(comparator), index_block_(index_block) {
BinarySearchIndexReader(const Comparator* comparator,
std::unique_ptr<Block>&& index_block)
: IndexReader(comparator), index_block_(std::move(index_block)) {
assert(index_block_ != nullptr);
}
std::unique_ptr<Block> index_block_;
@ -209,7 +212,7 @@ class HashIndexReader : public IndexReader {
const BlockHandle& index_handle,
Iterator* meta_index_iter, IndexReader** index_reader,
bool hash_index_allow_collision) {
Block* index_block = nullptr;
std::unique_ptr<Block> index_block;
auto s = ReadBlockFromFile(file, footer, ReadOptions(), index_handle,
&index_block, env);
@ -222,7 +225,7 @@ class HashIndexReader : public IndexReader {
// So, Create will succeed regardless, from this point on.
auto new_index_reader =
new HashIndexReader(comparator, index_block);
new HashIndexReader(comparator, std::move(index_block));
*index_reader = new_index_reader;
// Get prefixes block
@ -300,8 +303,9 @@ class HashIndexReader : public IndexReader {
}
private:
HashIndexReader(const Comparator* comparator, Block* index_block)
: IndexReader(comparator), index_block_(index_block) {
HashIndexReader(const Comparator* comparator,
std::unique_ptr<Block>&& index_block)
: IndexReader(comparator), index_block_(std::move(index_block)) {
assert(index_block_ != nullptr);
}
@ -615,7 +619,7 @@ Status BlockBasedTable::ReadMetaBlock(
// TODO(sanjay): Skip this if footer.metaindex_handle() size indicates
// it is an empty block.
// TODO: we never really verify check sum for meta index block
Block* meta = nullptr;
std::unique_ptr<Block> meta;
Status s = ReadBlockFromFile(
rep->file.get(),
rep->footer,
@ -628,13 +632,12 @@ Status BlockBasedTable::ReadMetaBlock(
Log(InfoLogLevel::ERROR_LEVEL, rep->ioptions.info_log,
"Encountered error while reading data from properties"
" block %s", s.ToString().c_str());
delete meta;
return s;
}
meta_block->reset(meta);
*meta_block = std::move(meta);
// meta block uses bytewise comparator.
iter->reset(meta->NewIterator(BytewiseComparator()));
iter->reset(meta_block->get()->NewIterator(BytewiseComparator()));
return Status::OK();
}
@ -970,7 +973,7 @@ Iterator* BlockBasedTable::NewDataBlockIterator(Rep* rep,
rep->table_options.format_version);
if (block.value == nullptr && !no_io && ro.fill_cache) {
Block* raw_block = nullptr;
std::unique_ptr<Block> raw_block;
{
StopWatch sw(rep->ioptions.env, statistics, READ_BLOCK_GET_MICROS);
s = ReadBlockFromFile(rep->file.get(), rep->footer, ro, handle,
@ -980,7 +983,7 @@ Iterator* BlockBasedTable::NewDataBlockIterator(Rep* rep,
if (s.ok()) {
s = PutDataBlockToCache(key, ckey, block_cache, block_cache_compressed,
ro, statistics, &block, raw_block,
ro, statistics, &block, raw_block.release(),
rep->table_options.format_version);
}
}
@ -997,8 +1000,12 @@ Iterator* BlockBasedTable::NewDataBlockIterator(Rep* rep,
return NewErrorIterator(Status::Incomplete("no blocking io"));
}
}
std::unique_ptr<Block> block_value;
s = ReadBlockFromFile(rep->file.get(), rep->footer, ro, handle,
&block.value, rep->ioptions.env);
&block_value, rep->ioptions.env);
if (s.ok()) {
block.value = block_value.release();
}
}
Iterator* iter;