Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r2768:7c0b1fadb4da Date: 2016-09-15 08:39 +0200 http://bitbucket.org/cffi/cffi/changeset/7c0b1fadb4da/
Log: Warn when implicitly casting between "char *" and a different pointer type, like C does (there is no special-case of "char *" in C) diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -128,7 +128,7 @@ #define CT_VOID 512 /* void */ /* other flags that may also be set in addition to the base flag: */ -#define CT_CAST_ANYTHING 1024 /* 'char *' and 'void *' only */ +#define CT_IS_VOIDCHAR_PTR 1024 #define CT_PRIMITIVE_FITS_LONG 2048 #define CT_IS_OPAQUE 4096 #define CT_IS_ENUM 8192 @@ -1358,9 +1358,26 @@ } } if (ctinit != ct) { - if ((ct->ct_flags & CT_CAST_ANYTHING) || - (ctinit->ct_flags & CT_CAST_ANYTHING)) - ; /* accept void* or char* as either source or target */ + int combined_flags = ct->ct_flags | ctinit->ct_flags; + if (combined_flags & CT_IS_VOID_PTR) + ; /* accept "void *" as either source or target */ + else if (combined_flags & CT_IS_VOIDCHAR_PTR) { + /* for backward compatibility, accept "char *" as either + source of target. This is not what C does, though, + so emit a warning that will eventually turn into an + error. */ + char *msg = (ct->ct_flags & CT_IS_VOIDCHAR_PTR ? + "implicit cast to 'char *' from a different pointer type: " + "will be forbidden in the future (check that the types " + "are as you expect; use an explicit ffi.cast() if they " + "are correct)" : + "implicit cast from 'char *' to a different pointer type: " + "will be forbidden in the future (check that the types " + "are as you expect; use an explicit ffi.cast() if they " + "are correct)"); + if (PyErr_WarnEx(PyExc_UserWarning, msg, 1)) + return -1; + } else { expected = "pointer to same type"; goto cannot_convert; @@ -2476,7 +2493,7 @@ if (PyBytes_Check(init)) { /* from a string: just returning the string here is fine. We assume that the C code won't modify the 'char *' data. */ - if ((ctptr->ct_flags & CT_CAST_ANYTHING) || + if ((ctptr->ct_flags & CT_IS_VOIDCHAR_PTR) || ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) && (ctitem->ct_size == sizeof(char)))) { #if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) @@ -3929,7 +3946,7 @@ if ((ctitem->ct_flags & CT_VOID) || ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) && ctitem->ct_size == sizeof(char))) - td->ct_flags |= CT_CAST_ANYTHING; /* 'void *' or 'char *' only */ + td->ct_flags |= CT_IS_VOIDCHAR_PTR; /* 'void *' or 'char *' only */ unique_key[0] = ctitem; return get_unique_type(td, unique_key, 1); } @@ -5903,7 +5920,7 @@ return NULL; } ct = ((CDataObject *)arg)->c_type; - if (!(ct->ct_flags & CT_CAST_ANYTHING)) { + if (!(ct->ct_flags & CT_IS_VOIDCHAR_PTR)) { PyErr_Format(PyExc_TypeError, "expected a 'cdata' object with a 'void *' out of " "new_handle(), got '%s'", ct->ct_name); diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -3676,3 +3676,25 @@ check_dir(pp, []) check_dir(pp[0], ['a1', 'a2']) check_dir(pp[0][0], ['a1', 'a2']) + +def test_char_pointer_conversion(): + import warnings + BCharP = new_pointer_type(new_primitive_type("char")) + BIntP = new_pointer_type(new_primitive_type("int")) + BVoidP = new_pointer_type(new_void_type()) + z1 = cast(BCharP, 0) + z2 = cast(BIntP, 0) + z3 = cast(BVoidP, 0) + with warnings.catch_warnings(record=True) as w: + newp(new_pointer_type(BIntP), z1) # warn + assert len(w) == 1 + newp(new_pointer_type(BVoidP), z1) # fine + assert len(w) == 1 + newp(new_pointer_type(BCharP), z2) # warn + assert len(w) == 2 + newp(new_pointer_type(BVoidP), z2) # fine + assert len(w) == 2 + newp(new_pointer_type(BCharP), z3) # fine + assert len(w) == 2 + newp(new_pointer_type(BIntP), z3) # fine + assert len(w) == 2 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit