diff --git a/bigfile/_bigfile.c b/bigfile/_bigfile.c
index 4ff424a9d0f4f7da1b633d8b84b2c78c1d1f22d6..acc8560474d11a0e54a3700d43dbad3507cdec3b 100644
--- a/bigfile/_bigfile.c
+++ b/bigfile/_bigfile.c
@@ -44,6 +44,7 @@
 #include <wendelin/bigfile/ram.h>
 #include <wendelin/bug.h>
 #include <wendelin/compat_py2.h>
+#include <ccan/container_of/container_of.h>
 
 static PyObject *gcmodule;
 static PyObject *pybuf_str;
@@ -85,10 +86,10 @@ static PyObject *pybuf_str;
  *      .pyuser                 generic python-level attribute (see below).
  */
 struct PyVMA {
-    PyObject;
+    PyObject pyobj;
     PyObject *in_weakreflist;
 
-    VMA;
+    VMA vma;
 
     /* python-level user of this VMA.
      *
@@ -116,10 +117,10 @@ typedef struct PyVMA PyVMA;
  *      .isdirty()              for knowing are there any changes at all
  */
 struct PyBigFileH {
-    PyObject;
+    PyObject pyobj;
     PyObject *in_weakreflist;
 
-    BigFileH;
+    BigFileH fileh;
 };
 typedef struct PyBigFileH PyBigFileH;
 
@@ -131,11 +132,11 @@ typedef struct PyBigFileH PyBigFileH;
  * For users .fileh_open() is exposed to get to file handles.
  */
 struct PyBigFile {
-    PyObject;
+    PyObject pyobj;
     /* NOTE no explicit weakref support is needed - this is a base class and python
      * automatically adds support for weakrefs for in-python defined children   */
 
-    BigFile;
+    BigFile file;
 };
 typedef struct PyBigFile PyBigFile;
 
@@ -191,25 +192,27 @@ static PyObject *FUNC
 static Py_ssize_t
 pyvma_getbuf(PyObject *pyvma0, Py_ssize_t segment, void **pptr)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
+    VMA   *vma   = &pyvma->vma;
 
     if (segment) {
         PyErr_SetString(PyExc_SystemError, "access to non-zero vma segment");
         return -1;
     }
 
-    *pptr = (void *)pyvma->addr_start;
-    return pyvma->addr_stop - pyvma->addr_start;
+    *pptr = (void *)vma->addr_start;
+    return vma->addr_stop - vma->addr_start;
 }
 
 
 static Py_ssize_t
 pyvma_getsegcount(PyObject *pyvma0, Py_ssize_t *lenp)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
+    VMA   *vma   = &pyvma->vma;
 
     if (lenp)
-        *lenp = pyvma->addr_stop - pyvma->addr_start;
+        *lenp = vma->addr_stop - vma->addr_start;
     return 1;
 }
 #endif
@@ -218,10 +221,11 @@ pyvma_getsegcount(PyObject *pyvma0, Py_ssize_t *lenp)
 static int
 pyvma_getbuffer(PyObject *pyvma0, Py_buffer *view, int flags)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
+    VMA   *vma   = &pyvma->vma;
 
-    return PyBuffer_FillInfo(view, pyvma,
-            (void *)pyvma->addr_start, pyvma->addr_stop - pyvma->addr_start,
+    return PyBuffer_FillInfo(view, &pyvma->pyobj,
+            (void *)vma->addr_start, vma->addr_stop - vma->addr_start,
             /*readonly=*/0, flags);
 }
 
@@ -230,9 +234,10 @@ pyvma_getbuffer(PyObject *pyvma0, Py_buffer *view, int flags)
 static Py_ssize_t
 pyvma_len(PyObject *pyvma0)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
+    VMA   *vma   = &pyvma->vma;
 
-    return pyvma->addr_stop - pyvma->addr_start;
+    return vma->addr_stop - vma->addr_start;
 }
 
 
@@ -240,7 +245,7 @@ pyvma_len(PyObject *pyvma0)
 static int
 pyvma_traverse(PyObject *pyvma0, visitproc visit, void *arg)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
 
     Py_VISIT(pyvma->pyuser);
     return 0;
@@ -249,7 +254,7 @@ pyvma_traverse(PyObject *pyvma0, visitproc visit, void *arg)
 static int
 pyvma_clear(PyObject *pyvma0)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
 
     Py_CLEAR(pyvma->pyuser);
     return 0;
@@ -259,11 +264,12 @@ pyvma_clear(PyObject *pyvma0)
 PyFunc(pyvma_filerange, "filerange() -> (pgoffset, pglen) -- file range this vma covers")
     (PyObject *pyvma0, PyObject *args)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
+    VMA   *vma   = &pyvma->vma;
     Py_ssize_t pgoffset, pglen;     // XXX Py_ssize_t vs pgoff_t
 
-    pgoffset = pyvma->f_pgoffset;
-    pglen    = (pyvma->addr_stop - pyvma->addr_start) / pyvma->fileh->ramh->ram->pagesize;
+    pgoffset = vma->f_pgoffset;
+    pglen    = (vma->addr_stop - vma->addr_start) / vma->fileh->ramh->ram->pagesize;
     /* NOTE ^^^ addr_stop and addr_start must be page-aligned */
 
     return Py_BuildValue("(nn)", pgoffset, pglen);
@@ -273,8 +279,9 @@ PyFunc(pyvma_filerange, "filerange() -> (pgoffset, pglen) -- file range this vma
 PyFunc(pyvma_pagesize, "pagesize() -> pagesize -- page size of RAM underlying this VMA")
     (PyObject *pyvma0, PyObject *args)
 {
-    PyVMA *pyvma = upcast(PyVMA *, pyvma0);
-    Py_ssize_t pagesize = pyvma->fileh->ramh->ram->pagesize;
+    PyVMA *pyvma = container_of(pyvma0, PyVMA, pyobj);
+    VMA   *vma   = &pyvma->vma;
+    Py_ssize_t pagesize = vma->fileh->ramh->ram->pagesize;
 
     return Py_BuildValue("n", pagesize);
 }
@@ -290,22 +297,23 @@ pyvma_dealloc(PyObject *pyvma0)
      * See https://bugs.python.org/issue31095 for details */
     PyObject_GC_UnTrack(pyvma0);
 
-    PyVMA       *pyvma = upcast(PyVMA *, pyvma0);
-    BigFileH    *fileh = pyvma->fileh;
+    PyVMA       *pyvma = container_of(pyvma0, PyVMA, pyobj);
+    VMA         *vma   = &pyvma->vma;
+    BigFileH    *fileh = vma->fileh;
 
     if (pyvma->in_weakreflist)
-        PyObject_ClearWeakRefs(pyvma);
+        PyObject_ClearWeakRefs(&pyvma->pyobj);
 
     /* pyvma->fileh indicates whether vma was yet created (via fileh_mmap()) or not */
     if (fileh) {
-        vma_unmap(pyvma);
+        vma_unmap(vma);
 
-        PyBigFileH *pyfileh = upcast(PyBigFileH *, fileh);
+        PyBigFileH *pyfileh = container_of(fileh, PyBigFileH, fileh);
         Py_DECREF(pyfileh);
     }
 
-    pyvma_clear(pyvma);
-    pyvma->ob_type->tp_free(pyvma);
+    pyvma_clear(&pyvma->pyobj);
+    pyvma->pyobj.ob_type->tp_free(&pyvma->pyobj);
 }
 
 
@@ -319,7 +327,7 @@ pyvma_new(PyTypeObject *type, PyObject *args, PyObject *kw)
         return NULL;
     self->in_weakreflist = NULL;
 
-    return self;
+    return &self->pyobj;
 }
 
 
@@ -355,10 +363,10 @@ const int _ =
 #define T_UINTPTR   T_ULONG
 
 static /*const*/ PyMemberDef pyvma_members[] = {
-    {"addr_start",  T_UINTPTR,      offsetof(PyVMA, addr_start),  READONLY, "vma's start addr"},
-    {"addr_stop",   T_UINTPTR,      offsetof(PyVMA, addr_stop),   READONLY, "vma's start addr"},
+    {"addr_start",  T_UINTPTR,      offsetof(PyVMA, vma.addr_start),    READONLY, "vma's start addr"},
+    {"addr_stop",   T_UINTPTR,      offsetof(PyVMA, vma.addr_stop),     READONLY, "vma's start addr"},
     // XXX pyuser: restrict to read-only access?
-    {"pyuser",      T_OBJECT_EX,    offsetof(PyVMA, pyuser),      0,        "user of this vma"},
+    {"pyuser",      T_OBJECT_EX,    offsetof(PyVMA, pyuser),            0,        "user of this vma"},
     {NULL}
 };
 
@@ -389,7 +397,7 @@ static PyTypeObject PyVMA_Type = {
 PyFunc(pyfileh_mmap, "mmap(pgoffset, pglen) - map fileh part into memory")
     (PyObject *pyfileh0, PyObject *args)
 {
-    PyBigFileH  *pyfileh = upcast(PyBigFileH *, pyfileh0);
+    PyBigFileH  *pyfileh = container_of(pyfileh0, PyBigFileH, pyobj);
     Py_ssize_t  pgoffset, pglen;    // XXX Py_ssize_t vs pgoff_t ?
     PyVMA       *pyvma;
     int         err;
@@ -402,7 +410,7 @@ PyFunc(pyfileh_mmap, "mmap(pgoffset, pglen) - map fileh part into memory")
         return NULL;
 
     Py_INCREF(pyfileh);
-    err = fileh_mmap(pyvma, pyfileh, pgoffset, pglen);
+    err = fileh_mmap(&pyvma->vma, &pyfileh->fileh, pgoffset, pglen);
     if (err) {
         Py_DECREF(pyfileh);
         Py_DECREF(pyvma);
@@ -410,7 +418,7 @@ PyFunc(pyfileh_mmap, "mmap(pgoffset, pglen) - map fileh part into memory")
         return NULL;
     }
 
-    return pyvma;
+    return &pyvma->pyobj;
 }
 
 
@@ -418,14 +426,15 @@ PyFunc(pyfileh_dirty_writeout,
         "dirty_writeout(flags) - write changes made to fileh memory back to file")
     (PyObject *pyfileh0, PyObject *args)
 {
-    PyBigFileH  *pyfileh = upcast(PyBigFileH *, pyfileh0);
+    PyBigFileH  *pyfileh = container_of(pyfileh0, PyBigFileH, pyobj);
+    BigFileH    *fileh   = &pyfileh->fileh;
     long flags;
     int err;
 
     if (!PyArg_ParseTuple(args, "l", &flags))
         return NULL;
 
-    err = fileh_dirty_writeout(pyfileh, flags);
+    err = fileh_dirty_writeout(fileh, flags);
     if (err) {
         if (!PyErr_Occurred())
             // XXX not very informative
@@ -440,12 +449,13 @@ PyFunc(pyfileh_dirty_writeout,
 PyFunc(pyfileh_dirty_discard, "dirty_discard() - discard changes made to fileh memory")
     (PyObject *pyfileh0, PyObject *args)
 {
-    PyBigFileH  *pyfileh = upcast(PyBigFileH *, pyfileh0);
+    PyBigFileH  *pyfileh = container_of(pyfileh0, PyBigFileH, pyobj);
+    BigFileH    *fileh   = &pyfileh->fileh;
 
     if (!PyArg_ParseTuple(args, ""))
         return NULL;
 
-    fileh_dirty_discard(pyfileh);
+    fileh_dirty_discard(fileh);
     Py_RETURN_NONE;
 }
 
@@ -453,26 +463,28 @@ PyFunc(pyfileh_dirty_discard, "dirty_discard() - discard changes made to fileh m
 PyFunc(pyfileh_isdirty, "isdirty() - are there any changes to fileh memory at all?")
     (PyObject *pyfileh0, PyObject *args)
 {
-    PyBigFileH  *pyfileh = upcast(PyBigFileH *, pyfileh0);
+    PyBigFileH  *pyfileh = container_of(pyfileh0, PyBigFileH, pyobj);
+    BigFileH    *fileh   = &pyfileh->fileh;
 
     if (!PyArg_ParseTuple(args, ""))
         return NULL;
 
     /* NOTE not strictly necessary to virt_lock() for checking ->dirty_pages not empty */
-    return PyBool_FromLong(!list_empty(&pyfileh->dirty_pages));
+    return PyBool_FromLong(!list_empty(&fileh->dirty_pages));
 }
 
 
 PyFunc(pyfileh_invalidate_page, "invalidate_page(pgoffset) - invalidate fileh page")
     (PyObject *pyfileh0, PyObject *args)
 {
-    PyBigFileH  *pyfileh = upcast(PyBigFileH *, pyfileh0);
+    PyBigFileH  *pyfileh = container_of(pyfileh0, PyBigFileH, pyobj);
+    BigFileH    *fileh   = &pyfileh->fileh;
     Py_ssize_t  pgoffset;   // XXX Py_ssize_t vs pgoff_t ?
 
     if (!PyArg_ParseTuple(args, "n", &pgoffset))
         return NULL;
 
-    fileh_invalidate_page(pyfileh, pgoffset);
+    fileh_invalidate_page(fileh, pgoffset);
 
     Py_RETURN_NONE;
 }
@@ -483,22 +495,23 @@ pyfileh_dealloc(PyObject *pyfileh0)
 {
     /* PyBigFileH does not support cyclic GC - no need to PyObject_GC_UnTrack it */
 
-    PyBigFileH  *pyfileh = upcast(PyBigFileH *, pyfileh0);
-    BigFile     *file = pyfileh->file;
+    PyBigFileH  *pyfileh = container_of(pyfileh0, PyBigFileH, pyobj);
+    BigFileH    *fileh   = &pyfileh->fileh;
+    BigFile     *file    = fileh->file;
     PyBigFile   *pyfile;
 
     if (pyfileh->in_weakreflist)
-        PyObject_ClearWeakRefs(pyfileh);
+        PyObject_ClearWeakRefs(&pyfileh->pyobj);
 
     /* pyfileh->file indicates whether fileh was yet opened (via fileh_open()) or not */
     if (file) {
-        fileh_close(pyfileh);
+        fileh_close(fileh);
 
-        pyfile = upcast(PyBigFile  *, file);
+        pyfile = container_of(file, PyBigFile, file);
         Py_DECREF(pyfile);
     }
 
-    pyfileh->ob_type->tp_free(pyfileh);
+    pyfileh->pyobj.ob_type->tp_free(&pyfileh->pyobj);
 }
 
 
@@ -512,7 +525,7 @@ pyfileh_new(PyTypeObject *type, PyObject *args, PyObject *kw)
         return NULL;
     self->in_weakreflist = NULL;
 
-    return self;
+    return &self->pyobj;
 }
 
 
@@ -548,7 +561,7 @@ static /*const*/ PyTypeObject PyBigFileH_Type = {
 
 static int pybigfile_loadblk(BigFile *file, blk_t blk, void *buf)
 {
-    PyBigFile *pyfile = upcast(PyBigFile *, file);
+    PyBigFile *pyfile = container_of(file, PyBigFile, file);
     PyObject  *pybuf = NULL;
     PyObject  *loadret = NULL;
 
@@ -641,7 +654,7 @@ static int pybigfile_loadblk(BigFile *file, blk_t blk, void *buf)
 
     /* NOTE K = unsigned long long */
     BUILD_ASSERT(sizeof(blk) == sizeof(unsigned long long));
-    loadret = PyObject_CallMethod(pyfile, "loadblk", "KO", blk, pybuf);
+    loadret = PyObject_CallMethod(&pyfile->pyobj, "loadblk", "KO", blk, pybuf);
 
     /* python should return to original frame */
     BUG_ON(ts != PyThreadState_GET());
@@ -894,7 +907,7 @@ err:
 
 static int pybigfile_storeblk(BigFile *file, blk_t blk, const void *buf)
 {
-    PyBigFile *pyfile = upcast(PyBigFile *, file);
+    PyBigFile *pyfile = container_of(file, PyBigFile, file);
     PyObject  *pybuf;
     PyObject  *storeret = NULL;
 
@@ -919,7 +932,7 @@ static int pybigfile_storeblk(BigFile *file, blk_t blk, const void *buf)
 
     /* NOTE K = unsigned long long */
     BUILD_ASSERT(sizeof(blk) == sizeof(unsigned long long));
-    storeret = PyObject_CallMethod(pyfile, "storeblk", "KO", blk, pybuf);
+    storeret = PyObject_CallMethod(&pyfile->pyobj, "storeblk", "KO", blk, pybuf);
 
     /* we need to know only whether storeret != NULL, decref it now */
     Py_XDECREF(storeret);
@@ -976,7 +989,7 @@ static const struct bigfile_ops pybigfile_ops = {
 static PyObject *
 pyfileh_open(PyObject *pyfile0, PyObject *args)
 {
-    PyBigFile   *pyfile = upcast(PyBigFile *, pyfile0);
+    PyBigFile   *pyfile = container_of(pyfile0, PyBigFile, pyobj);
     PyBigFileH  *pyfileh;
     /* NOTE no virtmem lock needed - default RAM does not change */
     RAM *ram = ram_get_default(NULL);   // TODO get ram from args
@@ -991,7 +1004,7 @@ pyfileh_open(PyObject *pyfile0, PyObject *args)
         return NULL;
 
     Py_INCREF(pyfile);
-    err = fileh_open(pyfileh, pyfile, ram);
+    err = fileh_open(&pyfileh->fileh, &pyfile->file, ram);
     if (err) {
         XPyErr_SetFromErrno();
         Py_DECREF(pyfile);
@@ -999,7 +1012,7 @@ pyfileh_open(PyObject *pyfile0, PyObject *args)
         return NULL;
     }
 
-    return pyfileh;
+    return &pyfileh->pyobj;
 }
 
 
@@ -1014,18 +1027,18 @@ pyfile_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 
     // FIXME "k" = unsigned long - we need size_t
     static char *kw_list[] = {"blksize", NULL};
-    if (!PyArg_ParseTupleAndKeywords(args, kw, "k", kw_list, &self->blksize)) {
+    if (!PyArg_ParseTupleAndKeywords(args, kw, "k", kw_list, &self->file.blksize)) {
         Py_DECREF(self);
         return NULL;
     }
 
-    self->file_ops = &pybigfile_ops;
-    return self;
+    self->file.file_ops = &pybigfile_ops;
+    return &self->pyobj;
 }
 
 
 static PyMemberDef pyfile_members[] = {
-    {"blksize", T_ULONG /* XXX vs typeof(blksize) = size_t ? */, offsetof(PyBigFile, blksize), READONLY, "block size"},
+    {"blksize", T_ULONG /* XXX vs typeof(blksize) = size_t ? */, offsetof(PyBigFile, file.blksize), READONLY, "block size"},
     {NULL}
 };