Unnamed repository; edit this file 'description' to name the repository.
Support `libc::getenv` in mir interpreter
hkalbasi 2023-08-06
parent cc5664c · commit 9b636e2
-rw-r--r--crates/base-db/src/fixture.rs4
-rw-r--r--crates/base-db/src/input.rs6
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs32
-rw-r--r--crates/hir-ty/src/mir/eval/tests.rs42
4 files changed, 83 insertions, 1 deletions
diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs
index 323ee4260e..aaac0fc379 100644
--- a/crates/base-db/src/fixture.rs
+++ b/crates/base-db/src/fixture.rs
@@ -130,6 +130,7 @@ impl ChangeFixture {
let mut default_crate_root: Option<FileId> = None;
let mut default_target_data_layout: Option<String> = None;
let mut default_cfg = CfgOptions::default();
+ let mut default_env = Env::new_for_test_fixture();
let mut file_set = FileSet::default();
let mut current_source_root_kind = SourceRootKind::Local;
@@ -200,6 +201,7 @@ impl ChangeFixture {
assert!(default_crate_root.is_none());
default_crate_root = Some(file_id);
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;
}
@@ -220,7 +222,7 @@ impl ChangeFixture {
None,
default_cfg,
Default::default(),
- Env::new_for_test_fixture(),
+ default_env,
false,
CrateOrigin::Local { repo: None, name: None },
default_target_data_layout
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index c47799f132..b75c7079be 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -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 {
fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
Env { entries: FromIterator::from_iter(iter) }
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index b2e29fd34b..bfd7d7c1f2 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -473,6 +473,38 @@ impl Evaluator<'_> {
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
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}"),
}
}
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index 46165cf3d6..ff30dc6dad 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -730,6 +730,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]
fn posix_tls() {
check_pass(
r#"