1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
11 #include "proto/gen/db_operation.pb.h"
12 #include "rocksdb/db.h"
13 #include "rocksdb/file_system.h"
14 #include "src/libfuzzer/libfuzzer_macro.h"
17 protobuf_mutator::libfuzzer::PostProcessorRegistration
<DBOperations
> reg
= {
18 [](DBOperations
* input
, unsigned int /* seed */) {
19 const ROCKSDB_NAMESPACE::Comparator
* comparator
=
20 ROCKSDB_NAMESPACE::BytewiseComparator();
21 auto ops
= input
->mutable_operations();
22 // Make sure begin <= end for DELETE_RANGE.
23 for (DBOperation
& op
: *ops
) {
24 if (op
.type() == OpType::DELETE_RANGE
) {
25 auto begin
= op
.key();
26 auto end
= op
.value();
27 if (comparator
->Compare(begin
, end
) > 0) {
28 std::swap(begin
, end
);
36 // Execute randomly generated operations on both a DB and a std::map,
37 // then reopen the DB and make sure that iterating the DB produces the
38 // same key-value pairs as iterating through the std::map.
39 DEFINE_PROTO_FUZZER(DBOperations
& input
) {
40 if (input
.operations().empty()) {
44 const std::string kDbPath
= "/tmp/db_map_fuzzer_test";
45 auto fs
= ROCKSDB_NAMESPACE::FileSystem::Default();
46 if (fs
->FileExists(kDbPath
, ROCKSDB_NAMESPACE::IOOptions(), /*dbg=*/nullptr)
48 std::cerr
<< "db path " << kDbPath
<< " already exists" << std::endl
;
52 std::map
<std::string
, std::string
> kv
;
53 ROCKSDB_NAMESPACE::DB
* db
= nullptr;
54 ROCKSDB_NAMESPACE::Options options
;
55 options
.create_if_missing
= true;
56 CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options
, kDbPath
, &db
));
58 for (const DBOperation
& op
: input
.operations()) {
62 db
->Put(ROCKSDB_NAMESPACE::WriteOptions(), op
.key(), op
.value()));
63 kv
[op
.key()] = op
.value();
69 case OpType::DELETE
: {
70 CHECK_OK(db
->Delete(ROCKSDB_NAMESPACE::WriteOptions(), op
.key()));
74 case OpType::DELETE_RANGE
: {
75 // [op.key(), op.value()) corresponds to [begin, end).
76 CHECK_OK(db
->DeleteRange(ROCKSDB_NAMESPACE::WriteOptions(),
77 db
->DefaultColumnFamily(), op
.key(),
79 kv
.erase(kv
.lower_bound(op
.key()), kv
.lower_bound(op
.value()));
83 std::cerr
<< "Unsupported operation" << static_cast<int>(op
.type());
88 CHECK_OK(db
->Close());
92 CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options
, kDbPath
, &db
));
93 auto kv_it
= kv
.begin();
94 ROCKSDB_NAMESPACE::Iterator
* it
=
95 db
->NewIterator(ROCKSDB_NAMESPACE::ReadOptions());
96 for (it
->SeekToFirst(); it
->Valid(); it
->Next(), kv_it
++) {
97 CHECK_TRUE(kv_it
!= kv
.end());
98 CHECK_EQ(it
->key().ToString(), kv_it
->first
);
99 CHECK_EQ(it
->value().ToString(), kv_it
->second
);
101 CHECK_TRUE(kv_it
== kv
.end());
104 CHECK_OK(db
->Close());
106 CHECK_OK(ROCKSDB_NAMESPACE::DestroyDB(kDbPath
, options
));