[pypy-commit] pypy default: Fix the out-of-range cases of socket.ntohl() & co., as an

arigo pypy.commits at gmail.com
Mon Jan 2 10:20:55 EST 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r89300:f934a882b7ba
Date: 2017-01-02 16:20 +0100
http://bitbucket.org/pypy/pypy/changeset/f934a882b7ba/

Log:	Fix the out-of-range cases of socket.ntohl() & co., as an attempt to
	pass the stricter tests of py3.5

diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py
--- a/pypy/module/_socket/interp_func.py
+++ b/pypy/module/_socket/interp_func.py
@@ -1,6 +1,6 @@
 from rpython.rlib import rsocket
 from rpython.rlib.rsocket import SocketError, INVALID_SOCKET
-from rpython.rlib.rarithmetic import intmask
+from rpython.rlib.rarithmetic import intmask, r_longlong, r_uint32
 
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
@@ -164,40 +164,58 @@
         space.wrap(W_Socket(space, sock2))
     ])
 
-# The following 4 functions refuse all negative numbers, like CPython 2.6.
-# They could also check that the argument is not too large, but CPython 2.6
-# is not doing that consistently.
- at unwrap_spec(x="c_uint")
+# The following 4 functions refuse all negative numbers.
+# They also check that the argument is not too large, but note that
+# CPython 2.7 is not doing that consistently (CPython 3.x does).
+LONGLONG_UINT32_MAX = r_longlong(2**32-1)
+
+ at unwrap_spec(x="c_int")
 def ntohs(space, x):
     """ntohs(integer) -> integer
 
     Convert a 16-bit integer from network to host byte order.
     """
+    if x < 0:
+        raise oefmt(space.w_OverflowError,
+                    "can't convert negative number to unsigned long")
     return space.wrap(rsocket.ntohs(intmask(x)))
 
- at unwrap_spec(x="c_uint")
+ at unwrap_spec(x=r_longlong)
 def ntohl(space, x):
     """ntohl(integer) -> integer
 
     Convert a 32-bit integer from network to host byte order.
     """
-    return space.wrap(rsocket.ntohl(x))
+    if x < r_longlong(0):
+        raise oefmt(space.w_OverflowError,
+                    "can't convert negative number to unsigned long")
+    if x > LONGLONG_UINT32_MAX:
+        raise oefmt(space.w_OverflowError, "long int larger than 32 bits")
+    return space.wrap(rsocket.ntohl(r_uint32(x)))
 
- at unwrap_spec(x="c_uint")
+ at unwrap_spec(x="c_int")
 def htons(space, x):
     """htons(integer) -> integer
 
     Convert a 16-bit integer from host to network byte order.
     """
-    return space.wrap(rsocket.htons(intmask(x)))
+    if x < 0:
+        raise oefmt(space.w_OverflowError,
+                    "can't convert negative number to unsigned long")
+    return space.wrap(rsocket.htons(x))
 
- at unwrap_spec(x="c_uint")
+ at unwrap_spec(x=r_longlong)
 def htonl(space, x):
     """htonl(integer) -> integer
 
     Convert a 32-bit integer from host to network byte order.
     """
-    return space.wrap(rsocket.htonl(x))
+    if x < r_longlong(0):
+        raise oefmt(space.w_OverflowError,
+                    "can't convert negative number to unsigned long")
+    if x > LONGLONG_UINT32_MAX:
+        raise oefmt(space.w_OverflowError, "long int larger than 32 bits")
+    return space.wrap(rsocket.htonl(r_uint32(x)))
 
 @unwrap_spec(ip=str)
 def inet_aton(space, ip):
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -320,9 +320,10 @@
         assert _socket.socket.__name__ == 'socket'
         assert _socket.socket.__module__ == '_socket'
 
-    def test_getservbyport(self):
+    def test_overflow_errors(self):
         import _socket
         raises(OverflowError, _socket.getservbyport, -1)
+        raises(OverflowError, _socket.getservbyport, 65536)
 
     def test_ntoa_exception(self):
         import _socket
@@ -518,44 +519,25 @@
     def test_NtoH(self):
         import sys
         import _socket as socket
-        # This just checks that htons etc. are their own inverse,
-        # when looking at the lower 16 or 32 bits.
+        # This checks that htons etc. are their own inverse,
+        # when looking at the lower 16 or 32 bits.  It also
+        # checks that we get OverflowErrors when calling with -1,
+        # or (for XtoXl()) with too large values.  For XtoXs()
+        # large values are silently truncated instead, like CPython.
         sizes = {socket.htonl: 32, socket.ntohl: 32,
                  socket.htons: 16, socket.ntohs: 16}
         for func, size in sizes.items():
             mask = (1 << size) - 1
-            for i in (0, 1, 0xffff, ~0xffff, 2, 0x01234567, 0x76543210):
+            for i in (0, 1, 0xffff, 0xffff0000, 2, 0x01234567, 0x76543210):
                 assert i & mask == func(func(i&mask)) & mask
 
             swapped = func(mask)
             assert swapped & mask == mask
-            try:
-                func(-1)
-            except (OverflowError, ValueError):
-                pass
-            else:
-                assert False
-            try:
-                func(sys.maxint*2+2)
-            except OverflowError:
-                pass
-            else:
-                assert False
-
-    def test_NtoH_overflow(self):
-        skip("we are not checking for overflowing values yet")
-        import _socket as socket
-        # Checks that we cannot give too large values to htons etc.
-        # Skipped for now; CPython 2.6 is also not consistent.
-        sizes = {socket.htonl: 32, socket.ntohl: 32,
-                 socket.htons: 16, socket.ntohs: 16}
-        for func, size in sizes.items():
-            try:
-                func(1 << size)
-            except OverflowError:
-                pass
-            else:
-                assert False
+            raises(OverflowError, func, -1)
+            raises(OverflowError, func, -1L)
+            if size > 16:    # else, values too large are ignored
+                raises(OverflowError, func, 2 ** size)
+                raises(OverflowError, func, 2L ** size)
 
     def test_newsocket(self):
         import socket


More information about the pypy-commit mailing list