Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9b636e2

Browse files
committed
Support libc::getenv in mir interpreter
1 parent cc5664c commit 9b636e2

File tree

4 files changed

+83
-1
lines changed

4 files changed

+83
-1
lines changed

crates/base-db/src/fixture.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ impl ChangeFixture {
130130
let mut default_crate_root: Option<FileId> = None;
131131
let mut default_target_data_layout: Option<String> = None;
132132
let mut default_cfg = CfgOptions::default();
133+
let mut default_env = Env::new_for_test_fixture();
133134

134135
let mut file_set = FileSet::default();
135136
let mut current_source_root_kind = SourceRootKind::Local;
@@ -200,6 +201,7 @@ impl ChangeFixture {
200201
assert!(default_crate_root.is_none());
201202
default_crate_root = Some(file_id);
202203
default_cfg = meta.cfg;
204+
default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
203205
default_target_data_layout = meta.target_data_layout;
204206
}
205207

@@ -220,7 +222,7 @@ impl ChangeFixture {
220222
None,
221223
default_cfg,
222224
Default::default(),
223-
Env::new_for_test_fixture(),
225+
default_env,
224226
false,
225227
CrateOrigin::Local { repo: None, name: None },
226228
default_target_data_layout

crates/base-db/src/input.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,12 @@ impl fmt::Display for Edition {
686686
}
687687
}
688688

689+
impl Extend<(String, String)> for Env {
690+
fn extend<T: IntoIterator<Item = (String, String)>>(&mut self, iter: T) {
691+
self.entries.extend(iter);
692+
}
693+
}
694+
689695
impl FromIterator<(String, String)> for Env {
690696
fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
691697
Env { entries: FromIterator::from_iter(iter) }

crates/hir-ty/src/mir/eval/shim.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,38 @@ impl Evaluator<'_> {
473473
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
474474
Ok(())
475475
}
476+
"getenv" => {
477+
let [name] = args else {
478+
return Err(MirEvalError::TypeError("libc::write args are not provided"));
479+
};
480+
let mut name_buf = vec![];
481+
let name = {
482+
let mut index = Address::from_bytes(name.get(self)?)?;
483+
loop {
484+
let byte = self.read_memory(index, 1)?[0];
485+
index = index.offset(1);
486+
if byte == 0 {
487+
break;
488+
}
489+
name_buf.push(byte);
490+
}
491+
String::from_utf8_lossy(&name_buf)
492+
};
493+
let value = self.db.crate_graph()[self.crate_id].env.get(&name);
494+
match value {
495+
None => {
496+
// Write null as fail
497+
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
498+
}
499+
Some(mut value) => {
500+
value.push('\0');
501+
let addr = self.heap_allocate(value.len(), 1)?;
502+
self.write_memory(addr, value.as_bytes())?;
503+
self.write_memory(destination.addr, &addr.to_bytes())?;
504+
}
505+
}
506+
Ok(())
507+
}
476508
_ => not_supported!("unknown external function {as_str}"),
477509
}
478510
}

crates/hir-ty/src/mir/eval/tests.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,48 @@ fn main() {
729729
)
730730
}
731731

732+
#[test]
733+
fn posix_getenv() {
734+
check_pass(
735+
r#"
736+
//- /main.rs env:foo=bar
737+
738+
type c_char = u8;
739+
740+
extern "C" {
741+
pub fn getenv(s: *const c_char) -> *mut c_char;
742+
}
743+
744+
fn should_not_reach() {
745+
_ // FIXME: replace this function with panic when that works
746+
}
747+
748+
fn main() {
749+
let result = getenv(b"foo\0" as *const _);
750+
if *result != b'b' {
751+
should_not_reach();
752+
}
753+
let result = (result as usize + 1) as *const c_char;
754+
if *result != b'a' {
755+
should_not_reach();
756+
}
757+
let result = (result as usize + 1) as *const c_char;
758+
if *result != b'r' {
759+
should_not_reach();
760+
}
761+
let result = (result as usize + 1) as *const c_char;
762+
if *result != 0 {
763+
should_not_reach();
764+
}
765+
let result = getenv(b"not found\0" as *const _);
766+
if result as usize != 0 {
767+
should_not_reach();
768+
}
769+
}
770+
"#,
771+
);
772+
}
773+
732774
#[test]
733775
fn posix_tls() {
734776
check_pass(

0 commit comments

Comments
 (0)