osdir.com

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Python-Dev] Python 2.7, long double vs allocator alignment, GCC 8 on x86-64


I hope this is the right list for this kind of question.  We recently
tried to build Python 2.6 with GCC 8, and ran into this issue:

  <https://bugzilla.redhat.com/show_bug.cgi?id=1540316>

Also quoting for context:

| PyInstance_NewRaw contains this code:
| 
|     inst = PyObject_GC_New(PyInstanceObject, &PyInstance_Type);
|     if (inst == NULL) {
|         Py_DECREF(dict);
|         return NULL;
|     }
|     inst->in_weakreflist = NULL;
|     Py_INCREF(klass);
|     inst->in_class = (PyClassObject *)klass;
|     inst->in_dict = dict;
|     _PyObject_GC_TRACK(inst);
| 
| _PyObject_GC_TRACK expands to:
| 
| #define _PyObject_GC_TRACK(o) do { \
|     PyGC_Head *g = _Py_AS_GC(o); \
|     if (g->gc.gc_refs != _PyGC_REFS_UNTRACKED) \
|         Py_FatalError("GC object already tracked"); \
| ?
| 
| Via:
| 
| #define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
| 
| We get to this:
| 
| /* GC information is stored BEFORE the object structure. */
| typedef union _gc_head {
|     struct {
|         union _gc_head *gc_next;
|         union _gc_head *gc_prev;
|         Py_ssize_t gc_refs;
|     } gc;
|     long double dummy;  /* force worst-case alignment */
| } PyGC_Head;
| 
| PyGC_Head has 16-byte alignment.  The net result is that
| 
|     _PyObject_GC_TRACK(inst);
| 
| promises to the compiler that inst is properly aligned for the
| PyGC_Head type, but it is not: PyObject_GC_New returns a pointer which
| is only 8-byte-aligned.
| 
| Objects/obmalloc.c contains this:
| 
| /*
|  * Alignment of addresses returned to the user. 8-bytes alignment works
|  * on most current architectures (with 32-bit or 64-bit address busses).
|  * The alignment value is also used for grouping small requests in size
|  * classes spaced ALIGNMENT bytes apart.
|  *
|  * You shouldn't change this unless you know what you are doing.
|  */
| #define ALIGNMENT               8               /* must be 2^N */
| #define ALIGNMENT_SHIFT         3
| #define ALIGNMENT_MASK          (ALIGNMENT - 1)
| 
| So either the allocator alignment needs to be increased, or the
| PyGC_Head alignment needs to be decreased.

Is this a known issue?  As far as I can see, it has not been fixed on
the 2.7 branch.

(Store merging is a relatively new GCC feature.  Among other things,
this means that on x86-64, for sufficiently aligned pointers, vector
instructions are used to update multiple struct fields at once.  These
vector instructions can trigger alignment traps, similar to what
happens on some other architectures for scalars.)