summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog51
-rw-r--r--NEWS20
-rw-r--r--_dbus_bindings/message-append.c116
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure38
-rw-r--r--configure.ac6
-rw-r--r--dbus/_version.py4
-rwxr-xr-xtest/test-standalone.py61
8 files changed, 252 insertions, 47 deletions
diff --git a/ChangeLog b/ChangeLog
index 325995a..3c62eed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 8d6c32f..4ab62bf 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/configure b/configure
index 4588c8b..1198f36 100755
--- a/configure
+++ b/configure
@@ -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 = {}