[pypy-commit] cffi default: Enum types are always 'int' so far. Detect overflows.

arigo noreply at buildbot.pypy.org
Wed Oct 10 09:27:27 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r996:edd85beeb288
Date: 2012-10-10 09:25 +0200
http://bitbucket.org/cffi/cffi/changeset/edd85beeb288/

Log:	Enum types are always 'int' so far. Detect overflows.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -34,6 +34,7 @@
 # define PyText_FromString PyUnicode_FromString
 # define PyText_FromStringAndSize PyUnicode_FromStringAndSize
 # define PyText_InternInPlace PyUnicode_InternInPlace
+# define PyIntOrLong_Check PyLong_Check
 #else
 # define STR_OR_BYTES "str"
 # define PyText_Type PyString_Type
@@ -45,6 +46,7 @@
 # define PyText_FromString PyString_FromString
 # define PyText_FromStringAndSize PyString_FromStringAndSize
 # define PyText_InternInPlace PyString_InternInPlace
+# define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op))
 #endif 
 
 #if PY_MAJOR_VERSION >= 3
@@ -430,11 +432,7 @@
         if (io == NULL)
             return -1;
 
-#if PY_MAJOR_VERSION < 3
-        if (PyInt_Check(io) || PyLong_Check(io)) {
-#else
-        if (PyLong_Check(io)) {
-#endif
+        if (PyIntOrLong_Check(io)) {
             res = _my_PyLong_AsLongLong(io);
         }
         else {
@@ -487,11 +485,7 @@
         if (io == NULL)
             return (unsigned PY_LONG_LONG)-1;
 
-#if PY_MAJOR_VERSION < 3
-        if (PyInt_Check(io) || PyLong_Check(io)) {
-#else
-        if (PyLong_Check(io)) {
-#endif
+        if (PyIntOrLong_Check(io)) {
             res = _my_PyLong_AsUnsignedLongLong(io, strict);
         }
         else {
@@ -2335,11 +2329,7 @@
     if (io == NULL)
         return -1;
 
-#if PY_MAJOR_VERSION < 3
-    if (PyInt_Check(io) || PyLong_Check(io) || PyFloat_Check(io)) {
-#else
-    if (PyLong_Check(io) || PyFloat_Check(io)) {
-#endif
+    if (PyIntOrLong_Check(io) || PyFloat_Check(io)) {
         res = _my_PyObject_AsBool(io);
     }
     else {
@@ -3943,8 +3933,22 @@
     if (dict1 == NULL)
         goto error;
     for (i=n; --i >= 0; ) {
-        if (PyDict_SetItem(dict1, PyTuple_GET_ITEM(enumerators, i),
-                                  PyTuple_GET_ITEM(enumvalues, i)) < 0)
+        PyObject *key = PyTuple_GET_ITEM(enumerators, i);
+        PyObject *value = PyTuple_GET_ITEM(enumvalues, i);
+        long lvalue;
+        if (!PyText_Check(key)) {
+            PyErr_SetString(PyExc_TypeError,
+                            "enumerators must be a list of strings");
+            goto error;
+        }
+        lvalue = PyLong_AsLong(value);
+        if ((lvalue == -1 && PyErr_Occurred()) || lvalue != (int)lvalue) {
+            PyErr_Format(PyExc_OverflowError,
+                         "enum '%s' declaration for '%s' does not fit an int",
+                         ename, PyText_AS_UTF8(key));
+            goto error;
+        }
+        if (PyDict_SetItem(dict1, key, value) < 0)
             goto error;
     }
 
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1160,6 +1160,13 @@
     e = py.test.raises(TypeError, newp, BStructPtr, [None])
     assert "must be a str or int, not NoneType" in str(e.value)
 
+def test_enum_overflow():
+    for ovf in (sys.maxint+1, -sys.maxint-2, 2**31, -2**31-1):
+        e = py.test.raises(OverflowError, new_enum_type, "foo", ('a', 'b'),
+                           (5, ovf))
+        assert str(e.value) == (
+            "enum 'foo' declaration for 'b' does not fit an int")
+
 def test_callback_returning_enum():
     BInt = new_primitive_type("int")
     BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -1084,6 +1084,11 @@
   length 0, allocating a ``char[]`` of the correct size, and casting
   it to a struct pointer)
 
+* Enum types are always ``int``.  GCC supports enums containing
+  larger constants (``unsigned int``, or ``long long``) as an extension
+  to the C standard, but CFFI does not.  Use
+  ``typedef <exact type> my_enum;`` and then some ``#define foo <value>``.
+
 .. versionadded:: 0.4
    Now supported: the common GCC extension of anonymous nested
    structs/unions inside structs/unions.


More information about the pypy-commit mailing list