[C++-sig] boost/python 1.33.1 breaks aliasing rules

David Abrahams dave at boost-consulting.com
Thu Dec 8 21:52:45 CET 2005

Philipp Thomas <pth at suse.de> writes:

> * David Abrahams (dave at boost-consulting.com) [20051208 07:06]:
>> Which, AFAICT, means that our casts aren't hurting anybody, regardless
>> of whether we use -fno-strict-aliasing.  Right?
> Right. Do you have an idea how to pass -fno-strict-aliasing *only* when
> build libboost_python?

Yes; we can put it in the Jamfile.

>> where the union performs, essentially, a reinterpret cast of a PyObject*&
>> to a PyTypeObject*&, which could be a completely different thing.
> Please? I'm still passing a PyObject*, as the union is essentially a
> reinterpret_cast<PyObject *>(PyTypeObject *).

No.  A reinterpret_cast is not required to simply interpret the same
bits differently, as the union trick does.  Aside from certain
round-trip conversion guarantees, its effects are completely
implementation-defined.  To put it differently, what you're doing
there is equivalent to:

  PyTypeObject* s = &PyString_Type;

which is another thing altogether.

Boost.Python is doing ((PyObject*)&PyString_Type) and passes the
result to Python.  That is not yet undefined behavior.  If Python
internally casts that back to PyTypeObject*, it's free to use the
pointer as it likes without undefined behavior.  If I treat Python as
a black box, I can assume it does something like that, since Python
documents that we can pass such punned pointers.  Instead Python uses
-fno-strict-aliasing, exploiting a compiler-specific feature to avoid
undefined behavior, but it's the same thing from my POV.  So right now
Boost.Python isn't doing anything unspecified or nonportable.

However, the reinterpretation of bits as you are doing does introduce
unspecified behavior at least, by 5.2.10, para 7:

  7 A pointer to an object can be explicitly converted to a pointer to
  an object of different type. 65) Except that converting an rvalue of
  type ``pointer to T1'' to the type ``pointer to T2'' (where T1 and
  T2 are object types and where the alignment requirements of T2 are
  no stricter than those of T1) and back to its original type yields
  the original pointer value, the result of such a pointer conversion
  is unspecified. 

>> I would strongly oppose the former, 
> There's no disagreement as I hate #ifdef because it always makes code nearly
> unreadable.
>> but the latter might be no worse
>> (and may be a little better) than leaving the C-style casts in there.
> Hmm, I'll try to come up with a way to encapsulate it in macros.

Forget the macros; we can do it with functions.  See

Dave Abrahams
Boost Consulting

More information about the Cplusplus-sig mailing list