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::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::rc::Rc;
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,
// then parses the binary data into a Class struct
// 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);
unsafe {
// not pretty...sorry
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
panic!();
// 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
// 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);
let resolved_path = find_class(&vm.classpath, class_name).unwrap();
// println!("full path {}", resolved_path);
let bytecode = read_bytecode(resolved_path).unwrap();
let mut class = load_class(bytecode).unwrap();
let super_class_name = class.super_class_name.as_ref();
let class = load_class(bytecode).unwrap();
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 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 {
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 methods: HashMap<String, Rc<Method>>,
pub attributes: HashMap<String, AttributeType>,
pub inited: bool,
pub(crate) object_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
// first key: this/super/supersuper-name(etc), second key: fieldname, value (type, index)
pub(crate) static_field_mapping: HashMap<String, HashMap<String, (String, usize)>>,
@ -125,6 +119,7 @@ impl Class {
fields,
methods,
attributes,
inited: false,
object_field_mapping: HashMap::new(),
static_field_mapping: HashMap::new(),
static_data: vec![],
@ -565,17 +560,18 @@ pub type UnsafeValue = Arc<UnsafeCell<Value>>;
pub type UnsafeRef = Arc<UnsafeCell<ObjectRef>>;
pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef{
return Arc::new(UnsafeCell::new(object))
pub fn unsafe_ref(object: ObjectRef) -> UnsafeRef {
return Arc::new(UnsafeCell::new(object));
}
pub fn unsafe_val(val: Value) -> UnsafeValue{
return Arc::new(UnsafeCell::new(val))
pub fn unsafe_val(val: Value) -> UnsafeValue {
return Arc::new(UnsafeCell::new(val));
}
pub fn type_ref(class: Class) -> Type{
return Arc::new(RefCell::new(class))
pub fn type_ref(class: Class) -> Type {
return Arc::new(RefCell::new(class));
}
pub type Type = Arc<RefCell<Class>>;
unsafe impl Send for Value {}

View file

@ -9,7 +9,10 @@ use std::io::Read;
/// * [jar/zip]#[package_path]/[class].class
/// * [dir]/[package_path]/[class].class
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();
path.push_str(class_name);
path.push_str(".class");

View file

@ -321,42 +321,32 @@ impl Vm {
let that_borrow = that.borrow();
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
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 => {
println!("PUTSTATIC");
let mut borrow = this_class.borrow_mut();
let cp_index = read_u16(&code.opcodes, pc);
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
let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
let (name) = borrow.cp_utf8(name_index).unwrap();
let class_name_index = borrow.cp_class_ref(class_index).unwrap();
println!("field {}", name);
let that_class_name = borrow.cp_utf8(class_name_index).unwrap();
// 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
// let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
// let (name) = borrow.cp_utf8(name_index).unwrap();
// let class_name_index = borrow.cp_class_ref(class_index).unwrap();
// println!("field {}", name);
// 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
let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap();
let val_index = *val_index;
let value = self.current_frame().pop()?;
borrow.static_data[val_index] = Some(value);
} else {
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 (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
let value = self.current_frame().pop()?;
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);
}
}
}
// 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 = *val_index;
// let value = self.current_frame().pop()?;
// borrow.static_data[val_index] = Some(value);
// } else {
// 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 (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
// let value = self.current_frame().pop()?;
// borrow.static_data[*val_index] = Some(value);
// }
}
GETFIELD => unsafe {
let borrow = this_class.borrow();
@ -414,7 +404,7 @@ impl Vm {
args.insert(0, copy(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()),
&invocation.class_name,
&invocation.method.name,
@ -432,6 +422,7 @@ impl Vm {
}
},
INVOKESTATIC => unsafe {
println!("INVOKESTATIC");
let cp_index = read_u16(&code.opcodes, pc);
if let Some(invocation) =
get_signature_for_invoke(&method.constant_pool, cp_index)
@ -440,7 +431,7 @@ impl Vm {
for _ in 0..invocation.method.num_args {
args.insert(0, copy(self.current_frame().pop()?));
}
let mut returnvalue = self.execute(
let returnvalue = self.execute(
Some(this_class.borrow().name.as_str()),
&invocation.class_name,
&invocation.method.name,
@ -680,14 +671,14 @@ unsafe fn copy(value: UnsafeValue) -> UnsafeValue {
unsafe_val(match (&*value.get()) {
Void => Void,
Null => Null,
BOOL(b)=> BOOL(*b),
CHAR(c)=> CHAR(*c),
I32(i)=> I32(*i),
I64(l)=> I64(*l),
F32(f)=> F32(*f),
F64(d)=> F64(*d),
Ref(r)=> Ref(r.clone()),
Utf8(s)=> Utf8(s.to_owned()),
BOOL(b) => BOOL(*b),
CHAR(c) => CHAR(*c),
I32(i) => I32(*i),
I64(l) => I64(*l),
F32(f) => F32(*f),
F64(d) => F64(*d),
Ref(r) => Ref(r.clone()),
Utf8(s) => Utf8(s.to_owned()),
})
}
@ -719,6 +710,7 @@ fn get_hum_args(signature: &str) -> usize {
while chars[i] != ';' {
i += 1;
}
i += 1;
num += 1;
} else if chars[i] == ')' {
break;