Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix segfault caused by modifying list within iteration. #922

Merged
merged 2 commits into from
May 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion source/common/upstream/cluster_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,12 @@ void ClusterManagerInitHelper::maybeFinishInitialize() {
if (!started_secondary_initialize_) {
log().info("cm init: initializing secondary clusters");
started_secondary_initialize_ = true;
for (Cluster* cluster : secondary_init_clusters_) {
// Cluster::initialize() method can modify the list of secondary_init_clusters_ to remove
// the item currently being initialized, so we eschew range-based-for and do this complicated
// dance to increment the iterator before calling initialize.
for (auto iter = secondary_init_clusters_.begin(); iter != secondary_init_clusters_.end();) {
Cluster* cluster = *iter;
++iter;
cluster->initialize();
}
}
Expand Down
21 changes: 21 additions & 0 deletions test/common/upstream/cluster_manager_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -838,4 +838,25 @@ TEST(ClusterManagerInitHelper, AddSecondaryAfterSecondaryInit) {
cluster2.initialize_callback_();
}

TEST(ClusterManagerInitHelper, RemoveClusterWithinInitLoop) {
// Tests the scenario encountered in Issue 903: The cluster was removed from
// the secondary init list while traversing the list.

InSequence s;
ClusterManagerInitHelper init_helper;
NiceMock<MockCluster> cluster;
ON_CALL(cluster, initializePhase()).WillByDefault(Return(Cluster::InitializePhase::Secondary));
init_helper.addCluster(cluster);

// Set up the scenario seen in Issue 903 where initialize() ultimately results
// in the removeCluster() call. In the real bug this was a long and complex call
// chain.
EXPECT_CALL(cluster, initialize())
.WillOnce(Invoke([&]() -> void { init_helper.removeCluster(cluster); }));

// Now call onStaticLoadComplete which will exercise maybeFinishInitialize()
// which calls initialize() on the members of the secondary init list.
init_helper.onStaticLoadComplete();
}

} // Upstream