@@ -55,7 +55,8 @@ impl GetDescriptor for PyProperty {
5555 let ( zelf, obj) = Self :: _unwrap ( & zelf_obj, obj, vm) ?;
5656 if vm. is_none ( & obj) {
5757 Ok ( zelf_obj)
58- } else if let Some ( getter) = zelf. getter . read ( ) . as_ref ( ) {
58+ } else if let Some ( getter) = zelf. getter . read ( ) . clone ( ) {
59+ // Clone and release lock before calling Python code to prevent deadlock
5960 getter. call ( ( obj, ) , vm)
6061 } else {
6162 let error_msg = zelf. format_property_error ( & obj, "getter" , vm) ?;
@@ -70,12 +71,12 @@ impl PyProperty {
7071 // Returns the name if available, None if not found, or propagates errors
7172 fn get_property_name ( & self , vm : & VirtualMachine ) -> PyResult < Option < PyObjectRef > > {
7273 // First check if name was set via __set_name__
73- if let Some ( name) = self . name . read ( ) . as_ref ( ) {
74- return Ok ( Some ( name. clone ( ) ) ) ;
74+ if let Some ( name) = self . name . read ( ) . clone ( ) {
75+ return Ok ( Some ( name) ) ;
7576 }
7677
77- let getter = self . getter . read ( ) ;
78- let Some ( getter) = getter. as_ref ( ) else {
78+ // Clone and release lock before calling Python code to prevent deadlock
79+ let Some ( getter) = self . getter . read ( ) . clone ( ) else {
7980 return Ok ( None ) ;
8081 } ;
8182
@@ -105,15 +106,17 @@ impl PyProperty {
105106 let zelf = zelf. try_to_ref :: < Self > ( vm) ?;
106107 match value {
107108 PySetterValue :: Assign ( value) => {
108- if let Some ( setter) = zelf. setter . read ( ) . as_ref ( ) {
109+ // Clone and release lock before calling Python code to prevent deadlock
110+ if let Some ( setter) = zelf. setter . read ( ) . clone ( ) {
109111 setter. call ( ( obj, value) , vm) . map ( drop)
110112 } else {
111113 let error_msg = zelf. format_property_error ( & obj, "setter" , vm) ?;
112114 Err ( vm. new_attribute_error ( error_msg) )
113115 }
114116 }
115117 PySetterValue :: Delete => {
116- if let Some ( deleter) = zelf. deleter . read ( ) . as_ref ( ) {
118+ // Clone and release lock before calling Python code to prevent deadlock
119+ if let Some ( deleter) = zelf. deleter . read ( ) . clone ( ) {
117120 deleter. call ( ( obj, ) , vm) . map ( drop)
118121 } else {
119122 let error_msg = zelf. format_property_error ( & obj, "deleter" , vm) ?;
@@ -273,23 +276,24 @@ impl PyProperty {
273276 }
274277 } ;
275278
279+ // Clone and release lock before calling Python code to prevent deadlock
276280 // Check getter
277- if let Some ( getter) = self . getter . read ( ) . as_ref ( )
278- && is_abstract ( getter) ?
281+ if let Some ( getter) = self . getter . read ( ) . clone ( )
282+ && is_abstract ( & getter) ?
279283 {
280284 return Ok ( vm. ctx . new_bool ( true ) . into ( ) ) ;
281285 }
282286
283287 // Check setter
284- if let Some ( setter) = self . setter . read ( ) . as_ref ( )
285- && is_abstract ( setter) ?
288+ if let Some ( setter) = self . setter . read ( ) . clone ( )
289+ && is_abstract ( & setter) ?
286290 {
287291 return Ok ( vm. ctx . new_bool ( true ) . into ( ) ) ;
288292 }
289293
290294 // Check deleter
291- if let Some ( deleter) = self . deleter . read ( ) . as_ref ( )
292- && is_abstract ( deleter) ?
295+ if let Some ( deleter) = self . deleter . read ( ) . clone ( )
296+ && is_abstract ( & deleter) ?
293297 {
294298 return Ok ( vm. ctx . new_bool ( true ) . into ( ) ) ;
295299 }
@@ -299,7 +303,8 @@ impl PyProperty {
299303
300304 #[ pygetset( setter) ]
301305 fn set___isabstractmethod__ ( & self , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
302- if let Some ( getter) = self . getter . read ( ) . to_owned ( ) {
306+ // Clone and release lock before calling Python code to prevent deadlock
307+ if let Some ( getter) = self . getter . read ( ) . clone ( ) {
303308 getter. set_attr ( "__isabstractmethod__" , value, vm) ?;
304309 }
305310 Ok ( ( ) )
0 commit comments