Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #197798

PyObjects From Python Via ctypes

Path csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail
From Lawrence D’Oliveiro <ldo@nz.invalid>
Newsgroups comp.lang.python
Subject PyObjects From Python Via ctypes
Date Thu, 11 Jun 2026 07:41:20 -0000 (UTC)
Organization A noiseless patient Spider
Lines 60
Message-ID <110doqv$19tv7$1@dont-email.me> (permalink)
MIME-Version 1.0
Content-Type text/plain; charset=UTF-8
Content-Transfer-Encoding 8bit
Injection-Date Thu, 11 Jun 2026 07:41:20 +0000 (UTC)
Injection-Info dont-email.me; logging-data="1374183"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/TyOTNlbvZ2fJb/8t19HMe"; posting-host="30790e76a89477aca572138a98dab22f"
User-Agent Pan/0.165 (Kostiantynivka)
Cancel-Lock sha1:hPuTJ89YCxArjXeIfUkDZt/OuPo= sha256:WoXTFm8KUdCmYCPPnO9TUqbzxHAf8jNHIiVnT5PmlZU= sha1:7Nb6PfxBexRPK4+3xbi6gP0NWpQ=
Xref csiph.com comp.lang.python:197798

Show key headers only | View raw


I see ctypes has a py_object type, but you can’t seem to do much with
it. The following might be more useful:

---- file: pyobjhack.py
import ctypes as ct

def _init_hack() :
    # works out the values of TRACE_REFS and PYOBJECT_HEADER_SIZE.
    global TRACE_REFS, PYOBJECT_HEADER_SIZE
    o = object()
    # CPython implementation detail: “id()” function returns address of object header
    if ct.c_size_t.from_address(id(o)).value == 1 :
        TRACE_REFS = False
        PYOBJECT_HEADER_SIZE = 2
    elif ct.c_size_t.from_address(id(o) + 2 * ct.sizeof(ct.c_void_p)).value == 1 :
        TRACE_REFS = True
        PYOBJECT_HEADER_SIZE = 4
    else :
        raise RuntimeError("cannot determine pyobject header size")
    #end if
      # header of every PyObject has ob_refcnt (type ssize_t) followed by ob_type (type pointer),
      # but these might be preceded by a pair of next/prev pointers if Py_TRACE_REFS is defined.
      # Only way I can figure out to determine which is the case is to construct an object
      # with a known refcount of 1, and see if I can find the value 1 at the start.
    # Confirm that the refcount field behaves as expected:
    o2 = o
    assert ct.c_size_t.from_address(id(o) + (PYOBJECT_HEADER_SIZE - 2) * ct.sizeof(ct.c_void_p)).value == 2
    del o2
    assert ct.c_size_t.from_address(id(o) + (PYOBJECT_HEADER_SIZE - 2) * ct.sizeof(ct.c_void_p)).value == 1
#end _init_hack
_init_hack()
del _init_hack

class PyObject(ct.Structure) :
    "header part of a PyObject structure."

    _fields_ = \
        (
            (
                [],
                [
                    ("_ob_next", ct.c_void_p),
                    ("_ob_prev", ct.c_void_p),
                ],
            )[TRACE_REFS]
        +
            [
                ("ob_refcnt", ct.c_ssize_t),
                ("ob_type", ct.c_void_p),
            ]
        )

    @classmethod
    def from_obj(celf, obj) :
        "aliases the object header to a PyObject struct."
        return \
            celf.from_address(id(obj))
    #end from_obj

#end PyObject

Back to comp.lang.python | Previous | Next — Next in thread | Find similar | Unroll thread


Thread

PyObjects From Python Via ctypes Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-11 07:41 +0000
  Re: PyObjects From Python Via ctypes Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-11 07:44 +0000

csiph-web