From f2dc2d2938cc994cd1cb10ec156e7bb471256012 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Sun, 12 Nov 2023 17:25:32 +0100 Subject: [PATCH] battling stackoverflow and invalid references --- src/classmanager.rs | 24 +++++---- src/vm/native.rs | 4 +- src/vm/operations.rs | 15 +++--- src/vm/vm.rs | 123 ++++++++++++++++++++++--------------------- 4 files changed, 86 insertions(+), 80 deletions(-) diff --git a/src/classmanager.rs b/src/classmanager.rs index d9ca87b..6f781fd 100644 --- a/src/classmanager.rs +++ b/src/classmanager.rs @@ -16,6 +16,7 @@ static mut CLASSMANAGER: Lazy = Lazy::new(|| ClassManager::new()); static PRIMITIVES: Lazy> = Lazy::new(|| vec!["B", "S", "I", "J", "F", "D", "Z", "J", "C"]); pub fn init() { + debug!("classmanager init"); unsafe { CLASSMANAGER.classes.clear(); CLASSMANAGER.names.clear(); @@ -31,9 +32,9 @@ pub fn set_classpath(classpath: &str) { } } -pub fn get_class_by_id(id: &ClassId) -> Option<&'static Class> { +pub fn get_class_by_id(id: ClassId) -> Option<&'static Class> { unsafe { - CLASSMANAGER.get_class_by_id(id) + CLASSMANAGER.get_class_by_id(&id) } } @@ -43,15 +44,15 @@ pub fn classdef_name(id: &ClassId) -> Option { } } -pub fn get_classid(name: &str) -> &ClassId { +pub fn get_classid(name: &str) -> ClassId { unsafe { - CLASSMANAGER.get_classid(name) + CLASSMANAGER.get_classid(name).clone() } } -pub fn get_classdef(id: &ClassId) -> &ClassDef { +pub fn get_classdef(id: ClassId) -> &'static ClassDef { unsafe { - CLASSMANAGER.get_classdef(id) + CLASSMANAGER.get_classdef(&id) } } @@ -79,15 +80,15 @@ pub fn get_static(id: &ClassId, index: usize) -> Value { } } -pub fn set_static(id: &ClassId, index: usize, value: Value) { +pub fn set_static(id: ClassId, index: usize, value: Value) { unsafe { - CLASSMANAGER.static_class_data.get_mut(id).unwrap()[index] = value; + CLASSMANAGER.static_class_data.get_mut(&id).unwrap()[index] = value; } } -pub fn get_classobject(id: &ClassId) -> Option<&Value> { +pub fn get_classobject(id: ClassId) -> Option<&'static Value> { unsafe { - CLASSMANAGER.class_objects.get(id) + CLASSMANAGER.class_objects.get(&id) } } @@ -198,7 +199,8 @@ impl ClassManager { /// get optional classid from cache fn get_class_by_name(&self, name: &str) -> Option<&Class> { let id = self.names.get(name); - self.classes.get(id.unwrap()) + let t = self.classes.get(id.unwrap()); + t } /// adds the class and calculates the 'offset' of it's fields (static and non-static) diff --git a/src/vm/native.rs b/src/vm/native.rs index 228ff1f..9512a17 100644 --- a/src/vm/native.rs +++ b/src/vm/native.rs @@ -14,10 +14,10 @@ use crate::{class, classmanager}; use crate::vm::stack::StackFrame; use crate::vm::Vm; -pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec, class_name: &String, method_name: &str, _args: Vec) -> Result { +pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec, class_name: &str, method_name: &str, _args: Vec) -> Result { debug!("native {}.{}", class_name, method_name); - match class_name.as_str() { + match class_name { "java/lang/Class" => java_lang_Class(vm, method_name), "java/lang/System" => java_lang_System(vm, method_name), "jdk/internal/misc/Unsafe" => jdk_internal_misc_Unsafe(vm, method_name), diff --git a/src/vm/operations.rs b/src/vm/operations.rs index 164f354..0bf8e89 100644 --- a/src/vm/operations.rs +++ b/src/vm/operations.rs @@ -5,20 +5,19 @@ use std::rc::Rc; use anyhow::Error; use log::debug; -use crate::class::{Class, ObjectRef, Value}; +use crate::{class, classmanager}; +use crate::class::{Class, ClassId, ObjectRef, Value}; use crate::class::ObjectRef::Object; use crate::class::Value::{I32, Ref}; use crate::classloader::classdef::{CpEntry, Method}; -use crate::{class, classmanager}; use crate::vm::stack::StackFrame; -use crate::vm::Vm; use crate::vm::vm::{current_frame, Invocation, MethodSignature}; /// the place for opcode implementations that are a bit long // GET_STATIC opcode -pub(crate) fn get_static(this_class: &Class, field_index: u16) -> Result { - let classdef = classmanager::get_classdef(&this_class.id); +pub(crate) fn get_static(this_class: ClassId, field_index: u16) -> Result { + let classdef = classmanager::get_classdef(this_class); let (class_index, field_name_and_type_index) = classdef.cp_field_ref(&field_index); // all these unwraps are safe as long as the class is valid let (name_index, _) = @@ -73,7 +72,7 @@ pub(crate) fn get_signature_for_invoke(cp: &HashMap, index: u16) - } /// LDC in all varieties (LDC, LDC_W, LDC2_W) -pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut Vec, this_class: &Class){ +pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut Vec, this_class: ClassId){ let c = method.constant_pool.get(cp_index).unwrap(); match c { CpEntry::Integer(i) => { @@ -87,7 +86,7 @@ pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut V } CpEntry::StringRef(utf8) => { //TODO - let string = classmanager::get_classdef(&this_class.id).cp_utf8(utf8); + let string = classmanager::get_classdef(this_class).cp_utf8(utf8); let string: Vec = string.as_bytes().into(); classmanager::load_class_by_name("java/lang/String"); let stringclass = classmanager::get_class_by_name("java/lang/String").unwrap(); @@ -102,7 +101,7 @@ pub(crate) fn load_constant(cp_index: &u16, method: &Method, stackframes: &mut V current_frame(stackframes).push(Value::I64(*l)); } CpEntry::ClassRef(utf8_index) => { - let classdef = classmanager::get_classdef(&this_class.id); + let classdef = classmanager::get_classdef(this_class); let class_name = classdef.cp_utf8(utf8_index); classmanager::load_class_by_name(class_name); let klass_id = classmanager::get_classid(class_name); diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 4e635c0..51e71ff 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -5,12 +5,12 @@ use std::rc::Rc; use anyhow::Error; use log::debug; -use crate::class::{Class, Object, ObjectRef, Value}; +use crate::class::{Class, ClassId, Object, ObjectRef, Value}; use crate::class::Value::{F32, F64, I32, I64, Null, Ref, Void}; use crate::classloader::classdef::{AttributeType, Modifier}; use crate::classloader::io::{read_u16, read_u8}; use crate::classmanager; -use crate::classmanager::get_class_by_id; +use crate::classmanager::{get_class_by_id, get_classid}; use crate::vm::array::{array_load, array_store}; use crate::vm::native::invoke_native; use crate::vm::opcodes; @@ -52,6 +52,7 @@ impl Vm { fn init(vm: &mut Vm, stack: &mut Vec) { classmanager::load_class_by_name("java/lang/Class"); + classmanager::load_class_by_name("jdk/internal/misc/Unsafe"); vm.execute_static(stack, "java/lang/System", "initPhase1()V", vec![]).expect("cannot create VM"); } @@ -71,12 +72,12 @@ impl Vm { if let Ref(this) = &args[0] { if let ObjectRef::Object(this) = this { let thisb= this.borrow(); - let cd = classmanager::get_classdef(&thisb.class_id); + let cd = classmanager::get_classdef(thisb.class_id); let method = cd.get_method(method_name); if let Some(method) = method { classmanager::load_class_by_name(class_name); let class = classmanager::get_class_by_name(class_name).unwrap(); - return self.execute_class(stack, class, method.name().as_str(), args.clone()); + return self.execute_class(stack, class.id, method.name().as_str(), args.clone()); } else { let name = classmanager::classdef_name(&this.borrow().class_id); if let Some(name) = name { @@ -84,10 +85,9 @@ impl Vm { let class = classmanager::get_class_by_name(&name).unwrap(); for parent_id in &class.parents { - let classdef = classmanager::get_classdef(parent_id); + let classdef = classmanager::get_classdef(*parent_id); if classdef.has_method(method_name) { - let class= get_class_by_id(parent_id).unwrap(); - return self.execute_class(stack, class, method_name, args.clone()); + return self.execute_class(stack, *parent_id, method_name, args.clone()); } } } else { @@ -96,7 +96,7 @@ impl Vm { } } else if let ObjectRef::Class(_class) = this { // special case for Class ? let klazz = classmanager::get_class_by_name("java/lang/Class").unwrap(); - return self.execute_class(stack, klazz, method_name, args); + return self.execute_class(stack, klazz.id, method_name, args); } } panic!("Method {} not found in class {}", method_name, class_name); @@ -110,8 +110,8 @@ impl Vm { args: Vec, ) -> Result { classmanager::load_class_by_name(class_name); - let class = classmanager::get_class_by_name(class_name).unwrap(); - self.execute_class(stack, class, method_name, args) + let classid = classmanager::get_classid(class_name); + self.execute_class(stack, classid, method_name, args) } pub fn execute_static( @@ -122,28 +122,28 @@ impl Vm { args: Vec, ) -> Result { classmanager::load_class_by_name(class_name); - let class = classmanager::get_class_by_name(class_name).unwrap(); - self.execute_class(stack, class, method_name, args) + self.execute_class(stack, get_classid(class_name), method_name, args) } pub fn execute_class( &mut self, stackframes: &mut Vec, - this_class: &Class, + this_class: ClassId, method_name: &str, args: Vec, ) -> Result { - debug!("execute {}.{}", this_class.name, method_name); + let this_class_name = &get_class_by_id(this_class).unwrap().name; + debug!("execute {}.{}", this_class_name, method_name); //TODO implement dynamic dispatch -> get method from instance - let method = classmanager::get_classdef(&this_class.id).get_method(method_name).unwrap(); + let method = classmanager::get_classdef(this_class).get_method(method_name).unwrap(); let mut local_params: Vec> = args.clone().iter().map(|e| Some(e.clone())).collect(); if method.is(Modifier::Native) { - return invoke_native(self, stackframes, &this_class.name, method_name, args); + return invoke_native(self, stackframes, this_class_name, method_name, args); } if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { - let stackframe = StackFrame::new(&this_class.name, method_name); + let stackframe = StackFrame::new(&this_class_name, method_name); stackframes.push(stackframe); let pc = &mut 0; @@ -151,6 +151,7 @@ impl Vm { let opcode = read_u8(&code.opcodes, pc); let cur_frame = current_frame(stackframes); debug!("\t{} #{} {} - {:?}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.data); + debug!("id {}", this_class); match opcode { ACONST_NULL => { current_frame(stackframes).push(Value::Null); @@ -337,7 +338,7 @@ impl Vm { current_frame(stackframes).push(field_value); } PUTSTATIC => { - let classdef = classmanager::get_classdef(&this_class.id); + let classdef = classmanager::get_classdef(this_class); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = classdef.cp_field_ref(&cp_index); // all these unwraps are safe as long as the class is valid @@ -354,10 +355,10 @@ impl Vm { .unwrap() .index; let value = current_frame(stackframes).pop()?; - classmanager::set_static(&this_class.id, val_index, value); + classmanager::set_static(this_class, val_index, value); } GETFIELD => { - let classdef = classmanager::get_classdef(&this_class.id); + let classdef = classmanager::get_classdef(this_class); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = classdef.cp_field_ref(&cp_index); @@ -371,7 +372,7 @@ impl Vm { let objectref = current_frame(stackframes).pop()?; if let Ref(instance) = objectref { if let ObjectRef::Object(object) = instance { - let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap(); + let runtime_type = classmanager::get_class_by_id(object.borrow().class_id).unwrap(); let object = object.borrow(); let value = object.get(runtime_type, declared_type, field_name); current_frame(stackframes).push(value.clone()); @@ -383,7 +384,7 @@ impl Vm { } } PUTFIELD => { - let classdef = classmanager::get_classdef(&this_class.id); + let classdef = classmanager::get_classdef(this_class); let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) = classdef.cp_field_ref(&cp_index); @@ -397,47 +398,13 @@ impl Vm { let objectref = current_frame(stackframes).pop()?; if let Ref(instance) = objectref { if let ObjectRef::Object(object) = instance { - let runtime_type = classmanager::get_class_by_id(&object.borrow().class_id).unwrap(); + let runtime_type = classmanager::get_class_by_id(object.borrow().class_id).unwrap(); object.borrow_mut().set(runtime_type, declared_type, field_name, value); } } else { unreachable!() } } - INVOKESPECIAL => { - // TODO differentiate these opcodes - let cp_index = read_u16(&code.opcodes, pc); - if let Some(invocation) = - get_signature_for_invoke(&method.constant_pool, cp_index) - { - debug!("invoke {:?}", invocation); - let mut args = Vec::with_capacity(invocation.method.num_args); - for _ in 0..invocation.method.num_args { - args.insert(0, current_frame(stackframes).pop()?.clone()); - } - args.insert(0, current_frame(stackframes).pop()?); - let return_value = self.execute_special(stackframes, - &invocation.class_name, - &invocation.method.name, - args, - )?; - if let Ref(objectref) = &return_value { - if let ObjectRef::Object(object) = objectref { - debug!("return {:?}", object); - } - } else { - debug!("return {:?}", return_value); - } - match return_value { - Void => {} - _ => { - current_frame(stackframes).push(return_value.clone()); - } - } - } else { - unreachable!() - } - } INVOKEVIRTUAL => { // TODO differentiate these opcodes let cp_index = read_u16(&code.opcodes, pc); @@ -473,6 +440,44 @@ impl Vm { unreachable!() } } + INVOKESPECIAL => { + // TODO differentiate these opcodes + let cp_index = read_u16(&code.opcodes, pc); + if let Some(invocation) = + get_signature_for_invoke(&method.constant_pool, cp_index) + { + debug!("id before new {}", this_class); + let mut args = Vec::with_capacity(invocation.method.num_args); + for _ in 0..invocation.method.num_args { + args.insert(0, current_frame(stackframes).pop()?.clone()); + } + args.insert(0, current_frame(stackframes).pop()?); + debug!("invoke special{:?}", invocation); + + let return_value = self.execute_special(stackframes, + &invocation.class_name, + &invocation.method.name, + args, + )?; + // let return_value = Null; + debug!("id after new {}", this_class); + if let Ref(objectref) = &return_value { + if let ObjectRef::Object(object) = objectref { + debug!("return {:?}", object); + } + } else { + debug!("return {:?}", return_value); + } + match return_value { + Void => {} + _ => { + current_frame(stackframes).push(return_value.clone()); + } + } + } else { + unreachable!() + } + } INVOKESTATIC => { let cp_index = read_u16(&code.opcodes, pc); if let Some(invocation) = @@ -505,7 +510,7 @@ impl Vm { } } NEW => { - let classdef = classmanager::get_classdef(&this_class.id); + let classdef = classmanager::get_classdef(this_class); let class_index = &read_u16(&code.opcodes, pc); let class_name_index = classdef.cp_class_ref(class_index); let class_name = classdef.cp_utf8(class_name_index); @@ -524,7 +529,7 @@ impl Vm { current_frame(stackframes).push(Ref(array)); } ANEWARRAY => { - let classdef = classmanager::get_classdef(&this_class.id); + let classdef = classmanager::get_classdef(this_class); let class_index = &read_u16(&code.opcodes, pc); let class_name_index = classdef.cp_class_ref(class_index); let class_name = classdef.cp_utf8(class_name_index);