From e2babb35f932b0ee817c61cee7616425a9483926 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 22 Nov 2014 13:02:01 -0600 Subject: [PATCH] More work on bound methods. --- _drafts/python-object-replacement.md | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/_drafts/python-object-replacement.md b/_drafts/python-object-replacement.md index 338ca75..81688c7 100644 --- a/_drafts/python-object-replacement.md +++ b/_drafts/python-object-replacement.md @@ -737,13 +737,48 @@ examine the internal C structure of bound methods, %3clusterPyMethodObjectobj<__main__.A object at 0xdeadbeef>structstruct _object* _ob_nextstruct _object* _ob_prevPy_ssize_t ob_refcntstruct _typeobject* ob_typePyObject* im_funcPyObject* im_selfPyObject* im_classPyObject* im_weakrefliststruct:f->obj -[`_PyObject_HEAD_EXTRA`](https://github.com/python/cpython/blob/2.7/Include/object.h#L64) +The four gray fields of the struct come from +[`PyObject_HEAD`](https://github.com/python/cpython/blob/2.7/Include/object.h#L78), +which exist in all Python objects. The first two fields are from +[`_PyObject_HEAD_EXTRA`](https://github.com/python/cpython/blob/2.7/Include/object.h#L66), +and only exist when the debugging macro `Py_TRACE_REFS` is defined, in order to +support more advanced reference counting. We can see that the `im_self` field, +which mantains the reference to our target object, is either forth or sixth in +the struct depending on `Py_TRACE_REFS`. If we can figure out the size of the +field and its offset from the start of the struct, then we can set its value +directly using `ctypes.memmove()`: + +{% highlight python %} + +ctypes.memmove(id(f) + offset, ctypes.byref(ctypes.py_object(b)), field_size) + +{% endhighlight %} + +Here, `id(f)` is the memory location of our method, which refers to the start +of the C struct from above. `offset` is the number of bytes between this memory +location and the start of the `im_self` field. We use +[`ctypes.byref()`](https://docs.python.org/2/library/ctypes.html#ctypes.byref) +to create a reference to the replacement object, `b`, which will be copied over +the existing reference to `a`. Finally, `field_size` is the number of bytes +we're copying, equal to the size of the `im_self` field. + +Well, all but one of these fields are pointers, meaning they have the same +size, equal to +[`ctypes.sizeof(ctypes.c_void_p)`](https://docs.python.org/2/library/ctypes.html#ctypes.sizeof). +This is (probably) 4 or 8 bytes, depending on whether you're on a 32-bit or a +64-bit system. The other field is a `Py_ssize_t` object—_very_ likely to be +the same size as a pointer, but we can't be sure—which is equal to +`ctypes.sizeof(ctypes.c_ssize_t)`. [`PyCFunctionObject`](https://github.com/python/cpython/blob/2.7/Include/methodobject.h#L81) +### Dictionary keys + +... + ### Closure cells -function closures +... ### Frames