Skip to content

Commit

Permalink
Use the C-unwind ABI instead of C when mocking extern C functions
Browse files Browse the repository at this point in the history
Begining within Rust 1.81
(rust-lang/rust#74990) Rust will abort when
attempting to unwind a panic across an "extern C" boundary.  Previously
it was technically UB, but it worked and Mockall relied on it.  Now,
unwinding across such a boundary requires the "extern C-unwind" ABI.
Use that ABI in the generated code.

However, don't use that ABI when mocking a C variadic function.  That
doesn't work, due to rust-lang/rust#126836 .

Fixes #584
  • Loading branch information
asomers committed Jun 22, 2024
1 parent 11a9206 commit 0e12d52
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ common: &COMMON
task:
name: MSRV
container:
image: rust:1.70.0
image: rust:1.71.0
cargo_lock_script:
- cp Cargo.lock.msrv Cargo.lock
<< : *COMMON
Expand Down
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- Raised MSRV to 1.70.0 to remove `lazy_static` dependency
([#550](https://github.com/asomers/mockall/pull/550))
- Raised MSRV to 1.71.0 due to the `C-unwind` ABI.
([#585](https://github.com/asomers/mockall/pull/585))

- No longer poison a Context object's internal `Mutex` when panicing. This
requires the "nightly" feature.
([#527](https://github.com/asomers/mockall/pull/527))

### Fixed

- Fixed panicing within mocked `extern "C"` functions, for example due to
unsatisfied expectations, with Rust 1.81.0 or newer.
([#585](https://github.com/asomers/mockall/pull/585))

## [ 0.12.1 ] - 2023-12-21

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ See the [API docs](https://docs.rs/mockall) for more information.

# Minimum Supported Rust Version (MSRV)

Mockall is supported on Rust 1.70.0 and higher. Mockall's MSRV will not be
Mockall is supported on Rust 1.71.0 and higher. Mockall's MSRV will not be
changed in the future without bumping the major or minor version.

# License
Expand Down
2 changes: 1 addition & 1 deletion mockall/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ categories = ["development-tools::testing"]
keywords = ["mock", "mocking", "testing"]
documentation = "https://docs.rs/mockall"
edition = "2021"
rust-version = "1.70"
rust-version = "1.71"
description = """
A powerful mock object library for Rust.
"""
Expand Down
2 changes: 1 addition & 1 deletion mockall/tests/automock_foreign_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ fn c_abi() {
let _m = FOO_MTX.lock();
let ctx = mock_ffi::foo_context();
ctx.expect().returning(i64::from);
let p: unsafe extern "C" fn(u32) -> i64 = mock_ffi::foo;
let p: unsafe extern "C-unwind" fn(u32) -> i64 = mock_ffi::foo;
assert_eq!(42, unsafe{p(42)});
}
13 changes: 13 additions & 0 deletions mockall/tests/automock_foreign_c_variadic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#[cfg(feature = "nightly")]
use mockall::*;
use std::sync::Mutex;

#[automock]
#[cfg(feature = "nightly")]
Expand All @@ -13,11 +14,23 @@ pub mod ffi {
}
}

static FOO_MTX: Mutex<()> = Mutex::new(());

#[test]
#[cfg(feature = "nightly")]
#[cfg_attr(miri, ignore)]
fn mocked_c_variadic() {
let _m = FOO_MTX.lock();
let ctx = mock_ffi::foo_context();
ctx.expect().returning(|x, y| x * y);
assert_eq!(6, unsafe{mock_ffi::foo(2, 3, 1, 4, 1)});
}

#[test]
#[cfg(feature = "nightly")]
#[cfg_attr(miri, ignore)]
#[ignore = "https://github.com/rust-lang/rust/issues/126836"]
fn panics() {
let _m = FOO_MTX.lock();
unsafe{ mock_ffi::foo(1,2,3) };
}
23 changes: 22 additions & 1 deletion mockall_derive/src/mock_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,28 @@ impl From<MockableModule> for MockItemModule {

// Set the ABI to match the ForeignMod's ABI
// for proper function linkage with external code.
f.sig.abi = Some(ifm.abi.clone());
//
// BUT, use C-unwind instead of C, so we can panic
// from the mock function (rust-lang/rust #74990)
//
// BUT, don't use C-unwind for variadic functions,
// because it doesn't work yet (rust-lang/rust
// #126836)
let needs_c_unwind = if let Some(n) = &ifm.abi.name
{
n.value() == "C" && f.sig.variadic.is_none()
} else {
false
};
f.sig.abi = Some(if needs_c_unwind {
Abi {
extern_token:ifm.abi.extern_token.clone(),
name: Some(LitStr::new("C-unwind",
ifm.abi.name.span()))
}
} else {
ifm.abi.clone()
});

let mf = mock_function::Builder::new(&f.sig, &f.vis)
.attrs(&f.attrs)
Expand Down

0 comments on commit 0e12d52

Please sign in to comment.