Еще есть tp_dealloc.
С него удаление начинается. tp_free удаляет память, не вызывая деструктора. Т.е. то, что было выделено через malloc - не удалится.
tp_free обычно указывает на PyObject_Free - аналог free, работающий с Питоновским memory pool.
tp_dealloc вызывает tp_free после того, как удалит все “внутренности”.
Как я вижу по исходникам, проблема таки в удалении.
Закомментирована проблемная строка, следующая - исправление.
static void
Message_dealloc(Message *self)
{
Message_clear(self);
/* self->base.ob_type->tp_free((PyObject*)self); */
PyUnicode_Type.tp_dealloc((PyObject*)self);
}
вызывалась именно tp_free, а нужно дергать деструктор базового класса.
Юникод держит в себе Py_UNICODE *str, которая не освобождалась.
Если хотите - можете слать баг-фикс.