mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 13:33:31 +00:00
Support libc::getenv
in mir interpreter
This commit is contained in:
parent
cc5664c5a2
commit
9b636e2326
4 changed files with 83 additions and 1 deletions
|
@ -130,6 +130,7 @@ impl ChangeFixture {
|
||||||
let mut default_crate_root: Option<FileId> = None;
|
let mut default_crate_root: Option<FileId> = None;
|
||||||
let mut default_target_data_layout: Option<String> = None;
|
let mut default_target_data_layout: Option<String> = None;
|
||||||
let mut default_cfg = CfgOptions::default();
|
let mut default_cfg = CfgOptions::default();
|
||||||
|
let mut default_env = Env::new_for_test_fixture();
|
||||||
|
|
||||||
let mut file_set = FileSet::default();
|
let mut file_set = FileSet::default();
|
||||||
let mut current_source_root_kind = SourceRootKind::Local;
|
let mut current_source_root_kind = SourceRootKind::Local;
|
||||||
|
@ -200,6 +201,7 @@ impl ChangeFixture {
|
||||||
assert!(default_crate_root.is_none());
|
assert!(default_crate_root.is_none());
|
||||||
default_crate_root = Some(file_id);
|
default_crate_root = Some(file_id);
|
||||||
default_cfg = meta.cfg;
|
default_cfg = meta.cfg;
|
||||||
|
default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
|
||||||
default_target_data_layout = meta.target_data_layout;
|
default_target_data_layout = meta.target_data_layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +222,7 @@ impl ChangeFixture {
|
||||||
None,
|
None,
|
||||||
default_cfg,
|
default_cfg,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
Env::new_for_test_fixture(),
|
default_env,
|
||||||
false,
|
false,
|
||||||
CrateOrigin::Local { repo: None, name: None },
|
CrateOrigin::Local { repo: None, name: None },
|
||||||
default_target_data_layout
|
default_target_data_layout
|
||||||
|
|
|
@ -686,6 +686,12 @@ impl fmt::Display for Edition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Extend<(String, String)> for Env {
|
||||||
|
fn extend<T: IntoIterator<Item = (String, String)>>(&mut self, iter: T) {
|
||||||
|
self.entries.extend(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromIterator<(String, String)> for Env {
|
impl FromIterator<(String, String)> for Env {
|
||||||
fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
|
||||||
Env { entries: FromIterator::from_iter(iter) }
|
Env { entries: FromIterator::from_iter(iter) }
|
||||||
|
|
|
@ -473,6 +473,38 @@ impl Evaluator<'_> {
|
||||||
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
|
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
"getenv" => {
|
||||||
|
let [name] = args else {
|
||||||
|
return Err(MirEvalError::TypeError("libc::write args are not provided"));
|
||||||
|
};
|
||||||
|
let mut name_buf = vec![];
|
||||||
|
let name = {
|
||||||
|
let mut index = Address::from_bytes(name.get(self)?)?;
|
||||||
|
loop {
|
||||||
|
let byte = self.read_memory(index, 1)?[0];
|
||||||
|
index = index.offset(1);
|
||||||
|
if byte == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
name_buf.push(byte);
|
||||||
|
}
|
||||||
|
String::from_utf8_lossy(&name_buf)
|
||||||
|
};
|
||||||
|
let value = self.db.crate_graph()[self.crate_id].env.get(&name);
|
||||||
|
match value {
|
||||||
|
None => {
|
||||||
|
// Write null as fail
|
||||||
|
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
|
||||||
|
}
|
||||||
|
Some(mut value) => {
|
||||||
|
value.push('\0');
|
||||||
|
let addr = self.heap_allocate(value.len(), 1)?;
|
||||||
|
self.write_memory(addr, value.as_bytes())?;
|
||||||
|
self.write_memory(destination.addr, &addr.to_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
_ => not_supported!("unknown external function {as_str}"),
|
_ => not_supported!("unknown external function {as_str}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -729,6 +729,48 @@ fn main() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn posix_getenv() {
|
||||||
|
check_pass(
|
||||||
|
r#"
|
||||||
|
//- /main.rs env:foo=bar
|
||||||
|
|
||||||
|
type c_char = u8;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn getenv(s: *const c_char) -> *mut c_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_not_reach() {
|
||||||
|
_ // FIXME: replace this function with panic when that works
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let result = getenv(b"foo\0" as *const _);
|
||||||
|
if *result != b'b' {
|
||||||
|
should_not_reach();
|
||||||
|
}
|
||||||
|
let result = (result as usize + 1) as *const c_char;
|
||||||
|
if *result != b'a' {
|
||||||
|
should_not_reach();
|
||||||
|
}
|
||||||
|
let result = (result as usize + 1) as *const c_char;
|
||||||
|
if *result != b'r' {
|
||||||
|
should_not_reach();
|
||||||
|
}
|
||||||
|
let result = (result as usize + 1) as *const c_char;
|
||||||
|
if *result != 0 {
|
||||||
|
should_not_reach();
|
||||||
|
}
|
||||||
|
let result = getenv(b"not found\0" as *const _);
|
||||||
|
if result as usize != 0 {
|
||||||
|
should_not_reach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn posix_tls() {
|
fn posix_tls() {
|
||||||
check_pass(
|
check_pass(
|
||||||
|
|
Loading…
Reference in a new issue