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

add basic support for android targets #2011

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ degree documented below):
supported on Windows. We also test `i686-pc-windows-msvc`, with the same
reduced feature set. We might ship Miri with a nightly even when some features
on these targets regress.
- `aarch64-linux-android` has basic support and should work for simple targets.
Copy link
Member

Choose a reason for hiding this comment

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

What are "simple targets"?

Also it seems a bit premature to add this if we don't have anything on CI and people need to patch stdlib to make it work.

Some concurrency and filesystem operations are not supported and will fail at
runtime.

### Common Problems

Expand Down
3 changes: 3 additions & 0 deletions ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function run_tests {
fi

./miri test --locked

if [ -z "${MIRI_TEST_TARGET+exists}" ]; then
# Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR
# optimizations up all the way).
Expand Down Expand Up @@ -50,6 +51,8 @@ case $HOST_TARGET in
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
# TODO: Enable once https://github.com/rust-lang/rust/pull/94813 lands
# MIRI_TEST_TARGET=aarch64-linux-android run_tests
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a note that @landaire is maintaining this target -- so that we know whom to ping when something android-specific breaks?

;;
x86_64-apple-darwin)
MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture
Expand Down
28 changes: 28 additions & 0 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
)
}

/// Helper function used inside the shims of foreign functions to assert that the target OS
/// is based on the Linux kernel. It panics showing a message with the `name` of the foreign function
/// if this is not the case.
fn assert_target_os_is_linux_based(&self, name: &str) {
assert!(
matches!(self.eval_context_ref().tcx.sess.target.os.as_ref(), "linux" | "android"),
"`{}` is only available for supported Linux-based targets",
name,
)
}

/// Helper function used inside the shims of foreign functions to assert that the target OS
/// is part of the UNIX family. It panics showing a message with the `name` of the foreign function
/// if this is not the case.
fn assert_target_os_is_unix(&self, name: &str) {
assert!(
target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()),
"`{}` is only available for supported UNIX family targets",
name,
);
}

/// Get last error variable as a place, lazily allocating thread-local storage for it if
/// necessary.
fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> {
Expand Down Expand Up @@ -883,3 +905,9 @@ impl std::fmt::Display for HexRange {
write!(f, "[{:#x}..{:#x}]", self.0.start.bytes(), self.0.end().bytes())
}
}

/// Helper function used inside the shims of foreign functions to check that the `target_os` is
/// part of the UNIX family.
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
/// part of the UNIX family.
/// a supported OS in the UNIX family.

pub fn target_os_is_unix(target_os: &str) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

Elsewhere we are using target.families.iter().any(|f| f == "unix"). I think that probably makes more sense?

So, please change this to take a &Target and also adjust the existing checks to call this function instead.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, thinking about it more -- I like explicitly listing the unix OSes that we do support. So let's go with your approach.

But please change the existing code that checks target.families to call target_os_is_unix instead.

Copy link
Member

Choose a reason for hiding this comment

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

Could you or @InfRandomness make a separate PR that does nothing but add target_os_is_unix and use it where appropriate? Then both the FreeBSD PR and this one can just adjust that function and don't need to change so many different places in the code.

matches!(target_os, "linux" | "macos" | "android")
}
35 changes: 35 additions & 0 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,41 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
this.write_scalar(Scalar::from_u8(0), &place.into())?;
Self::add_extern_static(this, "_tls_used", place.ptr);
}
"android" => {
// "environ"
Self::add_extern_static(
this,
"environ",
this.machine.env_vars.environ.unwrap().ptr,
);
// A couple zero-initialized pointer-sized extern statics.
// Most of them are for weak symbols, which we all set to null (indicating that the
// symbol is not supported, and triggering fallback code which ends up calling a
// syscall that we do support).
for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] {
let layout = this.machine.layouts.usize;
let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?;
Self::add_extern_static(this, name, place.ptr);
}
for symbol_name in &["signal", "bsd_signal"] {
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
for symbol_name in &["signal", "bsd_signal"] {
// Some weak symbols that we *do* (have to) support.
for symbol_name in &["signal", "bsd_signal"] {

Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't it be enough to implement one of them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately not. If you try to run without both you get the following panic:

error: unsupported operation: `extern` static `std::sys::unix::android::signal::bsd_signal` from crate `std` is not supported by Miri
  --> /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/sys/unix/android.rs:76:5
   |
76 |     weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern` static `std::sys::unix::android::signal::bsd_signal` from crate `std` is not supported by Miri
   |
   = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support

   = note: inside `std::sys::unix::android::signal` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/sys/unix/weak.rs:41:38
   = note: inside `std::sys::unix::init::reset_sigpipe` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/sys/unix/mod.rs:122:19
   = note: inside `std::sys::unix::init` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/sys/unix/mod.rs:64:5
   = note: inside `std::rt::init` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:78:9
   = note: inside closure at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:127:42
   = note: inside `std::panicking::try::do_call::<[closure@std::rt::lang_start_internal::{closure#1}], ()>` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/panicking.rs:492:40
   = note: inside `std::panicking::try::<(), [closure@std::rt::lang_start_internal::{closure#1}]>` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/panicking.rs:456:19
   = note: inside `std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#1}], ()>` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/panic.rs:137:14
   = note: inside `std::rt::lang_start_internal` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:127:5
   = note: inside `std::rt::lang_start::<()>` at /Users/hvx/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:144:17
   = note: this error originates in the macro `weak` (in Nightly builds, run with -Z macro-backtrace for more info)

This is caused by the standard library weak linking both symbols https://github.com/rust-lang/rust/blob/1eb72580d076935a3e590deb6e5813a5aef3eca4/library/std/src/sys/unix/android.rs#L74-L81

Copy link
Member

Choose a reason for hiding this comment

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

But you can make one of them NULL. Only one needs to be implemented.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah I see what you mean. Can do.

let layout = this.machine.layouts.mut_raw_ptr;
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
let dlsym = Dlsym::from_str(symbol_name.as_bytes(), &this.tcx.sess.target.os)?
.unwrap_or_else(|| {
panic!(
"hardcoded `extern static` symbol {} has no dlsym handler",
symbol_name
)
});
let ecx = this.eval_context_mut();
let ptr = ecx.create_fn_alloc_ptr(FnVal::Other(dlsym));
Comment on lines +459 to +460
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
let ecx = this.eval_context_mut();
let ptr = ecx.create_fn_alloc_ptr(FnVal::Other(dlsym));
let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym));


let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
this.write_pointer(ptr, &place.into())?;
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a helper function that takes the symbol name and returns a Place containing a pointer pointing to that function?
I'd like to keep init_extern_statics as short and readable as possible.


Self::add_extern_static(this, symbol_name, place.ptr);
}
}
_ => {} // No "extern statics" supported on this target
}
Ok(())
Expand Down
4 changes: 3 additions & 1 deletion src/shims/dlsym.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;

use crate::helpers::target_os_is_unix;
use crate::*;
use shims::posix::dlsym as posix;
use shims::windows::dlsym as windows;
Expand All @@ -18,7 +19,8 @@ impl Dlsym {
pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> {
let name = &*String::from_utf8_lossy(name);
Ok(match target_os {
"linux" | "macos" => posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix),
target if target_os_is_unix(target) =>
posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix),
"windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows),
os => bug!("dlsym not implemented for target_os {}", os),
})
Expand Down
33 changes: 7 additions & 26 deletions src/shims/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::layout::LayoutOf;
use rustc_target::abi::Size;

use crate::helpers::target_os_is_unix;
use crate::*;

/// Check whether an operation that writes to a target buffer was successful.
Expand Down Expand Up @@ -55,7 +56,7 @@ impl<'tcx> EnvVars<'tcx> {
};
if forward {
let var_ptr = match target_os {
"linux" | "macos" =>
target if target_os_is_unix(target) =>
alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?,
"windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?,
unsupported =>
Expand Down Expand Up @@ -113,11 +114,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Pointer<Option<Tag>>> {
let this = self.eval_context_mut();
let target_os = &this.tcx.sess.target.os;
assert!(
target_os == "linux" || target_os == "macos",
"`getenv` is only available for the UNIX target family"
);
this.assert_target_os_is_unix("getenv");

let name_ptr = this.read_pointer(name_op)?;
let name = this.read_os_str_from_c_str(name_ptr)?;
Expand Down Expand Up @@ -211,11 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
value_op: &OpTy<'tcx, Tag>,
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let target_os = &this.tcx.sess.target.os;
assert!(
target_os == "linux" || target_os == "macos",
"`setenv` is only available for the UNIX target family"
);
this.assert_target_os_is_unix("setenv");

let name_ptr = this.read_pointer(name_op)?;
let value_ptr = this.read_pointer(value_op)?;
Expand Down Expand Up @@ -285,11 +278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx

fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let target_os = &this.tcx.sess.target.os;
assert!(
target_os == "linux" || target_os == "macos",
"`unsetenv` is only available for the UNIX target family"
);
this.assert_target_os_is_unix("unsetenv");

let name_ptr = this.read_pointer(name_op)?;
let mut success = None;
Expand Down Expand Up @@ -319,11 +308,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
size_op: &OpTy<'tcx, Tag>,
) -> InterpResult<'tcx, Pointer<Option<Tag>>> {
let this = self.eval_context_mut();
let target_os = &this.tcx.sess.target.os;
assert!(
target_os == "linux" || target_os == "macos",
"`getcwd` is only available for the UNIX target family"
);
this.assert_target_os_is_unix("getcwd");

let buf = this.read_pointer(buf_op)?;
let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?;
Expand Down Expand Up @@ -378,11 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx

fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let target_os = &this.tcx.sess.target.os;
assert!(
target_os == "linux" || target_os == "macos",
"`getcwd` is only available for the UNIX target family"
landaire marked this conversation as resolved.
Show resolved Hide resolved
);
this.assert_target_os_is_unix("chdir");

let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;

Expand Down
4 changes: 2 additions & 2 deletions src/shims/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use rustc_target::{

use super::backtrace::EvalContextExt as _;
use crate::helpers::convert::Truncate;
use crate::helpers::target_os_is_unix;
use crate::*;

/// Returned by `emulate_foreign_item_by_name`.
Expand Down Expand Up @@ -700,9 +701,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
}

// Platform-specific shims
_ => match this.tcx.sess.target.os.as_ref() {
"linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
target if target_os_is_unix(target) => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
"windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
target => throw_unsup_format!("the target `{}` is not supported", target),
}
Expand Down
53 changes: 53 additions & 0 deletions src/shims/posix/android/dlsym.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use helpers::check_arg_count;
use log::trace;
use rustc_middle::mir;

use crate::*;

#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Dlsym {
signal,
}

impl Dlsym {
// Returns an error for unsupported symbols, and None if this symbol
// should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match &*name {
"__pthread_get_minstack" => None,
"getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL.
"statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL.
"signal" | "bsd_signal" => Some(Dlsym::signal), // these have the same signature/implementation
"android_set_abort_message" => None, // std falls back to just not doing anything when this is NULL.
_ => throw_unsup_format!("unsupported Android dlsym: {}", name),
})
}
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
fn call_dlsym(
&mut self,
dlsym: Dlsym,
args: &[OpTy<'tcx, Tag>],
dest: &PlaceTy<'tcx, Tag>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
assert!(this.tcx.sess.target.os == "android");

let ret = ret.expect("we don't support any diverging dlsym");

match dlsym {
Dlsym::signal => {
Copy link
Member

Choose a reason for hiding this comment

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

The POSIX version of this is gated on this.frame_in_std(), probably we should do the same here? After all we don't actually do anything...

let &[ref _sig, ref _func] = check_arg_count(args)?;
this.write_null(dest)?;
}
}

trace!("{:?}", this.dump_place(**dest));
this.go_to_block(ret);
Ok(())
}
}
28 changes: 28 additions & 0 deletions src/shims/posix/android/foreign_items.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use rustc_middle::mir;
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;

use crate::*;
use shims::foreign_items::EmulateByNameResult;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
fn emulate_foreign_item_by_name(
&mut self,
link_name: Symbol,
abi: Abi,
args: &[OpTy<'tcx, Tag>],
dest: &PlaceTy<'tcx, Tag>,
ret: mir::BasicBlock,
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut();

match &*link_name.as_str() {
_ => {
// By default we piggyback off the items emulated for Linux. For now this functions
// serves to make adding android-specific syscalls easy
return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret);
Copy link
Member

Choose a reason for hiding this comment

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

I am not very happy about this fallback. The linux functions are not prepared for android use, and we didn't check that their implementation is correct against their android specification. Android has its completely separate libc, and the API we are implementing here is basically that of libc.

So, I am not convinced that we want to fall back like this here; to me this seems to carry a huge risk of accidentally using the wrong shim implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes sense. I originally went with this approach since Android is Linux-based, but you're right that if we're implementing the libc API, we should probably ensure these are separate.

What would you suggest, just copying the Linux code here?

Copy link
Member

Choose a reason for hiding this comment

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

I would suggest copying enough of the Linux code to get hello.rs working on Android -- and leaving everything else to a future PR.

}
}
}
}
2 changes: 2 additions & 0 deletions src/shims/posix/android/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod dlsym;
pub mod foreign_items;
5 changes: 5 additions & 0 deletions src/shims/posix/dlsym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use rustc_middle::mir;
use rustc_target::spec::abi::Abi;

use crate::*;
use shims::posix::android::dlsym as android;
use shims::posix::linux::dlsym as linux;
use shims::posix::macos::dlsym as macos;

#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
Linux(linux::Dlsym),
MacOs(macos::Dlsym),
Android(android::Dlsym),
}

impl Dlsym {
Expand All @@ -18,6 +20,7 @@ impl Dlsym {
Ok(match target_os {
"linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux),
"macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs),
"android" => android::Dlsym::from_str(name)?.map(Dlsym::Android),
_ => unreachable!(),
})
}
Expand All @@ -40,6 +43,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
match dlsym {
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::Android(dlsym) =>
android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
}
}
}
18 changes: 18 additions & 0 deletions src/shims/posix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
this.write_null(dest)?;
}
"memalign" => {
let &[ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let align = this.read_scalar(align)?.to_machine_usize(this)?;
let size = this.read_scalar(size)?.to_machine_usize(this)?;

// Align must be power of 2.
if !align.is_power_of_two() {
throw_ub_format!("memalign: alignment must be a power of two, but is {}", align);
}

let ptr = this.allocate_ptr(
Copy link
Member

Choose a reason for hiding this comment

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

Like malloc, this probably should return NULL if the size is 0.

Size::from_bytes(size),
Align::from_bytes(align).unwrap(),
MiriMemoryKind::C.into(),
)?;
this.write_pointer(ptr, dest)?;
}

// Dynamic symbol loading
"dlsym" => {
Expand Down Expand Up @@ -479,6 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
match this.tcx.sess.target.os.as_ref() {
"linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
"macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
"android" => return shims::posix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
_ => unreachable!(),
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/shims/posix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();

this.assert_target_os("linux", "statx");
this.assert_target_os_is_linux_based("statx");

let dirfd = this.read_scalar(dirfd_op)?.to_i32()?;
let pathname_ptr = this.read_pointer(pathname_op)?;
Expand Down Expand Up @@ -1278,7 +1278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>> {
let this = self.eval_context_mut();

this.assert_target_os("linux", "readdir64");
this.assert_target_os_is_linux_based("readdir64");

let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;

Expand Down
Loading