Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r3254:1af377542a51
Date: 2019-04-02 15:42 +0200
http://bitbucket.org/cffi/cffi/changeset/1af377542a51/

Log:    merge heads

diff --git a/cffi/_embedding.h b/cffi/_embedding.h
--- a/cffi/_embedding.h
+++ b/cffi/_embedding.h
@@ -169,8 +169,10 @@
     global_dict = PyDict_New();
     if (global_dict == NULL)
         goto error;
-    if (PyDict_SetItemString(global_dict, "__builtins__",
-                             PyThreadState_GET()->interp->builtins) < 0)
+    PyObject *builtins = PyEval_GetBuiltins();
+    if (builtins == NULL)
+        goto error;
+    if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0)
         goto error;
     x = PyEval_EvalCode(
 #if PY_MAJOR_VERSION < 3
@@ -263,23 +265,33 @@
        So we use a global variable as a simple spin lock.  This global
        variable must be from 'libpythonX.Y.so', not from this
        cffi-based extension module, because it must be shared from
-       different cffi-based extension modules.  We choose
+       different cffi-based extension modules.
+
+       In Python < 3.8, we choose
        _PyParser_TokenNames[0] as a completely arbitrary pointer value
        that is never written to.  The default is to point to the
        string "ENDMARKER".  We change it temporarily to point to the
        next character in that string.  (Yes, I know it's REALLY
        obscure.)
+
+       In Python >= 3.8, this string array is no longer writable, so
+       instead we pick PyCapsuleType.tp_version_tag.  We can't change
+       Python < 3.8 because someone might use a mixture of cffi
+       embedded modules, some of which were compiled before this file
+       changed.
     */
 
 #ifdef WITH_THREAD
+# if PY_VERSION_HEX < 0x03080000
     char *volatile *lock = (char *volatile *)_PyParser_TokenNames;
-    char *old_value;
+    char *old_value, *locked_value;
 
     while (1) {    /* spin loop */
         old_value = *lock;
+        locked_value = old_value + 1;
         if (old_value[0] == 'E') {
             assert(old_value[1] == 'N');
-            if (cffi_compare_and_swap(lock, old_value, old_value + 1))
+            if (cffi_compare_and_swap(lock, old_value, locked_value))
                 break;
         }
         else {
@@ -290,6 +302,27 @@
                this is only run at start-up anyway. */
         }
     }
+# else
+    int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag;
+    int old_value, locked_value;
+    assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG));
+
+    while (1) {    /* spin loop */
+        old_value = *lock;
+        locked_value = -42;
+        if (old_value == 0) {
+            if (cffi_compare_and_swap(lock, old_value, locked_value))
+                break;
+        }
+        else {
+            assert(old_value == locked_value);
+            /* should ideally do a spin loop instruction here, but
+               hard to do it portably and doesn't really matter I
+               think: PyEval_InitThreads() should be very fast, and
+               this is only run at start-up anyway. */
+        }
+    }
+# endif
 #endif
 
     /* call Py_InitializeEx() */
@@ -306,7 +339,7 @@
 
 #ifdef WITH_THREAD
     /* release the lock */
-    while (!cffi_compare_and_swap(lock, old_value + 1, old_value))
+    while (!cffi_compare_and_swap(lock, locked_value, old_value))
         ;
 #endif
 
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -817,12 +817,20 @@
         # or positive/negative number
         if isinstance(exprnode, pycparser.c_ast.Constant):
             s = exprnode.value
-            if s.startswith('0'):
-                if s.startswith('0x') or s.startswith('0X'):
-                    return int(s, 16)
-                return int(s, 8)
-            elif '1' <= s[0] <= '9':
-                return int(s, 10)
+            if '0' <= s[0] <= '9':
+                s = s.rstrip('uUlL')
+                try:
+                    if s.startswith('0'):
+                        return int(s, 8)
+                    else:
+                        return int(s, 10)
+                except ValueError:
+                    if len(s) > 1:
+                        if s.lower()[0:2] == '0x':
+                            return int(s, 16)
+                        elif s.lower()[0:2] == '0b':
+                            return int(s, 2)
+                raise CDefError("invalid constant %r" % (s,))
             elif s[0] == "'" and s[-1] == "'" and (
                     len(s) == 3 or (len(s) == 4 and s[1] == "\\")):
                 return ord(s[-2])
diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py
--- a/testing/cffi0/test_parsing.py
+++ b/testing/cffi0/test_parsing.py
@@ -466,3 +466,40 @@
     e = py.test.raises(CDefError, ffi.cdef, 'void foo(void) {}')
     assert str(e.value) == ('<cdef source string>:1: unexpected <FuncDef>: '
                             'this construct is valid C but not valid in 
cdef()')
+
+def test_unsigned_int_suffix_for_constant():
+    ffi = FFI()
+    ffi.cdef("""enum e {
+                    bin_0=0b10,
+                    bin_1=0b10u,
+                    bin_2=0b10U,
+                    bin_3=0b10l,
+                    bin_4=0b10L,
+                    bin_5=0b10ll,
+                    bin_6=0b10LL,
+                    oct_0=010,
+                    oct_1=010u,
+                    oct_2=010U,
+                    oct_3=010l,
+                    oct_4=010L,
+                    oct_5=010ll,
+                    oct_6=010LL,
+                    dec_0=10,
+                    dec_1=10u,
+                    dec_2=10U,
+                    dec_3=10l,
+                    dec_4=10L,
+                    dec_5=10ll,
+                    dec_6=10LL,
+                    hex_0=0x10,
+                    hex_1=0x10u,
+                    hex_2=0x10U,
+                    hex_3=0x10l,
+                    hex_4=0x10L,
+                    hex_5=0x10ll,
+                    hex_6=0x10LL,};""")
+    needs_dlopen_none()
+    C = ffi.dlopen(None)
+    for base, expected_result in (('bin', 2), ('oct', 8), ('dec', 10), ('hex', 
16)):
+        for index in range(7):
+            assert getattr(C, '{base}_{index}'.format(base=base, index=index)) 
== expected_result
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -21,7 +21,8 @@
         extra_compile_args.append('-Qunused-arguments')
     else:
         # assume a standard gcc
-        extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion']
+        extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
+                              '-Wno-unused-parameter']
 
     class FFI(FFI):
         def verify(self, *args, **kwds):
@@ -2104,6 +2105,11 @@
             raise errors[0][1]
 
 def test_errno_working_even_with_pypys_jit():
+    # NOTE: on some platforms, to work correctly, this test needs to be
+    # compiled with -pthread.  Otherwise, the accesses to errno done from f()
+    # are compiled by assuming this small library won't be used from multiple
+    # threads, which is wrong.  If you see failures _and_ if you pass your
+    # own CFLAGS environment variable, please make sure "-pthread" is in it.
     ffi = FFI()
     ffi.cdef("int f(int);")
     lib = ffi.verify("""
diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -23,7 +23,8 @@
         extra_compile_args.append('-Qunused-arguments')
     else:
         # assume a standard gcc
-        extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion']
+        extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
+                              '-Wno-unused-parameter']
 
 class FFI(FFI):
     error = _cffi_backend.FFI.error
diff --git a/testing/embedding/test_basic.py b/testing/embedding/test_basic.py
--- a/testing/embedding/test_basic.py
+++ b/testing/embedding/test_basic.py
@@ -172,7 +172,8 @@
         result = popen.stdout.read()
         err = popen.wait()
         if err:
-            raise OSError("%r failed with exit code %r" % (name, err))
+            raise OSError("%r failed with exit code %r" % (
+                os.path.join(path, executable_name), err))
         return result
 
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to