From f85c7dc7e06b9da1c64ae6cc6a6ae810a09dc4f2 Mon Sep 17 00:00:00 2001 From: naweiss Date: Mon, 23 Jun 2025 23:50:22 +0300 Subject: [PATCH 01/10] gh-107545: Fix misleading setsockopt error message --- Modules/socketmodule.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index f3ad01854de93b..25e1e465926c5c 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3373,6 +3373,9 @@ sock_setsockopt(PyObject *self, PyObject *args) (char*)&flag, sizeof flag); goto done; } + if (!PyErr_ExceptionMatches(PyExc_TypeError)) { + return NULL; + } PyErr_Clear(); /* setsockopt(level, opt, None, flag) */ @@ -3383,6 +3386,9 @@ sock_setsockopt(PyObject *self, PyObject *args) NULL, (socklen_t)optlen); goto done; } + if (!PyErr_ExceptionMatches(PyExc_TypeError)) { + return NULL; + } PyErr_Clear(); /* setsockopt(level, opt, buffer) */ From 82be24527b8f8485cd0145478ed909829b605554 Mon Sep 17 00:00:00 2001 From: naweiss Date: Tue, 24 Jun 2025 00:03:31 +0300 Subject: [PATCH 02/10] Add tests for setsockopt errors --- Lib/test/test_socket.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 3dd67b2a2aba97..29c979b53a6720 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1538,6 +1538,31 @@ def testSetSockOpt(self): reuse = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) self.assertFalse(reuse == 0, "failed to set reuse mode") + @unittest.skipIf(_testcapi is None, "requires _testcapi") + def test_setsockopt_errors(self): + # See issue #107546. + from _testcapi import INT_MAX, INT_MIN + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(sock.close) + + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # No error expected. + + with self.assertRaises(OverflowError): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, INT_MAX + 1) + + with self.assertRaises(OverflowError): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, INT_MIN - 1) + + with self.assertRaises(OverflowError): + sock.setsockopt(socket.SOL_SOCKET, INT_MAX + 1, 1) + + with self.assertRaises(OverflowError): + sock.setsockopt(INT_MAX + 1, socket.SO_REUSEADDR, 1) + + with self.assertRaises(TypeError): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, dict()) + def testSendAfterClose(self): # testing send() after close() with timeout with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: From 167d212bb6a998cd45dfdef174680fa7c152aa22 Mon Sep 17 00:00:00 2001 From: naweiss Date: Tue, 24 Jun 2025 00:11:45 +0300 Subject: [PATCH 03/10] Add issue to news --- .../2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst new file mode 100644 index 00000000000000..3dc853987e0e0b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst @@ -0,0 +1,2 @@ +Improve error message when :meth:`~socket.socket.setsockopt` raises an error +other than a :exc:`TypeError`. From e3d4e7469626f3b0ac1d1ae23024b5205c8be977 Mon Sep 17 00:00:00 2001 From: naweiss Date: Mon, 7 Jul 2025 20:02:50 +0300 Subject: [PATCH 04/10] Cleanup setsockopt implementation --- Lib/test/test_socket.py | 11 +++---- Modules/socketmodule.c | 73 +++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 29c979b53a6720..8b13f6cdc66c74 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1538,27 +1538,24 @@ def testSetSockOpt(self): reuse = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) self.assertFalse(reuse == 0, "failed to set reuse mode") - @unittest.skipIf(_testcapi is None, "requires _testcapi") def test_setsockopt_errors(self): # See issue #107546. - from _testcapi import INT_MAX, INT_MIN - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.addCleanup(sock.close) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # No error expected. with self.assertRaises(OverflowError): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, INT_MAX + 1) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 2 ** 100) with self.assertRaises(OverflowError): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, INT_MIN - 1) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, - 2 ** 100) with self.assertRaises(OverflowError): - sock.setsockopt(socket.SOL_SOCKET, INT_MAX + 1, 1) + sock.setsockopt(socket.SOL_SOCKET, 2 ** 100, 1) with self.assertRaises(OverflowError): - sock.setsockopt(INT_MAX + 1, socket.SO_REUSEADDR, 1) + sock.setsockopt(2 ** 100, socket.SO_REUSEADDR, 1) with self.assertRaises(TypeError): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, dict()) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 25e1e465926c5c..fa92c144921551 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3338,26 +3338,32 @@ sock_setsockopt(PyObject *self, PyObject *args) Py_buffer optval; int flag; unsigned int optlen; - PyObject *none; + PyObject *type; + + if (!PyArg_ParseTuple(args, "iiO|I:setsockopt", + &level, &optname, &type, &optlen)) { + return NULL; + } #ifdef AF_VSOCK if (s->sock_family == AF_VSOCK) { uint64_t vflag; // Must be set width of 64 bits /* setsockopt(level, opt, flag) */ - if (PyArg_ParseTuple(args, "iiK:setsockopt", - &level, &optname, &vflag)) { - // level should always be set to AF_VSOCK - res = setsockopt(get_sock_fd(s), level, optname, - (void*)&vflag, sizeof vflag); - goto done; + if (!PyArg_Parse(type, "K", &vflag)) { + return NULL; } - return NULL; + // level should always be set to AF_VSOCK + res = setsockopt(get_sock_fd(s), level, optname, + (void*)&vflag, sizeof vflag); + goto done; } #endif /* setsockopt(level, opt, flag) */ - if (PyArg_ParseTuple(args, "iii:setsockopt", - &level, &optname, &flag)) { + if (PyIndex_Check(type)) { + if (!PyArg_Parse(type, "i", &flag)) { + return NULL; + } #ifdef MS_WINDOWS if (optname == SIO_TCP_SET_ACK_FREQUENCY) { DWORD dummy; @@ -3373,43 +3379,40 @@ sock_setsockopt(PyObject *self, PyObject *args) (char*)&flag, sizeof flag); goto done; } - if (!PyErr_ExceptionMatches(PyExc_TypeError)) { - return NULL; - } - PyErr_Clear(); /* setsockopt(level, opt, None, flag) */ - if (PyArg_ParseTuple(args, "iiO!I:setsockopt", - &level, &optname, Py_TYPE(Py_None), &none, &optlen)) { + if (type == Py_None) { assert(sizeof(socklen_t) >= sizeof(unsigned int)); res = setsockopt(get_sock_fd(s), level, optname, NULL, (socklen_t)optlen); goto done; } - if (!PyErr_ExceptionMatches(PyExc_TypeError)) { - return NULL; - } - PyErr_Clear(); /* setsockopt(level, opt, buffer) */ - if (!PyArg_ParseTuple(args, "iiy*:setsockopt", - &level, &optname, &optval)) - return NULL; - + if (PyObject_CheckBuffer(type)) { + if (!PyArg_Parse(type, "y*", &optval)) { + return NULL; + } #ifdef MS_WINDOWS - if (optval.len > INT_MAX) { - PyBuffer_Release(&optval); - PyErr_Format(PyExc_OverflowError, - "socket option is larger than %i bytes", - INT_MAX); - return NULL; - } - res = setsockopt(get_sock_fd(s), level, optname, - optval.buf, (int)optval.len); + if (optval.len > INT_MAX) { + PyBuffer_Release(&optval); + PyErr_Format(PyExc_OverflowError, + "socket option is larger than %i bytes", + INT_MAX); + return NULL; + } + res = setsockopt(get_sock_fd(s), level, optname, + optval.buf, (int)optval.len); #else - res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len); + res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len); #endif - PyBuffer_Release(&optval); + PyBuffer_Release(&optval); + goto done; + } + + PyErr_Format(PyExc_TypeError, + "socket option should be integer, bytes-like object or None"); + return NULL; done: if (res < 0) { From ca87487d4b05077dc3d025922a6249a725a5401c Mon Sep 17 00:00:00 2001 From: naweiss Date: Tue, 8 Jul 2025 11:16:33 +0300 Subject: [PATCH 05/10] Add clearer error messages to setsockopt --- Lib/test/test_socket.py | 15 ++++++++++- Modules/socketmodule.c | 55 +++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 8b13f6cdc66c74..4b85ceb68c18bf 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1557,9 +1557,22 @@ def test_setsockopt_errors(self): with self.assertRaises(OverflowError): sock.setsockopt(2 ** 100, socket.SO_REUSEADDR, 1) - with self.assertRaises(TypeError): + msg = "socket option should be should be integer, bytes-like object or None" + with self.assertRaises(TypeError, msg=msg): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, dict()) + msg = "setsockopt() takes 3 or 4 arguments (2 given)" + with self.assertRaises(TypeError, msg=msg): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) + + msg = "setsockopt() take 4 arguments when socket option is None (3 given)" + with self.assertRaises(TypeError, msg=msg): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, None) + + msg = "setsockopt() argument 3 must be NoneType, not int" + with self.assertRaises(TypeError, msg=msg): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2) + def testSendAfterClose(self): # testing send() after close() with timeout with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index fa92c144921551..da8d51d46fcf55 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3332,24 +3332,41 @@ sock_setsockopt(PyObject *self, PyObject *args) { PySocketSockObject *s = _PySocketSockObject_CAST(self); + Py_ssize_t arglen; int level; int optname; int res; - Py_buffer optval; + Py_buffer buffer; int flag; unsigned int optlen; - PyObject *type; + PyObject *optval; - if (!PyArg_ParseTuple(args, "iiO|I:setsockopt", - &level, &optname, &type, &optlen)) { - return NULL; + arglen = PyTuple_Size(args); + switch (arglen) { + case 3: + if (!PyArg_ParseTuple(args, "iiO:setsockopt", + &level, &optname, &optval)) { + return NULL; + } + break; + case 4: + if (!PyArg_ParseTuple(args, "iiO!I:setsockopt", + &level, &optname, Py_TYPE(Py_None), &optval, &optlen)) { + return NULL; + } + break; + default: + PyErr_Format(PyExc_TypeError, + "setsockopt() takes 3 or 4 arguments (%zd given)", + arglen); + return NULL; } #ifdef AF_VSOCK if (s->sock_family == AF_VSOCK) { uint64_t vflag; // Must be set width of 64 bits /* setsockopt(level, opt, flag) */ - if (!PyArg_Parse(type, "K", &vflag)) { + if (!PyArg_Parse(optval, "K", &vflag)) { return NULL; } // level should always be set to AF_VSOCK @@ -3360,8 +3377,8 @@ sock_setsockopt(PyObject *self, PyObject *args) #endif /* setsockopt(level, opt, flag) */ - if (PyIndex_Check(type)) { - if (!PyArg_Parse(type, "i", &flag)) { + if (PyIndex_Check(optval)) { + if (!PyArg_Parse(optval, "i", &flag)) { return NULL; } #ifdef MS_WINDOWS @@ -3381,7 +3398,13 @@ sock_setsockopt(PyObject *self, PyObject *args) } /* setsockopt(level, opt, None, flag) */ - if (type == Py_None) { + if (optval == Py_None) { + if (arglen != 4) { + PyErr_Format(PyExc_TypeError, + "setsockopt() take 4 arguments when socket option is None (%zd given)", + arglen); + return NULL; + } assert(sizeof(socklen_t) >= sizeof(unsigned int)); res = setsockopt(get_sock_fd(s), level, optname, NULL, (socklen_t)optlen); @@ -3389,24 +3412,24 @@ sock_setsockopt(PyObject *self, PyObject *args) } /* setsockopt(level, opt, buffer) */ - if (PyObject_CheckBuffer(type)) { - if (!PyArg_Parse(type, "y*", &optval)) { + if (PyObject_CheckBuffer(optval)) { + if (!PyArg_Parse(optval, "y*", &buffer)) { return NULL; } #ifdef MS_WINDOWS - if (optval.len > INT_MAX) { - PyBuffer_Release(&optval); + if (buffer.len > INT_MAX) { + PyBuffer_Release(&buffer); PyErr_Format(PyExc_OverflowError, "socket option is larger than %i bytes", INT_MAX); return NULL; } res = setsockopt(get_sock_fd(s), level, optname, - optval.buf, (int)optval.len); + buffer.buf, (int)buffer.len); #else - res = setsockopt(get_sock_fd(s), level, optname, optval.buf, optval.len); + res = setsockopt(get_sock_fd(s), level, optname, buffer.buf, buffer.len); #endif - PyBuffer_Release(&optval); + PyBuffer_Release(&buffer); goto done; } From 543c20b34cee2be4f80ea6e31d3e0d27ff9a0b40 Mon Sep 17 00:00:00 2001 From: naweiss Date: Fri, 11 Jul 2025 11:31:28 +0300 Subject: [PATCH 06/10] Simplify error checking implementation for setsockopt --- Lib/test/test_socket.py | 19 ++++++++--------- Modules/socketmodule.c | 47 ++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 4b85ceb68c18bf..927881b7fa5e7e 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1557,22 +1557,21 @@ def test_setsockopt_errors(self): with self.assertRaises(OverflowError): sock.setsockopt(2 ** 100, socket.SO_REUSEADDR, 1) - msg = "socket option should be should be integer, bytes-like object or None" - with self.assertRaises(TypeError, msg=msg): + with self.assertRaisesRegex(TypeError, "socket option should be int, bytes-like object or None"): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, dict()) - msg = "setsockopt() takes 3 or 4 arguments (2 given)" - with self.assertRaises(TypeError, msg=msg): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) - - msg = "setsockopt() take 4 arguments when socket option is None (3 given)" - with self.assertRaises(TypeError, msg=msg): + with self.assertRaisesRegex(TypeError, "take 4 arguments when socket option is None"): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, None) - msg = "setsockopt() argument 3 must be NoneType, not int" - with self.assertRaises(TypeError, msg=msg): + with self.assertRaisesRegex(TypeError, "argument 3 must be NoneType"): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2) + with self.assertRaisesRegex(TypeError, "takes at least 3 arguments"): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) + + with self.assertRaisesRegex(TypeError, "takes at most 4 arguments"): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2, 3) + def testSendAfterClose(self): # testing send() after close() with timeout with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index da8d51d46fcf55..555d251b89d72f 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3341,25 +3341,23 @@ sock_setsockopt(PyObject *self, PyObject *args) unsigned int optlen; PyObject *optval; + if (!PyArg_ParseTuple(args, "iiO|I:setsockopt", + &level, &optname, &optval, &optlen)) { + return NULL; + } + arglen = PyTuple_Size(args); - switch (arglen) { - case 3: - if (!PyArg_ParseTuple(args, "iiO:setsockopt", - &level, &optname, &optval)) { - return NULL; - } - break; - case 4: - if (!PyArg_ParseTuple(args, "iiO!I:setsockopt", - &level, &optname, Py_TYPE(Py_None), &optval, &optlen)) { - return NULL; - } - break; - default: - PyErr_Format(PyExc_TypeError, - "setsockopt() takes 3 or 4 arguments (%zd given)", - arglen); - return NULL; + if (arglen == 3 && optval == Py_None) { + PyErr_Format(PyExc_TypeError, + "setsockopt() take 4 arguments when socket option is None (%zd given)", + arglen); + return NULL; + } + if (arglen == 4 && optval != Py_None) { + PyErr_Format(PyExc_TypeError, + "setsockopt() argument 3 must be NoneType, not %s", + Py_TYPE(optval)->tp_name); + return NULL; } #ifdef AF_VSOCK @@ -3397,14 +3395,8 @@ sock_setsockopt(PyObject *self, PyObject *args) goto done; } - /* setsockopt(level, opt, None, flag) */ + /* setsockopt(level, opt, None, optlen) */ if (optval == Py_None) { - if (arglen != 4) { - PyErr_Format(PyExc_TypeError, - "setsockopt() take 4 arguments when socket option is None (%zd given)", - arglen); - return NULL; - } assert(sizeof(socklen_t) >= sizeof(unsigned int)); res = setsockopt(get_sock_fd(s), level, optname, NULL, (socklen_t)optlen); @@ -3425,7 +3417,7 @@ sock_setsockopt(PyObject *self, PyObject *args) return NULL; } res = setsockopt(get_sock_fd(s), level, optname, - buffer.buf, (int)buffer.len); + buffer.buf, (int)buffer.len); #else res = setsockopt(get_sock_fd(s), level, optname, buffer.buf, buffer.len); #endif @@ -3434,7 +3426,8 @@ sock_setsockopt(PyObject *self, PyObject *args) } PyErr_Format(PyExc_TypeError, - "socket option should be integer, bytes-like object or None"); + "socket option should be int, bytes-like object or None (got %s)", + Py_TYPE(optval)->tp_name); return NULL; done: From 2ca926dc2d8789fe0bcd35d886becd7d36f2985b Mon Sep 17 00:00:00 2001 From: naweiss Date: Fri, 11 Jul 2025 12:34:22 +0300 Subject: [PATCH 07/10] Update news entry --- .../2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst | 2 -- .../2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst | 2 ++ Modules/socketmodule.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst deleted file mode 100644 index 3dc853987e0e0b..00000000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-24-00-21-27.gh-issue-107545.GDa7Zs.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve error message when :meth:`~socket.socket.setsockopt` raises an error -other than a :exc:`TypeError`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst new file mode 100644 index 00000000000000..b3ac56a27d942e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst @@ -0,0 +1,2 @@ +Improve the error messages that may be raised by +:meth:`~socket.socket.setsockopt` diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 555d251b89d72f..4a3b09f0c21c98 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3355,8 +3355,8 @@ sock_setsockopt(PyObject *self, PyObject *args) } if (arglen == 4 && optval != Py_None) { PyErr_Format(PyExc_TypeError, - "setsockopt() argument 3 must be NoneType, not %s", - Py_TYPE(optval)->tp_name); + "setsockopt() argument 3 must be NoneType, not %T", + optval); return NULL; } @@ -3426,8 +3426,8 @@ sock_setsockopt(PyObject *self, PyObject *args) } PyErr_Format(PyExc_TypeError, - "socket option should be int, bytes-like object or None (got %s)", - Py_TYPE(optval)->tp_name); + "socket option should be int, bytes-like object or None (got %T)", + optval); return NULL; done: From 97ee4dd2158194a6888b3db52a538b5aef0b63cd Mon Sep 17 00:00:00 2001 From: naweiss Date: Tue, 15 Jul 2025 10:58:28 +0300 Subject: [PATCH 08/10] Fix some setsockopt error messages --- Lib/test/test_socket.py | 4 ++-- Modules/socketmodule.c | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 927881b7fa5e7e..76fd33c7dc8767 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1560,10 +1560,10 @@ def test_setsockopt_errors(self): with self.assertRaisesRegex(TypeError, "socket option should be int, bytes-like object or None"): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, dict()) - with self.assertRaisesRegex(TypeError, "take 4 arguments when socket option is None"): + with self.assertRaisesRegex(TypeError, "requires 4 arguments when the third argument is None"): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, None) - with self.assertRaisesRegex(TypeError, "argument 3 must be NoneType"): + with self.assertRaisesRegex(TypeError, "only takes 4 arguments when the third argument is None"): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1, 2) with self.assertRaisesRegex(TypeError, "takes at least 3 arguments"): diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 4a3b09f0c21c98..f3606182193774 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3349,19 +3349,24 @@ sock_setsockopt(PyObject *self, PyObject *args) arglen = PyTuple_Size(args); if (arglen == 3 && optval == Py_None) { PyErr_Format(PyExc_TypeError, - "setsockopt() take 4 arguments when socket option is None (%zd given)", + "setsockopt() requires 4 arguments when the third argument is None", arglen); return NULL; } if (arglen == 4 && optval != Py_None) { PyErr_Format(PyExc_TypeError, - "setsockopt() argument 3 must be NoneType, not %T", + "setsockopt() only takes 4 arguments when the third argument is None (got %T)", optval); return NULL; } #ifdef AF_VSOCK if (s->sock_family == AF_VSOCK) { + if (!PyIndex_Check(optval)) { + PyErr_Format(PyExc_TypeError, + "setsockopt() argument 3 for AF_VSOCK must be an int (got %T)", + optval); + } uint64_t vflag; // Must be set width of 64 bits /* setsockopt(level, opt, flag) */ if (!PyArg_Parse(optval, "K", &vflag)) { From de95e315995f7069b51f670cf728dceae1dfc993 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Aug 2025 12:13:45 +0300 Subject: [PATCH 09/10] Update Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst Co-authored-by: Victor Stinner --- .../2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst index b3ac56a27d942e..23122415e8a46f 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-12-29-09.gh-issue-107545.ipfl7U.rst @@ -1,2 +1,2 @@ Improve the error messages that may be raised by -:meth:`~socket.socket.setsockopt` +:meth:`~socket.socket.setsockopt`. From 9c6b8ec785f88fb1dc173764ef578c073f40d51a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Aug 2025 12:34:58 +0300 Subject: [PATCH 10/10] Fix indentation. --- Modules/socketmodule.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index f3606182193774..bca9e7bb712e38 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3342,21 +3342,22 @@ sock_setsockopt(PyObject *self, PyObject *args) PyObject *optval; if (!PyArg_ParseTuple(args, "iiO|I:setsockopt", - &level, &optname, &optval, &optlen)) { - return NULL; + &level, &optname, &optval, &optlen)) + { + return NULL; } arglen = PyTuple_Size(args); if (arglen == 3 && optval == Py_None) { PyErr_Format(PyExc_TypeError, - "setsockopt() requires 4 arguments when the third argument is None", - arglen); + "setsockopt() requires 4 arguments when the third argument is None", + arglen); return NULL; } if (arglen == 4 && optval != Py_None) { PyErr_Format(PyExc_TypeError, - "setsockopt() only takes 4 arguments when the third argument is None (got %T)", - optval); + "setsockopt() only takes 4 arguments when the third argument is None (got %T)", + optval); return NULL; } @@ -3364,9 +3365,9 @@ sock_setsockopt(PyObject *self, PyObject *args) if (s->sock_family == AF_VSOCK) { if (!PyIndex_Check(optval)) { PyErr_Format(PyExc_TypeError, - "setsockopt() argument 3 for AF_VSOCK must be an int (got %T)", - optval); - } + "setsockopt() argument 3 for AF_VSOCK must be an int (got %T)", + optval); + } uint64_t vflag; // Must be set width of 64 bits /* setsockopt(level, opt, flag) */ if (!PyArg_Parse(optval, "K", &vflag)) { @@ -3374,7 +3375,7 @@ sock_setsockopt(PyObject *self, PyObject *args) } // level should always be set to AF_VSOCK res = setsockopt(get_sock_fd(s), level, optname, - (void*)&vflag, sizeof vflag); + (void*)&vflag, sizeof vflag); goto done; } #endif @@ -3417,8 +3418,8 @@ sock_setsockopt(PyObject *self, PyObject *args) if (buffer.len > INT_MAX) { PyBuffer_Release(&buffer); PyErr_Format(PyExc_OverflowError, - "socket option is larger than %i bytes", - INT_MAX); + "socket option is larger than %i bytes", + INT_MAX); return NULL; } res = setsockopt(get_sock_fd(s), level, optname, @@ -3431,8 +3432,8 @@ sock_setsockopt(PyObject *self, PyObject *args) } PyErr_Format(PyExc_TypeError, - "socket option should be int, bytes-like object or None (got %T)", - optval); + "socket option should be int, bytes-like object or None (got %T)", + optval); return NULL; done: