Skip to content
Prev Previous commit
Next Next commit
Move int_max_str_digits out of PyInterpreterState
Abigail does not like the fact that `PyInterpreterState` has changed
size and some fields have been moved around. Even placing
`int_max_str_digits` after `_initial_thread` does not make her happy.

Let's move the field out ouf the state and make the setting a
process-wide global. It's ugly, but better ugly than breaking somebody's
code.

```
  [C]'function void PyEval_AcquireThread(PyThreadState*)' at ceval.c:452:1 has some indirect sub-type changes:
    parameter 1 of type 'PyThreadState*' has sub-type changes:
      in pointed to type 'typedef PyThreadState' at pytypedefs.h:24:1:
        underlying type 'struct _ts' at pystate.h:82:1 changed:
          type size hasn't changed
          1 data member changes (2 filtered):
           type of 'PyInterpreterState* _ts::interp' changed:
             in pointed to type 'typedef PyInterpreterState' at pytypedefs.h:25:1:
               underlying type 'struct _is' at pycore_interp.h:78:1 changed:
                 type size changed from 861952 to 862016 (in bits)
                 1 data member insertion:
                   'int _is::int_max_str_digits', at offset 859072 (in bits) at pycore_interp.h:179:1
                 2 data member changes (3 filtered):
                  type of 'pyruntimestate* _is::runtime' changed:
                    in pointed to type 'struct pyruntimestate' at pycore_runtime.h:59:1:
                      type size changed from 1333440 to 1333504 (in bits)
                      1 data member changes (2 filtered):

                  'PyThreadState _is::_initial_thread' offset changed from 859072 to 859136 (in bits) (by +64 bits)
```
  • Loading branch information
tiran committed Sep 1, 2022
commit 9e1f13d48f52cfe24fb49967bda97d05904c1c95
6 changes: 4 additions & 2 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ struct _is {
struct type_cache type_cache;
struct callable_cache callable_cache;

int int_max_str_digits;

/* The following fields are here to avoid allocation during init.
The data is exposed through PyInterpreterState pointer fields.
These fields should not be accessed directly outside of init.
Expand All @@ -194,6 +192,10 @@ struct _is {
PyThreadState _initial_thread;
};

/* The value should be part of PyInterpreterState. However that would change
* the size of the struct and therefore break our ABI promise. Abigail
* does not like it... Oh my! */
extern int _Py_int_max_str_digits;

/* other API */

Expand Down
14 changes: 7 additions & 7 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1786,8 +1786,7 @@ long_to_decimal_string_internal(PyObject *aa,
strlen++;
}
if (strlen > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) {
PyInterpreterState *interp = _PyInterpreterState_GET();
int max_str_digits = interp->int_max_str_digits;
int max_str_digits = _Py_int_max_str_digits;
Py_ssize_t strlen_nosign = strlen - negative;
if ((max_str_digits > 0) && (strlen_nosign > max_str_digits)) {
Py_DECREF(scratch);
Expand Down Expand Up @@ -2463,8 +2462,7 @@ digit beyond the first.

/* Limit the size to avoid excessive computation attacks. */
if (digits > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) {
PyInterpreterState *interp = _PyInterpreterState_GET();
int max_str_digits = interp->int_max_str_digits;
int max_str_digits = _Py_int_max_str_digits;
if ((max_str_digits > 0) && (digits > max_str_digits)) {
PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT,
max_str_digits, digits);
Expand Down Expand Up @@ -6129,6 +6127,8 @@ PyLong_GetInfo(void)

/* runtime lifecycle */

int _Py_int_max_str_digits;

PyStatus
_PyLong_InitTypes(PyInterpreterState *interp)
{
Expand All @@ -6146,9 +6146,9 @@ _PyLong_InitTypes(PyInterpreterState *interp)
return _PyStatus_ERR("can't init int info type");
}
}
interp->int_max_str_digits = _Py_global_config_int_max_str_digits;
if (interp->int_max_str_digits == -1) {
interp->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS;
_Py_int_max_str_digits = _Py_global_config_int_max_str_digits;
if (_Py_int_max_str_digits == -1) {
_Py_int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS;
}

return _PyStatus_OK();
Expand Down
5 changes: 2 additions & 3 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1633,7 +1633,7 @@ sys_get_int_max_str_digits_impl(PyObject *module)
/*[clinic end generated code: output=0042f5e8ae0e8631 input=8dab13e2023e60d5]*/
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return PyLong_FromSsize_t(interp->int_max_str_digits);
return PyLong_FromSsize_t(_Py_int_max_str_digits);
}

/*[clinic input]
Expand All @@ -1648,9 +1648,8 @@ static PyObject *
sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits)
/*[clinic end generated code: output=734d4c2511f2a56d input=d7e3f325db6910c5]*/
{
PyThreadState *tstate = _PyThreadState_GET();
if ((!maxdigits) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)) {
tstate->interp->int_max_str_digits = maxdigits;
_Py_int_max_str_digits = maxdigits;
Py_RETURN_NONE;
} else {
PyErr_Format(
Expand Down