Title: WinError(): Python int too large to convert to C long
Type: behavior Stage: patch review
Components: ctypes, Windows Versions: Python 3.10, Python 3.9, Python 3.8
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Kelvin You, amaury.forgeotdarc, belopolsky, eryksun, josh.r, meador.inge, meilyadam, paul.moore, steve.dower, tim.golden, zach.ware
Priority: normal Keywords: patch

Created on 2016-10-19 07:28 by Kelvin You, last changed 2021-08-26 01:28 by meilyadam.

Pull Requests
URL Status Linked Edit
PR 27959 open meilyadam, 2021-08-26 01:28
Messages (8)
msg278963 - (view) Author: Kelvin You (Kelvin You) Date: 2016-10-19 07:28
// callproc.c
static PyObject *format_error(PyObject *self, PyObject *args)
    PyObject *result;
    wchar_t *lpMsgBuf;
    DWORD code = 0;
    if (!PyArg_ParseTuple(args, "|i:FormatError", &code))  
                                  ^ Here the format string should be "|I:FormatError"
        return NULL;
    if (code == 0)
        code = GetLastError();
    lpMsgBuf = FormatError(code);
    if (lpMsgBuf) {
        result = PyUnicode_FromWideChar(lpMsgBuf, wcslen(lpMsgBuf));
    } else {
        result = PyUnicode_FromString("<no description>");
    return result;
msg279005 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2016-10-20 01:16
You can't use I as a format code safely; it silently ignores/wraps overflow on the conversion, where i raises on overflow. The unsigned converters are basically useless for resilient code in 99% of cases.

I *think* I remember some private utility functions for doing this using O& though, not sure if they're available in callproc.c...
msg279008 - (view) Author: Kelvin You (Kelvin You) Date: 2016-10-20 03:35
I report this issue because the function WlanScan( returns a error code 0x80342002 when the WLAN is disabled on Windows 10.  ctypes.WinError() raise an exception of 'Python int too large to convert to C long' when handle this error code.
msg279009 - (view) Author: Kelvin You (Kelvin You) Date: 2016-10-20 03:53
Here is the full list of windows error code:
You can see a lot of error codes is above 0x80000000.
msg279033 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2016-10-20 14:15
All HRESULT values are, since the topmost bit indicates that it's an error, but all the others should be 16-bit positive integers IIRC. I don't think this function is meant to work with HRESULTs, but I could be wrong - fairly sure it's meant for Win32 error codes, though I'd have to dig into the format function it calls.

What function are you calling that produces an HRESULT from GetLastError?
msg279047 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2016-10-20 16:48
Kelvin is calling WlanScan [1], which returns an error code that apparently can include HRESULT (signed) values cast as DWORD (unsigned) values, including 0x80342002 (ERROR_NDIS_DOT11_POWER_STATE_INVALID). 

ctypes.FormatError calls FormatMessage [2] with the flag FORMAT_MESSAGE_FROM_SYSTEM. About half of the system error codes defined in winerror.h consist of COM HRESULT codes. But, to clarify Kelvin's link [3], this does not include NTSTATUS values from kernel-mode system calls. NTSTATUS values require the ntdll.dll message table.


A workaround in this case is to use the default c_int restype to return the error as a signed integer:

    >>> ctypes.FormatError(0x80342002 - 2**32)
    "The wireless local area network interface is powered down and doesn't
    support the requested operation."

A similar workaround works for setting the exit code to an HRESULT or NTSTATUS error code:

    >>> hex('python -c "import os; os._exit(0xC0000001)"'))
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    OverflowError: Python int too large to convert to C long
    >>> hex('python -c "import sys; sys.exit(0xC0000001)"'))

    >>> hex('python -c "import os; os._exit(0xC0000001 - 2**32)"'))
    >>> hex('python -c "import sys; sys.exit(0xC0000001 - 2**32)"'))
msg387744 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-02-26 20:32
format_error() can use format "L" (long long) and then check for a value in the accepted range `value >= LONG_MIN && value <= ULONG_MAX`. If the value is out of range, raise OverflowError. Otherwise assign the value to DWORD `code`.
msg400134 - (view) Author: Adam Meily (meilyadam) * Date: 2021-08-23 13:22
I can potentially take a stab at writing up a PR for this. I've also seen this affecting other locations that eventually call FormatMessage, including:

- ctypes.format_error() - this original issue
- os.strerror()
- OSError(winerror=X)

I will most likely look into fixing all three.
Date User Action Args
2021-08-26 01:28:22meilyadamsetkeywords: + patch
stage: patch review
pull_requests: + pull_request26407
2021-08-23 13:22:52meilyadamsetnosy: + meilyadam
messages: + msg400134
2021-02-26 20:32:21eryksunsetmessages: + msg387744
versions: + Python 3.8, Python 3.9, Python 3.10, - Python 2.7, Python 3.5, Python 3.6, Python 3.7
2016-10-20 16:48:50eryksunsetnosy: + eryksun
messages: + msg279047
2016-10-20 14:15:49steve.dowersetmessages: + msg279033
2016-10-20 03:53:49Kelvin Yousetmessages: + msg279009
2016-10-20 03:35:15Kelvin Yousetmessages: + msg279008
2016-10-20 01:16:20josh.rsetnosy: + josh.r
messages: + msg279005
2016-10-19 07:59:48serhiy.storchakasetnosy: + belopolsky, amaury.forgeotdarc, paul.moore, tim.golden, meador.inge, zach.ware, steve.dower

type: crash -> behavior
components: + Windows
versions: + Python 3.7, - Python 3.3, Python 3.4
2016-10-19 07:28:00Kelvin Youcreate