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

backport to 1.13: Prevent SEGFAULT when disabling listener (#13515) #14036

Closed
wants to merge 2 commits into from
Closed
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
1 change: 1 addition & 0 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Version history
================
Changes
-------
* listener: fix crash when disabling or re-enabling listeners due to overload while processing LDS updates.

1.13.6 (September 29, 2020)
===========================
Expand Down
2 changes: 1 addition & 1 deletion source/common/common/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ bool StringUtil::findToken(absl::string_view source, absl::string_view delimiter
absl::string_view key_token, bool trim_whitespace) {
const auto tokens = splitToken(source, delimiters, trim_whitespace);
if (trim_whitespace) {
for (const auto token : tokens) {
for (const auto& token : tokens) {
if (key_token == trim(token)) {
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion source/common/http/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ std::string Utility::parseCookieValue(const HeaderMap& headers, const std::strin
if (header.key() == Http::Headers::get().Cookie.get()) {

// Split the cookie header into individual cookies.
for (const auto s : StringUtil::splitToken(header.value().getStringView(), ";")) {
for (const auto& s : StringUtil::splitToken(header.value().getStringView(), ";")) {
// Find the key part of the cookie (i.e. the name of the cookie).
size_t first_non_space = s.find_first_not_of(" ");
size_t equals_index = s.find('=');
Expand Down
8 changes: 4 additions & 4 deletions source/common/router/retry_state_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ RetryStateImpl::RetryStateImpl(const RetryPolicy& route_policy, Http::HeaderMap&
}

if (request_headers.EnvoyRetriableStatusCodes()) {
for (const auto code : StringUtil::splitToken(
for (const auto& code : StringUtil::splitToken(
request_headers.EnvoyRetriableStatusCodes()->value().getStringView(), ",")) {
unsigned int out;
if (absl::SimpleAtoi(code, &out)) {
Expand All @@ -128,7 +128,7 @@ RetryStateImpl::RetryStateImpl(const RetryPolicy& route_policy, Http::HeaderMap&
// to provide HeaderMatcher serialized into a string. To avoid this extra
// complexity we only support name-only header matchers via request
// header. Anything more sophisticated needs to be provided via config.
for (const auto header_name : StringUtil::splitToken(
for (const auto& header_name : StringUtil::splitToken(
request_headers.EnvoyRetriableHeaderNames()->value().getStringView(), ",")) {
envoy::config::route::v3::HeaderMatcher header_matcher;
header_matcher.set_name(std::string(absl::StripAsciiWhitespace(header_name)));
Expand All @@ -152,7 +152,7 @@ void RetryStateImpl::enableBackoffTimer() {
std::pair<uint32_t, bool> RetryStateImpl::parseRetryOn(absl::string_view config) {
uint32_t ret = 0;
bool all_fields_valid = true;
for (const auto retry_on : StringUtil::splitToken(config, ",")) {
for (const auto& retry_on : StringUtil::splitToken(config, ",")) {
if (retry_on == Http::Headers::get().EnvoyRetryOnValues._5xx) {
ret |= RetryPolicy::RETRY_ON_5XX;
} else if (retry_on == Http::Headers::get().EnvoyRetryOnValues.GatewayError) {
Expand Down Expand Up @@ -180,7 +180,7 @@ std::pair<uint32_t, bool> RetryStateImpl::parseRetryOn(absl::string_view config)
std::pair<uint32_t, bool> RetryStateImpl::parseRetryGrpcOn(absl::string_view retry_grpc_on_header) {
uint32_t ret = 0;
bool all_fields_valid = true;
for (const auto retry_on : StringUtil::splitToken(retry_grpc_on_header, ",")) {
for (const auto& retry_on : StringUtil::splitToken(retry_grpc_on_header, ",")) {
if (retry_on == Http::Headers::get().EnvoyRetryOnGrpcValues.Cancelled) {
ret |= RetryPolicy::RETRY_ON_GRPC_CANCELLED;
} else if (retry_on == Http::Headers::get().EnvoyRetryOnGrpcValues.DeadlineExceeded) {
Expand Down
2 changes: 1 addition & 1 deletion source/common/runtime/runtime_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ void DiskLayer::walkDirectory(const std::string& path, const std::string& prefix
// Comments are useful for placeholder files with no value.
const std::string text_file{api.fileSystem().fileReadToEnd(full_path)};
const auto lines = StringUtil::splitToken(text_file, "\n");
for (const auto line : lines) {
for (const auto& line : lines) {
if (!line.empty() && line.front() == '#') {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ typename std::enable_if<std::is_signed<T>::value, T>::type leftShift(T left, uin
inline void addByte(Buffer::Instance& buffer, const uint8_t value) { buffer.add(&value, 1); }

void addSeq(Buffer::Instance& buffer, const std::initializer_list<uint8_t>& values) {
for (const int8_t& value : values) {
for (const uint8_t& value : values) {
buffer.add(&value, 1);
}
}
Expand Down
2 changes: 1 addition & 1 deletion source/extensions/stat_sinks/hystrix/hystrix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void HystrixSink::addHistogramToStream(const QuantileLatencyMap& latency_map, ab
// TODO: Consider if we better use join here
ss << ", \"" << key << "\": {";
bool is_first = true;
for (const std::pair<double, double>& element : latency_map) {
for (const auto& element : latency_map) {
const std::string quantile = fmt::sprintf("%g", element.first * 100);
HystrixSink::addDoubleToStream(quantile, element.second, ss, is_first);
is_first = false;
Expand Down
12 changes: 12 additions & 0 deletions source/server/connection_handler_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,18 @@ void ConnectionHandlerImpl::ActiveTcpListener::onAcceptWorker(
}
}

void ConnectionHandlerImpl::ActiveTcpListener::pauseListening() {
if (listener_ != nullptr) {
listener_->disable();
}
}

void ConnectionHandlerImpl::ActiveTcpListener::resumeListening() {
if (listener_ != nullptr) {
listener_->enable();
}
}

void ConnectionHandlerImpl::ActiveTcpListener::newConnection(
Network::ConnectionSocketPtr&& socket) {
// Find matching filter chain.
Expand Down
3 changes: 3 additions & 0 deletions source/server/connection_handler_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ class ConnectionHandlerImpl : public Network::ConnectionHandler,
// ActiveListenerImplBase
Network::Listener* listener() override { return listener_.get(); }
void destroy() override { listener_.reset(); }
void pauseListening() override;
void resumeListening() override;
void shutdownListener() override { listener_.reset(); }

// Network::BalancedConnectionHandler
uint64_t numConnections() const override { return num_listener_connections_; }
Expand Down
16 changes: 16 additions & 0 deletions test/server/connection_handler_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,22 @@ TEST_F(ConnectionHandlerTest, AddDisabledListener) {
handler_->addListener(*test_listener);
}

TEST_F(ConnectionHandlerTest, DisableListenerAfterStop) {
InSequence s;

Network::TcpListenerCallbacks* listener_callbacks;
auto listener = new NiceMock<Network::MockListener>();
TestListener* test_listener =
addListener(1, false, false, "test_listener", listener, &listener_callbacks);
EXPECT_CALL(*socket_factory_, localAddress()).WillOnce(ReturnRef(local_address_));
handler_->addListener(absl::nullopt, *test_listener);

EXPECT_CALL(*listener, onDestroy());

handler_->stopListeners();
handler_->disableListeners();
}

TEST_F(ConnectionHandlerTest, DestroyCloseConnections) {
InSequence s;

Expand Down