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

freebsd add *stat calls interception support #3181

Merged
merged 2 commits into from
Jan 28, 2024

Conversation

devnexen
Copy link
Contributor

No description provided.

@devnexen devnexen marked this pull request as ready for review November 20, 2023 21:05
this.assert_target_os("macos", "stat");

if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
throw_unsup_format!("macos_fbsd_stat not meant for os {}", this.tcx.sess.target.os);
Copy link
Member

Choose a reason for hiding this comment

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

This shouldn't throw a nice error, it should panic. There's a bug in Miri when this happens.

@devnexen devnexen force-pushed the stat_calls_fbsd branch 7 times, most recently from 68ae0f7 to 97446f8 Compare November 21, 2023 20:07
@devnexen
Copy link
Contributor Author

@rustbot review

@rustbot rustbot added the S-waiting-on-review Status: Waiting for a review to complete label Nov 21, 2023
Cargo.lock Outdated Show resolved Hide resolved
this.assert_target_os("macos", "lstat");

if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
panic!("macos_fbsd_lstat not meant for os {}", this.tcx.sess.target.os);
Copy link
Member

Choose a reason for hiding this comment

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

There's a verb missing in this sentence.

Suggested change
panic!("macos_fbsd_lstat not meant for os {}", this.tcx.sess.target.os);
panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os);

(Do this everywhere you have the new panic.)

}

// FIXME?: oddily it seems to pick up the old libc crate's freebsd11 definition instead of freebsd13, should be 6
let name_offset = if this.tcx.sess.target.os == "macos" { 5 } else { 4 };
Copy link
Member

Choose a reason for hiding this comment

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

Not sure why you mention libc here, this is a hard-coded offset, how should that pick up anything...?

Also, did that offset change between different versions of freebsd?!? How are we supposed to handle that, not knowing which version the program is built for?

Copy link
Member

Choose a reason for hiding this comment

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

Oh wait, the name is just confusing. This is not an offset! It is a field index.

This should pick up the version of libc that comes with the standard library.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

after freebsd 11 dirent had been updated with the missing field (d_off) in same order than Linux (while making it cache friendly) pushing further d_name down the road.

Copy link
Member

Choose a reason for hiding this comment

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

And so the Rust libc crate then got that update as well at time point? Which libc crate version is that?

This file here should be defining which libc is picked up by Miri here. It's the latest version currently.

Copy link
Contributor Author

@devnexen devnexen Nov 23, 2023

Choose a reason for hiding this comment

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

in fact freebsd is one of the few oses in the libc's crate which maintains several os releases versions e.g. freebsd 11 up to 14 having their own definitions when there are changes. So for our example there is dirent definition for freebsd 11 and later releases in same crate if that makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

I don't quite follow, can you point me at the code for that in the libc crate? Which type does one get when asking for libc::dirent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure
freebsd 11 and later

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I think I found it... here. The libc build script runs some code to determine the FreeBSD version. When the FreeBSD standard library is built on a different OS (like e.g. when Miri CI tests the freebsd target on a Linux host), that will fail, and it defaults to freebsd11. But if you are using Miri on a freebsd host, it will use the host freebsd version.

Gosh, what a nightmare.^^ This is impossible to test properly.

Copy link
Member

@RalfJung RalfJung Nov 23, 2023

Choose a reason for hiding this comment

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

Okay so what this means for Miri is we have to support all versions of freebsd since we can't know what the build script picks. But we can only test one of them. Amazing. Maybe long-term we want to work with the libc crate to overwrite the version detection inside Miri, though maybe that has other issues.

For this PR, it means:

  • definitely use project_field_named to get the name_place, that part should be easy
  • for writing all the other fields, do a dynamic check whether the d_off field is present. We can't test "is this freebsd or not" since the type is different for different versions of freebsd, we need to check the presence of this field. You will need to add a new helper function that checks whether a field of a given name exists.

@@ -1424,7 +1433,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// }

let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
let name_place = this.project_field(&entry_place, 5)?;
let name_place = this.project_field(&entry_place, name_offset)?;
Copy link
Member

Choose a reason for hiding this comment

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

Please use project_field_named, that should avoid this index hard-coding.

@@ -1,4 +1,5 @@
//@ignore-target-windows: File handling is not implemented yet
//@ignore-target-freebsd
Copy link
Member

Choose a reason for hiding this comment

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

what goes wrong when this runs on freebsd? please add a FIXME

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no I just forgot to enable it again..

use std::collections::HashMap;
#[cfg(not(target_os = "freebsd"))]
use std::ffi::OsString;
Copy link
Member

Choose a reason for hiding this comment

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

Please move these imports to inside test_directory rather than having such global cfg

@@ -296,6 +300,7 @@ fn test_canonicalize() {
remove_dir_all(&dir_path).unwrap();
}

#[cfg(not(target_os = "freebsd"))]
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
#[cfg(not(target_os = "freebsd"))]
#[cfg(not(target_os = "freebsd"))] // FIXME freebsd does not support readdir yet

@RalfJung
Copy link
Member

Can you add a 32bit freebsd target to CI? With this exposure of previously 64bit-only code to 32bit targets, we definitely need that test coverage.

@devnexen devnexen force-pushed the stat_calls_fbsd branch 6 times, most recently from a04ac72 to ffa8f29 Compare November 23, 2023 17:16
@@ -296,7 +309,11 @@ fn test_canonicalize() {
remove_dir_all(&dir_path).unwrap();
}

#[cfg(not(target_os = "freebsd"))] // FIXME: freebsd does not support readdir yet
Copy link
Member

Choose a reason for hiding this comment

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

Hm I just saw you implemented readdir. Why does this test fail?

@RalfJung
Copy link
Member

You need to make sure that every single function that you add for freebsd is actually called by some test, on 32bit and 64bit. This is the standard we expect for all our targets. Don't just disable tests, that's now how one develops reliable software.

@rustbot review

@RalfJung
Copy link
Member

Eh I meant @rustbot author.^^

Btw I am looking into why the existing libc-fs test is already failing on FreeBSD. Is it possible that ftruncate on 32bit FreeBSD takes a 64bit argument...?

@rustbot rustbot added S-waiting-on-author Status: Waiting for the PR author to address review comments and removed S-waiting-on-review Status: Waiting for a review to complete labels Nov 25, 2023
@RalfJung
Copy link
Member

Yes, that does seem to be the case on all BSDs. Oh wow.

@RalfJung
Copy link
Member

RalfJung commented Nov 25, 2023

I decided to help with the 32bit issue since it's a bit tricky to debug. #3190 makes the existing tests pass on 32bit FreeBSD, so once that lands please rebase your PR and then you only have to worry about the new functions -- and you can use the same approach for reading off_t arguments.

@bors
Copy link
Contributor

bors commented Nov 25, 2023

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

@devnexen devnexen force-pushed the stat_calls_fbsd branch 3 times, most recently from 29c1344 to 653bcbe Compare November 25, 2023 14:31
@devnexen
Copy link
Contributor Author

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Waiting for a review to complete and removed S-waiting-on-author Status: Waiting for the PR author to address review comments labels Nov 25, 2023
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.

We're getting there I think. :)

src/helpers.rs Outdated
@@ -225,6 +225,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
bug!("No field named {} in type {}", name, base.layout().ty);
}

/// Search if Project (which must be a struct or union type) contains the `name` field.
fn project_field_has_field<P: Projectable<'tcx, Provenance>>(
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
fn project_field_has_field<P: Projectable<'tcx, Provenance>>(
fn projectable_has_field<P: Projectable<'tcx, Provenance>>(

Comment on lines 1469 to 1471
} else {
// freebsd 12 and onwards had added the d_off field
if this.project_field_has_field(&entry_place, "d_off") {
Copy link
Member

Choose a reason for hiding this comment

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

Please collapse this into } else if {

@@ -123,7 +120,9 @@ fn test_file_create_new() {
remove_file(&path).unwrap();
}

#[cfg(not(all(target_os = "freebsd", target_pointer_width = "32")))]
Copy link
Member

Choose a reason for hiding this comment

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

There's still something wrong here, why is this disabled on 32bit?
I said it multiple times: please don't just disable tests when they fail! Sometimes it is okay to cfg-out a particular test on a particular target, but that always needs a comment explaining why it is done. And here I would expect the test should pass on freebsd so when it fails that needs investigation, not cfg.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I forgot to reenable this one (especially there is no cfg upon test_seek above), no need to assume bad intentions ..

@@ -64,6 +59,7 @@ fn test_path_conversion() {
}

fn test_file() {
use std::io::{IsTerminal, Read};
Copy link
Member

Choose a reason for hiding this comment

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

Seems unnecessary to do this for functions that are always enabled? This is only needed for cfg-gated functions.

@RalfJung RalfJung added S-waiting-on-author Status: Waiting for the PR author to address review comments and removed S-waiting-on-review Status: Waiting for a review to complete labels Nov 26, 2023
@devnexen
Copy link
Contributor Author

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Waiting for a review to complete and removed S-waiting-on-author Status: Waiting for the PR author to address review comments labels Nov 29, 2023
@devnexen
Copy link
Contributor Author

devnexen commented Dec 3, 2023

@saethlin I think I ve done all was asked can you have a look at it pls ?

src/helpers.rs Outdated Show resolved Hide resolved
src/shims/unix/fs.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member

Sorry for the long delay!
@bors r+

@bors
Copy link
Contributor

bors commented Jan 28, 2024

📌 Commit e7d4fba has been approved by RalfJung

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Jan 28, 2024

⌛ Testing commit e7d4fba with merge d85d147...

@bors
Copy link
Contributor

bors commented Jan 28, 2024

☀️ Test successful - checks-actions
Approved by: RalfJung
Pushing d85d147 to master...

@bors bors merged commit d85d147 into rust-lang:master Jan 28, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Waiting for a review to complete
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants