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]