invalid pointer

This commit is contained in:
Shautvast 2023-10-19 07:33:08 +02:00
parent 656b6aa66a
commit 050c1821c2
3 changed files with 73 additions and 82 deletions

View file

@ -1,7 +1,6 @@
use std::cell::{RefCell, UnsafeCell}; use std::cell::{RefCell, UnsafeCell};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::hash::Hash;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -20,55 +19,49 @@ static mut CLASSDEFS: Lazy<HashMap<String, Arc<RefCell<Class>>>> = Lazy::new(||
// gets the Class from cache, or reads it from classpath, // gets the Class from cache, or reads it from classpath,
// then parses the binary data into a Class struct // then parses the binary data into a Class struct
// Vm keeps ownership of the class and hands out Arc references to it // Vm keeps ownership of the class and hands out Arc references to it
pub fn get_class(vm: &mut Vm, calling_class_name: Option<&str>, class_name: &str) -> Result<Arc<RefCell<Class>>, Error> { pub fn get_class(vm: &mut Vm, _calling_class_name: Option<&str>, class_name: &str) -> Result<Arc<RefCell<Class>>, Error> {
println!("get_class {}", class_name); println!("get_class {}", class_name);
unsafe { unsafe {
// not pretty...sorry // not pretty...sorry
if let Some(calling_class_name) = calling_class_name { // if let Some(calling_class_name) = calling_class_name {
if class_name == calling_class_name { // works around the situation that static initializer needs a ref to the class it's in // if class_name == calling_class_name { // works around the situation that static initializer needs a ref to the class it's in
panic!();
// return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here // return Ok(CLASSDEFS.get(class_name.into()).unwrap().clone()); // in that case the class is guaranteed to be here
} // }
} // }
let new_class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| { let class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| {
println!("read class {} ", class_name); println!("read class {} ", class_name);
let resolved_path = find_class(&vm.classpath, class_name).unwrap(); let resolved_path = find_class(&vm.classpath, class_name).unwrap();
// println!("full path {}", resolved_path); // println!("full path {}", resolved_path);
let bytecode = read_bytecode(resolved_path).unwrap(); let bytecode = read_bytecode(resolved_path).unwrap();
let mut class = load_class(bytecode).unwrap(); let class = load_class(bytecode).unwrap();
let super_class_name = class.super_class_name.as_ref(); Arc::new(RefCell::new(class))
});
let clone = class.clone();
let clone2 = class.clone();
if !class.borrow().inited {
let super_class_name = class.borrow().super_class_name.as_ref().map(|n| n.to_owned());
{
if let Some(super_class_name) = super_class_name { if let Some(super_class_name) = super_class_name {
if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) { if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) {
class.super_class = Some(super_class); class.borrow_mut().super_class = Some(super_class);
} else { } else {
unreachable!() unreachable!()
} }
} }
let class = Arc::new(RefCell::new(class));
Class::initialize_fields(class.clone());
class
});
// calling clinit before the end of this function has been a PITA
// 1. infinite recursion
// panic after second borrow.
// the problem is pretty fundamental: method (clinit) should be called before the class is returned,
// but the executing code needs a reference to itself. So get_class is called recursively, but clinit must be called exactly once!
// putting the call to clinit in the closure above is way nicer, but the signature change (wrap it in Arc<RefCell>)
//update: this is probably not needed anymore because of the check in PUTSTATIC
//somehow this clone needs to be there before clinit is called, even though the newclass ref remains in scope
let clone = new_class.clone();
if new_class.clone().borrow().methods.contains_key("<clinit>()V") {
vm.execute_class(new_class.clone(), "<clinit>()V", vec![]).unwrap();
} }
Ok(clone) Class::initialize_fields(class.clone());
let clinit = clone.borrow().methods.contains_key("<clinit>()V");
if clinit{
vm.execute_class(class.clone(), "<clinit>()V", vec![]).unwrap();
}
clone.borrow_mut().inited = true;
}
Ok(clone2)
} }
} }
@ -89,6 +82,7 @@ pub struct Class {
pub fields: HashMap<String, Field>, pub fields: HashMap<String, Field>,
pub methods: HashMap<String, Rc<Method>>, pub methods: HashMap<String, Rc<Method>>,
pub attributes: HashMap<String, AttributeType>, pub attributes: HashMap<String, AttributeType>,
pub inited: bool,
pub(crate) object_field_mapping: HashMap<String, HashMap<String, (String, usize)>>, pub(crate) object_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index) // first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>, pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
@ -125,6 +119,7 @@ impl Class {
fields, fields,
methods, methods,
attributes, attributes,
inited: false,
object_field_mapping: HashMap::new(), object_field_mapping: HashMap::new(),
static_field_mapping: HashMap::new(), static_field_mapping: HashMap::new(),
static_data: vec![], static_data: vec![],
@ -565,17 +560,18 @@ pub type UnsafeValue = Arc<UnsafeCell<Value>>;
pub type UnsafeRef = Arc<UnsafeCell<ObjectRef>>; pub type UnsafeRef = Arc<UnsafeCell<ObjectRef>>;
pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef{ pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef {
return Arc::new(UnsafeCell::new(object)) return Arc::new(UnsafeCell::new(object));
} }
pub fn unsafe_val(val: Value) -> UnsafeValue{ pub fn unsafe_val(val: Value) -> UnsafeValue {
return Arc::new(UnsafeCell::new(val)) return Arc::new(UnsafeCell::new(val));
} }
pub fn type_ref(class: Class) -> Type{ pub fn type_ref(class: Class) -> Type {
return Arc::new(RefCell::new(class)) return Arc::new(RefCell::new(class));
} }
pub type Type = Arc<RefCell<Class>>; pub type Type = Arc<RefCell<Class>>;
unsafe impl Send for Value {} unsafe impl Send for Value {}

View file

@ -9,7 +9,10 @@ use std::io::Read;
/// * [jar/zip]#[package_path]/[class].class /// * [jar/zip]#[package_path]/[class].class
/// * [dir]/[package_path]/[class].class /// * [dir]/[package_path]/[class].class
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> { pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
if class_name.starts_with("java/") { if class_name.starts_with("java")
|| class_name.starts_with("sun/")
|| class_name.starts_with("com/sun/")
|| class_name.starts_with("jdk/") {
let mut path: String = "jmods/java.base.jmod#classes/".into(); let mut path: String = "jmods/java.base.jmod#classes/".into();
path.push_str(class_name); path.push_str(class_name);
path.push_str(".class"); path.push_str(".class");

View file

@ -321,42 +321,32 @@ impl Vm {
let that_borrow = that.borrow(); let that_borrow = that.borrow();
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap(); let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
println!("get static field {}", name); println!("get static field {}", name);
self.current_frame().push_ref(borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone()); self.current_frame().push_ref(that_borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone());
} }
PUTSTATIC => { PUTSTATIC => {
println!("PUTSTATIC"); println!("PUTSTATIC");
let mut borrow = this_class.borrow_mut(); let mut borrow = this_class.borrow_mut();
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) = // let (class_index, field_name_and_type_index) =
borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid // borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap(); // let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
let (name) = borrow.cp_utf8(name_index).unwrap(); // let (name) = borrow.cp_utf8(name_index).unwrap();
let class_name_index = borrow.cp_class_ref(class_index).unwrap(); // let class_name_index = borrow.cp_class_ref(class_index).unwrap();
println!("field {}", name); // println!("field {}", name);
let that_class_name = borrow.cp_utf8(class_name_index).unwrap(); // let that_class_name = borrow.cp_utf8(class_name_index).unwrap();
if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too // if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too
let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap(); // let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap();
let val_index = *val_index; // let val_index = *val_index;
let value = self.current_frame().pop()?; // let value = self.current_frame().pop()?;
borrow.static_data[val_index] = Some(value); // borrow.static_data[val_index] = Some(value);
} else { // } else {
let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?; // let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?;
let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class // let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap(); // let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
let value = self.current_frame().pop()?; // let value = self.current_frame().pop()?;
borrow.static_data[*val_index] = Some(value); // borrow.static_data[*val_index] = Some(value);
} // }
unsafe {
for v in &borrow.static_data {
let v = &*v.as_ref().unwrap().get();
if let Value::Ref(vv) = v {
println!("{:?}", &*vv.get())
} else {
println!("{:?}", *v);
}
}
}
} }
GETFIELD => unsafe { GETFIELD => unsafe {
let borrow = this_class.borrow(); let borrow = this_class.borrow();
@ -414,7 +404,7 @@ impl Vm {
args.insert(0, copy(self.current_frame().pop()?)); args.insert(0, copy(self.current_frame().pop()?));
} }
args.insert(0, self.current_frame().pop()?); args.insert(0, self.current_frame().pop()?);
let mut return_value = self.execute( let return_value = self.execute(
Some(this_class.borrow().name.as_str()), Some(this_class.borrow().name.as_str()),
&invocation.class_name, &invocation.class_name,
&invocation.method.name, &invocation.method.name,
@ -432,6 +422,7 @@ impl Vm {
} }
}, },
INVOKESTATIC => unsafe { INVOKESTATIC => unsafe {
println!("INVOKESTATIC");
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
if let Some(invocation) = if let Some(invocation) =
get_signature_for_invoke(&method.constant_pool, cp_index) get_signature_for_invoke(&method.constant_pool, cp_index)
@ -440,7 +431,7 @@ impl Vm {
for _ in 0..invocation.method.num_args { for _ in 0..invocation.method.num_args {
args.insert(0, copy(self.current_frame().pop()?)); args.insert(0, copy(self.current_frame().pop()?));
} }
let mut returnvalue = self.execute( let returnvalue = self.execute(
Some(this_class.borrow().name.as_str()), Some(this_class.borrow().name.as_str()),
&invocation.class_name, &invocation.class_name,
&invocation.method.name, &invocation.method.name,
@ -680,14 +671,14 @@ unsafe fn copy(value: UnsafeValue) -> UnsafeValue {
unsafe_val(match (&*value.get()) { unsafe_val(match (&*value.get()) {
Void => Void, Void => Void,
Null => Null, Null => Null,
BOOL(b)=> BOOL(*b), BOOL(b) => BOOL(*b),
CHAR(c)=> CHAR(*c), CHAR(c) => CHAR(*c),
I32(i)=> I32(*i), I32(i) => I32(*i),
I64(l)=> I64(*l), I64(l) => I64(*l),
F32(f)=> F32(*f), F32(f) => F32(*f),
F64(d)=> F64(*d), F64(d) => F64(*d),
Ref(r)=> Ref(r.clone()), Ref(r) => Ref(r.clone()),
Utf8(s)=> Utf8(s.to_owned()), Utf8(s) => Utf8(s.to_owned()),
}) })
} }
@ -719,6 +710,7 @@ fn get_hum_args(signature: &str) -> usize {
while chars[i] != ';' { while chars[i] != ';' {
i += 1; i += 1;
} }
i += 1;
num += 1; num += 1;
} else if chars[i] == ')' { } else if chars[i] == ')' {
break; break;