[Python-Dev] ANSI strict aliasing and Python

Martin v. Löwis martin@v.loewis.de
18 Jul 2003 01:01:24 +0200


Neil Schemenauer <nas@python.ca> writes:

> It looks like most (maybe all) of those warnings are triggered by
> Py_True and Py_False.  

While it is the case that only those places trigger the warning, the
issue goes beyond that. All usages of PyObject* in Python are
incorrect, and may result in bad code.

> Is there some other way of defining Py_True and
> Py_False so that we can avoid those errors?  

We would have to give up PyObject_HEAD, and make that a structure.

> Does this mean that code like:
> 
>     void f (PyObject *a, PyDictObject *b)
>     {
>         a->ob_refcnt += 1;
>         b->ob_refcnt -= 1;
>     }
>     [...]
>         f((PyObject *)somedict, somedict);
> 
> is disallowed?

Correct. 

a->ob_refcnt += 1

has undefined behaviour, as 'a' does *not* point to a PyObject, but
instead points to, say, a PyDictObject, and PyObject is not a field of
PyDictObject.

As a result of that, gcc can infer that 'a' and 'b' are different
pointers, and it could implement that sequence as

  tmp1 = a->ob_refcnt;
  tmp2 = b->ob_refcnt;
  tmp1 += 1;
  tmp2 -= 1;
  a->ob_refcnt = tmp1;
  b->ob_refcnt = tmp2;

The compiler could not use this optimization if we had

struct _dictobject {
	PyObject _o;
	int ma_fill;
	int ma_used;
	int ma_mask;
	PyDictEntry *ma_table;
	PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, long hash);
	PyDictEntry ma_smalltable[PyDict_MINSIZE];
};

Then, of course, we'ld have to write

  b->_o->ob_refcnt -= 1;

Regards,
Martin