Skip to content

Commit cb8bc56

Browse files
omkarhgawdemeta-codesync[bot]
authored andcommitted
Fix memory leak on error in C API create_column_family (facebook#14447)
Summary: Pull Request resolved: facebook#14447 `rocksdb_create_column_family()` and `rocksdb_transactiondb_create_column_family()` allocate a `rocksdb_column_family_handle_t` but always return it even when `CreateColumnFamily()` fails. This leaks the handle and returns an object with an indeterminate `rep` pointer. Other similar functions like `rocksdb_create_column_family_with_import()` correctly delete the handle and return nullptr on error. Fix: Initialize `handle->rep = nullptr`, check `SaveError()` return value, and on error delete the handle and return nullptr. Reviewed By: anand1976 Differential Revision: D95303444 fbshipit-source-id: 5fde7a3ed588794d78429d5cb3d9f621f0fb6388
1 parent 1ed5052 commit cb8bc56

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

db/c.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,9 +1759,13 @@ rocksdb_column_family_handle_t* rocksdb_create_column_family(
17591759
rocksdb_t* db, const rocksdb_options_t* column_family_options,
17601760
const char* column_family_name, char** errptr) {
17611761
rocksdb_column_family_handle_t* handle = new rocksdb_column_family_handle_t;
1762-
SaveError(errptr, db->rep->CreateColumnFamily(
1763-
ColumnFamilyOptions(column_family_options->rep),
1764-
std::string(column_family_name), &(handle->rep)));
1762+
handle->rep = nullptr;
1763+
if (SaveError(errptr, db->rep->CreateColumnFamily(
1764+
ColumnFamilyOptions(column_family_options->rep),
1765+
std::string(column_family_name), &(handle->rep)))) {
1766+
delete handle;
1767+
return nullptr;
1768+
}
17651769
handle->immortal = false;
17661770
return handle;
17671771
}
@@ -7534,9 +7538,13 @@ rocksdb_column_family_handle_t* rocksdb_transactiondb_create_column_family(
75347538
const rocksdb_options_t* column_family_options,
75357539
const char* column_family_name, char** errptr) {
75367540
rocksdb_column_family_handle_t* handle = new rocksdb_column_family_handle_t;
7537-
SaveError(errptr, txn_db->rep->CreateColumnFamily(
7538-
ColumnFamilyOptions(column_family_options->rep),
7539-
std::string(column_family_name), &(handle->rep)));
7541+
handle->rep = nullptr;
7542+
if (SaveError(errptr, txn_db->rep->CreateColumnFamily(
7543+
ColumnFamilyOptions(column_family_options->rep),
7544+
std::string(column_family_name), &(handle->rep)))) {
7545+
delete handle;
7546+
return nullptr;
7547+
}
75407548
handle->immortal = false;
75417549
return handle;
75427550
}

db/c_test.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4880,6 +4880,21 @@ int main(int argc, char** argv) {
48804880
rocksdb_sst_file_manager_destroy(sst_file_manager);
48814881
}
48824882

4883+
StartPhase("create_column_family_error_returns_null");
4884+
{
4885+
// Creating a column family with a name that already exists should fail
4886+
// and return NULL. Without the fix, the handle is leaked and a non-NULL
4887+
// pointer with an indeterminate rep field is returned.
4888+
char* cf_err = NULL;
4889+
rocksdb_column_family_handle_t* cf_handle =
4890+
rocksdb_create_column_family(db, options, "default", &cf_err);
4891+
// Should have an error since "default" already exists
4892+
CheckCondition(cf_err != NULL);
4893+
// The handle should be NULL on error (this is the bug fix)
4894+
CheckCondition(cf_handle == NULL);
4895+
free(cf_err);
4896+
}
4897+
48834898
StartPhase("cancel_all_background_work");
48844899
rocksdb_cancel_all_background_work(db, 1);
48854900

0 commit comments

Comments
 (0)