X Tutup
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions crates/vm/src/builtins/classmethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ impl GetDescriptor for PyClassMethod {
) -> PyResult {
let (zelf, _obj) = Self::_unwrap(&zelf, obj, vm)?;
let cls = cls.unwrap_or_else(|| _obj.class().to_owned().into());
let call_descr_get: PyResult<PyObjectRef> = zelf.callable.lock().get_attr("__get__", vm);
// Clone and release lock before calling Python code to prevent deadlock
let callable = zelf.callable.lock().clone();
let call_descr_get: PyResult<PyObjectRef> = callable.get_attr("__get__", vm);
match call_descr_get {
Err(_) => Ok(PyBoundMethod::new(cls, zelf.callable.lock().clone())
.into_ref(&vm.ctx)
.into()),
Err(_) => Ok(PyBoundMethod::new(cls, callable).into_ref(&vm.ctx).into()),
Ok(call_descr_get) => call_descr_get.call((cls.clone(), cls), vm),
}
}
Expand Down
33 changes: 19 additions & 14 deletions crates/vm/src/builtins/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ impl GetDescriptor for PyProperty {
let (zelf, obj) = Self::_unwrap(&zelf_obj, obj, vm)?;
if vm.is_none(&obj) {
Ok(zelf_obj)
} else if let Some(getter) = zelf.getter.read().as_ref() {
} else if let Some(getter) = zelf.getter.read().clone() {
// Clone and release lock before calling Python code to prevent deadlock
getter.call((obj,), vm)
} else {
let error_msg = zelf.format_property_error(&obj, "getter", vm)?;
Expand All @@ -70,12 +71,12 @@ impl PyProperty {
// Returns the name if available, None if not found, or propagates errors
fn get_property_name(&self, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
// First check if name was set via __set_name__
if let Some(name) = self.name.read().as_ref() {
return Ok(Some(name.clone()));
if let Some(name) = self.name.read().clone() {
return Ok(Some(name));
}

let getter = self.getter.read();
let Some(getter) = getter.as_ref() else {
// Clone and release lock before calling Python code to prevent deadlock
let Some(getter) = self.getter.read().clone() else {
return Ok(None);
};

Expand Down Expand Up @@ -105,15 +106,17 @@ impl PyProperty {
let zelf = zelf.try_to_ref::<Self>(vm)?;
match value {
PySetterValue::Assign(value) => {
if let Some(setter) = zelf.setter.read().as_ref() {
// Clone and release lock before calling Python code to prevent deadlock
if let Some(setter) = zelf.setter.read().clone() {
setter.call((obj, value), vm).map(drop)
} else {
let error_msg = zelf.format_property_error(&obj, "setter", vm)?;
Err(vm.new_attribute_error(error_msg))
}
}
PySetterValue::Delete => {
if let Some(deleter) = zelf.deleter.read().as_ref() {
// Clone and release lock before calling Python code to prevent deadlock
if let Some(deleter) = zelf.deleter.read().clone() {
deleter.call((obj,), vm).map(drop)
} else {
let error_msg = zelf.format_property_error(&obj, "deleter", vm)?;
Expand Down Expand Up @@ -273,23 +276,24 @@ impl PyProperty {
}
};

// Clone and release lock before calling Python code to prevent deadlock
// Check getter
if let Some(getter) = self.getter.read().as_ref()
&& is_abstract(getter)?
if let Some(getter) = self.getter.read().clone()
&& is_abstract(&getter)?
{
return Ok(vm.ctx.new_bool(true).into());
}

// Check setter
if let Some(setter) = self.setter.read().as_ref()
&& is_abstract(setter)?
if let Some(setter) = self.setter.read().clone()
&& is_abstract(&setter)?
{
return Ok(vm.ctx.new_bool(true).into());
}

// Check deleter
if let Some(deleter) = self.deleter.read().as_ref()
&& is_abstract(deleter)?
if let Some(deleter) = self.deleter.read().clone()
&& is_abstract(&deleter)?
{
return Ok(vm.ctx.new_bool(true).into());
}
Expand All @@ -299,7 +303,8 @@ impl PyProperty {

#[pygetset(setter)]
fn set___isabstractmethod__(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if let Some(getter) = self.getter.read().to_owned() {
// Clone and release lock before calling Python code to prevent deadlock
if let Some(getter) = self.getter.read().clone() {
getter.set_attr("__isabstractmethod__", value, vm)?;
}
Ok(())
Expand Down
36 changes: 26 additions & 10 deletions crates/vm/src/stdlib/functools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,24 @@ mod _functools {
type Args = FuncArgs;

fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
let inner = zelf.inner.read();
let mut combined_args = inner.args.as_slice().to_vec();
// Clone and release lock before calling Python code to prevent deadlock
let (func, stored_args, keywords) = {
let inner = zelf.inner.read();
(
inner.func.clone(),
inner.args.clone(),
inner.keywords.clone(),
)
};

let mut combined_args = stored_args.as_slice().to_vec();
combined_args.extend_from_slice(&args.args);

// Merge keywords from self.keywords and args.kwargs
let mut final_kwargs = IndexMap::new();

// Add keywords from self.keywords
for (key, value) in &*inner.keywords {
for (key, value) in &*keywords {
let key_str = key
.downcast::<crate::builtins::PyStr>()
.map_err(|_| vm.new_type_error("keywords must be strings"))?;
Expand All @@ -268,9 +277,7 @@ mod _functools {
final_kwargs.insert(key, value);
}

inner
.func
.call(FuncArgs::new(combined_args, KwArgs::new(final_kwargs)), vm)
func.call(FuncArgs::new(combined_args, KwArgs::new(final_kwargs)), vm)
}
}

Expand All @@ -280,15 +287,24 @@ mod _functools {
// Check for recursive repr
let obj = zelf.as_object();
if let Some(_guard) = ReprGuard::enter(vm, obj) {
let inner = zelf.inner.read();
let func_repr = inner.func.repr(vm)?;
// Clone and release lock before calling Python code to prevent deadlock
let (func, args, keywords) = {
let inner = zelf.inner.read();
(
inner.func.clone(),
inner.args.clone(),
inner.keywords.clone(),
)
};

let func_repr = func.repr(vm)?;
let mut parts = vec![func_repr.as_str().to_owned()];

for arg in inner.args.as_slice() {
for arg in args.as_slice() {
parts.push(arg.repr(vm)?.as_str().to_owned());
}

for (key, value) in inner.keywords.clone() {
for (key, value) in &*keywords {
// For string keys, use them directly without quotes
let key_part = if let Ok(s) = key.clone().downcast::<crate::builtins::PyStr>() {
s.as_str().to_owned()
Expand Down
Loading
X Tutup