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

android: set abort message #81469

Merged
merged 1 commit into from
Apr 11, 2021
Merged

Conversation

tweksteen
Copy link
Contributor

Android has the ability to supply an abort message [1]. This message is
automatically included in the debug trace, which helps debugging [2].
Modify panic_abort to populate this message before calling abort().

[1] https://android.googlesource.com/platform/bionic/+/master/libc/include/android/set_abort_message.h
[2] https://source.android.com/devices/tech/debug/native-crash

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @m-ou-se (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 28, 2021
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@m-ou-se
Copy link
Member

m-ou-se commented Jan 28, 2021

android_set_abort_message is only available in Android API level 21. In our tests we're testing against 14 as well. If we want to use this function, we should first raise our minimum supported Android API level.

Also, it might not be a great idea to have the panic_abort crate do any allocations. On all platforms, this panic handler does nothing other than just one (sys)call or instruction to abort the program. Not pulling in any other code is one of the reasons for using the panic_abort crate.

@tweksteen
Copy link
Contributor Author

android_set_abort_message is only available in Android API level 21. In our tests we're testing against 14 as well. If we want to use this function, we should first raise our minimum supported Android API level.

Sounds good, I can send a change for that as well. Would something similar to #45580 be sufficient?

Also, it might not be a great idea to have the panic_abort crate do any allocations. On all platforms, this panic handler does nothing other than just one (sys)call or instruction to abort the program. Not pulling in any other code is one of the reasons for using the panic_abort crate.

I agree, although I don't think I can avoid the allocation here. I can mark the dependency on alloc as specific to target_os = "android" so there is no impact on other platforms?

@m-ou-se
Copy link
Member

m-ou-se commented Jan 28, 2021

Sounds good, I can send a change for that as well. Would something similar to #45580 be sufficient?

A PR to raise it to level 21 was submitted a few months ago, but not merged: #78601

I agree, although I don't think I can avoid the allocation here. I can mark the dependency on alloc as specific to target_os = "android" so there is no impact on other platforms?

That wouldn't make much of a difference. If alloc is not referred to from the code, having it listed as dependency doesn't do much. Regardless, it's probably best to keep this panic handler a trivial abort on all platforms including Android.

Is it common to use panic = "abort" on Android? And if so, what are the most common reasons for doing so?

@tweksteen
Copy link
Contributor Author

A PR to raise it to level 21 was submitted a few months ago, but not merged: #78601

Thanks, I understand that such API update is unlikely to happen for now. For future reference, I'd still like to discuss the other points.

That wouldn't make much of a difference. If alloc is not referred to from the code, having it listed as dependency doesn't do much. Regardless, it's probably best to keep this panic handler a trivial abort on all platforms including Android.

The issue with the current definition of __rust_panic_start is that the payload argument cannot be used, unless one has some definition from alloc (for instance, to see if the payload can be downcasted to a String). Another option could be to update the definition of __rust_panic_start to pass the current payload as well as a &str of it (which can be used by low-level routine without trying to inspect/parse payload).

Is it common to use panic = "abort" on Android? And if so, what are the most common reasons for doing so?

Using abort is the standard on Android to terminate a native process on error (see https://source.android.com/devices/tech/debug/native-crash#abort). More specifically, in C/C++ a log with the FATAL level, will call abort (see https://developer.android.com/ndk/reference/group/logging). It seems natural to have a similar behaviour for panic in Rust.

@tweksteen
Copy link
Contributor Author

Some more thoughts on the approach:

It is possible to move some of the pre-processing in std. For instance, panic_output could be modified for Android (similarly to SgxPanicOutput) to keep track of the formatted panic message. This would work for std (not no_std) and only if the default_hook is being used. It is not possible to call android_set_abort_message directly in std though because only the first call to this function will be used by libc. Since this panic could be caught (if the panic_runtime is unwind), this could be misleading (if a later abort do occur).

There is also an issue for panic_abort to actually consume that message: it cannot depend on std. The only option at hand seems to be to modify the arguments of __rust_panic_start to include a value that is somewhat usable by panic_abort. The main reasoning here is that payload is not useful at all for panic_abort currently.

@m-ou-se Would you have any feedback on this approach? I can send another PR but I want to make sure this design is likely to be accepted first. Thanks.

@m-ou-se
Copy link
Member

m-ou-se commented Mar 3, 2021

I've looked a bit deeper into all the panic logic, and I think it's perfectly fine to have panic_abort depend on alloc.

I would still want to avoid allocating anything if possible, so ideally the implementation should use BoxMeUp::get() instead of BoxMeUp::take_box() to get to the payload, and not copy a &'static str into a new String. Unfortunately, that'll not get a zero terminated string like the android_set_abort_message wants. A failure to allocate here will result in another panic, repeatedly panicking until the stack overflows.

If you can implement it in such a way that allocation failures will not cause another panic, but just silently cause it to skip setting the abort message (or set it to a default message or something), I feel comfortable moving forward with this.

As for the minimum Android API level problem: we should be able to use weak linkage to android_set_abort_message such that it's only used when available. The current state of weak linkage in Rust is not great though, so you'll have to do some experimentation to see what works.

@m-ou-se m-ou-se added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 3, 2021
@rust-log-analyzer

This comment has been minimized.

@tweksteen
Copy link
Contributor Author

Done. Please take a look. Thanks.

Copy link
Member

@m-ou-se m-ou-se left a comment

Choose a reason for hiding this comment

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

Looks good. Did you test it?

Two small comments:

library/panic_abort/src/android.rs Outdated Show resolved Hide resolved
library/panic_abort/src/android.rs Outdated Show resolved Hide resolved
@tweksteen
Copy link
Contributor Author

Thanks for the review. I tested it in-tree using Android build system (Soong). I just tested using x.py. I had to rearrange the feature attribute to build successfully here.

@m-ou-se
Copy link
Member

m-ou-se commented Mar 27, 2021

Thanks!

@bors r+

@bors
Copy link
Contributor

bors commented Mar 27, 2021

📌 Commit f41d0a4 has been approved by m-ou-se

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 27, 2021
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Mar 27, 2021
…ou-se

android: set abort message

Android has the ability to supply an abort message [1]. This message is
automatically included in the debug trace, which helps debugging [2].
Modify panic_abort to populate this message before calling abort().

[1] https://android.googlesource.com/platform/bionic/+/master/libc/include/android/set_abort_message.h
[2] https://source.android.com/devices/tech/debug/native-crash
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Mar 27, 2021
…ou-se

android: set abort message

Android has the ability to supply an abort message [1]. This message is
automatically included in the debug trace, which helps debugging [2].
Modify panic_abort to populate this message before calling abort().

[1] https://android.googlesource.com/platform/bionic/+/master/libc/include/android/set_abort_message.h
[2] https://source.android.com/devices/tech/debug/native-crash
@tweksteen
Copy link
Contributor Author

The CI error does not contain much details. I managed to reproduce it locally and here is the error I got from llvm:

rustc: /checkout/src/llvm-project/llvm/include/llvm/Support/Casting.h:269: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::Function; Y = llvm::Value; typename llvm::cast_retty<X, Y*>::ret_type = llvm::Function*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
[RUSTC-TIMING] panic_abort test:false 0.094
rustc exited with signal: 6
error: could not compile `panic_abort`

I initially thought this was related to one of the casting I made, but by commenting out the code, I found out that this was caused by the call to try_reserve. This can be reproduced with the function body:

pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) {
    let mut v = Vec::<u8>::new();
    if v.try_reserve(1).is_err() {
        return;
    }
}

@tweksteen
Copy link
Contributor Author

The use of try_reserve requires the correct setup of rust_eh_personality, which is not the case for the panic_abort crate. Document this limitation and use malloc() instead, as recommended by @bjorn3.

Copy link
Member

@bjorn3 bjorn3 left a comment

Choose a reason for hiding this comment

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

Mostly LGTM, but not an android expert and I am not sure if the new alloc dependency of panic_abort isn't going to cause issues in the future.

@Urgau
Copy link
Member

Urgau commented Apr 6, 2021

Mostly LGTM, but not an android expert and I am not sure if the new alloc dependency of panic_abort isn't going to cause issues in the future.

Maybe using some platform specific dependencies in the Cargo.toml, like this:

[target.'cfg(target_os = "android")'.dependencies]
alloc = { path = "../alloc" }

could be enough, so that the alloc crate is only pull when building for android but @m-ou-se has already said that this might not be a good idea.

@tweksteen tweksteen requested a review from m-ou-se April 7, 2021 13:55
Copy link
Member

@m-ou-se m-ou-se left a comment

Choose a reason for hiding this comment

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

Thanks! I have one small comment, but otherwise r=me:

library/panic_abort/src/android.rs Outdated Show resolved Hide resolved
@m-ou-se
Copy link
Member

m-ou-se commented Apr 9, 2021

I am not sure if the new alloc dependency of panic_abort isn't going to cause issues in the future.

panic_abort is only used in combination with std, so it's safe to assume the alloc crate is available.

@rust-log-analyzer

This comment has been minimized.

Android has the ability to supply an abort message [1]. This message is
automatically included in the debug trace, which helps debugging [2].
Modify panic_abort to populate this message before calling abort().

[1] https://android.googlesource.com/platform/bionic/+/master/libc/include/android/set_abort_message.h
[2] https://source.android.com/devices/tech/debug/native-crash
@m-ou-se
Copy link
Member

m-ou-se commented Apr 11, 2021

Thanks!

@bors r+

@bors
Copy link
Contributor

bors commented Apr 11, 2021

📌 Commit 52ee9fb has been approved by m-ou-se

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 11, 2021
@bors
Copy link
Contributor

bors commented Apr 11, 2021

⌛ Testing commit 52ee9fb with merge 7953910...

@bors
Copy link
Contributor

bors commented Apr 11, 2021

☀️ Test successful - checks-actions
Approved by: m-ou-se
Pushing 7953910 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Apr 11, 2021
@bors bors merged commit 7953910 into rust-lang:master Apr 11, 2021
@rustbot rustbot added this to the 1.53.0 milestone Apr 11, 2021
wip-sync pushed a commit to NetBSD/pkgsrc-wip that referenced this pull request Jun 20, 2021
Pkgsrc changes:
 * Bump bootstrap requirements to 1.52.1
 * Adjust patches, adapt to upstream changes, adjust cargo checksums
 * If using an external llvm, require >= 10.0

Upsteream changes:

Version 1.53.0 (2021-06-17)
============================

Language
-----------------------
- [You can now use unicode for identifiers.][83799] This allows
  multilingual identifiers but still doesn't allow glyphs that are
  not considered characters such as `#` (diamond) or `<U+1F980>`
  (crab). More specifically you can now use any identifier that
  matches the UAX #31 "Unicode Identifier and Pattern Syntax" standard. This
  is the same standard as languages like Python, however Rust uses NFC
  normalization which may be different from other languages.
- [You can now specify "or patterns" inside pattern matches.][79278]
  Previously you could only use `|` (OR) on complete patterns. E.g.
  ```rust
  let x = Some(2u8);
  // Before
  matches!(x, Some(1) | Some(2));
  // Now
  matches!(x, Some(1 | 2));
  ```
- [Added the `:pat_param` `macro_rules!` matcher.][83386] This matcher
  has the same semantics as the `:pat` matcher. This is to allow `:pat`
  to change semantics to being a pattern fragment in a future edition.

Compiler
-----------------------
- [Updated the minimum external LLVM version to LLVM 10.][83387]
- [Added Tier 3\* support for the `wasm64-unknown-unknown` target.][80525]
- [Improved debuginfo for closures and async functions on Windows MSVC.][83941]

\* Refer to Rust's [platform support page][platform-support-doc] for more
information on Rust's tiered platform support.

Libraries
-----------------------
- [Abort messages will now forward to `android_set_abort_message` on
  Android platforms when available.][81469]
- [`slice::IterMut<'_, T>` now implements `AsRef<[T]>`][82771]
- [Arrays of any length now implement `IntoIterator`.][84147]
  Currently calling `.into_iter()` as a method on an array will
  return `impl Iterator<Item=&T>`, but this may change in a
  future edition to change `Item` to `T`. Calling `IntoIterator::into_iter`
  directly on arrays will provide `impl Iterator<Item=T>` as expected.
- [`leading_zeros`, and `trailing_zeros` are now available on all
  `NonZero` integer types.][84082]
- [`{f32, f64}::from_str` now parse and print special values
  (`NaN`, `-0`) according to IEEE RFC 754.][78618]
- [You can now index into slices using `(Bound<usize>, Bound<usize>)`.][77704]
- [Add the `BITS` associated constant to all numeric types.][82565]

Stabilised APIs
---------------
- [`AtomicBool::fetch_update`]
- [`AtomicPtr::fetch_update`]
- [`BTreeMap::retain`]
- [`BTreeSet::retain`]
- [`BufReader::seek_relative`]
- [`DebugStruct::non_exhaustive`]
- [`Duration::MAX`]
- [`Duration::ZERO`]
- [`Duration::is_zero`]
- [`Duration::saturating_add`]
- [`Duration::saturating_mul`]
- [`Duration::saturating_sub`]
- [`ErrorKind::Unsupported`]
- [`Option::insert`]
- [`Ordering::is_eq`]
- [`Ordering::is_ge`]
- [`Ordering::is_gt`]
- [`Ordering::is_le`]
- [`Ordering::is_lt`]
- [`Ordering::is_ne`]
- [`OsStr::is_ascii`]
- [`OsStr::make_ascii_lowercase`]
- [`OsStr::make_ascii_uppercase`]
- [`OsStr::to_ascii_lowercase`]
- [`OsStr::to_ascii_uppercase`]
- [`Peekable::peek_mut`]
- [`Rc::decrement_strong_count`]
- [`Rc::increment_strong_count`]
- [`Vec::extend_from_within`]
- [`array::from_mut`]
- [`array::from_ref`]
- [`char::MAX`]
- [`char::REPLACEMENT_CHARACTER`]
- [`char::UNICODE_VERSION`]
- [`char::decode_utf16`]
- [`char::from_digit`]
- [`char::from_u32_unchecked`]
- [`char::from_u32`]
- [`cmp::max_by_key`]
- [`cmp::max_by`]
- [`cmp::min_by_key`]
- [`cmp::min_by`]
- [`f32::is_subnormal`]
- [`f64::is_subnormal`]

Cargo
-----------------------
- [Cargo now supports git repositories where the default `HEAD` branch is not
  "master".][cargo/9392] This also includes a switch to the version
  3 `Cargo.lock` format which can handle default branches correctly.
- [macOS targets now default to `unpacked` split-debuginfo.][cargo/9298]
- [The `authors` field is no longer included in `Cargo.toml` for new
  projects.][cargo/9282]

Rustdoc
-----------------------
- [Added the `rustdoc::bare_urls` lint that warns when you have URLs
  without hyperlinks.][81764]

Compatibility Notes
-------------------
- [Implement token-based handling of attributes during expansion][82608]
- [`Ipv4::from_str` will now reject octal format IP addresses in addition
  to rejecting hexadecimal IP addresses.][83652] The octal format can lead
  to confusion and potential security vulnerabilities and [is no
  longer recommended][ietf6943].

Internal Only
-------------
These changes provide no direct user facing benefits, but represent significant
improvements to the internals and overall performance of rustc and
related tools.

- [Rework the `std::sys::windows::alloc` implementation.][83065]
- [rustdoc: Don't enter an infer_ctxt in get_blanket_impls for
  impls that aren't blanket impls.][82864]
- [rustdoc: Only look at blanket impls in `get_blanket_impls`][83681]
- [Rework rustdoc const type][82873]

[83386]: rust-lang/rust#83386
[82771]: rust-lang/rust#82771
[84147]: rust-lang/rust#84147
[84082]: rust-lang/rust#84082
[83799]: rust-lang/rust#83799
[83681]: rust-lang/rust#83681
[83652]: rust-lang/rust#83652
[83387]: rust-lang/rust#83387
[82873]: rust-lang/rust#82873
[82864]: rust-lang/rust#82864
[82608]: rust-lang/rust#82608
[82565]: rust-lang/rust#82565
[80525]: rust-lang/rust#80525
[79278]: rust-lang/rust#79278
[78618]: rust-lang/rust#78618
[77704]: rust-lang/rust#77704
[83941]: rust-lang/rust#83941
[83065]: rust-lang/rust#83065
[81764]: rust-lang/rust#81764
[81469]: rust-lang/rust#81469
[cargo/9298]: rust-lang/cargo#9298
[cargo/9282]: rust-lang/cargo#9282
[cargo/9392]: rust-lang/cargo#9392
[`char::MAX`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.MAX
[`char::REPLACEMENT_CHARACTER`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.REPLACEMENT_CHARACTER
[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.UNICODE_VERSION
[`char::decode_utf16`]: https://doc.rust-lang.org/std/primitive.char.html#method.decode_utf16
[`char::from_u32`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32
[`char::from_u32_unchecked`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32_unchecked
[`char::from_digit`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_digit
[`AtomicBool::fetch_update`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_update
[`AtomicPtr::fetch_update`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.fetch_update
[`BTreeMap::retain`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.retain
[`BTreeSet::retain`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html#method.retain
[`BufReader::seek_relative`]: https://doc.rust-lang.org/std/io/struct.BufReader.html#method.seek_relative
[`DebugStruct::non_exhaustive`]: https://doc.rust-lang.org/std/fmt/struct.DebugStruct.html#method.finish_non_exhaustive
[`Duration::MAX`]: https://doc.rust-lang.org/std/time/struct.Duration.html#associatedconstant.MAX
[`Duration::ZERO`]: https://doc.rust-lang.org/std/time/struct.Duration.html#associatedconstant.ZERO
[`Duration::is_zero`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.is_zero
[`Duration::saturating_add`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_add
[`Duration::saturating_mul`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_mul
[`Duration::saturating_sub`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_sub
[`ErrorKind::Unsupported`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.Unsupported
[`Option::insert`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.insert
[`Ordering::is_eq`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_eq
[`Ordering::is_ge`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_ge
[`Ordering::is_gt`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_gt
[`Ordering::is_le`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_le
[`Ordering::is_lt`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_lt
[`Ordering::is_ne`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_ne
[`OsStr::eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.eq_ignore_ascii_case
[`OsStr::is_ascii`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.is_ascii
[`OsStr::make_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_lowercase
[`OsStr::make_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_uppercase
[`OsStr::to_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_lowercase
[`OsStr::to_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_uppercase
[`Peekable::peek_mut`]: https://doc.rust-lang.org/std/iter/struct.Peekable.html#method.peek_mut
[`Rc::decrement_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
[`Rc::increment_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
[`Vec::extend_from_within`]: https://doc.rust-lang.org/beta/std/vec/struct.Vec.html#method.extend_from_within
[`array::from_mut`]: https://doc.rust-lang.org/beta/std/array/fn.from_mut.html
[`array::from_ref`]: https://doc.rust-lang.org/beta/std/array/fn.from_ref.html
[`cmp::max_by_key`]: https://doc.rust-lang.org/beta/std/cmp/fn.max_by_key.html
[`cmp::max_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.max_by.html
[`cmp::min_by_key`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by_key.html
[`cmp::min_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by.html
[`f32::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
[`f64::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
[ietf6943]: https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1
bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 18, 2021
Use existing declaration of rust_eh_personality

If crate declares `rust_eh_personality`, re-use existing declaration
as otherwise attempts to set function attributes that follow the
declaration will fail (unless it happens to have exactly the same
type signature as the one predefined in the compiler).

Fixes rust-lang#70117.
Fixes rust-lang#81469 (comment); probably.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants