Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,9 @@ def LoadLibrary(self, name):

def WinError(code=None, descr=None):
if code is None:
code = GetLastError()
# GetLastError returns a DWORD, cast large error codes
# to unsigned
code = GetLastError() & 0xffffffff
if descr is None:
descr = FormatError(code).strip()
return OSError(None, descr, None, code)
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_ctypes/test_win32.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ def test_winerror(self):
self.assertEqual(e.errno, errno.EINVAL)
self.assertEqual(e.winerror, ERROR_INVALID_PARAMETER)

def test_winerror_dword(self):
# see Issue 28474
E_POINTER = 0x80000005
msg = FormatError(E_POINTER).strip()
args = (E_POINTER, msg, None, E_POINTER)

e = WinError(E_POINTER)
self.assertEqual(e.args, args)
self.assertEqual(e.errno, E_POINTER)
self.assertEqual(e.winerror, E_POINTER)

windll.kernel32.SetLastError(E_POINTER)
try:
raise WinError()
except OSError as exc:
e = exc
self.assertEqual(e.args, args)
self.assertEqual(e.errno, E_POINTER)
self.assertEqual(e.winerror, E_POINTER)

class Structures(unittest.TestCase):
def test_struct_by_value(self):
class POINT(Structure):
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,14 @@ def test_WindowsError(self):
self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, None)
self.assertEqual(w.filename2, None)
# DWORD error code (issue #28474)
E_POINTER = 0x80000005
w = OSError(E_POINTER, 'foo', 'bar', E_POINTER)
self.assertEqual(w.errno, E_POINTER)
self.assertEqual(w.winerror, E_POINTER)
self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, 'bar')
self.assertEqual(w.filename2, None)

@unittest.skipUnless(sys.platform == 'win32',
'test specific to Windows')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve handling and reporting of unsigned win32 error codes.
Patch by Adam Meily.
13 changes: 10 additions & 3 deletions Modules/_ctypes/callproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1334,12 +1334,19 @@ static PyObject *format_error(PyObject *self, PyObject *args)
{
PyObject *result;
wchar_t *lpMsgBuf;
DWORD code = 0;
if (!PyArg_ParseTuple(args, "|i:FormatError", &code))
long long code = 0;

if (!PyArg_ParseTuple(args, "|L:FormatError", &code))
return NULL;

if((DWORD)code != code) {
PyErr_Format(PyExc_OverflowError, "error code %lld too big for int", code);
return NULL;
}

if (code == 0)
code = GetLastError();
lpMsgBuf = FormatError(code);
lpMsgBuf = FormatError((DWORD)code);
if (lpMsgBuf) {
result = PyUnicode_FromWideChar(lpMsgBuf, wcslen(lpMsgBuf));
LocalFree(lpMsgBuf);
Expand Down
14 changes: 10 additions & 4 deletions Objects/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1700,15 +1700,21 @@ oserror_parse_args(PyObject **p_args,
return -1;
#ifdef MS_WINDOWS
if (*winerror && PyLong_Check(*winerror)) {
long errcode, winerrcode;
long long errcode, winerrcode;
PyObject *newargs;
Py_ssize_t i;

winerrcode = PyLong_AsLong(*winerror);
winerrcode = PyLong_AsLongLong(*winerror);
if (winerrcode == -1 && PyErr_Occurred())
return -1;
errcode = winerror_to_errno(winerrcode);
*myerrno = PyLong_FromLong(errcode);

if(winerrcode < LONG_MIN || winerrcode > ULONG_MAX) {
PyErr_Format(PyExc_OverflowError, "error code %lld too big for int", winerrcode);
return -1;
}

errcode = (long long)winerror_to_errno((int)winerrcode);
*myerrno = PyLong_FromLongLong(errcode);
if (!*myerrno)
return -1;
newargs = PyTuple_New(nargs);
Expand Down