diff options
-rw-r--r-- | ChangeLog | 51 | ||||
-rw-r--r-- | NEWS | 20 | ||||
-rw-r--r-- | _dbus_bindings/message-append.c | 116 | ||||
-rw-r--r-- | config.h.in | 3 | ||||
-rwxr-xr-x | configure | 38 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | dbus/_version.py | 4 | ||||
-rwxr-xr-x | test/test-standalone.py | 61 |
8 files changed, 252 insertions, 47 deletions
@@ -1,3 +1,54 @@ +commit f6066573d25508f5cbbc5c12254086d419bb8828 +Author: Simon McVittie <simon.mcvittie@collabora.co.uk> +Date: 2012-06-25 17:01:51 +0100 + + fd.o #40817: validate UTF-8 according to the same rules as libdbus + + NEWS | 8 +++ + _dbus_bindings/message-append.c | 102 ++++++++++++++++++++++++++++----------- + configure.ac | 4 ++ + test/test-standalone.py | 59 +++++++++++++++++++++- + 4 files changed, 143 insertions(+), 30 deletions(-) + +commit 4a0f4379d4a5783d576aec90019a39459eff007d +Author: Simon McVittie <simon.mcvittie@collabora.co.uk> +Date: 2012-06-05 19:39:20 +0100 + + NEWS + + NEWS | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +commit 6ff89bf0d05a550cf1aff2053579fc1f0192cd97 +Author: Simon McVittie <simon.mcvittie@collabora.co.uk> +Date: 2012-06-05 19:07:51 +0100 + + Py3: correctly guess the signature of ObjectPath(...) and Signature(...) + + Under Python 2, ObjectPath and Signature are subtypes of str (= bytes), + and the existing type-guessing worked. + + The type-guessing code assumed that all unicode objects were just + strings, but that assumption became false in the Python 3 port: + ObjectPath and Signature are still subtypes of str, but str now means + unicode, not bytes. + + Bug: https://bugs.freedesktop.org/show_bug.cgi?id=50740 + + _dbus_bindings/message-append.c | 14 ++++++++++++-- + test/test-standalone.py | 2 ++ + 2 files changed, 14 insertions(+), 2 deletions(-) + +commit 2f08b9e644c8530c4d324c4bd9d8a0cdb24edc92 +Author: Simon McVittie <simon.mcvittie@collabora.co.uk> +Date: 2012-05-09 17:50:59 +0100 + + Back to unreleased status + + NEWS | 5 +++++ + configure.ac | 2 +- + 2 files changed, 6 insertions(+), 1 deletion(-) + commit 4a4bce958b3257b7cb2adc050022879660aface1 Author: Simon McVittie <simon.mcvittie@collabora.co.uk> Date: 2012-05-09 15:47:48 +0100 @@ -1,3 +1,23 @@ +D-Bus Python Bindings 1.1.1 (2012-06-25) +======================================== + +The "Lemonade Sky" release. + +Dependencies: + +* libdbus 1.6 or later is now recommended. It is not strictly required yet. + +Fixes: + +• Validate UTF-8 according to the rules libdbus uses, falling back to our + own (inefficient) implementation if not compiled against dbus >= 1.6 + (fd.o #40817) + +• Under Python 3, in the absence of introspection or signature='...', + pass dbus.ObjectPath or dbus.Signature arguments with the obvious + signature 'o' or 'g', not 's'. This previously only worked in Python 2. + (fd.o #50740) + D-Bus Python Bindings 1.1.0 (2012-05-09) ======================================== diff --git a/_dbus_bindings/message-append.c b/_dbus_bindings/message-append.c index f4f843b..e519ae2 100644 --- a/_dbus_bindings/message-append.c +++ b/_dbus_bindings/message-append.c @@ -249,8 +249,16 @@ _signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr) return NATIVESTR_FROMSTR(DBUS_TYPE_INT64_AS_STRING); } #endif /* PY3 */ - else if (PyUnicode_Check(obj)) - return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING); + else if (PyUnicode_Check(obj)) { + /* Object paths and signatures are unicode subtypes in Python 3 + * (the first two cases will never be true in Python 2) */ + if (DBusPyObjectPath_Check(obj)) + return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING); + else if (DBusPySignature_Check(obj)) + return NATIVESTR_FROMSTR(DBUS_TYPE_SIGNATURE_AS_STRING); + else + return NATIVESTR_FROMSTR(DBUS_TYPE_STRING_AS_STRING); + } #if defined(DBUS_TYPE_UNIX_FD) else if (DBusPyUnixFd_Check(obj)) return NATIVESTR_FROMSTR(DBUS_TYPE_UNIX_FD_AS_STRING); @@ -266,6 +274,8 @@ _signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr) return NATIVESTR_FROMSTR(DBUS_TYPE_DOUBLE_AS_STRING); } else if (PyBytes_Check(obj)) { + /* Object paths and signatures are bytes subtypes in Python 2 + * (the first two cases will never be true in Python 3) */ if (DBusPyObjectPath_Check(obj)) return NATIVESTR_FROMSTR(DBUS_TYPE_OBJECT_PATH_AS_STRING); else if (DBusPySignature_Check(obj)) @@ -521,6 +531,7 @@ _message_iter_append_string(DBusMessageIter *appender, dbus_bool_t allow_object_path_attr) { char *s; + PyObject *utf8; if (sig_type == DBUS_TYPE_OBJECT_PATH && allow_object_path_attr) { PyObject *object_path = get_object_path (obj); @@ -540,44 +551,87 @@ _message_iter_append_string(DBusMessageIter *appender, } if (PyBytes_Check(obj)) { - PyObject *unicode; - - /* Raise TypeError if the string has embedded NULs */ - if (PyBytes_AsStringAndSize(obj, &s, NULL) < 0) return -1; - /* Surely there's a faster stdlib way to validate UTF-8... */ - unicode = PyUnicode_DecodeUTF8(s, PyBytes_GET_SIZE(obj), NULL); - if (!unicode) { - PyErr_SetString(PyExc_UnicodeError, "String parameters " - "to be sent over D-Bus must be valid UTF-8"); - return -1; - } - Py_CLEAR(unicode); - - DBG("Performing actual append: string %s", s); - if (!dbus_message_iter_append_basic(appender, sig_type, - &s)) { - PyErr_NoMemory(); - return -1; - } + utf8 = obj; + Py_INCREF(obj); } else if (PyUnicode_Check(obj)) { - PyObject *utf8 = PyUnicode_AsUTF8String(obj); + utf8 = PyUnicode_AsUTF8String(obj); if (!utf8) return -1; - /* Raise TypeError if the string has embedded NULs */ - if (PyBytes_AsStringAndSize(utf8, &s, NULL) < 0) return -1; - DBG("Performing actual append: string (from unicode) %s", s); - if (!dbus_message_iter_append_basic(appender, sig_type, &s)) { - Py_CLEAR(utf8); - PyErr_NoMemory(); - return -1; - } - Py_CLEAR(utf8); } else { PyErr_SetString(PyExc_TypeError, "Expected a string or unicode object"); return -1; } + + /* Raise TypeError if the string has embedded NULs */ + if (PyBytes_AsStringAndSize(utf8, &s, NULL) < 0) + return -1; + + /* Validate UTF-8, strictly */ +#ifdef HAVE_DBUS_VALIDATE_UTF8 + if (!dbus_validate_utf8(s, NULL)) { + PyErr_SetString(PyExc_UnicodeError, "String parameters " + "to be sent over D-Bus must be valid UTF-8 " + "with no noncharacter code points"); + return -1; + } +#else + { + PyObject *back_to_unicode; + PyObject *utf32; + Py_ssize_t i; + + /* This checks for syntactically valid UTF-8, but does not check + * for noncharacters (U+nFFFE, U+nFFFF for any n, or U+FDD0..U+FDEF). + */ + back_to_unicode = PyUnicode_DecodeUTF8(s, PyBytes_GET_SIZE(utf8), + "strict"); + + if (!back_to_unicode) { + return -1; + } + + utf32 = PyUnicode_AsUTF32String(back_to_unicode); + Py_CLEAR(back_to_unicode); + + if (!utf32) { + return -1; + } + + for (i = 0; i < PyBytes_GET_SIZE(utf32) / 4; i++) { + dbus_uint32_t *p; + + p = (dbus_uint32_t *) (PyBytes_AS_STRING(utf32)) + i; + + if (/* noncharacters U+nFFFE, U+nFFFF */ + (*p & 0xFFFF) == 0xFFFE || + (*p & 0xFFFF) == 0xFFFF || + /* noncharacters U+FDD0..U+FDEF */ + (*p >= 0xFDD0 && *p <= 0xFDEF) || + /* surrogates U+D800..U+DBFF (low), U+DC00..U+DFFF (high) */ + (*p >= 0xD800 && *p <= 0xDFFF) || + (*p >= 0x110000)) { + Py_CLEAR(utf32); + PyErr_SetString(PyExc_UnicodeError, "String parameters " + "to be sent over D-Bus must be valid UTF-8 " + "with no noncharacter code points"); + return -1; + } + } + + Py_CLEAR(utf32); + } +#endif + + DBG("Performing actual append: string (from unicode) %s", s); + if (!dbus_message_iter_append_basic(appender, sig_type, &s)) { + Py_CLEAR(utf8); + PyErr_NoMemory(); + return -1; + } + + Py_CLEAR(utf8); return 0; } diff --git a/config.h.in b/config.h.in index 31ae1f1..72d1bc1 100644 --- a/config.h.in +++ b/config.h.in @@ -12,6 +12,9 @@ /* Define to 1 if the system has the type `DBusBasicValue'. */ #undef HAVE_DBUSBASICVALUE +/* Define to 1 if you have the `dbus_validate_utf8' function. */ +#undef HAVE_DBUS_VALIDATE_UTF8 + /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for dbus-python 1.1.0. +# Generated by GNU Autoconf 2.69 for dbus-python 1.1.1. # # Report bugs to <http://bugs.freedesktop.org/enter_bug.cgi?product=dbus&component=python>. # @@ -591,8 +591,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='dbus-python' PACKAGE_TARNAME='dbus-python' -PACKAGE_VERSION='1.1.0' -PACKAGE_STRING='dbus-python 1.1.0' +PACKAGE_VERSION='1.1.1' +PACKAGE_STRING='dbus-python 1.1.1' PACKAGE_BUGREPORT='http://bugs.freedesktop.org/enter_bug.cgi?product=dbus&component=python' PACKAGE_URL='' @@ -1356,7 +1356,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures dbus-python 1.1.0 to adapt to many kinds of systems. +\`configure' configures dbus-python 1.1.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1426,7 +1426,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dbus-python 1.1.0:";; + short | recursive ) echo "Configuration of dbus-python 1.1.1:";; esac cat <<\_ACEOF @@ -1554,7 +1554,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dbus-python configure 1.1.0 +dbus-python configure 1.1.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1886,7 +1886,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dbus-python $as_me 1.1.0, which was +It was created by dbus-python $as_me 1.1.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2286,9 +2286,9 @@ $as_echo "#define DBUS_PYTHON_MINOR_VERSION 1" >>confdefs.h DBUS_PYTHON_MINOR_VERSION=1 -$as_echo "#define DBUS_PYTHON_MICRO_VERSION 0" >>confdefs.h +$as_echo "#define DBUS_PYTHON_MICRO_VERSION 1" >>confdefs.h -DBUS_PYTHON_MICRO_VERSION=0 +DBUS_PYTHON_MICRO_VERSION=1 @@ -2762,7 +2762,7 @@ fi # Define the identity of the package. PACKAGE='dbus-python' - VERSION='1.1.0' + VERSION='1.1.1' cat >>confdefs.h <<_ACEOF @@ -12509,7 +12509,9 @@ $as_echo "yes" >&6; } fi dbuspy_save_CFLAGS="$CFLAGS" +dbuspy_save_LIBS="$LIBS" CFLAGS="$CFLAGS $DBUS_CFLAGS" +LIBS="$CFLAGS $DBUS_LIBS" ac_fn_c_check_type "$LINENO" "DBusBasicValue" "ac_cv_type_DBusBasicValue" "#include <dbus/dbus.h> " if test "x$ac_cv_type_DBusBasicValue" = xyes; then : @@ -12521,7 +12523,19 @@ _ACEOF fi +for ac_func in dbus_validate_utf8 +do : + ac_fn_c_check_func "$LINENO" "dbus_validate_utf8" "ac_cv_func_dbus_validate_utf8" +if test "x$ac_cv_func_dbus_validate_utf8" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DBUS_VALIDATE_UTF8 1 +_ACEOF + +fi +done + CFLAGS="$dbuspy_save_CFLAGS" +LIBS="$dbuspy_save_LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if compiler understands " >&5 @@ -13373,7 +13387,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by dbus-python $as_me 1.1.0, which was +This file was extended by dbus-python $as_me 1.1.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13439,7 +13453,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -dbus-python config.status 1.1.0 +dbus-python config.status 1.1.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 19b9a5b..1ce8965 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ m4_define(dbus_python_released, 1) dnl The dbus-python version number (must actually be numeric at the moment) m4_define(dbus_python_major_version, 1) m4_define(dbus_python_minor_version, 1) -m4_define(dbus_python_micro_version, 0) +m4_define(dbus_python_micro_version, 1) m4_define(dbus_python_maybe_datestamp, m4_esyscmd([if test x]dbus_python_released[ != x1; then date +.%Y%m%d | tr -d '\n\r'; fi])) @@ -158,9 +158,13 @@ PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.4]) PKG_CHECK_MODULES(DBUS_GLIB, [dbus-glib-1 >= 0.70]) dbuspy_save_CFLAGS="$CFLAGS" +dbuspy_save_LIBS="$LIBS" CFLAGS="$CFLAGS $DBUS_CFLAGS" +LIBS="$CFLAGS $DBUS_LIBS" AC_CHECK_TYPES([DBusBasicValue], [], [], [#include <dbus/dbus.h>]) +AC_CHECK_FUNCS([dbus_validate_utf8]) CFLAGS="$dbuspy_save_CFLAGS" +LIBS="$dbuspy_save_LIBS" TP_COMPILER_WARNINGS([CFLAGS_WARNINGS], [test] dbus_python_released [= 0], [all \ diff --git a/dbus/_version.py b/dbus/_version.py index 491f95f..4a304ed 100644 --- a/dbus/_version.py +++ b/dbus/_version.py @@ -1,3 +1,3 @@ # dbus/_version.py. Generated from _version.py.in by configure. -version = (1, 1, 0) -__version__ = "1.1.0" +version = (1, 1, 1) +__version__ = "1.1.1" diff --git a/test/test-standalone.py b/test/test-standalone.py index 95b636a..584ba4f 100755 --- a/test/test-standalone.py +++ b/test/test-standalone.py @@ -322,6 +322,8 @@ class TestMessageMarshalling(unittest.TestCase): aeq(Message.guess_signature(('a',)), '(s)') aeq(Message.guess_signature(['a']), 'as') aeq(Message.guess_signature({'a':'b'}), 'a{ss}') + aeq(Message.guess_signature(types.ObjectPath('/')), 'o') + aeq(Message.guess_signature(types.Signature('x')), 'g') def test_guess_signature_python_ints(self): aeq = self.assertEqual @@ -421,6 +423,64 @@ class TestMessageMarshalling(unittest.TestCase): raise AssertionError('Appending too many things in a struct ' 'should fail') + def test_utf8(self): + from _dbus_bindings import SignalMessage + if is_py3: + def utf8(*xs): + return bytes(xs) + def uni(x): + return chr(x) + else: + def utf8(*xs): + return str('').join(map(chr, xs)) + def uni(x): + return unichr(x) + for bad in [ + uni(0xD800), + utf8(0xed, 0xa0, 0x80), + uni(0xFDD0), + utf8(0xef, 0xb7, 0x90), + uni(0xFDD7), + utf8(0xef, 0xb7, 0x97), + uni(0xFDEF), + utf8(0xef, 0xb7, 0xaf), + uni(0xFFFE), + utf8(0xef, 0xbf, 0xbe), + uni(0xFFFF), + utf8(0xef, 0xbf, 0xbf), + uni(0x0001FFFE), + utf8(0xf0, 0x9f, 0xbf, 0xbe), + uni(0x0001FFFF), + utf8(0xf0, 0x9f, 0xbf, 0xbf), + uni(0x0007FFFE), + utf8(0xf1, 0xbf, 0xbf, 0xbe), + uni(0x0007FFFF), + utf8(0xf1, 0xbf, 0xbf, 0xbf), + uni(0x0010FFFE), + utf8(0xf4, 0x8f, 0xbf, 0xbe), + uni(0x0010FFFF), + utf8(0xf4, 0x8f, 0xbf, 0xbf), + ]: + s = SignalMessage('/', 'foo.bar', 'baz') + try: + s.append(bad, signature='s') + except UnicodeError: + pass + else: + raise AssertionError('Appending %r should fail' % bad) + for good in [ + uni(0xfdcf), + uni(0xfdf0), + uni(0xfeff), + uni(0x0001feff), + uni(0x00020000), + uni(0x0007feff), + uni(0x00080000), + uni(0x0010feff), + ]: + s = SignalMessage('/', 'foo.bar', 'baz') + s.append(good, signature='s') + s.append(good.encode('utf-8'), signature='s') class TestMatching(unittest.TestCase): def setUp(self): @@ -440,7 +500,6 @@ class TestMatching(unittest.TestCase): self._message.append('/', signature='o') self.assertFalse(self._match.maybe_handle_message(self._message)) - if __name__ == '__main__': # Python 2.6 doesn't accept a `verbosity` keyword. kwargs = {} |