You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PYLONG_BITS_IN_DIGIT differs between MinGW and MSVC #79218
I see reports from Cython users on Windows-64 that extension modules that use "longintrepr.h" get miscompiled by MinGW. A failing setup looks as follows:
Stock 64 bit CPython on Windows, e.g.
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
MinGW uses this compile time setup, i.e. 15 bit digits:
PyLong_BASE 0x8000
PyLong_MASK 7FFF
PyLong_SHIFT 15
sizeof(digit) 2
sizeof(sdigit) 2
Whereas CPython reports the following, indicating that it was in fact built with 30 bit digits:
sys.getsize(1, 2**14, 2**15, 2**29, 2**30, 2**63, 2**64) (28, 28, 28, 28, 32, 36, 36)
I'm not sure if this also applies to Py2.7, but I don't think the PyLong implementations differ in this regard.
The compile time PyLong digit size is not remembered by the CPython installation and instead determined on the fly by the extension compiler. It seems that the MSVC build of the stock CPython packages differs from what MinGW decides here. This renders MinGW unusable for code that uses "longintrepr.h", which Cython does by default in order to accelerate its unpacking of PyLong values.
Is there a reason why CPython cannot store its compile time value for the PYLONG_BITS_IN_DIGIT setting somewhere?
Thanks, I understand that this information can be found at runtime. However, in order to correctly compile C code against a given CPython runtime, there needs to be a guarantee that extension module builds use the same configuration as the CPython build.
Misconfiguration
I searched some more, and it looks like this was already reported almost ten years ago in bpo-4709.
The work-around there is to pass -DMS_WIN64, which apparently is not defined by MinGW but required by the CPython headers.
That variable should be inferred somewhere, either in PC/pyconfig.h or pyport.h. If there's a way to also infer it on 64-bit MinGW then we would consider a patch for that.
The relevant macro seems to be "__MINGW64__". I have neither a Windows environment nor MinGW-64 for testing, but the logic should be the same as for the "_WIN64" macro, i.e.
And then there's probably also something to do to record the compiler version in the long CPython version string, etc. I also can't say if MinGW-64 sets the "MS_WIN32" macro. Having "MS_WIN64" without "MS_WIN32" might be unexpected for some code.
This should probably be a separate issue, but I wonder whether the 15-bit digit option has value any more. Should we just drop that option and always use 30-bit digits?
30-bit digits were introduced at a time when we couldn't rely on a 64-bit integer type always being available, so we still needed to keep the 15-bit fallback option. But I think that's no longer the case.
@gpshead I guess the PYLONG_BITS_IN_DIGIT issue still exists in theory, but it would be harder to hit it by accident at this point. The wider issue of SIZEOF_VOID_P being wrong seems like it would still be relevant.
Activity
scoder commentedon Oct 21, 2018
I see reports from Cython users on Windows-64 that extension modules that use "longintrepr.h" get miscompiled by MinGW. A failing setup looks as follows:
Stock 64 bit CPython on Windows, e.g.
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
MinGW uses this compile time setup, i.e. 15 bit digits:
PyLong_BASE 0x8000
PyLong_MASK 7FFF
PyLong_SHIFT 15
sizeof(digit) 2
sizeof(sdigit) 2
Whereas CPython reports the following, indicating that it was in fact built with 30 bit digits:
sys.getsize(1, 2**14, 2**15, 2**29, 2**30, 2**63, 2**64) (28, 28, 28, 28, 32, 36, 36)
I'm not sure if this also applies to Py2.7, but I don't think the PyLong implementations differ in this regard.
The compile time PyLong digit size is not remembered by the CPython installation and instead determined on the fly by the extension compiler. It seems that the MSVC build of the stock CPython packages differs from what MinGW decides here. This renders MinGW unusable for code that uses "longintrepr.h", which Cython does by default in order to accelerate its unpacking of PyLong values.
Is there a reason why CPython cannot store its compile time value for the PYLONG_BITS_IN_DIGIT setting somewhere?
scoder commentedon Oct 21, 2018
Some more information. CPython uses this code snippet to decide on the PyLong digit size:
In MinGW, "SIZEOF_VOID_P" is 4, whereas "sizeof(void*)" resolves to 8.
mdickinson commentedon Oct 21, 2018
There's PyLong_GetInfo [1], and at Python level, the corresponding sys.long_info (Python 2) / sys.int_info (Python 3). Does that help?
[1]
cpython/Objects/longobject.c
Lines 5578 to 5595 in b2e2025
serhiy-storchaka commentedon Oct 21, 2018
At runtime this information is available as sys.int_info.bits_per_digit.
Looks like a misconfiguration. I suppose this will cause more issues than just wrong PYLONG_BITS_IN_DIGIT.
scoder commentedon Oct 21, 2018
Thanks, I understand that this information can be found at runtime. However, in order to correctly compile C code against a given CPython runtime, there needs to be a guarantee that extension module builds use the same configuration as the CPython build.
I searched some more, and it looks like this was already reported almost ten years ago in bpo-4709.
The work-around there is to pass -DMS_WIN64, which apparently is not defined by MinGW but required by the CPython headers.
zooba commentedon Oct 21, 2018
That variable should be inferred somewhere, either in PC/pyconfig.h or pyport.h. If there's a way to also infer it on 64-bit MinGW then we would consider a patch for that.
scoder commentedon Oct 23, 2018
The relevant macro seems to be "__MINGW64__". I have neither a Windows environment nor MinGW-64 for testing, but the logic should be the same as for the "_WIN64" macro, i.e.
And then there's probably also something to do to record the compiler version in the long CPython version string, etc. I also can't say if MinGW-64 sets the "MS_WIN32" macro. Having "MS_WIN64" without "MS_WIN32" might be unexpected for some code.
mdickinson commentedon Oct 22, 2021
This should probably be a separate issue, but I wonder whether the 15-bit digit option has value any more. Should we just drop that option and always use 30-bit digits?
30-bit digits were introduced at a time when we couldn't rely on a 64-bit integer type always being available, so we still needed to keep the 15-bit fallback option. But I think that's no longer the case.
mdickinson commentedon Dec 22, 2021
Specifically, bpo-45569.
gpshead commentedon Aug 5, 2022
is this still relevant now that we always default to 30-bit?
mdickinson commentedon Aug 6, 2022
@gpshead I guess the
PYLONG_BITS_IN_DIGITissue still exists in theory, but it would be harder to hit it by accident at this point. The wider issue ofSIZEOF_VOID_Pbeing wrong seems like it would still be relevant.gh-79218: Define `MS_WIN64` macro for Mingw-w64 64bit on Windows (GH-…
Merge branch 'main' into typedocs