[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