mod appdomain;
mod collections;
mod crypto;
mod interop;
mod io;
mod reflection;
mod runtime;
mod statics;
mod system;
mod text;
mod threading;
pub use statics::get_bcl_static_field;
use crate::{emulation::runtime::hook::HookManager, Result};
pub fn register(manager: &HookManager) -> Result<()> {
system::register(manager)?;
collections::register(manager)?;
io::register(manager)?;
reflection::register(manager)?;
crypto::register(manager)?;
text::register(manager)?;
interop::register(manager)?;
appdomain::register(manager)?;
runtime::register(manager)?;
threading::register(manager)?;
Ok(())
}
#[cfg(test)]
mod tests {
use crate::{
emulation::{memory::DictionaryKey, EmValue},
metadata::{token::Token, typesystem::CilFlavor},
test::emulation::create_test_thread,
};
#[test]
fn test_list_to_array_pattern() {
let thread = create_test_thread();
let obj = thread
.heap_mut()
.alloc_object(Token::new(0x02000001))
.unwrap();
thread.heap().replace_with_list(obj).unwrap();
thread.heap().list_add(obj, EmValue::I32(10)).unwrap();
thread.heap().list_add(obj, EmValue::I32(20)).unwrap();
thread.heap().list_add(obj, EmValue::I32(30)).unwrap();
assert_eq!(thread.heap().list_count(obj).unwrap(), 3);
assert_eq!(
thread.heap().list_get(obj, 0).unwrap(),
Some(EmValue::I32(10))
);
assert_eq!(
thread.heap().list_get(obj, 1).unwrap(),
Some(EmValue::I32(20))
);
assert_eq!(
thread.heap().list_get(obj, 2).unwrap(),
Some(EmValue::I32(30))
);
}
#[test]
fn test_dictionary_keys_values() {
let thread = create_test_thread();
let dict = thread.heap_mut().alloc_dictionary().unwrap();
thread
.heap()
.dictionary_add(dict, DictionaryKey::Integer(1), EmValue::I32(100))
.unwrap();
thread
.heap()
.dictionary_add(dict, DictionaryKey::Integer(2), EmValue::I32(200))
.unwrap();
thread
.heap()
.dictionary_add(dict, DictionaryKey::Integer(3), EmValue::I32(300))
.unwrap();
assert_eq!(thread.heap().dictionary_count(dict).unwrap(), 3);
let keys = thread.heap().dictionary_keys(dict).unwrap();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&DictionaryKey::Integer(1)));
assert!(keys.contains(&DictionaryKey::Integer(2)));
assert!(keys.contains(&DictionaryKey::Integer(3)));
let values = thread.heap().dictionary_values(dict).unwrap();
assert_eq!(values.len(), 3);
assert!(values.contains(&EmValue::I32(100)));
assert!(values.contains(&EmValue::I32(200)));
assert!(values.contains(&EmValue::I32(300)));
}
#[test]
fn test_stack_push_pop_interleaved() {
let thread = create_test_thread();
let obj = thread
.heap_mut()
.alloc_object(Token::new(0x02000001))
.unwrap();
thread.heap().replace_with_stack(obj).unwrap();
thread.heap().stack_push(obj, EmValue::I32(1)).unwrap();
thread.heap().stack_push(obj, EmValue::I32(2)).unwrap();
thread.heap().stack_push(obj, EmValue::I32(3)).unwrap();
assert_eq!(thread.heap().stack_count(obj).unwrap(), 3);
assert_eq!(thread.heap().stack_pop(obj).unwrap(), Some(EmValue::I32(3)));
assert_eq!(thread.heap().stack_pop(obj).unwrap(), Some(EmValue::I32(2)));
thread.heap().stack_push(obj, EmValue::I32(4)).unwrap();
thread.heap().stack_push(obj, EmValue::I32(5)).unwrap();
assert_eq!(thread.heap().stack_count(obj).unwrap(), 3);
assert_eq!(thread.heap().stack_pop(obj).unwrap(), Some(EmValue::I32(5)));
assert_eq!(thread.heap().stack_pop(obj).unwrap(), Some(EmValue::I32(4)));
assert_eq!(thread.heap().stack_pop(obj).unwrap(), Some(EmValue::I32(1)));
assert_eq!(thread.heap().stack_count(obj).unwrap(), 0);
}
#[test]
fn test_queue_fifo_order() {
let thread = create_test_thread();
let obj = thread
.heap_mut()
.alloc_object(Token::new(0x02000001))
.unwrap();
thread.heap().replace_with_queue(obj).unwrap();
thread.heap().queue_enqueue(obj, EmValue::I32(10)).unwrap();
thread.heap().queue_enqueue(obj, EmValue::I32(20)).unwrap();
thread.heap().queue_enqueue(obj, EmValue::I32(30)).unwrap();
assert_eq!(
thread.heap().queue_dequeue(obj).unwrap(),
Some(EmValue::I32(10))
);
assert_eq!(
thread.heap().queue_dequeue(obj).unwrap(),
Some(EmValue::I32(20))
);
assert_eq!(
thread.heap().queue_dequeue(obj).unwrap(),
Some(EmValue::I32(30))
);
assert_eq!(thread.heap().queue_count(obj).unwrap(), 0);
}
#[test]
fn test_hashset_add_contains_remove() {
let thread = create_test_thread();
let obj = thread
.heap_mut()
.alloc_object(Token::new(0x02000001))
.unwrap();
thread.heap().replace_with_hashset(obj).unwrap();
assert!(thread
.heap()
.hashset_add(obj, DictionaryKey::Integer(42))
.unwrap());
assert!(!thread
.heap()
.hashset_add(obj, DictionaryKey::Integer(42))
.unwrap()); assert_eq!(thread.heap().hashset_count(obj).unwrap(), 1);
assert!(thread
.heap()
.hashset_contains(obj, &DictionaryKey::Integer(42))
.unwrap());
assert!(!thread
.heap()
.hashset_contains(obj, &DictionaryKey::Integer(99))
.unwrap());
assert!(thread
.heap()
.hashset_remove(obj, &DictionaryKey::Integer(42))
.unwrap());
assert_eq!(thread.heap().hashset_count(obj).unwrap(), 0);
}
#[test]
fn test_array_copy_and_reverse() {
let thread = create_test_thread();
let src = thread.heap_mut().alloc_array(CilFlavor::I4, 4).unwrap();
thread
.heap_mut()
.set_array_element(src, 0, EmValue::I32(1))
.unwrap();
thread
.heap_mut()
.set_array_element(src, 1, EmValue::I32(2))
.unwrap();
thread
.heap_mut()
.set_array_element(src, 2, EmValue::I32(3))
.unwrap();
thread
.heap_mut()
.set_array_element(src, 3, EmValue::I32(4))
.unwrap();
let dst = thread.heap_mut().alloc_array(CilFlavor::I4, 4).unwrap();
for i in 0..4 {
let val = thread.heap().get_array_element(src, i).unwrap();
thread.heap_mut().set_array_element(dst, i, val).unwrap();
}
thread
.heap_mut()
.set_array_element(src, 0, EmValue::I32(99))
.unwrap();
assert_eq!(
thread.heap().get_array_element(dst, 0).unwrap(),
EmValue::I32(1)
);
}
#[test]
fn test_string_to_bytes_roundtrip() {
let thread = create_test_thread();
let s = thread.heap_mut().alloc_string("Hello World").unwrap();
let text = thread.heap().get_string(s).unwrap();
let bytes = text.as_bytes();
let arr = thread.heap_mut().alloc_byte_array(bytes).unwrap();
let retrieved = thread.heap().get_byte_array(arr).unwrap().unwrap();
assert_eq!(retrieved, b"Hello World");
let decoded = String::from_utf8_lossy(&retrieved).into_owned();
let s2 = thread.heap_mut().alloc_string(&decoded).unwrap();
assert_eq!(&*thread.heap().get_string(s2).unwrap(), "Hello World");
}
#[test]
fn test_dictionary_string_key_pattern() {
let thread = create_test_thread();
let dict = thread.heap_mut().alloc_dictionary().unwrap();
let key1 = thread.heap_mut().alloc_string("method_a").unwrap();
let key2 = thread.heap_mut().alloc_string("method_b").unwrap();
thread
.heap()
.dictionary_add(dict, DictionaryKey::ObjectRef(key1), EmValue::I32(1))
.unwrap();
thread
.heap()
.dictionary_add(dict, DictionaryKey::ObjectRef(key2), EmValue::I32(2))
.unwrap();
assert_eq!(
thread
.heap()
.dictionary_get(dict, &DictionaryKey::ObjectRef(key1))
.unwrap(),
Some(EmValue::I32(1))
);
assert_eq!(
thread
.heap()
.dictionary_get(dict, &DictionaryKey::ObjectRef(key2))
.unwrap(),
Some(EmValue::I32(2))
);
assert_eq!(thread.heap().dictionary_count(dict).unwrap(), 2);
}
}