Skip to content

Commit

Permalink
Initialize ob_type for class type objects early
Browse files Browse the repository at this point in the history
When creating classes, the `ob_type` field of the class's `PyTypeObject`
is statically initialized to `NULL`, and then becomes dynamically
initialized to `&PyType_Type` when `PyType_Ready()` is called.  This is
too late.  If GC occurs during the initialization of the class before
`PyType_Ready()` is called, then the garbage collector will encounter
the `NULL` `ob_type` and segfault.

The Python docs say this field should be dynamically initialized to
`&PyType_Type` before doing any more class initialization.
  • Loading branch information
markbt committed Nov 16, 2017
1 parent 15c4405 commit 317e018
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 0 deletions.
7 changes: 7 additions & 0 deletions python27-sys/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,13 @@ pub const PyTypeObject_INIT : PyTypeObject = PyTypeObject {
tp_version_tag: 0,
};

impl PyTypeObject {
#[inline]
pub fn init_ob_type(&mut self, type_object: *mut PyTypeObject) {
self.ob_type = type_object;
}
}

#[repr(C)]
#[derive(Copy)]
pub struct PyHeapTypeObject {
Expand Down
7 changes: 7 additions & 0 deletions python3-sys/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,13 @@ mod typeobject {
tp_reserved,
);

impl PyTypeObject {
#[inline]
pub fn init_ob_type(&mut self, type_object: *mut PyTypeObject) {
self.ob_base.ob_base.ob_type = type_object;
}
}

#[repr(C)]
#[derive(Copy)]
pub struct PyHeapTypeObject {
Expand Down
1 change: 1 addition & 0 deletions src/py_class/slots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ macro_rules! py_class_type_object_dynamic_init {
}
) => {
unsafe {
$type_object.init_ob_type(&mut $crate::_detail::ffi::PyType_Type);
$type_object.tp_name = $crate::py_class::slots::build_tp_name($module_name, stringify!($class));
$type_object.tp_basicsize = <$class as $crate::py_class::BaseObject>::size()
as $crate::_detail::ffi::Py_ssize_t;
Expand Down

0 comments on commit 317e018

Please sign in to comment.