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

dataroaring 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 5704db91e5b [imp](checker) add NPE check for mysql_fetch_row to 
prevent coredump (#57853)
5704db91e5b is described below

commit 5704db91e5b58065a35e04abb233cd8f1b5b9615
Author: Yixuan Wang <[email protected]>
AuthorDate: Tue Nov 25 02:24:44 2025 +0800

    [imp](checker) add NPE check for mysql_fetch_row to prevent coredump 
(#57853)
    
    ### What problem does this PR solve?
    
    `mysql_fetch_row()` can return `NULL` when the result set is empty, even
    if `mysql_store_result()` returns a valid result pointer.
    
      **Root Cause:**
    - `mysql_store_result() != NULL` **only indicates query executed
    successfully, not that data rows exist**
    - When queries like `show tablet xxx` don't find the target,
    `mysql_fetch_row()` returns `NULL`
    
      When `row` is NULL, log warning and continue instead of crashing.
---
 cloud/src/recycler/meta_checker.cpp                | 49 +++++++++++++++++++++-
 .../suites/cloud_p0/recycler/check_meta.groovy     | 37 ++++++++++++++++
 2 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/cloud/src/recycler/meta_checker.cpp 
b/cloud/src/recycler/meta_checker.cpp
index d07ff44691c..3fbd8ab451d 100644
--- a/cloud/src/recycler/meta_checker.cpp
+++ b/cloud/src/recycler/meta_checker.cpp
@@ -130,6 +130,12 @@ bool 
MetaChecker::do_meta_tablet_key_check(std::vector<TabletInfo>& tablets_info
         result = mysql_store_result(&conn);
         if (result) {
             MYSQL_ROW row = mysql_fetch_row(result);
+            if (!row) {
+                LOG(WARNING) << "check failed, fdb meta: " << 
tablet_info.debug_string()
+                             << " fe tablet not found";
+                check_res = false;
+                continue;
+            }
             auto [db_id, table_id, partition_id, index_id] =
                     std::make_tuple(atoll(row[4]), atoll(row[5]), 
atoll(row[6]), atoll(row[7]));
             if (tablet_info.table_id != table_id) {
@@ -298,6 +304,12 @@ bool 
MetaChecker::do_meta_tablet_key_index_check(std::vector<TabletInfo>& tablet
         result = mysql_store_result(&conn);
         if (result) {
             MYSQL_ROW row = mysql_fetch_row(result);
+            if (!row) {
+                LOG(WARNING) << "check failed, fdb meta: " << 
tablet_info.debug_string()
+                             << " fe tablet not found";
+                check_res = false;
+                continue;
+            }
             auto [db_id, table_id, partition_id, index_id] =
                     std::make_tuple(atoll(row[4]), atoll(row[5]), 
atoll(row[6]), atoll(row[7]));
             if (tablet_info.db_id != db_id) {
@@ -407,6 +419,12 @@ bool 
MetaChecker::do_meta_schema_key_check(std::vector<TabletInfo>& tablets_info
         result = mysql_store_result(&conn);
         if (result) {
             MYSQL_ROW row = mysql_fetch_row(result);
+            if (!row) {
+                LOG(WARNING) << "check failed, fdb meta: " << 
tablet_schema.ShortDebugString()
+                             << " fe tablet schema not found";
+                check_res = false;
+                continue;
+            }
             int64_t schema_version = atoll(row[2]);
             if (tablet_schema.schema_version() != schema_version) {
                 LOG(WARNING) << "check failed, fdb meta: " << 
tablet_schema.ShortDebugString()
@@ -454,6 +472,12 @@ bool 
MetaChecker::do_version_partition_key_check(std::vector<PartitionInfo>& par
         result = mysql_store_result(&conn);
         if (result) {
             MYSQL_ROW row = mysql_fetch_row(result);
+            if (!row) {
+                LOG(WARNING) << "check failed, fdb meta: " << 
partition_info.debug_string()
+                             << " fe partition not found";
+                check_res = false;
+                continue;
+            }
             if (partition_info.table_id != atoll(row[4])) {
                 LOG(WARNING) << "check failed, fdb meta: " << 
partition_info.debug_string()
                              << " fe partition of table_id: " << atoll(row[4]);
@@ -505,6 +529,12 @@ bool 
MetaChecker::do_version_table_key_check(std::vector<TableInfo>& tables_info
         result = mysql_store_result(&conn);
         if (result) {
             MYSQL_ROW row = mysql_fetch_row(result);
+            if (!row) {
+                LOG(WARNING) << "check failed, fdb meta: " << 
table_info.debug_string()
+                             << " fe table not found";
+                check_res = false;
+                continue;
+            }
             int64_t db_id = atoll(row[2]);
             if (table_info.db_id != db_id) {
                 LOG(WARNING) << "check failed, fdb meta: " << 
table_info.debug_string()
@@ -794,6 +824,9 @@ void MetaChecker::init_db_meta() {
         int num_row = mysql_num_rows(result);
         for (int i = 0; i < num_row; ++i) {
             MYSQL_ROW row = mysql_fetch_row(result);
+            if (!row) {
+                continue;
+            }
             auto [db_id, db_name] = std::make_tuple(atoll(row[0]), row[1]);
             db_meta_.insert({db_id, db_name});
         }
@@ -899,6 +932,9 @@ void 
MetaChecker::init_tablet_and_partition_info_from_fe_meta() {
         int num_row = mysql_num_rows(result);
         for (int i = 0; i < num_row; ++i) {
             MYSQL_ROW row = mysql_fetch_row(result);
+            if (!row) {
+                continue;
+            }
             if (strcmp(row[0], "__internal_schema") == 0 ||
                 strcmp(row[0], "information_schema") == 0 || strcmp(row[0], 
"mysql") == 0) {
                 continue;
@@ -917,7 +953,9 @@ void 
MetaChecker::init_tablet_and_partition_info_from_fe_meta() {
             int num_row = mysql_num_rows(result);
             for (int i = 0; i < num_row; ++i) {
                 MYSQL_ROW row = mysql_fetch_row(result);
-                elem.second.emplace_back(row[0]);
+                if (row) {
+                    elem.second.emplace_back(row[0]);
+                }
             }
             mysql_free_result(result);
         }
@@ -933,6 +971,9 @@ void 
MetaChecker::init_tablet_and_partition_info_from_fe_meta() {
                 int num_row = mysql_num_rows(result);
                 for (int i = 0; i < num_row; ++i) {
                     MYSQL_ROW row = mysql_fetch_row(result);
+                    if (!row) {
+                        continue;
+                    }
                     TabletInfo tablet_info;
                     tablet_info.tablet_id = atoll(row[0]);
                     VLOG_DEBUG << "get tablet info log"
@@ -961,6 +1002,9 @@ void 
MetaChecker::init_tablet_and_partition_info_from_fe_meta() {
             int num_row = mysql_num_rows(result);
             for (int i = 0; i < num_row; ++i) {
                 MYSQL_ROW row = mysql_fetch_row(result);
+                if (!row) {
+                    continue;
+                }
                 tablet_info.db_id = atoll(row[4]);
                 tablet_info.table_id = atoll(row[5]);
                 tablet_info.partition_id = atoll(row[6]);
@@ -978,6 +1022,9 @@ void 
MetaChecker::init_tablet_and_partition_info_from_fe_meta() {
                         continue;
                     }
                     MYSQL_ROW row = mysql_fetch_row(result);
+                    if (!row) {
+                        continue;
+                    }
                     schema_version = atoll(row[2]);
                     mysql_free_result(result);
                 }
diff --git a/regression-test/suites/cloud_p0/recycler/check_meta.groovy 
b/regression-test/suites/cloud_p0/recycler/check_meta.groovy
index 1e6e2137ed9..a9f34f19787 100644
--- a/regression-test/suites/cloud_p0/recycler/check_meta.groovy
+++ b/regression-test/suites/cloud_p0/recycler/check_meta.groovy
@@ -22,6 +22,8 @@ suite("check_meta", "check_meta") {
     def caseStartTime = System.currentTimeMillis()
     def errMsg = "OK"
     def status = 200
+    def recyclerLastSuccessTime = -1
+    def recyclerLastFinishTime = -1
 
     String jdbcUrl = context.config.jdbcUrl
     String urlWithoutSchema = jdbcUrl.substring(jdbcUrl.indexOf("://") + 3)
@@ -38,6 +40,30 @@ suite("check_meta", "check_meta") {
         sqlPort = urlWithoutSchema.substring(urlWithoutSchema.indexOf(":") + 1)
     }
 
+    def getRecycleJobInfo = {
+        def recycleJobInfoApi = { checkFunc ->
+            httpTest {
+                endpoint context.config.recycleServiceHttpAddress
+                uri 
"/RecyclerService/http/recycle_job_info?token=$token&instance_id=$instanceId"
+                op "get"
+                check checkFunc
+            }
+        }
+        recycleJobInfoApi.call() {
+            respCode, body ->
+                logger.info("http cli result: ${body} ${respCode}")
+                def recycleJobInfoResult = body
+                logger.info("recycleJobInfoResult:${recycleJobInfoResult}")
+                assertEquals(respCode, 200)
+                def info = parseJson(recycleJobInfoResult.trim())
+                if (info.last_finish_time_ms != null) {
+                    recyclerLastFinishTime = 
Long.parseLong(info.last_finish_time_ms)
+                    assertTrue(info.last_success_time_ms != null)
+                    recyclerLastSuccessTime = 
Long.parseLong(info.last_success_time_ms)
+                }
+        }
+    }
+
     def checkMeta = {
         def metaCheckApi = { checkFunc ->
             httpTest {
@@ -55,6 +81,17 @@ suite("check_meta", "check_meta") {
         }
     }
 
+    do {
+        triggerRecycle(token, instanceId)
+        Thread.sleep(10000)
+        getRecycleJobInfo()
+        logger.info("caseStartTime=${caseStartTime}, 
recyclerLastSuccessTime=${recyclerLastSuccessTime}")
+        if (recyclerLastSuccessTime > caseStartTime) {
+            break
+        }
+    } while (true)
+    assertEquals(recyclerLastFinishTime, recyclerLastSuccessTime)
+
     def start = System.currentTimeMillis()
     def now = -1;
     do {


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

Reply via email to