Skip to content

Commit

Permalink
Initialize harvard variable memory to 0 (#329)
Browse files Browse the repository at this point in the history
* fix

* fix test

* move opt level test

* split up tests
  • Loading branch information
evan-schott authored and sjudson committed Feb 5, 2025
1 parent a0cb150 commit 48c58aa
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 32 deletions.
1 change: 1 addition & 0 deletions tests/testing-framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ nexus-common = { path = "../../common" }
nexus-vm = { path = "../../vm" }
postcard = { version = "1.0.10", features = ["alloc"] }
serde.workspace = true
serial_test = "3.2.0"
219 changes: 192 additions & 27 deletions tests/testing-framework/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod test {
use nexus_vm::emulator::{Emulator, HarvardEmulator, LinearEmulator, LinearMemoryLayout};
use postcard::{from_bytes, to_allocvec};
use serde::{de::DeserializeOwned, Serialize};
use serial_test::serial;
use std::{path::PathBuf, process::Command};
use tempfile::{tempdir, TempDir};

Expand Down Expand Up @@ -138,7 +139,7 @@ mod test {
elfs: Vec<ElfFile>,
input: Option<T>,
expected_output: Option<U>,
expected_result: Result<
expected_result: &Result<
(Vec<InstructionResult>, MemoryTranscript),
nexus_vm::error::VMError,
>,
Expand All @@ -160,7 +161,7 @@ mod test {
let mut emulator = HarvardEmulator::from_elf(elf.clone(), &input_bytes, &[]);

// Check that the program exits correctly.
assert_eq!(emulator.execute(), expected_result);
assert_eq!(&emulator.execute(), expected_result);

// Deserialize the output.
if expected_output.is_some() {
Expand All @@ -179,7 +180,7 @@ mod test {
LinearEmulator::from_harvard(emulator, elf, &ad, &[]).unwrap();

// Check that the program exits correctly.
assert_eq!(linear_emulator.execute(), expected_result);
assert_eq!(&linear_emulator.execute(), expected_result);

// Deserialize the output.
if expected_output.is_some() {
Expand Down Expand Up @@ -213,7 +214,7 @@ mod test {
LinearEmulator::from_elf(memory_layout, &ad, elf, &input_bytes, &[]);

// Check that the program exits correctly.
assert_eq!(emulator.execute(), expected_result);
assert_eq!(&emulator.execute(), expected_result);

// Deserialize the output.
if expected_output.is_some() {
Expand All @@ -229,8 +230,175 @@ mod test {
assert_eq!(deserialized_output, expected_output);
}

/// Helper function to run test accross multiple emulators, multiple opt levels, and multiple inputs.
fn test_example_multi<
T: Serialize + Clone,
U: Serialize + DeserializeOwned + std::fmt::Debug + PartialEq + Clone,
>(
emulators: Vec<EmulatorType>,
compile_flags: Vec<&str>,
name: &str,
inputs: Vec<T>,
outputs: Vec<U>,
expected_result: Result<
(Vec<InstructionResult>, MemoryTranscript),
nexus_vm::error::VMError,
>,
) {
let elfs = compile_multi(name, &compile_flags);

for emulator in &emulators {
for (input, output) in inputs.iter().zip(outputs.iter()) {
emulate::<T, U>(
elfs.clone(),
Some(input.clone()),
Some(output.clone()),
&expected_result,
emulator.clone(),
);
}
}
}

#[test]
#[serial]
fn test_fact_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/fact",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(0)),
);
}

#[test]
#[serial]
fn test_fib_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/fib",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(0)),
);
}

#[test]
#[serial]
fn test_fib1000_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/fib1000",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(0)),
);
}

#[test]
#[serial]
fn test_main_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/main",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(0)),
);
}

#[test]
#[serial]
fn test_palindromes_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/palindromes",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(0)),
);
}

#[test]
fn test_examples() {
#[serial]
fn test_galeshapley_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/galeshapley",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(0)),
);
}

#[test]
#[serial]
fn test_lambda_calculus_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/lambda_calculus",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(0)),
);
}

#[test]
#[serial]
fn test_fail_example() {
test_example_multi(
vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
],
vec!["-C opt-level=3"],
"../../examples/src/fail",
vec![()],
vec![()],
Err(nexus_vm::error::VMError::VMExited(1)),
);
}

#[test]
#[ignore]
fn test_examples_all_opt_levels() {
let emulators = vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
Expand All @@ -242,7 +410,15 @@ mod test {
"-C opt-level=2",
"-C opt-level=3",
];
let examples = vec!["fact", "fib", "fib1000", "main", "palindromes"];
let examples = vec![
"fact",
"fib",
"fib1000",
"main",
"palindromes",
"galeshapley",
"lambda_calculus",
];

// Test simple examples.
for example in examples {
Expand All @@ -254,7 +430,7 @@ mod test {
elfs.clone(),
None,
Some(()),
Err(nexus_vm::error::VMError::VMExited(0)),
&Err(nexus_vm::error::VMError::VMExited(0)),
emulator.clone(),
);
}
Expand All @@ -269,25 +445,21 @@ mod test {
fail_elfs.clone(),
None,
Some(()),
Err(nexus_vm::error::VMError::VMExited(1)),
&Err(nexus_vm::error::VMError::VMExited(1)),
emulator.clone(),
);
}
}

#[test]
#[serial]
fn test_emulate() {
let emulators = vec![
EmulatorType::Harvard,
EmulatorType::default_linear(),
EmulatorType::TwoPass,
];
let compile_flags = vec![
"-C opt-level=0",
"-C opt-level=1",
"-C opt-level=2",
"-C opt-level=3",
];
let compile_flags = vec!["-C opt-level=3"];
let io_u32_elfs = compile_multi("io_u32", &compile_flags);
let io_u64_elfs = compile_multi("io_u64", &compile_flags);
let io_u128_elfs = compile_multi("io_u128", &compile_flags);
Expand All @@ -297,27 +469,28 @@ mod test {
io_u32_elfs.clone(),
Some(123u32),
Some(123u32),
Err(nexus_vm::error::VMError::VMExited(0)),
&Err(nexus_vm::error::VMError::VMExited(0)),
emulator.clone(),
);
emulate::<u64, u64>(
io_u64_elfs.clone(),
Some(1u64 << 32),
Some(1u64 << 32),
Err(nexus_vm::error::VMError::VMExited(0)),
&Err(nexus_vm::error::VMError::VMExited(0)),
emulator.clone(),
);
emulate::<u128, u128>(
io_u128_elfs.clone(),
Some(332306998946228968225970211937533483u128),
Some(332306998946228968225970211937533483u128),
Err(nexus_vm::error::VMError::VMExited(0)),
&Err(nexus_vm::error::VMError::VMExited(0)),
emulator,
);
}
}

#[test]
#[serial]
fn test_fib() {
let inputs = vec![1u32, 10u32, 20u32];
let outputs = vec![1u32, 34u32, 4181u32];
Expand All @@ -326,23 +499,15 @@ mod test {
EmulatorType::default_linear(),
EmulatorType::TwoPass,
];
let elfs = compile_multi(
"fib",
&[
"-C opt-level=0",
"-C opt-level=1",
"-C opt-level=2",
"-C opt-level=3",
],
);
let elfs = compile_multi("fib", &["-C opt-level=3"]);

for (input, output) in inputs.iter().zip(outputs.iter()) {
for emulator in emulators.clone() {
emulate::<u32, u32>(
elfs.clone(),
Some(input.clone()),
Some(output.clone()),
Err(nexus_vm::error::VMError::VMExited(0)),
&Err(nexus_vm::error::VMError::VMExited(0)),
emulator.clone(),
);
}
Expand Down
2 changes: 1 addition & 1 deletion vm/src/memory/unified.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ mod tests {
// Read from an uninitialized address
assert_eq!(
memory.read(0x4000, MemAccessSize::Word),
Err(MemoryError::InvalidMemoryAccess(0x4000))
Ok(LoadOp::Op(MemAccessSize::Word, 0x4000, 0x00000000))
);
}

Expand Down
7 changes: 3 additions & 4 deletions vm/src/memory/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ impl<M: Mode> VariableMemory<M> {
.0
.get(&aligned_address) // Align to word boundary
.map(|&value| ((value >> shift) & mask))
.ok_or(MemoryError::InvalidMemoryAccess(address))?;

.unwrap_or(0);
Ok(LoadOp::Op(size, address, value))
}
/// For bounded segments, returns a slice of memory between start and end addresses, if they form a contiguous segment.
Expand Down Expand Up @@ -441,13 +440,13 @@ mod tests {
}

#[test]
fn test_invalid_read() {
fn test_uninitialized_read() {
let memory = VariableMemory::<RW>::default();

// Read from an uninitialized address
assert_eq!(
memory.read(0x2000, MemAccessSize::Word),
Err(MemoryError::InvalidMemoryAccess(0x2000))
Ok(LoadOp::Op(MemAccessSize::Word, 0x2000, 0x00000000))
);
}

Expand Down

0 comments on commit 48c58aa

Please sign in to comment.