From b3a0002f3712c6fdef7db452db3d2433a2ddb70b Mon Sep 17 00:00:00 2001 From: ColinLee Date: Mon, 27 Jul 2026 18:40:56 +0800 Subject: [PATCH] fix(cpp): fix memory leaks and null dereference crashes - ChunkReader::reset() now clears wrapped buffer pointer after free to prevent double-free in subsequent destroy() - ChunkReader::load_by_meta() now frees allocated buffer and returns early on read failure, preventing memory leak - LZ4Compressor::compress() now frees compressed_buf_ on both LZ4_compress_default failure and mem_realloc failure paths - C wrapper string getters (by_name/by_index) now null-check the return value of get_value() before dereferencing, preventing crash on non-STRING/TEXT/BLOB column types --- cpp/src/compress/lz4_compressor.cc | 4 ++++ cpp/src/cwrapper/tsfile_cwrapper.cc | 6 ++++++ cpp/src/reader/chunk_reader.cc | 7 ++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cpp/src/compress/lz4_compressor.cc b/cpp/src/compress/lz4_compressor.cc index 0f19ce179..a7333f246 100644 --- a/cpp/src/compress/lz4_compressor.cc +++ b/cpp/src/compress/lz4_compressor.cc @@ -56,12 +56,16 @@ int LZ4Compressor::compress(char* uncompressed_buf, uncompressed_buf_len, max_dst_size); if (compressed_data_size <= 0) { + mem_free(compressed_buf_); + compressed_buf_ = nullptr; ret = E_COMPRESS_ERR; } else { char* compressed_data = (char*)mem_realloc( compressed_buf_, (size_t)compressed_data_size); if (compressed_data == nullptr) { + mem_free(compressed_buf_); + compressed_buf_ = nullptr; ret = E_OOM; } else { compressed_buf_ = compressed_data; diff --git a/cpp/src/cwrapper/tsfile_cwrapper.cc b/cpp/src/cwrapper/tsfile_cwrapper.cc index 4ec70e00b..ffe2f59b6 100644 --- a/cpp/src/cwrapper/tsfile_cwrapper.cc +++ b/cpp/src/cwrapper/tsfile_cwrapper.cc @@ -555,6 +555,9 @@ char* tsfile_result_set_get_value_by_name_string(ResultSet result_set, auto* r = static_cast(result_set); std::string column_name_(column_name); common::String* ret = r->get_value(column_name_); + if (ret == nullptr) { + return nullptr; + } // Caller should free return's char* 's space. char* dup = (char*)malloc(ret->len_ + 1); if (dup) { @@ -581,6 +584,9 @@ char* tsfile_result_set_get_value_by_index_string(ResultSet result_set, uint32_t column_index) { auto* r = static_cast(result_set); common::String* ret = r->get_value(column_index); + if (ret == nullptr) { + return nullptr; + } // Caller should free return's char* 's space. char* dup = (char*)malloc(ret->len_ + 1); if (dup) { diff --git a/cpp/src/reader/chunk_reader.cc b/cpp/src/reader/chunk_reader.cc index 6b3d853d9..f127ee2ee 100644 --- a/cpp/src/reader/chunk_reader.cc +++ b/cpp/src/reader/chunk_reader.cc @@ -57,6 +57,7 @@ void ChunkReader::reset() { char* file_data_buf = in_stream_.get_wrapped_buf(); if (file_data_buf != nullptr) { mem_free(file_data_buf); + in_stream_.clear_wrapped_buf(); } in_stream_.reset(); file_data_buf_size_ = 0; @@ -113,7 +114,11 @@ int ChunkReader::load_by_meta(ChunkMeta* meta) { } ret = read_file_->read(chunk_meta_->offset_of_chunk_header_, file_data_buf, file_data_buf_size_, ret_read_len); - if (IS_SUCC(ret) && ret_read_len < ChunkHeader::MIN_SERIALIZED_SIZE) { + if (!IS_SUCC(ret)) { + mem_free(file_data_buf); + return ret; + } + if (ret_read_len < ChunkHeader::MIN_SERIALIZED_SIZE) { ret = E_TSFILE_CORRUPTED; LOGE("file corrupted, ret=" << ret << ", offset=" << chunk_meta_->offset_of_chunk_header_