[New-bugs-announce] [issue27725] Use Py_SIZE(x) instead of x->ob_size

REIX Tony report at bugs.python.org
Wed Aug 10 05:51:37 EDT 2016


New submission from REIX Tony:

I'm porting Python 2.7.* on AIX.

I am now using a version 13.1.3.2 of XLC.
I was previously using version 12.1.0.14 .
It appears that this new compiler shows a potential issue in Python v2 code. This issue seems to appear when -O2 is used.

I was porting Python 2.7.11 with -O2 instead of -O0 when I got it.

The issue appears when running tests involving power() with Decimals where the x_sub() routine is used.

The following Python code shows the issue:
  from decimal import *
  c = Context(7, ROUND_UP)
  d = c.power(Decimal(0.7), Decimal(3.4))
  print d
Good result is:  0.2973948 .
The bug returns: 2.440099 

However, I have about 22 errors when running:
./python Lib/test/regrtest.py -v test_decimal
It is random in 64bit and quite constant in 32bit.

The issue deals with using x->ob-size.
There is a macro:
Include/object.h:#define Py_SIZE(ob)  (((PyVarObject*)(ob))->ob_size)

The issue appears in last lines of Objects/longobject.c:x_sub() routine, when changing the sign:   z->ob_size = -(z->ob_size);

I have looked at version 2.7.12 and 2.7.10 of Python: they contain the same code as in 2.7.11.
And ->ob_size is used about 45 times, mainly in Objects/longobject.c. However, Py_SIZE(...) is used ten times more (475).

- Looking at version 3.5.1 of Python, I see that ->ob_size is now used only once, in: Objects/object.c .
And Py_SIZE(...) is now used 616 times.

And I also see that the Python 2.7.11-12 x_sub() code:
      if (sign < 0)
        z->ob_size = -(z->ob_size);
      return long_normalize(z);
has been replaced in Python 3.5.1 by:
      if (sign < 0) {
        _PyLong_Negate(&z);
        if (z == NULL)
            return NULL;
      }
      return long_normalize(z);

  /* If a freshly-allocated int is already shared, it must
      be a small integer, so negating it must go to PyLong_FromLong */
  Py_LOCAL_INLINE(void)
  _PyLong_Negate(PyLongObject **x_p)
  {
     PyLongObject *x;

     x = (PyLongObject *)*x_p;
     if (Py_REFCNT(x) == 1) {
         Py_SIZE(x) = -Py_SIZE(x);
         return;
     }

     *x_p = (PyLongObject *)PyLong_FromLong(-MEDIUM_VALUE(x));
     Py_DECREF(x);
 }


So, it looks to me that Python v2 version should do the same that Python v3 has done: replace x->ob-size by Py_SIZE(x) everywhere, and improve the code of x_sub() by using some _PyLong_Negate() routine or macro.

----------
components: Library (Lib)
messages: 272324
nosy: trex58
priority: normal
severity: normal
status: open
title: Use Py_SIZE(x) instead of x->ob_size
type: behavior
versions: Python 2.7

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue27725>
_______________________________________


More information about the New-bugs-announce mailing list