Класс Monkey Patching, полученный из ctypes. Union не работает - PullRequest
0 голосов
/ 30 ноября 2018

Я пытаюсь «обезьянить патч» для класса, производного от Python ctypes «Union», но я не могу этого сделать - получаю странные ошибки, а иногда и ошибки seg.То же самое работает довольно хорошо при выводе из ctypes "Structure".

Я сузил это до самого простого возможного теста, который я публикую ниже.Я использую Python 3.6.4.Мне интересно, если я делаю что-то не так (или есть проблема с реализацией ctypes "Union"?).Пожалуйста, смотрите код ниже и соответствующий вывод.

import ctypes

def display(self):
  """ A new kind of display """
  return f'Print Type #2: ( {self.y1}, {self.y2} )'

class MyStruct(ctypes.Structure):
  _fields_ = [ 
      ('y1', ctypes.c_uint32),
      ('y2', ctypes.c_uint32)
      ] 

  def __str__(self):
    return f'Print Type #1: [ {self.y1}, {self.y2} ]'

class MyUnion(ctypes.Union):
  _fields_ = [ 
      ('y1', ctypes.c_uint32),
      ('y2', ctypes.c_uint32)
      ] 

  def __str__(self):
    return f'Print Type #1: [ {self.y1}, {self.y2} ]'

if __name__ == '__main__':

  a = MyStruct()
  a.y1 = 10
  a.y2 = 20

  print('Using Structure:')
  print('----------------')
  print(a)
  print('Original :', MyStruct.__str__)
  # monkey patch  __str__ with a different function.
  MyStruct.__str__ = display
  print('Patched :', MyStruct.__str__)
  print('Patched (dict) :', MyStruct.__dict__['__str__'])
  print(a)

  a = MyUnion()
  a.y1 = 10
  a.y2 = 20

  print('Using Union:')
  print('------------')
  print(a)
  print('Original :', MyUnion.__str__)
  # monkey patch  __str__ with a different function.
  MyUnion.__str__ = display
  print('Patched :', MyUnion.__str__)
  print('Patched (dict) :', MyUnion.__dict__['__str__'])
  print(a)

Вот вывод, когда я запускаю программу.

Using Structure:
----------------
Print Type #1: [ 10, 20 ]
Original : <function MyStruct.__str__ at 0x7fdf89d02e18>
Patched : <function display at 0x7fdf8b0ebe18>
Patched (dict) : <function display at 0x7fdf8b0ebe18>
Print Type #2: ( 10, 20 )
Using Union:
------------
Print Type #1: [ 20, 20 ]
Original : <function MyUnion.__str__ at 0x7fdf89d02f28>
Patched : <function MyUnion.__str__ at 0x7fdf89d02f28>
Patched (dict) : <function display at 0x7fdf8b0ebe18>
Traceback (most recent call last):
  File "ctypes_bug.py", line 54, in <module>
    print(a)
TypeError: 'managedbuffer' object is not callable

Ясно, что я могу "исправить" __str__, когда соответствующий объект Python был получен из "Structure", но я не могу "исправить" __str__, когда соответствующий объект Python былпроисходит от "Union".

Интересно, что MyUnion.__dict__[__str__] и MyUnion.__str__ показывают разные результаты - что тоже странно.

Есть ли что-то, что я здесь не так делаю?Я высоко ценю любую помощь или понимание!

1 Ответ

0 голосов
/ 30 ноября 2018

Я думаю, что здесь есть настоящая ошибка CPython.В __setattr__ реализации для объектов типов для структурных типов используется PyType_Type.tp_setattro:

static int
PyCStructType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
    /* XXX Should we disallow deleting _fields_? */
    if (-1 == PyType_Type.tp_setattro(self, key, value))
        return -1;

    if (value && PyUnicode_Check(key) &&
        _PyUnicode_EqualToASCIIString(key, "_fields_"))
        return PyCStructUnionType_update_stgdict(self, value, 1);
    return 0;
}

, но для объектов типов для типов объединения используется PyObject_GenericSetAttr:

static int
UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
    /* XXX Should we disallow deleting _fields_? */
    if (-1 == PyObject_GenericSetAttr(self, key, value))
        return -1;

    if (PyUnicode_Check(key) &&
        _PyUnicode_EqualToASCIIString(key, "_fields_"))
        return PyCStructUnionType_update_stgdict(self, value, 0);
    return 0;
}

Использование PyType_Type.tp_setattro необходимо для обновления слотов типов и аннулирования внутреннего кэша атрибутов типа .PyObject_GenericSetAttr не знает, что он должен делать что-либо из этого, что может привести к повреждению памяти из-за кэшированных атрибутов "зомби".Похоже, что та же ошибка была исправлена ​​ в начале 2008 года для структур, но они забыли обработать союзы.

...