python-peps / pep-3123.txt

PEP: 3123
Title: Making PyObject_HEAD conform to standard C
Version: $Revision$
Last-Modified: $Date$
Author: Martin von Löwis <>
Status: Final
Type: Standards Track
Content-Type: text/x-rst
Created: 27-Apr-2007
Python-Version: 3.0


Python currently relies on undefined C behavior, with its
usage of ``PyObject_HEAD``. This PEP proposes to change that
into standard C.


Standard C defines that an object must be accessed only through a
pointer of its type, and that all other accesses are undefined
behavior, with a few exceptions. In particular, the following
code has undefined behavior::

  struct FooObject{
    int data;

  PyObject *foo(struct FooObject*f){
   return (PyObject*)f;

  int bar(){
   struct FooObject *f = malloc(sizeof(struct FooObject));
   struct PyObject *o = foo(f);
   f->ob_refcnt = 0;
   o->ob_refcnt = 1;
   return f->ob_refcnt;

The problem here is that the storage is both accessed as
if it where struct ``PyObject``, and as struct ``FooObject``.

Historically, compilers did not have any problems with this
code. However, modern compilers use that clause as an 
optimization opportunity, finding that ``f->ob_refcnt`` and
``o->ob_refcnt`` cannot possibly refer to the same memory, and
that therefore the function should return 0, without having
to fetch the value of ob_refcnt at all in the return
statement. For GCC, Python now uses ``-fno-strict-aliasing``
to work around that problem; with other compilers, it
may just see undefined behavior. Even with GCC, using
``-fno-strict-aliasing`` may pessimize the generated code


Standard C has one specific exception to its aliasing rules precisely
designed to support the case of Python: a value of a struct type may
also be accessed through a pointer to the first field. E.g. if a
struct starts with an ``int``, the ``struct *`` may also be cast to
an ``int *``, allowing to write int values into the first field.

For Python, ``PyObject_HEAD`` and ``PyObject_VAR_HEAD`` will be changed
to not list all fields anymore, but list a single field of type

  typedef struct _object {
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
  } PyObject;

  typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size;
  } PyVarObject;

  #define PyObject_HEAD        PyObject ob_base;
  #define PyObject_VAR_HEAD    PyVarObject ob_base;

Types defined as fixed-size structure will then include PyObject
as its first field, PyVarObject for variable-sized objects. E.g.::

  typedef struct {
    PyObject ob_base;
    PyObject *start, *stop, *step;
  } PySliceObject;

  typedef struct {
    PyVarObject ob_base;
    PyObject **ob_item;
    Py_ssize_t allocated;
  } PyListObject;

The above definitions of ``PyObject_HEAD`` are normative, so extension
authors MAY either use the macro, or put the ``ob_base`` field explicitly
into their structs.

As a convention, the base field SHOULD be called ob_base. However, all
accesses to ob_refcnt and ob_type MUST cast the object pointer to
PyObject* (unless the pointer is already known to have that type), and
SHOULD use the respective accessor macros. To simplify access to
ob_type, ob_refcnt, and ob_size, macros::

  #define Py_TYPE(o)    (((PyObject*)(o))->ob_type)
  #define Py_REFCNT(o)  (((PyObject*)(o))->ob_refcnt)
  #define Py_SIZE(o)    (((PyVarObject*)(o))->ob_size)

are added. E.g. the code blocks ::

  #define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type)

  return func->ob_type->tp_name;

needs to be changed to::

  #define PyList_CheckExact(op) (Py_TYPE(op) == &PyList_Type)

  return Py_TYPE(func)->tp_name;

For initialization of type objects, the current sequence ::

  0, /* ob_size */

becomes incorrect, and must be replaced with ::

  PyVarObject_HEAD_INIT(NULL, 0)

Compatibility with Python 2.6

To support modules that compile with both Python 2.6 and Python 3.0,
the ``Py_*`` macros are added to Python 2.6. The macros ``Py_INCREF``
and ``Py_DECREF`` will be changed to cast their argument to ``PyObject *``,
so that module authors can also explicitly declare the ``ob_base``
field in modules designed for Python 2.6. 


This document has been placed in the public domain.

   Local Variables:
   mode: indented-text
   indent-tabs-mode: nil
   sentence-end-double-space: t
   fill-column: 70
   coding: utf-8
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.