diff --git a/bazel/BUILD b/bazel/BUILD index ca8db723eb3e..1ad963a26072 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -375,6 +375,13 @@ config_setting( values = {"define": "envoy_yaml=disabled"}, ) +# The goal here is to allow Envoy to build with this option but it is not yet +# complete. See https://github.com/envoyproxy/envoy/issues/27412 +config_setting( + name = "disable_exceptions", + values = {"define": "envoy_exceptions=disabled"}, +) + config_setting( name = "disable_envoy_mobile_listener", values = {"define": "envoy_mobile_listener=disabled"}, diff --git a/bazel/envoy_build_system.bzl b/bazel/envoy_build_system.bzl index da025768f034..8f05c9fcb8ff 100644 --- a/bazel/envoy_build_system.bzl +++ b/bazel/envoy_build_system.bzl @@ -22,6 +22,7 @@ load( _envoy_select_admin_html = "envoy_select_admin_html", _envoy_select_admin_no_html = "envoy_select_admin_no_html", _envoy_select_boringssl = "envoy_select_boringssl", + _envoy_select_disable_exceptions = "envoy_select_disable_exceptions", _envoy_select_disable_logging = "envoy_select_disable_logging", _envoy_select_enable_http3 = "envoy_select_enable_http3", _envoy_select_enable_http_datagrams = "envoy_select_enable_http_datagrams", @@ -242,6 +243,7 @@ envoy_select_disable_logging = _envoy_select_disable_logging envoy_select_google_grpc = _envoy_select_google_grpc envoy_select_enable_http3 = _envoy_select_enable_http3 envoy_select_enable_yaml = _envoy_select_enable_yaml +envoy_select_disable_exceptions = _envoy_select_disable_exceptions envoy_select_hot_restart = _envoy_select_hot_restart envoy_select_enable_http_datagrams = _envoy_select_enable_http_datagrams envoy_select_signal_trace = _envoy_select_signal_trace diff --git a/bazel/envoy_internal.bzl b/bazel/envoy_internal.bzl index 472dfd2fa483..a1f8f1dc6e50 100644 --- a/bazel/envoy_internal.bzl +++ b/bazel/envoy_internal.bzl @@ -1,6 +1,6 @@ # DO NOT LOAD THIS FILE. Targets from this file should be considered private # and not used outside of the @envoy//bazel package. -load(":envoy_select.bzl", "envoy_select_admin_html", "envoy_select_disable_logging", "envoy_select_google_grpc", "envoy_select_hot_restart", "envoy_select_signal_trace", "envoy_select_static_extension_registration") +load(":envoy_select.bzl", "envoy_select_admin_html", "envoy_select_disable_exceptions", "envoy_select_disable_logging", "envoy_select_google_grpc", "envoy_select_hot_restart", "envoy_select_signal_trace", "envoy_select_static_extension_registration") # Compute the final copts based on various options. def envoy_copts(repository, test = False): @@ -119,6 +119,7 @@ def envoy_copts(repository, test = False): repository + "//bazel:uhv_enabled": ["-DENVOY_ENABLE_UHV"], "//conditions:default": [], }) + envoy_select_hot_restart(["-DENVOY_HOT_RESTART"], repository) + \ + envoy_select_disable_exceptions(["-fno-unwind-tables", "-fno-exceptions"], repository) + \ envoy_select_admin_html(["-DENVOY_ADMIN_HTML"], repository) + \ envoy_select_static_extension_registration(["-DENVOY_STATIC_EXTENSION_REGISTRATION"], repository) + \ envoy_select_disable_logging(["-DENVOY_DISABLE_LOGGING"], repository) + \ diff --git a/bazel/envoy_mobile_defines.bzl b/bazel/envoy_mobile_defines.bzl index df2fd7a7cdbf..5bce8ebef8bf 100644 --- a/bazel/envoy_mobile_defines.bzl +++ b/bazel/envoy_mobile_defines.bzl @@ -1,11 +1,12 @@ # DO NOT LOAD THIS FILE. Load envoy_build_system.bzl instead. -load(":envoy_select.bzl", "envoy_select_admin_functionality", "envoy_select_enable_http3", "envoy_select_enable_http_datagrams", "envoy_select_enable_yaml", "envoy_select_envoy_mobile_listener", "envoy_select_envoy_mobile_request_compression", "envoy_select_envoy_mobile_stats_reporting", "envoy_select_google_grpc") +load(":envoy_select.bzl", "envoy_select_admin_functionality", "envoy_select_disable_exceptions", "envoy_select_enable_http3", "envoy_select_enable_http_datagrams", "envoy_select_enable_yaml", "envoy_select_envoy_mobile_listener", "envoy_select_envoy_mobile_request_compression", "envoy_select_envoy_mobile_stats_reporting", "envoy_select_google_grpc") # Compute the defines needed for Envoy Mobile libraries that don't use Envoy's main library wrappers. def envoy_mobile_defines(repository): return envoy_select_admin_functionality(["ENVOY_ADMIN_FUNCTIONALITY"], repository) + \ envoy_select_enable_http3(["ENVOY_ENABLE_QUIC"], repository) + \ envoy_select_enable_yaml(["ENVOY_ENABLE_YAML"], repository) + \ + envoy_select_disable_exceptions(["ENVOY_DISABLE_EXCEPTIONS"], repository) + \ envoy_select_enable_http_datagrams(["ENVOY_ENABLE_HTTP_DATAGRAMS"], repository) + \ envoy_select_envoy_mobile_listener(["ENVOY_MOBILE_ENABLE_LISTENER"], repository) + \ envoy_select_envoy_mobile_stats_reporting(["ENVOY_MOBILE_STATS_REPORTING"], repository) + \ diff --git a/bazel/envoy_select.bzl b/bazel/envoy_select.bzl index 7fee86b3eeab..7cd774bd460e 100644 --- a/bazel/envoy_select.bzl +++ b/bazel/envoy_select.bzl @@ -94,6 +94,13 @@ def envoy_select_enable_yaml(xs, repository = ""): "//conditions:default": xs, }) +# Selects the given values if exceptions are disabled in the current build. +def envoy_select_disable_exceptions(xs, repository = ""): + return select({ + repository + "//bazel:disable_exceptions": xs, + "//conditions:default": [], + }) + # Selects the given values if HTTP datagram support is enabled in the current build. def envoy_select_enable_http_datagrams(xs, repository = ""): return select({ diff --git a/mobile/library/common/engine.cc b/mobile/library/common/engine.cc index a21c37c80ac5..125b443728fe 100644 --- a/mobile/library/common/engine.cc +++ b/mobile/library/common/engine.cc @@ -49,7 +49,7 @@ envoy_status_t Engine::main(std::unique_ptr&& options) { std::unique_ptr main_common; { Thread::LockGuard lock(mutex_); - try { + TRY_NEEDS_AUDIT { if (event_tracker_.track != nullptr) { assert_handler_registration_ = Assert::addDebugAssertionFailureRecordAction([this](const char* location) { @@ -79,13 +79,9 @@ envoy_status_t Engine::main(std::unique_ptr&& options) { event_dispatcher_ = &server_->dispatcher(); cv_.notifyAll(); - } catch (const Envoy::NoServingException& e) { - PANIC(e.what()); - } catch (const Envoy::MalformedArgvException& e) { - PANIC(e.what()); - } catch (const Envoy::EnvoyException& e) { - PANIC(e.what()); } + END_TRY + CATCH(const Envoy::EnvoyException& e, { PANIC(e.what()); }); // Note: We're waiting longer than we might otherwise to drain to the main thread's dispatcher. // This is because we're not simply waiting for its availability and for it to have started, but diff --git a/source/common/common/thread.h b/source/common/common/thread.h index b3f2fa17652c..a1d651efe679 100644 --- a/source/common/common/thread.h +++ b/source/common/common/thread.h @@ -237,9 +237,34 @@ class MainThread { #define END_TRY } +#ifdef ENVOY_DISABLE_EXCEPTIONS +#define TRY_NEEDS_AUDIT { +#else // TODO(chaoqinli-1123): Remove this macros after we have removed all the exceptions from data // plane. -#define TRY_NEEDS_AUDIT try +#define TRY_NEEDS_AUDIT try { +#endif + +#ifdef ENVOY_DISABLE_EXCEPTIONS +#define CATCH(ExceptionType, Handler) +#else +#define CATCH(Exception, Handler) \ + catch (Exception) { \ + Handler \ + } +#endif + +#ifdef ENVOY_DISABLE_EXCEPTIONS +#define MULTI_CATCH(ExceptionType, Handler) +#else +#define MULTI_CATCH(Exception, Handler, Handler2) \ + catch (Exception) { \ + Handler \ + } \ + catch (...) { \ + Handler2 \ + } +#endif // These convenience macros assert properties of the threading system, when // feasible. There is a platform-specific mechanism for determining whether the @@ -277,6 +302,9 @@ class MainThread { #endif +#ifdef ENVOY_DISABLE_EXCEPTIONS +#define TRY_ASSERT_MAIN_THREAD { +#else /** * To improve exception safety in data plane, we plan to forbid the use of raw * try in the core code base. This macros uses main thread assertion to make @@ -285,6 +313,7 @@ class MainThread { #define TRY_ASSERT_MAIN_THREAD \ try { \ ASSERT_IS_MAIN_OR_TEST_THREAD(); +#endif /** * RAII class to override thread assertions checks in the macros: diff --git a/source/common/filter/config_discovery_impl.cc b/source/common/filter/config_discovery_impl.cc index c08e0d146383..3f6c40cce4b4 100644 --- a/source/common/filter/config_discovery_impl.cc +++ b/source/common/filter/config_discovery_impl.cc @@ -220,11 +220,12 @@ void FilterConfigProviderManagerImplBase::applyLastOrDefaultConfig( subscription->lastFactoryName()); last_config_valid = true; } - END_TRY catch (const EnvoyException& e) { + END_TRY CATCH(const EnvoyException& e, { ENVOY_LOG(debug, "ECDS subscription {} is invalid in a listener context: {}.", filter_config_name, e.what()); subscription->incrementConflictCounter(); - } + }); + if (last_config_valid) { provider.onConfigUpdate(*subscription->lastConfig(), subscription->lastVersionInfo(), nullptr); diff --git a/source/common/router/header_parser_utils.cc b/source/common/router/header_parser_utils.cc index 39136cfce837..d278e04de445 100644 --- a/source/common/router/header_parser_utils.cc +++ b/source/common/router/header_parser_utils.cc @@ -51,10 +51,7 @@ std::string HeaderParser::translateMetadataFormat(const std::string& header_valu int subs = absl::StrReplaceAll({{matches[0].as_string(), new_format}}, &new_header_value); ASSERT(subs > 0); } - END_TRY - catch (Json::Exception& e) { - return header_value; - } + END_TRY CATCH(Json::Exception & e, { return header_value; }); } return new_header_value; diff --git a/source/common/runtime/runtime_impl.cc b/source/common/runtime/runtime_impl.cc index 423493601583..bce5ae8e16a7 100644 --- a/source/common/runtime/runtime_impl.cc +++ b/source/common/runtime/runtime_impl.cc @@ -690,13 +690,13 @@ SnapshotImplPtr LoaderImpl::createNewSnapshot() { ++disk_layers; } END_TRY - catch (EnvoyException& e) { + CATCH(EnvoyException & e, { // TODO(htuch): Consider latching here, rather than ignoring the // layer. This would be consistent with filesystem RTDS. ++error_layers; ENVOY_LOG(debug, "error loading runtime values for layer {} from disk: {}", layer.DebugString(), e.what()); - } + }); } break; } diff --git a/source/common/secret/sds_api.cc b/source/common/secret/sds_api.cc index e20ca282f22e..effcac5a1a62 100644 --- a/source/common/secret/sds_api.cc +++ b/source/common/secret/sds_api.cc @@ -73,10 +73,10 @@ void SdsApi::onWatchUpdate() { } } END_TRY - catch (const EnvoyException& e) { + CATCH(const EnvoyException& e, { ENVOY_LOG_MISC(warn, fmt::format("Failed to reload certificates: {}", e.what())); sds_api_stats_.key_rotation_failed_.inc(); - } + }); } void SdsApi::onConfigUpdate(const std::vector& resources, diff --git a/source/common/stats/tag_extractor_impl.cc b/source/common/stats/tag_extractor_impl.cc index 2ac20ee1648f..75efdcf73017 100644 --- a/source/common/stats/tag_extractor_impl.cc +++ b/source/common/stats/tag_extractor_impl.cc @@ -21,9 +21,8 @@ namespace { std::regex parseStdRegex(const std::string& regex) { TRY_ASSERT_MAIN_THREAD { return std::regex(regex, std::regex::optimize); } END_TRY - catch (const std::regex_error& e) { - throw EnvoyException(fmt::format("Invalid regex '{}': {}", regex, e.what())); - } + CATCH(const std::regex_error& e, + { throw EnvoyException(fmt::format("Invalid regex '{}': {}", regex, e.what())); }); } } // namespace diff --git a/source/common/upstream/cds_api_helper.cc b/source/common/upstream/cds_api_helper.cc index 6bd1655d4a5e..306d6c0fe1e9 100644 --- a/source/common/upstream/cds_api_helper.cc +++ b/source/common/upstream/cds_api_helper.cc @@ -54,10 +54,10 @@ CdsApiHelper::onConfigUpdate(const std::vector& adde } } END_TRY - catch (const EnvoyException& e) { - exception_msgs.push_back(fmt::format("{}: {}", cluster.name(), e.what())); - } + CATCH(const EnvoyException& e, + { exception_msgs.push_back(fmt::format("{}: {}", cluster.name(), e.what())); }); } + for (const auto& resource_name : removed_resources) { if (cm_.removeCluster(resource_name)) { any_applied = true; diff --git a/source/common/upstream/health_discovery_service.cc b/source/common/upstream/health_discovery_service.cc index 30f16ac78084..08815cb4acdd 100644 --- a/source/common/upstream/health_discovery_service.cc +++ b/source/common/upstream/health_discovery_service.cc @@ -289,14 +289,14 @@ void HdsDelegate::onReceiveMessage( server_context_.messageValidationContext().dynamicValidationVisitor()); } END_TRY - catch (const ProtoValidationException& ex) { + CATCH(const ProtoValidationException& ex, { // Increment error count stats_.errors_.inc(); ENVOY_LOG(warn, "Unable to validate health check specifier: {}", ex.what()); // Do not continue processing message return; - } + }); // Set response auto server_response_ms = PROTOBUF_GET_MS_OR_DEFAULT(*message, interval, 1000); diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index 5bda8581a491..1a09f4e6fb86 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -1623,7 +1623,7 @@ const Network::Address::InstanceConstSharedPtr ClusterImplBase::resolveProtoAddress(const envoy::config::core::v3::Address& address) { TRY_ASSERT_MAIN_THREAD { return Network::Address::resolveProtoAddress(address); } END_TRY - catch (EnvoyException& e) { + CATCH(EnvoyException & e, { if (info_->type() == envoy::config::cluster::v3::Cluster::STATIC || info_->type() == envoy::config::cluster::v3::Cluster::EDS) { throw EnvoyException(fmt::format("{}. Consider setting resolver_name or setting cluster type " @@ -1631,7 +1631,7 @@ ClusterImplBase::resolveProtoAddress(const envoy::config::core::v3::Address& add e.what())); } throw e; - } + }); } void ClusterImplBase::validateEndpointsForZoneAwareRouting( diff --git a/source/exe/stripped_main_base.cc b/source/exe/stripped_main_base.cc index 9d532a993b90..878e72a75735 100644 --- a/source/exe/stripped_main_base.cc +++ b/source/exe/stripped_main_base.cc @@ -129,10 +129,10 @@ void StrippedMainBase::configureHotRestarter(Random::RandomGenerator& random_gen options_.socketMode()); } END_TRY - catch (Server::HotRestartDomainSocketInUseException& ex) { + CATCH(Server::HotRestartDomainSocketInUseException & ex, { // No luck, try again. ENVOY_LOG_MISC(debug, "dynamic base id: {}", ex.what()); - } + }); } if (restarter == nullptr) { diff --git a/source/extensions/grpc_credentials/file_based_metadata/config.cc b/source/extensions/grpc_credentials/file_based_metadata/config.cc index aebba3b17150..1fa300a2f711 100644 --- a/source/extensions/grpc_credentials/file_based_metadata/config.cc +++ b/source/extensions/grpc_credentials/file_based_metadata/config.cc @@ -75,8 +75,9 @@ FileBasedMetadataAuthenticator::GetMetadata(grpc::string_ref, grpc::string_ref, std::string header_value = Envoy::Config::DataSource::read(config_.secret_data(), true, api_); metadata->insert(std::make_pair(header_key, header_prefix + header_value)); } + END_TRY catch (const EnvoyException& e) { - return grpc::Status(grpc::StatusCode::NOT_FOUND, e.what()); + return {grpc::StatusCode::NOT_FOUND, e.what()}; } return grpc::Status::OK; } diff --git a/source/extensions/network/dns_resolver/cares/dns_impl.cc b/source/extensions/network/dns_resolver/cares/dns_impl.cc index 1c4bd6fa6a51..12cf91e9c33f 100644 --- a/source/extensions/network/dns_resolver/cares/dns_impl.cc +++ b/source/extensions/network/dns_resolver/cares/dns_impl.cc @@ -287,6 +287,7 @@ void DnsResolverImpl::PendingResolution::finishResolve() { TRY_NEEDS_AUDIT { callback_(pending_response_.status_, std::move(pending_response_.address_list_)); } + END_TRY catch (const EnvoyException& e) { ENVOY_LOG(critical, "EnvoyException in c-ares callback: {}", e.what()); dispatcher_.post([s = std::string(e.what())] { throw EnvoyException(s); }); diff --git a/source/server/options_impl.cc b/source/server/options_impl.cc index 6345c789e897..81d7490c095e 100644 --- a/source/server/options_impl.cc +++ b/source/server/options_impl.cc @@ -161,25 +161,24 @@ OptionsImpl::OptionsImpl(std::vector args, false, "string", cmd); cmd.setExceptionHandling(false); - TRY_ASSERT_MAIN_THREAD { - cmd.parse(args); - count_ = cmd.getArgList().size(); - } - END_TRY - catch (TCLAP::ArgException& e) { + + std::function failure_function = [&](TCLAP::ArgException& e) { TRY_ASSERT_MAIN_THREAD { cmd.getOutput()->failure(cmd, e); } END_TRY - catch (const TCLAP::ExitException&) { + CATCH(const TCLAP::ExitException&, { // failure() has already written an informative message to stderr, so all that's left to do // is throw our own exception with the original message. throw MalformedArgvException(e.what()); - } - } - catch (const TCLAP::ExitException& e) { - // parse() throws an ExitException with status 0 after printing the output for --help and - // --version. - throw NoServingException(); + }); + }; + + TRY_ASSERT_MAIN_THREAD { + cmd.parse(args); + count_ = cmd.getArgList().size(); } + END_TRY + MULTI_CATCH( + TCLAP::ArgException & e, { failure_function(e); }, { throw NoServingException(); }); hot_restart_disabled_ = disable_hot_restart.getValue(); mutex_tracing_enabled_ = enable_mutex_tracing.getValue(); diff --git a/source/server/server.cc b/source/server/server.cc index 8ed78eb8b139..91c72e529197 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -105,41 +105,41 @@ InstanceImpl::InstanceImpl( router_context_(store.symbolTable()), process_context_(std::move(process_context)), hooks_(hooks), quic_stat_names_(store.symbolTable()), server_contexts_(*this), enable_reuse_port_default_(true), stats_flush_in_progress_(false) { + std::function set_up_logger = [&] { + TRY_ASSERT_MAIN_THREAD { + file_logger_ = std::make_unique( + options.logPath(), access_log_manager_, Logger::Registry::getSink()); + } + END_TRY + CATCH(const EnvoyException& e, { + throw EnvoyException( + fmt::format("Failed to open log-file '{}'. e.what(): {}", options.logPath(), e.what())); + }); + }; + TRY_ASSERT_MAIN_THREAD { if (!options.logPath().empty()) { - TRY_ASSERT_MAIN_THREAD { - file_logger_ = std::make_unique( - options.logPath(), access_log_manager_, Logger::Registry::getSink()); - } - END_TRY - catch (const EnvoyException& e) { - throw EnvoyException( - fmt::format("Failed to open log-file '{}'. e.what(): {}", options.logPath(), e.what())); - } + set_up_logger(); } - restarter_.initialize(*dispatcher_, *this); drain_manager_ = component_factory.createDrainManager(*this); initialize(std::move(local_address), component_factory); } END_TRY - catch (const EnvoyException& e) { - ENVOY_LOG(critical, "error initializing config '{} {} {}': {}", - options.configProto().DebugString(), options.configYaml(), options.configPath(), - e.what()); - terminate(); - throw; - } - catch (const std::exception& e) { - ENVOY_LOG(critical, "error initializing due to unexpected exception: {}", e.what()); - terminate(); - throw; - } - catch (...) { - ENVOY_LOG(critical, "error initializing due to unknown exception"); - terminate(); - throw; - } + MULTI_CATCH( + const EnvoyException& e, + { + ENVOY_LOG(critical, "error initializing config '{} {} {}': {}", + options.configProto().DebugString(), options.configYaml(), options.configPath(), + e.what()); + terminate(); + throw; + }, + { + ENVOY_LOG(critical, "error initializing due to unknown exception"); + terminate(); + throw; + }); } InstanceImpl::~InstanceImpl() {