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

yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 0947bf4e97f [opt](mysql serde) Avoid core dump when converting invalid 
block to mysql result (#28069)
0947bf4e97f is described below

commit 0947bf4e97f43b92ad48ff471424bde5d37a8479
Author: zhiqiang <[email protected]>
AuthorDate: Fri Dec 8 10:21:09 2023 +0800

    [opt](mysql serde) Avoid core dump when converting invalid block to mysql 
result (#28069)
    
    BE will core dump if result block is invalid when we doing result 
serialization.
    An existing bug case is described in #28030, so we add check branch to 
avoid BE core dump due to out of range related problem.
---
 .../vec/data_types/serde/data_type_array_serde.cpp | 12 ++++---
 be/src/vec/sink/vmysql_result_writer.cpp           | 40 +++++++++++++++-------
 2 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/be/src/vec/data_types/serde/data_type_array_serde.cpp 
b/be/src/vec/data_types/serde/data_type_array_serde.cpp
index 91dfa8452e2..7aa5ab78cc7 100644
--- a/be/src/vec/data_types/serde/data_type_array_serde.cpp
+++ b/be/src/vec/data_types/serde/data_type_array_serde.cpp
@@ -299,18 +299,22 @@ void DataTypeArraySerDe::read_column_from_arrow(IColumn& 
column, const arrow::Ar
 template <bool is_binary_format>
 Status DataTypeArraySerDe::_write_column_to_mysql(const IColumn& column,
                                                   
MysqlRowBuffer<is_binary_format>& result,
-                                                  int row_idx, bool col_const) 
const {
+                                                  int row_idx_of_mysql, bool 
col_const) const {
     auto& column_array = assert_cast<const ColumnArray&>(column);
     auto& offsets = column_array.get_offsets();
     auto& data = column_array.get_data();
     bool is_nested_string = data.is_column_string();
-    const auto col_index = index_check_const(row_idx, col_const);
+    const auto row_idx_of_col_arr = index_check_const(row_idx_of_mysql, 
col_const);
     result.open_dynamic_mode();
+
     if (0 != result.push_string("[", 1)) {
         return Status::InternalError("pack mysql buffer failed.");
     }
-    for (int j = offsets[col_index - 1]; j < offsets[col_index]; ++j) {
-        if (j != offsets[col_index - 1]) {
+
+    const auto begin_arr_element = offsets[row_idx_of_col_arr - 1];
+    const auto end_arr_element = offsets[row_idx_of_col_arr];
+    for (int j = begin_arr_element; j < end_arr_element; ++j) {
+        if (j != begin_arr_element) {
             if (0 != result.push_string(", ", 2)) {
                 return Status::InternalError("pack mysql buffer failed.");
             }
diff --git a/be/src/vec/sink/vmysql_result_writer.cpp 
b/be/src/vec/sink/vmysql_result_writer.cpp
index 867cd7dc1d0..336f627fcc3 100644
--- a/be/src/vec/sink/vmysql_result_writer.cpp
+++ b/be/src/vec/sink/vmysql_result_writer.cpp
@@ -112,17 +112,17 @@ Status 
VMysqlResultWriter<is_binary_format>::append_block(Block& input_block) {
         return status;
     }
 
+    DCHECK(_output_vexpr_ctxs.empty() != true);
+
     // Exec vectorized expr here to speed up, block.rows() == 0 means expr exec
     // failed, just return the error status
     Block block;
     
RETURN_IF_ERROR(VExprContext::get_output_block_after_execute_exprs(_output_vexpr_ctxs,
                                                                        
input_block, &block));
-
     // convert one batch
     auto result = std::make_unique<TFetchDataResult>();
     auto num_rows = block.rows();
     result->result_batch.rows.resize(num_rows);
-
     uint64_t bytes_sent = 0;
     {
         SCOPED_TIMER(_convert_tuple_timer);
@@ -138,15 +138,19 @@ Status 
VMysqlResultWriter<is_binary_format>::append_block(Block& input_block) {
             DataTypeSerDeSPtr serde;
         };
 
+        const size_t num_cols = _output_vexpr_ctxs.size();
         std::vector<Arguments> arguments;
-        for (int i = 0; i < _output_vexpr_ctxs.size(); ++i) {
-            const auto& [column_ptr, col_const] = 
unpack_if_const(block.get_by_position(i).column);
-            int scale = _output_vexpr_ctxs[i]->root()->type().scale;
+        arguments.reserve(num_cols);
+
+        for (size_t col_idx = 0; col_idx < num_cols; ++col_idx) {
+            const auto& [column_ptr, col_const] =
+                    unpack_if_const(block.get_by_position(col_idx).column);
+            int scale = _output_vexpr_ctxs[col_idx]->root()->type().scale;
             // decimalv2 scale and precision is hard code, so we should get 
real scale and precision
             // from expr
             DataTypeSerDeSPtr serde;
-            if (_output_vexpr_ctxs[i]->root()->type().is_decimal_v2_type()) {
-                if (_output_vexpr_ctxs[i]->root()->is_nullable()) {
+            if 
(_output_vexpr_ctxs[col_idx]->root()->type().is_decimal_v2_type()) {
+                if (_output_vexpr_ctxs[col_idx]->root()->is_nullable()) {
                     auto nested_serde =
                             
std::make_shared<DataTypeDecimalSerDe<vectorized::Decimal128>>(scale,
                                                                                
            27);
@@ -156,16 +160,28 @@ Status 
VMysqlResultWriter<is_binary_format>::append_block(Block& input_block) {
                                                                                
            27);
                 }
             } else {
-                serde = block.get_by_position(i).type->get_serde();
+                serde = block.get_by_position(col_idx).type->get_serde();
             }
             serde->set_return_object_as_string(output_object_data());
             arguments.emplace_back(column_ptr.get(), col_const, serde);
         }
 
-        for (size_t row_idx = 0; row_idx != num_rows; ++row_idx) {
-            for (int i = 0; i < _output_vexpr_ctxs.size(); ++i) {
-                RETURN_IF_ERROR(arguments[i].serde->write_column_to_mysql(
-                        *(arguments[i].column), row_buffer, row_idx, 
arguments[i].is_const));
+        for (size_t col_idx = 0; col_idx < num_cols; ++col_idx) {
+            const auto& argument = arguments[col_idx];
+            // const column will only have 1 row, see unpack_if_const
+            if (argument.column->size() < num_rows && !argument.is_const) {
+                return Status::InternalError(
+                        "Required row size is out of range, need {} rows, 
column {} has {} "
+                        "rows in fact.",
+                        num_rows, argument.column->get_name(), 
argument.column->size());
+            }
+        }
+
+        for (size_t row_idx = 0; row_idx < num_rows; ++row_idx) {
+            for (size_t col_idx = 0; col_idx < num_cols; ++col_idx) {
+                
RETURN_IF_ERROR(arguments[col_idx].serde->write_column_to_mysql(
+                        *(arguments[col_idx].column), row_buffer, row_idx,
+                        arguments[col_idx].is_const));
             }
 
             // copy MysqlRowBuffer to Thrift


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to