Title: PySlice_GetIndicesEx change broke ABI in 3.5 and 3.6 branches
Type: behavior Stage: patch review
Components: Interpreter Core Versions: Python 3.6, Python 3.5, Python 2.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: benjamin.peterson, cgohlke, cstratak, hroncok, larry, ned.deily, njs, serhiy.storchaka, steve.dower
Priority: release blocker Keywords:

Created on 2017-03-29 23:36 by njs, last changed 2017-04-20 15:12 by njs.

Pull Requests
URL Status Linked Edit
PR 1049 merged serhiy.storchaka, 2017-04-08 09:26
PR 1050 merged serhiy.storchaka, 2017-04-08 09:27
Messages (11)
msg290796 - (view) Author: Nathaniel Smith (njs) * Date: 2017-03-29 23:36
In the process of fixing issue 27867, a new function PySlice_AdjustIndices was added, and PySlice_GetIndicesEx was converted into a macro that calls this new function. The patch was backported to both the 3.5 and 3.6 branches, was released in 3.6.1, and is currently slated to be released as part of 3.5.4.

Unfortunately, this breaks our normal ABI stability guarantees for micro releases: it means that if a C module that uses PySlice_GetIndicesEx is compiled against e.g. 3.6.1, then it cannot be imported on 3.6.0. This affects a number of high-profile packages (cffi, pandas, mpi4py, dnf, ...). The only workaround is that if you are distributing binary extension modules (e.g. wheels), then you need to be careful not to upgrade to 3.6.1. It's not possible for a wheel to declare that it requires 3.6.1-or-better, because CPython normally follows the rule that we don't make these kinds of changes. Oops.

CC'ing Ned and Larry, because it's possible this should trigger a 3.6.2, and I think it's a blocker for 3.5.4. CC'ing Serhiy as the author of the original patch, since you probably have the best idea how this could be unwound with minimal breakage :-).

python-dev discussion:

Fedora bug:
msg290797 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2017-03-29 23:38
Let's make it a release blocker for now.
msg290806 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-03-30 05:09
My apologies for breaking the world.

The workaround is to undefine PySlice_GetIndicesEx after #include "Python.h".

#if PY_VERSION_HEX < 0x03070000 && defined(PySlice_GetIndicesEx)
#undef PySlice_GetIndicesEx

But this restores the initial bug.

Other obvious solution -- declare 3.6.0 broken and require upgrading to 3.6.1.

For 3.5.4 we can disable defining the macro when Py_LIMITED_API is not defined. This will restore the initial bug in many extensions. And we need other way to detect if we compile the CPython core or standard extensions for fixing the bug in standard collections. Or expand all uses of PySlice_GetIndicesEx to PySlice_Unpack+PySlice_AdjustIndices (the patch can be generated automatically).
msg290815 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-03-30 05:59
2.7 is affected too.

Nathaniel, could you add references to this issue and to original issue27867 on the Fedora bug tracker?
msg291118 - (view) Author: Charalampos Stratakis (cstratak) * Date: 2017-04-04 09:29
Currently we haven't updated to Python 3.6.1 at Fedora 26 due to this issue.

While it is a release blocker for 3.6.2, what can be done for 3.6.1?
msg291331 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-08 09:36
PR 1049 and PR 1050 restore ABI compatibility in 3.5 and 2.7. Unfortunately this restores the original bug with using PySlice_GetIndicesEx in third-party code (but CPython core and standard extensions no longer use PySlice_GetIndicesEx).

Can we consider 3.6.0 rather than 3.6.1 as broken release?
msg291406 - (view) Author: Nathaniel Smith (njs) * Date: 2017-04-10 03:02
> Can we consider 3.6.0 rather than 3.6.1 as broken release?

In the last week, pypi downloads were about evenly split between 3.6.0 and 3.6.1 (2269969 for "3.6.1", 1927189 for "3.6.0", and those two were ~2 orders of magnitude more common than other strings like "3.6.1+", "3.6.0b2", etc. [1]). Not sure what that to conclude from that, but certainly if people start uploading 3.6.1-only wheels right now then it will break things for a lot of end users.

With my manylinux docker image maintainer hat on: we're currently shipping 3.6.0. I'm extremely confident that if we stick with this we'll never get any complaints about the obscure bug with malicious __index__ implementations that's being fixed here. OTOH if we upgrade to 3.6.1, or any version with this ABI change, then we'll definitely get many complaints so long as there's anyone at all still using 3.6.0, which is probably forever. So I'm not sure not sure what incentive we would have to ever upgrade to 3.6.1+ if this ABI change is kept?

(This isn't saying the bug is unimportant! But it sure is hard to sell its importance to folks trying to ship packages and support end-users...)


[1] Somewhat crude query I used in case it's useful for future reference:

  REGEXP_EXTRACT(details.python, r"^([^\.]+\.[^\.]+\.[^\.]+)") as python_version,
  COUNT(*) as download_count,
  REGEXP_MATCH(details.python, r"^3\.6\.")
  download_count DESC
msg291408 - (view) Author: Nathaniel Smith (njs) * Date: 2017-04-10 03:22
It looks like PyTorch got bitten by this:
msg291743 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-16 07:08
New changeset 89f9eb5b192b875c017d37cac16bd514aad9a801 by Serhiy Storchaka in branch '2.7':
bpo-29943: Remove the PySlice_GetIndicesEx() macro. (#1050)
msg291746 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-16 09:03
New changeset 49a905958ffc2fcd5d1d1a293ae453d45deeb884 by Serhiy Storchaka in branch '3.5':
[3.5] bpo-29943: Do not replace the function PySlice_GetIndicesEx() with a macro (#1049)
msg291979 - (view) Author: Nathaniel Smith (njs) * Date: 2017-04-20 15:12
Date User Action Args
2017-04-20 15:12:22njssetmessages: + msg291979
2017-04-16 09:03:54serhiy.storchakasetmessages: + msg291746
2017-04-16 07:08:49serhiy.storchakasetmessages: + msg291743
2017-04-10 03:22:55njssetmessages: + msg291408
2017-04-10 03:02:58njssetmessages: + msg291406
2017-04-08 09:36:31serhiy.storchakasettype: behavior
messages: + msg291331
components: + Interpreter Core
stage: patch review
2017-04-08 09:27:37serhiy.storchakasetpull_requests: + pull_request1202
2017-04-08 09:26:33serhiy.storchakasetpull_requests: + pull_request1201
2017-04-06 17:58:21cgohlkesetnosy: + cgohlke
2017-04-04 09:29:28cstrataksetmessages: + msg291118
2017-04-01 09:16:02hroncoksetnosy: + hroncok
2017-03-30 08:56:25cstrataksetnosy: + cstratak
2017-03-30 05:59:17serhiy.storchakasetnosy: + benjamin.peterson

messages: + msg290815
versions: + Python 2.7
2017-03-30 05:09:17serhiy.storchakasetmessages: + msg290806
2017-03-30 01:17:10steve.dowersetnosy: + steve.dower
2017-03-29 23:38:15larrysetpriority: normal -> release blocker

messages: + msg290797
2017-03-29 23:36:28njscreate