This is an automated email from the ASF dual-hosted git repository.

ColinLeeo pushed a commit to branch fix_memory_crash
in repository https://gitbox.apache.org/repos/asf/tsfile.git

commit b3a0002f3712c6fdef7db452db3d2433a2ddb70b
Author: ColinLee <[email protected]>
AuthorDate: Mon Jul 27 18:40:56 2026 +0800

    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<String*>() 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<storage::ResultSet*>(result_set);
     std::string column_name_(column_name);
     common::String* ret = r->get_value<common::String*>(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<storage::ResultSet*>(result_set);
     common::String* ret = r->get_value<common::String*>(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_

Reply via email to