Skip to content

Commit 14aebed

Browse files
committed
BUG#35998554: get_group_member_info_*() does not distinguish member not found from error
It was discovered that some methods from `Group_member_info_manager` class did return the same value for distinct situations, which could be masquerading errors. One case is ``` Group_member_info * Group_member_info_manager::get_group_member_info_by_member_id( const Gcs_member_identifier &id); ``` that does return a allocated copy of the `member_info` when the member exists on the `Group_member_info_manager`, or returns `nullprt` when the member does not exist. Though `nullptr` can also be returned when the memory allocation of the copy fails, which means that the method caller is unable to distinguish: * member not found; * no memory available to construct the object. On both situations the method caller will interpret `nullptr` as member not found which can leverage incorrect decisions. The same pattern exists on the methods: * Group_member_info_manager::get_group_member_info() * Group_member_info_manager::get_group_member_info_by_index() * Group_member_info_manager::get_group_member_info_by_member_id() * Group_member_info_manager::get_primary_member_info() To solve the above issue, the four methods were refactored to: 1) return a boolean value to state if the member was found; 2) receive a out parameter that is a local reference to the method caller that is updated when the member is found. The use of the reference eliminates the allocation of the memory. Change-Id: Ic10263943fc63f40cdda506a59f10962aa208d92
1 parent 4799ae8 commit 14aebed

16 files changed

+401
-299
lines changed

plugin/group_replication/include/member_info.h

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <string>
4141
#include <vector>
4242

43+
#include "libbinlogevents/include/nodiscard.h"
4344
#include "my_inttypes.h"
4445
#include "my_sys.h"
4546
#include "plugin/group_replication/include/gcs_plugin_messages.h"
@@ -242,6 +243,14 @@ class Group_member_info : public Plugin_gcs_message {
242243
*/
243244
void operator delete(void *ptr) noexcept { my_free(ptr); }
244245

246+
/**
247+
Group_member_info empty constructor
248+
249+
@param[in] psi_mutex_key_arg mutex key
250+
*/
251+
Group_member_info(PSI_mutex_key psi_mutex_key_arg =
252+
key_GR_LOCK_group_member_info_update_lock);
253+
245254
/**
246255
Group_member_info constructor
247256
@@ -263,13 +272,13 @@ class Group_member_info : public Plugin_gcs_message {
263272
check
264273
@param[in] member_weight_arg member_weight
265274
@param[in] lower_case_table_names_arg lower case table names
266-
@param[in] psi_mutex_key_arg mutex key
267275
@param[in] default_table_encryption_arg default_table_encryption
268276
@param[in] recovery_endpoints_arg recovery endpoints
269277
@param[in] view_change_uuid_arg view change uuid
270278
advertised
271279
@param[in] allow_single_leader flag indicating whether or
272280
not to use single-leader behavior
281+
@param[in] psi_mutex_key_arg mutex key
273282
*/
274283
Group_member_info(const char *hostname_arg, uint port_arg,
275284
const char *uuid_arg, int write_set_extraction_algorithm,
@@ -691,8 +700,8 @@ class Group_member_info : public Plugin_gcs_message {
691700
uint port;
692701
std::string uuid;
693702
Group_member_status status;
694-
Gcs_member_identifier *gcs_member_id;
695-
Member_version *member_version;
703+
Gcs_member_identifier *gcs_member_id{nullptr};
704+
Member_version *member_version{nullptr};
696705
std::string executed_gtid_set;
697706
std::string purged_gtid_set;
698707
std::string retrieved_gtid_set;
@@ -768,21 +777,32 @@ class Group_member_info_manager_interface {
768777
/**
769778
Retrieves a registered Group member by its uuid
770779
771-
@param[in] uuid uuid to retrieve
772-
@return reference to a copy of Group_member_info. NULL if not managed.
773-
The return value must deallocated by the caller.
780+
@param[in] uuid uuid to retrieve
781+
@param[out] member_info_arg a member info reference local to the
782+
method caller that is updated when the
783+
member is found.
784+
785+
@return true if the member is not found.
786+
false if the member is found.
774787
*/
775-
virtual Group_member_info *get_group_member_info(const std::string &uuid) = 0;
788+
[[NODISCARD]] virtual bool get_group_member_info(
789+
const std::string &uuid, Group_member_info &member_info_arg) = 0;
776790

777791
/**
778792
Retrieves a registered Group member by an index function.
779793
One is free to determine the index function. Nevertheless, it should have
780794
the same result regardless of the member of the group where it is called
781795
782-
@param[in] idx the index
783-
@return reference to a Group_member_info. NULL if not managed
796+
@param[in] idx the index
797+
@param[out] member_info_arg a member info reference local to the
798+
method caller that is updated when the
799+
member is found.
800+
801+
@return true if the member is not found.
802+
false if the member is found.
784803
*/
785-
virtual Group_member_info *get_group_member_info_by_index(int idx) = 0;
804+
[[NODISCARD]] virtual bool get_group_member_info_by_index(
805+
int idx, Group_member_info &member_info_arg) = 0;
786806

787807
/**
788808
Return lowest member version.
@@ -795,12 +815,16 @@ class Group_member_info_manager_interface {
795815
/**
796816
Retrieves a registered Group member by its backbone GCS identifier.
797817
798-
@param[in] id the GCS identifier
799-
@return reference to a copy of Group_member_info. NULL if not managed.
800-
The return value must be deallocated by the caller.
818+
@param[in] id the GCS identifier
819+
@param[out] member_info_arg a member info reference local to the
820+
method caller that is updated when the
821+
member is found.
822+
823+
@return true if the member is not found.
824+
false if the member is found.
801825
*/
802-
virtual Group_member_info *get_group_member_info_by_member_id(
803-
const Gcs_member_identifier &id) = 0;
826+
[[NODISCARD]] virtual bool get_group_member_info_by_member_id(
827+
const Gcs_member_identifier &id, Group_member_info &member_info_arg) = 0;
804828

805829
/**
806830
Return the status of the member with the given GCS identifier.
@@ -977,11 +1001,15 @@ class Group_member_info_manager_interface {
9771001
/**
9781002
Return the group member info for the current group primary
9791003
980-
@note the returned reference must be deallocated by the caller.
1004+
@param[out] member_info_arg a member info reference local to the
1005+
method caller that is updated when the
1006+
member is found.
9811007
982-
@return reference to a Group_member_info. NULL if not managed
1008+
@return true if the member is not found.
1009+
false if the member is found.
9831010
*/
984-
virtual Group_member_info *get_primary_member_info() = 0;
1011+
[[NODISCARD]] virtual bool get_primary_member_info(
1012+
Group_member_info &member_info_arg) = 0;
9851013

9861014
/**
9871015
Check if majority of the group is unreachable
@@ -1106,14 +1134,17 @@ class Group_member_info_manager : public Group_member_info_manager_interface {
11061134

11071135
bool is_member_info_present(const std::string &uuid) override;
11081136

1109-
Group_member_info *get_group_member_info(const std::string &uuid) override;
1137+
[[NODISCARD]] bool get_group_member_info(
1138+
const std::string &uuid, Group_member_info &member_info_arg) override;
11101139

1111-
Group_member_info *get_group_member_info_by_index(int idx) override;
1140+
[[NODISCARD]] bool get_group_member_info_by_index(
1141+
int idx, Group_member_info &member_info_arg) override;
11121142

11131143
Member_version get_group_lowest_online_version() override;
11141144

1115-
Group_member_info *get_group_member_info_by_member_id(
1116-
const Gcs_member_identifier &id) override;
1145+
[[NODISCARD]] bool get_group_member_info_by_member_id(
1146+
const Gcs_member_identifier &id,
1147+
Group_member_info &member_info_arg) override;
11171148

11181149
Group_member_info::Group_member_status get_group_member_status_by_member_id(
11191150
const Gcs_member_identifier &id) override;
@@ -1164,7 +1195,8 @@ class Group_member_info_manager : public Group_member_info_manager_interface {
11641195

11651196
bool get_primary_member_uuid(std::string &primary_member_uuid) override;
11661197

1167-
Group_member_info *get_primary_member_info() override;
1198+
[[NODISCARD]] bool get_primary_member_info(
1199+
Group_member_info &member_info_arg) override;
11681200

11691201
bool is_majority_unreachable() override;
11701202

plugin/group_replication/src/gcs_event_handlers.cc

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -356,13 +356,10 @@ void Plugin_gcs_events_handler::handle_recovery_message(
356356
*/
357357
disable_read_mode_for_compatible_members(true);
358358
} else {
359-
Group_member_info *member_info =
360-
group_member_mgr->get_group_member_info(member_uuid);
361-
if (member_info != nullptr) {
359+
Group_member_info member_info;
360+
if (!group_member_mgr->get_group_member_info(member_uuid, member_info)) {
362361
LogPluginErr(SYSTEM_LEVEL, ER_GRP_RPL_MEM_ONLINE,
363-
member_info->get_hostname().c_str(),
364-
member_info->get_port());
365-
delete member_info;
362+
member_info.get_hostname().c_str(), member_info.get_port());
366363

367364
/*
368365
The member is declared as online upon receiving this message
@@ -486,38 +483,42 @@ void Plugin_gcs_events_handler::on_suspicions(
486483
if (!members.empty()) {
487484
for (mit = members.begin(); mit != members.end(); mit++) {
488485
Gcs_member_identifier member = *mit;
489-
Group_member_info *member_info =
490-
group_member_mgr->get_group_member_info_by_member_id(member);
491-
492-
if (member_info == nullptr) // Trying to update a non-existing member
493-
continue; /* purecov: inspected */
486+
Group_member_info member_info;
487+
488+
if (group_member_mgr->get_group_member_info_by_member_id(member,
489+
member_info)) {
490+
LogPluginErr(WARNING_LEVEL, ER_GRP_RPL_MEMBER_INFO_DOES_NOT_EXIST,
491+
"by the Gcs_member_identifier",
492+
member.get_member_id().c_str(),
493+
"REACHABLE/UNREACHABLE notification from group "
494+
"communication engine");
495+
continue; /* purecov: inspected */
496+
}
494497

495498
uit = std::find(tmp_unreachable.begin(), tmp_unreachable.end(), member);
496499
if (uit != tmp_unreachable.end()) {
497-
if (!member_info->is_unreachable()) {
500+
if (!member_info.is_unreachable()) {
498501
LogPluginErr(WARNING_LEVEL, ER_GRP_RPL_MEM_UNREACHABLE,
499-
member_info->get_hostname().c_str(),
500-
member_info->get_port());
502+
member_info.get_hostname().c_str(),
503+
member_info.get_port());
501504
// flag as a member having changed state
502505
m_notification_ctx.set_member_state_changed();
503-
group_member_mgr->set_member_unreachable(member_info->get_uuid());
506+
group_member_mgr->set_member_unreachable(member_info.get_uuid());
504507
}
505508
// remove to not check again against this one
506509
tmp_unreachable.erase(uit);
507510
} else {
508-
if (member_info->is_unreachable()) {
511+
if (member_info.is_unreachable()) {
509512
LogPluginErr(WARNING_LEVEL, ER_GRP_RPL_MEM_REACHABLE,
510-
member_info->get_hostname().c_str(),
511-
member_info->get_port());
513+
member_info.get_hostname().c_str(),
514+
member_info.get_port());
512515
/* purecov: begin inspected */
513516
// flag as a member having changed state
514517
m_notification_ctx.set_member_state_changed();
515-
group_member_mgr->set_member_reachable(member_info->get_uuid());
518+
group_member_mgr->set_member_reachable(member_info.get_uuid());
516519
/* purecov: end */
517520
}
518521
}
519-
520-
delete member_info;
521522
}
522523
}
523524

@@ -588,31 +589,30 @@ void Plugin_gcs_events_handler::get_hosts_from_view(
588589
members.begin();
589590

590591
while (all_members_it != members.end()) {
591-
Group_member_info *member_info =
592-
group_member_mgr->get_group_member_info_by_member_id((*all_members_it));
592+
Group_member_info member_info;
593+
const bool member_not_found =
594+
group_member_mgr->get_group_member_info_by_member_id((*all_members_it),
595+
member_info);
593596
all_members_it++;
594597

595-
if (member_info == nullptr) continue;
598+
if (member_not_found) continue;
596599

597-
hosts_string << member_info->get_hostname() << ":"
598-
<< member_info->get_port();
600+
hosts_string << member_info.get_hostname() << ":" << member_info.get_port();
599601

600602
/**
601603
Check in_primary_mode has been added for safety.
602604
Since primary role is in single-primary mode.
603605
*/
604-
if (member_info->in_primary_mode() &&
605-
member_info->get_role() == Group_member_info::MEMBER_ROLE_PRIMARY) {
606+
if (member_info.in_primary_mode() &&
607+
member_info.get_role() == Group_member_info::MEMBER_ROLE_PRIMARY) {
606608
if (primary_string.rdbuf()->in_avail() != 0) primary_string << ", ";
607-
primary_string << member_info->get_hostname() << ":"
608-
<< member_info->get_port();
609+
primary_string << member_info.get_hostname() << ":"
610+
<< member_info.get_port();
609611
}
610612

611613
if (all_members_it != members.end()) {
612614
hosts_string << ", ";
613615
}
614-
615-
delete member_info;
616616
}
617617
all_hosts.assign(hosts_string.str());
618618
primary_host.assign(primary_string.str());
@@ -1180,13 +1180,12 @@ int Plugin_gcs_events_handler::process_local_exchanged_data(
11801180
Gcs_member_identifier *member_id = exchanged_data_it->first;
11811181
if (data == nullptr) {
11821182
/* purecov: begin inspected */
1183-
Group_member_info *member_info =
1184-
group_member_mgr->get_group_member_info_by_member_id(*member_id);
1185-
if (member_info != nullptr) {
1183+
Group_member_info member_info;
1184+
if (!group_member_mgr->get_group_member_info_by_member_id(*member_id,
1185+
member_info)) {
11861186
LogPluginErr(ERROR_LEVEL, ER_GRP_RPL_DATA_NOT_PROVIDED_BY_MEM,
1187-
member_info->get_hostname().c_str(),
1188-
member_info->get_port());
1189-
delete member_info;
1187+
member_info.get_hostname().c_str(),
1188+
member_info.get_port());
11901189
}
11911190
continue;
11921191
/* purecov: end */
@@ -1441,10 +1440,9 @@ void Plugin_gcs_events_handler::update_member_status(
14411440
for (vector<Gcs_member_identifier>::const_iterator it = members.begin();
14421441
it != members.end(); ++it) {
14431442
Gcs_member_identifier member = *it;
1444-
Group_member_info *member_info =
1445-
group_member_mgr->get_group_member_info_by_member_id(member);
1446-
1447-
if (member_info == nullptr) {
1443+
Group_member_info member_info;
1444+
if (group_member_mgr->get_group_member_info_by_member_id(member,
1445+
member_info)) {
14481446
// Trying to update a non-existing member
14491447
continue;
14501448
}
@@ -1455,18 +1453,16 @@ void Plugin_gcs_events_handler::update_member_status(
14551453
// (the old_status_different_from is not defined or
14561454
// the previous status is different from old_status_different_from)
14571455
if ((old_status_equal_to == Group_member_info::MEMBER_END ||
1458-
member_info->get_recovery_status() == old_status_equal_to) &&
1456+
member_info.get_recovery_status() == old_status_equal_to) &&
14591457
(old_status_different_from == Group_member_info::MEMBER_END ||
1460-
member_info->get_recovery_status() != old_status_different_from)) {
1458+
member_info.get_recovery_status() != old_status_different_from)) {
14611459
/*
14621460
The notification will be handled on the top level handle
14631461
function that calls this one down the stack.
14641462
*/
1465-
group_member_mgr->update_member_status(member_info->get_uuid(), status,
1463+
group_member_mgr->update_member_status(member_info.get_uuid(), status,
14661464
m_notification_ctx);
14671465
}
1468-
1469-
delete member_info;
14701466
}
14711467
}
14721468

plugin/group_replication/src/group_actions/communication_protocol_action.cc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,13 @@ int Communication_protocol_action::set_consensus_leaders() const {
5353
Gcs_member_identifier const my_gcs_id =
5454
local_member_info->get_gcs_member_id();
5555
if (is_single_primary_mode) {
56-
Group_member_info *primary_info =
57-
group_member_mgr->get_primary_member_info();
58-
if (primary_info == nullptr) {
56+
Group_member_info primary_info;
57+
if (group_member_mgr->get_primary_member_info(primary_info)) {
5958
return 1;
6059
}
6160

6261
Gcs_member_identifier const primary_gcs_id =
63-
primary_info->get_gcs_member_id();
64-
delete primary_info;
62+
primary_info.get_gcs_member_id();
6563
bool const am_i_the_primary = (my_gcs_id == primary_gcs_id);
6664
my_role = (am_i_the_primary ? Group_member_info::MEMBER_ROLE_PRIMARY
6765
: Group_member_info::MEMBER_ROLE_SECONDARY);

plugin/group_replication/src/group_actions/multi_primary_migration_action.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,11 @@ int Multi_primary_migration_action::process_action_message(
8282
return 1; /* purecov: inspected */
8383
}
8484

85-
Group_member_info *primary_info = group_member_mgr->get_primary_member_info();
86-
if (primary_info != nullptr) {
87-
primary_uuid.assign(primary_info->get_uuid());
88-
primary_gcs_id.assign(primary_info->get_gcs_member_id().get_member_id());
85+
Group_member_info primary_info;
86+
if (!group_member_mgr->get_primary_member_info(primary_info)) {
87+
primary_uuid.assign(primary_info.get_uuid());
88+
primary_gcs_id.assign(primary_info.get_gcs_member_id().get_member_id());
8989
is_primary = !primary_uuid.compare(local_member_info->get_uuid());
90-
delete primary_info;
9190
}
9291

9392
group_events_observation_manager->register_group_event_observer(this);

0 commit comments

Comments
 (0)