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

exception: make Ipv6Instance and Ipv4Instance not throw and remove some try catch pattern #16122

Merged
merged 35 commits into from
Jun 23, 2021

Conversation

chaoqin-li1123
Copy link
Member

For an explanation of how to fill out the fields, please see the relevant section
in PULL_REQUESTS.md

Commit Message:This is part of the effort to remove C++ exception from data plane by adding assertion that the code is executed in main thread when an exception is caught.(#14320) By making the constructor of instances(PipeInstance, Ipv6Instance, Ipv4Instance) no throw, remove some try catch code from envoy.
Additional Description:
Risk Level:
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Deprecated:]
[Optional API Considerations:]

Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great, thank! Mostly just don't want to drop error message detail here.

source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Show resolved Hide resolved
source/common/network/io_socket_handle_impl.cc Outdated Show resolved Hide resolved
test/common/network/dns_impl_test.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/cidr_range.cc Outdated Show resolved Hide resolved
source/common/network/dns_impl.cc Outdated Show resolved Hide resolved
source/common/network/utility.cc Outdated Show resolved Hide resolved
@chaoqin-li1123
Copy link
Member Author

chaoqin-li1123 commented Apr 25, 2021

We need a template method to return different type of instance instead of a ptr to their base class because some Instance has non-virtual method. I would like to name these two methods createInstancePtr and createInstance.

source/common/network/address_impl.cc Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.h Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/io_socket_handle_impl.cc Outdated Show resolved Hide resolved
source/common/network/io_socket_handle_impl.cc Outdated Show resolved Hide resolved
source/common/network/utility.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
@chaoqin-li1123 chaoqin-li1123 changed the title [WIP]: make Ipv6Instance and Ipv4Instance not throw and remove some try catch pattern [exception]: make Ipv6Instance and Ipv4Instance not throw and remove some try catch pattern Apr 26, 2021
Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what state this is in. Can you ping me directly when this is ready for another round of deep review?

include/envoy/network/address.h Outdated Show resolved Hide resolved
@jmarantz
Copy link
Contributor

jmarantz commented Apr 27, 2021

Per f2f discussion, in cases where there are a large number of references to raw constructors in the codebase, a better way to go might be:

  • Put the constructor logic in a new constructor that takes an absl::Status& as its first arg, and returns its error status that way
  • Make the existing constructor somehow call that one, capturing the Status and throwing if there is a failure, propagating the message. Independent of whether it fails, assert isMainThread

This way most of the call-sites don't need to change, but we are verifying you can only call them in the main thread context.

I think the tricky part is the pattern of having the throwing constructor calling the non-throwing one as it won't have a good place to store the Status. So factoring out the logic might be a little annoying. One possible remedy is to put all the logic in an 'init' method that returns the Status, so the two calls are:

// throwing-constructor:
Foo::Foo(ags...) {
  ASSERT(Thread::isMainThread());
  absl::Status status = init(args);
  if (!status.ok()) {
    throw EnvoyException(status.message());
  }
}

// non-throwing-constructor
Foo::Foo(absl::Status& status, args...) {
  status = init(args);
}

The drawback here is that you won't be able to use contructor-initializers which means none of the member vars can be const. Not sure how important that is.

@yanavlasov yanavlasov self-assigned this Apr 27, 2021
@chaoqin-li1123
Copy link
Member Author

Per f2f discussion, in cases where there are a large number of references to raw constructors in the codebase, a better way to go might be:

  • Put the constructor logic in a new constructor that takes an absl::Status& as its first arg, and returns its error status that way
  • Make the existing constructor somehow call that one, capturing the Status and throwing if there is a failure, propagating the message. Independent of whether it fails, assert isMainThread

This way most of the call-sites don't need to change, but we are verifying you can only call them in the main thread context.

I think the tricky part is the pattern of having the throwing constructor calling the non-throwing one as it won't have a good place to store the Status. So factoring out the logic might be a little annoying. One possible remedy is to put all the logic in an 'init' method that returns the Status, so the two calls are:

// throwing-constructor:
Foo::Foo(ags...) {
  ASSERT(Thread::isMainThread());
  absl::Status status = init(args);
  if (!status.ok()) {
    throw EnvoyException(status.message());
  }
}

// non-throwing-constructor
Foo::Foo(absl::Status& status, args...) {
  status = init(args);
}

The drawback here is that you won't be able to use contructor-initializers which means none of the member vars can be const. Not sure how important that is.

I think it is fine to change all the caller, since most of the code that call instance constructor directly are inside a test file instead of source code, it is safe to replace them all.

Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are basically on the right track but need a few passes to clean up, factor out common patterns like "OrDie" correctly, avoid swallowing errors where they weren't swallowed before.

source/common/network/address_impl.cc Outdated Show resolved Hide resolved
source/common/network/address_impl.cc Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/address_impl.h Outdated Show resolved Hide resolved
source/common/network/utility.cc Outdated Show resolved Hide resolved
}
NOT_REACHED_GCOVR_EXCL_LINE;
if (!addr.ok()) {
return nullptr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously an error here would have resulted in a Throw, right? Should we return the StatusOr here so that callers can find the error message where they previously had caught an error and logged it in context?

In general you should make sure your changes don't drop information that may be needed when debugging a crash with logs.

source/extensions/transport_sockets/tls/utility.cc Outdated Show resolved Hide resolved
chaoqin-li1123 added 2 commits May 5, 2021 16:44
Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
@chaoqin-li1123
Copy link
Member Author

Change the implementation of addressFromSockAddr(), parseInternetAddressNoThrow() and getAddressWithPort()
to use non throw version.

Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
@jmarantz
Copy link
Contributor

/wait

Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
jmarantz
jmarantz previously approved these changes Jun 17, 2021
Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much, Chaoqin! This looks like a great improvement and a major step in the right direction.

/assign-from @envoyproxy/senior-maintainers

@repokitteh-read-only
Copy link

@envoyproxy/senior-maintainers assignee is @htuch

🐱

Caused by: a #16122 (review) was submitted by @jmarantz.

see: more, trace.

@@ -53,6 +69,21 @@ class InstanceBase : public Instance {
const Type type_;
};

class InstanceFactory {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is used in multiple .cc, it's basically a public interface, can you please document it better? Thanks.

absl::Status status;
// Use new instead of make_unique here because the instance constructors are private and must be
// called directly here.
std::unique_ptr<InstanceType> instance(new InstanceType(status, std::forward<Args>(args)...));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we no longer returning shared ptr but instead unique ptr?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think I never fully understood the answer to this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning a unique_ptr from factory is a good practice because it makes the interface more general. unique_ptr can be implicitly cast to shared_ptr but not vice versa. So return a unique_ptr is equivalent to return a unique_ptr or shared_ptr.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's probably better not to change this interface in this PR just because it's better practice. A separate PR can be filed for that.

Large PRs that change semantics should minimize other changes, especially to interfaces.

@@ -77,6 +77,15 @@ StatusOr<Address::InstanceConstSharedPtr> addressFromSockAddr(const sockaddr_sto
NOT_REACHED_GCOVR_EXCL_LINE;
}

Address::InstanceConstSharedPtr addressFromSockAddrOrThrow(const sockaddr_storage& ss,
socklen_t ss_len, bool v6only) {
StatusOr<InstanceConstSharedPtr> address = addressFromSockAddr(ss, ss_len, v6only);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm missing something here, but it seems we're not improving anything if we're still either throwing or dying on the working thread?

Can you maybe explain the context of this PR so I can understand scope better. I.e. what's the long term game plan here.

@jmarantz
Copy link
Contributor

/wait

@chaoqin-li1123
Copy link
Member Author

This was an attempt to remove 2 TRY_NEEDS_AUDIT at first. But the try in the dns_impl.cc can't be actually removed because of fuzz test issue, so we only remove the TRY_NEEDS_AUDIT in addressFromSockAddrOrDie. I think eventually we want to clean up all the TRY_NEEDS_AUDIT by either whitelisting them or refactoring them.

@chaoqin-li1123
Copy link
Member Author

the non-throw constructor of address instance allow creating an instance in worker thread without throwing, though I can't find any code where these error status can be handled and then return back to normal execution.

@chaoqin-li1123
Copy link
Member Author

From my point of view, we are trying to clean up the TRY_NEEDS_AUDIT.

Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
source/common/network/address_impl.cc Outdated Show resolved Hide resolved
memset(&ip_.ipv4_.address_, 0, sizeof(ip_.ipv4_.address_));
ip_.ipv4_.address_.sin_family = AF_INET;
ip_.ipv4_.address_.sin_port = htons(port);
ip_.ipv4_.address_.sin_addr.s_addr = INADDR_ANY;
friendly_name_ = absl::StrCat("0.0.0.0:", port);
validateIpv4Supported(friendly_name_);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't initHelper() or some variant be used here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Friendly ping

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because initHelper() is used to remove duplicate code in throw and not throw version of ctors, we don't have a not throw version of this ctor.

source/common/network/address_impl.cc Show resolved Hide resolved
Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
@@ -300,8 +357,40 @@ PipeInstance::PipeInstance(const std::string& pipe_path, mode_t mode,
pipe_.mode_ = mode;
}

PipeInstance::PipeInstance(absl::Status& error, const sockaddr_un* address, socklen_t ss_len,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not spotting where this new constructor variant is used, can you point out?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Address::InstanceFactory::createInstancePtrAddress::PipeInstance(sun, ss_len); In addressFromSockAddr()

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as a step forward, I guess we're not fundamentally changing exception safety yet here.

// Use a raw try here because it is used in both main thread and filter.
// Can not convert to use status code as there may be unexpected exceptions in server fuzz
// tests, which must be handled. Potential exception may come from getAddressWithPort() or
// portFromTcpUrl().
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: seems unrelated, but since it's a minor comment fix don't feel that strongly.

@jmarantz jmarantz merged commit b58b5f2 into envoyproxy:main Jun 23, 2021
baojr added a commit to baojr/envoy that referenced this pull request Jun 23, 2021
…bridge-stream

* upstream/main: (268 commits)
  tools: adding dio,better comments (envoyproxy#17104)
  doc: fix misplaced #[extension-category] for Wasm runtimes (envoyproxy#17078)
  ci: Speedup deps precheck (envoyproxy#17102)
  doc: fix wrong link on wasm network filter. (envoyproxy#17079)
  docs: Added v3 API reference. (envoyproxy#17095)
  docs: Update include paths in repo (envoyproxy#17098)
  exception: make Ipv6Instance and Ipv4Instance not throw and remove some try catch pattern (envoyproxy#16122)
  tools: adding reminders for API shephards (envoyproxy#17081)
  ci: Fix wasm verify example (envoyproxy#17086)
  [fuzz]: fix oss fuzz bug 34515, limit maglev table size (envoyproxy#16671)
  test: silencing flaky test (envoyproxy#17084)
  Set `validate` flag when the SAN(SubjectAltName) matching is performed (envoyproxy#16816)
  Listener: reset the file event when destroying listener filters (envoyproxy#16952)
  docs: link additional filters that emit dynamic metadata (envoyproxy#17059)
  rds: add config reload time stat for rds (envoyproxy#17033)
  bazel: Use color by default for build and run commands (envoyproxy#17077)
  ci: Add timing for docker pull (envoyproxy#17074)
  [Windows] Adding note section in Original Source HTTP Filter (envoyproxy#17058)
  quic: add quic version counters in http3 codec stats. (envoyproxy#16943)
  quiche: change crypto stream factory interfaces (envoyproxy#17046)
  ...

Signed-off-by: Garrett Bourg <bourg@squareup.com>
chrisxrepo pushed a commit to chrisxrepo/envoy that referenced this pull request Jul 8, 2021
…me try catch pattern (envoyproxy#16122)

Commit Message:This is part of the effort to remove C++ exception from data plane by adding assertion that the code is executed in main thread when an exception is caught.(envoyproxy#14320) By making the constructor of instances(PipeInstance, Ipv6Instance, Ipv4Instance) no throw, remove some try catch code from envoy.

Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
Signed-off-by: chris.xin <xinchuantao@qq.com>
alyssawilk added a commit that referenced this pull request Sep 22, 2021
#16122 added asserts to utilities to make sure they were called from the correct thread.
Over on the Envoy mobile side when we do QUIC we're doing it from the main thread, and failing some of the assert checks.
I think the right thing to do here is just remove the assert

This is the only use of isWorkerThread() so I'm inclined to just remove it.
cc @goaway

Risk Level: n/a
Testing: n/a
Docs Changes: n/a
Release Notes: n/a
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
…me try catch pattern (envoyproxy#16122)

Commit Message:This is part of the effort to remove C++ exception from data plane by adding assertion that the code is executed in main thread when an exception is caught.(envoyproxy#14320) By making the constructor of instances(PipeInstance, Ipv6Instance, Ipv4Instance) no throw, remove some try catch code from envoy.

Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants