@@ -1362,28 +1362,44 @@ impl PyType {
13621362 ) -> Option < T > {
13631363 use crate :: builtins:: descriptor:: PyWrapper ;
13641364
1365+ // Helper to check if a class is a subclass of another by checking MRO
1366+ let is_subclass_of = |subclass_mro : & [ PyRef < PyType > ] , superclass : & Py < PyType > | -> bool {
1367+ subclass_mro. iter ( ) . any ( |c| c. is ( superclass) )
1368+ } ;
1369+
13651370 // Helper to extract slot from an attribute if it's a wrapper descriptor
1366- let try_extract = |attr : & PyObjectRef | -> Option < T > {
1371+ // and the wrapper's type is compatible with the given class.
1372+ // bpo-37619: wrapper descriptor from wrong class should not be used directly.
1373+ let try_extract = |attr : & PyObjectRef , for_class_mro : & [ PyRef < PyType > ] | -> Option < T > {
13671374 if attr. class ( ) . is ( ctx. types . wrapper_descriptor_type ) {
1368- attr. downcast_ref :: < PyWrapper > ( )
1369- . and_then ( |wrapper| extract ( & wrapper. wrapped ) )
1375+ attr. downcast_ref :: < PyWrapper > ( ) . and_then ( |wrapper| {
1376+ // Only extract slot if for_class is a subclass of wrapper.typ
1377+ if is_subclass_of ( for_class_mro, wrapper. typ ) {
1378+ extract ( & wrapper. wrapped )
1379+ } else {
1380+ None
1381+ }
1382+ } )
13701383 } else {
13711384 None
13721385 }
13731386 } ;
13741387
1388+ let mro = self . mro . read ( ) ;
1389+
13751390 // Look up in self's dict first
13761391 if let Some ( attr) = self . attributes . read ( ) . get ( name) . cloned ( ) {
1377- if let Some ( func) = try_extract ( & attr) {
1392+ if let Some ( func) = try_extract ( & attr, & mro ) {
13781393 return Some ( func) ;
13791394 }
13801395 return None ;
13811396 }
13821397
13831398 // Look up in MRO (mro[0] is self, so skip it)
1384- for cls in self . mro . read ( ) [ 1 ..] . iter ( ) {
1399+ for ( i , cls) in mro[ 1 ..] . iter ( ) . enumerate ( ) {
13851400 if let Some ( attr) = cls. attributes . read ( ) . get ( name) . cloned ( ) {
1386- if let Some ( func) = try_extract ( & attr) {
1401+ // Use the slice starting from this class in MRO
1402+ if let Some ( func) = try_extract ( & attr, & mro[ i + 1 ..] ) {
13871403 return Some ( func) ;
13881404 }
13891405 return None ;
0 commit comments