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

Adding support for external C functions that have integer (or empty) args and/or returns #2363

Merged
merged 1 commit into from
Aug 26, 2022

Conversation

emarteca
Copy link

@emarteca emarteca commented Jul 12, 2022

Starts addressing @#11

Implementation

Adding support for calling external C functions that have any number of integer arguments (types of integers: i8, i16, i32, i64, u8, u16, u32, u64) and an integer return type (or void).
As suggested in @#11, the libffi crate is used to dispatch the calls to external C functions.

Modifications

Main modifications are to:

  • helper.rs : adding a function call_and_add_external_c_fct_to_context to read the code pointer to the external C function, dispatch the call, and save the return in MIRI internal memory. Handles all conversions between MIRI and C values (using some macros, also defined in this file).
  • foreign_items.rs : handles the calling of call_and_add_external_c_fct_to_context in helper.rs when a foreign item is encountered. Also adds some structs to model C representations of arguments, and the signature of the external C call.

Testing

Adds tests for the following external functions which are now supported:

  • int tests:
    • adds 2 to a provided int (no type of int specified, so autocasts)
    • takes the sum of its 12 arguments (tests stack spill)
    • adds 3 to a 16 bit int
    • adds an i16 to an i64
    • returns -10 as an unsigned int
  • void tests
    • void function that prints from C

Code review

The code in this PR was reviewed by @maurer on another fork -- thanks!

@RalfJung
Copy link
Member

RalfJung commented Jul 12, 2022

Wow, that's amazing, thanks a ton. :)
(And hello from Cambridge, I'm just across the Charles from Northeastern ;)

One high-level comment based just on the PR summary: I think it'd be better to put this new functionality into new file(s) dedicated to C FFI support. That should help things be more structured.

@LegNeato
Copy link
Contributor

This is awesome! It would be nice to have this support as optional / gated...similar to how miri has an option for isolation, it is useful to assert that no c code is called (if you take the extreme view that C = UB 😄 ) .

Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

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

This is really cool!

src/eval.rs Outdated Show resolved Hide resolved
src/helpers.rs Outdated Show resolved Hide resolved
src/helpers.rs Outdated Show resolved Hide resolved
src/helpers.rs Outdated Show resolved Hide resolved
src/helpers.rs Outdated Show resolved Hide resolved
src/helpers.rs Outdated Show resolved Hide resolved
src/shims/foreign_items.rs Outdated Show resolved Hide resolved
src/shims/foreign_items.rs Outdated Show resolved Hide resolved
tests/compiletest.rs Outdated Show resolved Hide resolved
tests/pass/external_C/int_c_tests.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member

This is awesome! It would be nice to have this support as optional / gated...similar to how miri has an option for isolation, it is useful to assert that no c code is called (if you take the extreme view that C = UB smile ) .

Oh definitely, this should be off-by-default.

@emarteca
Copy link
Author

Hey guys, thanks for the quick and thorough review! And hello fellow Boston squad :)
I'll go through these changes and push an updated version of the code soon.

@emarteca emarteca requested a review from oli-obk July 14, 2022 01:13
@emarteca
Copy link
Author

Hey all -- thanks again for the feedback! I've just pushed an updated version of the code, with the main changes being:

  • removed macros: instead now just matching on the pattern and dispatching directly (and similarly for the other macro)
  • modified some of the error handling logic in a few cases as requested by @oli-obk
  • moved all the C FFI supporting functionality into its own file c_ffi_support.rs as requested by @RalfJung
  • updated comment style as requested by @oli-obk

I did not fix Oli's comment about supporting the external C tests only on certain platforms as I'm not sure how best to do this.

Copy link
Contributor

@oli-obk oli-obk 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 we'll limit everything to linux for now and then look into expanding the support (and CI coverage) to other platforms in separate PRs. Please set it up so that the shared object is only built on linux for now

src/machine.rs Outdated Show resolved Hide resolved
src/machine.rs Outdated Show resolved Hide resolved
src/shims/foreign_items.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member

It would be great if you could resolve those conflicts by doing a rebase over latest master, so that CI can run on this PR.

@emarteca emarteca requested a review from oli-obk July 16, 2022 00:51
@emarteca
Copy link
Author

It would be great if you could resolve those conflicts by doing a rebase over latest master, so that CI can run on this PR.

It looks like the linux build is failing because the install is trying to download a new dependency abort_on_panic but it's supposed to be in offline mode -- if this is the issue, I'm not sure how to add new dependencies to the CI build.

Error message from CI build log:

./miri install
  Installing miri v0.1.0 (/home/runner/work/miri/miri)
error: failed to compile `miri v0.1.0 (/home/runner/work/miri/miri)`, intermediate artifacts can be found at `/home/runner/work/miri/miri/target`
Caused by:
  failed to download `abort_on_panic v2.0.0`
Caused by:
  attempting to make an HTTP request, but --offline was specified

abort_on_panic is a dependency of libffi: see in Cargo.lock

src/c_ffi_support.rs Outdated Show resolved Hide resolved
@oli-obk
Copy link
Contributor

oli-obk commented Jul 16, 2022

It looks like the linux build is failing because the install is trying to download a new dependency abort_on_panic but it's supposed to be in offline mode -- if this is the issue, I'm not sure how to add new dependencies to the CI build.

I think it has been so long since we added a dependency to miri itself, we've since made CI broken in case we do.

@RalfJung I guess we should remove the --offline from the install command and require ppl to pass it themselves if needed?

@RalfJung
Copy link
Member

I guess we should remove the --offline from the install command and require ppl to pass it themselves if needed?

I think I added it because at the time I used ./miri install a lot and was annoyed that it spent so much time querying the registry for yanked packages. But maybe that got better, so, yeah, feel free to remove the flag.

@oli-obk
Copy link
Contributor

oli-obk commented Jul 16, 2022

Our test suite needs a new feature: //@only-on-host before this can work. I'll add it first thing tomorrow

@emarteca
Copy link
Author

Our test suite needs a new feature: //@only-on-host before this can work. I'll add it first thing tomorrow

Thank you! :) 🙏

@RalfJung
Copy link
Member

RalfJung commented Jul 17, 2022

@oli-obk Can you also make the --offline change part of that PR? Would be good to leave "global infrastructure changes" out of this already large PR.

@bors
Copy link
Collaborator

bors commented Jul 17, 2022

☔ The latest upstream changes (presumably #2377) made this pull request unmergeable. Please resolve the merge conflicts.

@oli-obk
Copy link
Contributor

oli-obk commented Jul 17, 2022

OK, after a rebase everything should work now

Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

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

Please rebase instead of merge

tests/panic/external_C/incorrect_SO_file.stderr Outdated Show resolved Hide resolved
@bors
Copy link
Collaborator

bors commented Jul 18, 2022

☔ The latest upstream changes (presumably #2382) made this pull request unmergeable. Please resolve the merge conflicts.

Copy link
Member

@RalfJung RalfJung left a comment

Choose a reason for hiding this comment

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

I am quite excited by this, but do have a bunch of comments. :)

miri Outdated Show resolved Hide resolved
src/bin/miri.rs Outdated Show resolved Hide resolved
src/c_ffi_support.rs Outdated Show resolved Hide resolved
src/c_ffi_support.rs Outdated Show resolved Hide resolved
src/c_ffi_support.rs Outdated Show resolved Hide resolved
tests/external_C/test.c Outdated Show resolved Hide resolved
tests/external_C/test.c Outdated Show resolved Hide resolved
tests/fail/external_C/function_not_in_SO.rs Outdated Show resolved Hide resolved
tests/panic/external_C/incorrect_SO_file.rs Outdated Show resolved Hide resolved
tests/pass/external_C/print_from_c.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
// Check if host target == the session target.
// This check needs to happen _after_ we check if the shared object file does not
// export the function: we don't want to throw an error if we are just going to use
// one of the shims.
Copy link
Member

Choose a reason for hiding this comment

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

I disagree. In fact I think the check should be somewhere way earlier, during initiailization. Passing this flag at all for cross-interpretation is an error.

Also throw_ub is definitely wrong here. UB is when the Abstract Machine says you did something wrong. This here is just a misconfiguration of the user, similar to setting -Zmiri-preemption-rate=notafloat.

Copy link
Author

Choose a reason for hiding this comment

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

Ah ok, sounds good.

@@ -410,6 +413,18 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
preemption_rate: config.preemption_rate,
report_progress: config.report_progress,
since_progress_report: 0,
external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| {
Copy link
Member

Choose a reason for hiding this comment

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

I think this is the right spot to error if host != target.

@bors
Copy link
Collaborator

bors commented Aug 22, 2022

☔ The latest upstream changes (presumably #2441) made this pull request unmergeable. Please resolve the merge conflicts.

@emarteca emarteca requested a review from oli-obk August 24, 2022 22:18
Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

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

should probably squash commits again after addressing these.

I'm checking out your branch locally now to see if it actually works in x.py

src/eval.rs Outdated Show resolved Hide resolved
src/shims/ffi_support.rs Outdated Show resolved Hide resolved

#[derive(Debug, Clone)]
/// Enum of supported arguments to external C functions.
pub enum CArg {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should probably document why this intermediate enum is used instead of directly invoking ffi::args and using libffi::high::Arg immediately

@oli-obk
Copy link
Contributor

oli-obk commented Aug 25, 2022

I'm checking out your branch locally now to see if it actually works in x.py

All the tests pass! So I guess after my nits, rebase to eliminate any merge commits and squash the other commits.

@bors
Copy link
Collaborator

bors commented Aug 25, 2022

☔ The latest upstream changes (presumably #2448) made this pull request unmergeable. Please resolve the merge conflicts.

@oli-obk
Copy link
Contributor

oli-obk commented Aug 26, 2022

@bors r+

@bors
Copy link
Collaborator

bors commented Aug 26, 2022

📌 Commit 88a7882 has been approved by oli-obk

It is now in the queue for this repository.

@bors
Copy link
Collaborator

bors commented Aug 26, 2022

⌛ Testing commit 88a7882 with merge 6418501...

@bors
Copy link
Collaborator

bors commented Aug 26, 2022

☀️ Test successful - checks-actions
Approved by: oli-obk
Pushing 6418501 to master...

@bors bors merged commit 6418501 into rust-lang:master Aug 26, 2022
Comment on lines +12 to +18
<<<<<<< HEAD
=======
<<<<<<< HEAD
tests/extern-so/libtestlib.so
=======
>>>>>>> master
>>>>>>> 58ba05a0 (C FFI support for functions with int args and returns)
Copy link
Member

Choose a reason for hiding this comment

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

Is this a merge conflict issue?

Copy link
Contributor

Choose a reason for hiding this comment

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

yea, I created a fix PR for this

Copy link
Author

Choose a reason for hiding this comment

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

oh no -- good catch and thanks for fixing it!

@oli-obk oli-obk mentioned this pull request Aug 26, 2022
bors added a commit that referenced this pull request Aug 26, 2022
@@ -412,6 +416,24 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
preemption_rate: config.preemption_rate,
report_progress: config.report_progress,
since_progress_report: 0,
external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| {
// Check if host target == the session target.
if option_env!("TARGET") == Some(target_triple) {
Copy link
Member

Choose a reason for hiding this comment

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

So we panic if they are equal? How does that make sense?

Copy link
Member

Choose a reason for hiding this comment

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

This is hiding a bug, the comparison doesn't actually work right now.

Copy link
Member

Choose a reason for hiding this comment

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

Fixed by #2511

@RalfJung
Copy link
Member

Unless we can quickly find a solution for this licensing issue, we might have to revert this PR (or disable some of its code, at least) in order to be able to update Miri in rustc. :/

@emarteca
Copy link
Author

emarteca commented Sep 1, 2022

Unless we can quickly find a solution for this licensing issue, we might have to revert this PR (or disable some of its code, at least) in order to be able to update Miri in rustc. :/

Oh yikes 😢
If this turns into a huge problem I guess I can try rebuilding this using a different crate than libffi (that is the dependency that introduces the dependency that's causing this issue).

@saethlin
Copy link
Member

saethlin commented Sep 1, 2022

Have we reached out to libffi about this? Maybe there's something easy that can be done on their end?

@RalfJung
Copy link
Member

RalfJung commented Sep 1, 2022

Yeah I am trying that: tov/libffi-rs#58.

@emarteca what alternatives to libffi are there?

@emarteca
Copy link
Author

emarteca commented Sep 1, 2022

Yeah I am trying that: tov/libffi-rs#58.

@emarteca what alternatives to libffi are there?

Hmm, libffi is apparently higher level bindings for libffi-sys, which doesn't depend on abort_on_panic, so we could potentially try using libffi-sys directly

@RalfJung
Copy link
Member

RalfJung commented Sep 1, 2022

Honestly it seems easier to fork libffi and remove their use of abort_on_panic.

@RalfJung
Copy link
Member

RalfJung commented Sep 1, 2022

But I hope tov/libffi-rs#58 won't take too long so we can avoid any such drastic steps. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: Waiting for the PR author to address review comments
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants