[pygobject] Fix signedness, overflow checking, and 32 bit overflow of GFlags
- From: Martin Pitt <martinpitt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] Fix signedness, overflow checking, and 32 bit overflow of GFlags
- Date: Wed, 27 Feb 2013 07:59:43 +0000 (UTC)
commit caeeeb7e4282e183eefc3c53b2d53c8c2bb7de89
Author: Martin Pitt <martinpitt gnome org>
Date: Wed Feb 27 08:07:20 2013 +0100
Fix signedness, overflow checking, and 32 bit overflow of GFlags
GFlagsValue.value is a guint, so we must access it as unsigned type. Define two
new macros PYGLIB_PyLong_FromUnsignedLong() and PYGLIB_PyLong_AsUnsignedLong()
for that purpose, and consistently use them for handling flag values. Use the
checked variant of these functions which produce OverflowErrors instead
of the unchecked PYGLIB_PyLong_AS_LONG().
Insert zero padding after the PyLongObject in PyGFlags and PyGEnum. Without
this, the directly adjacent GType field seems to confuse
PyLong_FromUnsignedLong() and includes the GType into the numeric value.
https://bugzilla.gnome.org/show_bug.cgi?id=693121
gi/_glib/pyglib-python-compat.h | 8 ++++++
gi/_gobject/gobjectmodule.c | 2 +-
gi/_gobject/pygflags.c | 52 ++++++++++++++++++++++++---------------
gi/_gobject/pygobject-private.h | 10 ++++---
gi/_gobject/pygobject.h | 4 +-
gi/_gobject/pygtype.c | 6 ++--
tests/test_overrides_gdk.py | 15 +++++++++++
7 files changed, 67 insertions(+), 30 deletions(-)
---
diff --git a/gi/_glib/pyglib-python-compat.h b/gi/_glib/pyglib-python-compat.h
index 96a20c0..9ba68f7 100644
--- a/gi/_glib/pyglib-python-compat.h
+++ b/gi/_glib/pyglib-python-compat.h
@@ -137,6 +137,11 @@ static int _pyglib_init_##modname(PyObject *module)
#define PYGLIB_PyLong_AS_LONG PyInt_AS_LONG
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+/* Python 2.7 lacks a PyInt_FromUnsignedLong function; use signed longs, and
+ * rely on PyInt_AsUnsignedLong() to interpret them correctly */
+#define PYGLIB_PyLong_FromUnsignedLong PyInt_FromLong
+#define PYGLIB_PyLong_AsUnsignedLong(o) PyInt_AsUnsignedLongMask((PyObject*)(o))
+
#define PYGLIB_PyNumber_Long PyNumber_Int
#ifndef PyVarObject_HEAD_INIT
@@ -225,6 +230,9 @@ PyTypeObject symbol = { \
#define PYGLIB_PyLongObject PyLongObject
#define PYGLIB_PyLong_Type PyLong_Type
+#define PYGLIB_PyLong_FromUnsignedLong PyLong_FromUnsignedLong
+#define PYGLIB_PyLong_AsUnsignedLong(o) PyLong_AsUnsignedLongMask((PyObject*)(o))
+
#define PYGLIB_PyBytes_FromString PyBytes_FromString
#define PYGLIB_PyBytes_FromStringAndSize PyBytes_FromStringAndSize
#define PYGLIB_PyBytes_Resize(o, len) _PyBytes_Resize(o, len)
diff --git a/gi/_gobject/gobjectmodule.c b/gi/_gobject/gobjectmodule.c
index 9fb7564..c49b412 100644
--- a/gi/_gobject/gobjectmodule.c
+++ b/gi/_gobject/gobjectmodule.c
@@ -572,7 +572,7 @@ create_property (const gchar *prop_name,
return NULL;
if (pyg_flags_get_value(prop_type, pydefault,
- (gint *)&default_value))
+ &default_value))
return NULL;
pspec = g_param_spec_flags (prop_name, nick, blurb,
diff --git a/gi/_gobject/pygflags.c b/gi/_gobject/pygflags.c
index bad32c6..bb12d4a 100644
--- a/gi/_gobject/pygflags.c
+++ b/gi/_gobject/pygflags.c
@@ -3,7 +3,7 @@
* Copyright (C) 1998-2003 James Henstridge
* Copyright (C) 2004 Johan Dahlin
*
- * pygenum.c: GFlags wrapper
+ * pygflags.c: GFlags wrapper
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -40,11 +40,12 @@ pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval)
{
PyObject *args, *item;
args = Py_BuildValue("(O)", intval);
- item = (&PYGLIB_PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL);
+ g_assert(PyObject_IsSubclass(subclass, (PyObject*) &PyGFlags_Type));
+ item = PYGLIB_PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL);
Py_DECREF(args);
if (!item)
return NULL;
- ((PyGEnum*)item)->gtype = gtype;
+ ((PyGFlags*)item)->gtype = gtype;
return item;
}
@@ -70,7 +71,7 @@ pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op)
}
static char *
-generate_repr(GType gtype, int value)
+generate_repr(GType gtype, guint value)
{
GFlagsClass *flags_class;
char *retval = NULL, *tmp;
@@ -108,13 +109,13 @@ pyg_flags_repr(PyGFlags *self)
char *tmp, *retval;
PyObject *pyretval;
- tmp = generate_repr(self->gtype, PYGLIB_PyLong_AS_LONG(self));
+ tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self));
if (tmp)
retval = g_strdup_printf("<flags %s of type %s>", tmp,
g_type_name(self->gtype));
else
- retval = g_strdup_printf("<flags %ld of type %s>", PYGLIB_PyLong_AS_LONG(self),
+ retval = g_strdup_printf("<flags %ld of type %s>", PYGLIB_PyLong_AsUnsignedLong(self),
g_type_name(self->gtype));
g_free(tmp);
@@ -128,7 +129,7 @@ static PyObject *
pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "value", NULL };
- long value;
+ guint value;
PyObject *pytc, *values, *ret, *pyint;
GType gtype;
GFlagsClass *eclass;
@@ -167,7 +168,7 @@ pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
g_type_class_unref(eclass);
- pyint = PYGLIB_PyLong_FromLong(value);
+ pyint = PYGLIB_PyLong_FromUnsignedLong(value);
ret = PyDict_GetItem(values, pyint);
if (!ret) {
PyErr_Clear();
@@ -185,10 +186,13 @@ pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
}
PyObject*
-pyg_flags_from_gtype (GType gtype, int value)
+pyg_flags_from_gtype (GType gtype, guint value)
{
PyObject *pyclass, *values, *retval, *pyint;
+ if (PyErr_Occurred())
+ return PYGLIB_PyLong_FromUnsignedLong(0);
+
g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
/* Get a wrapper class by:
@@ -202,11 +206,11 @@ pyg_flags_from_gtype (GType gtype, int value)
if (!pyclass)
pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype);
if (!pyclass)
- return PYGLIB_PyLong_FromLong(value);
+ return PYGLIB_PyLong_FromUnsignedLong(value);
values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
"__flags_values__");
- pyint = PYGLIB_PyLong_FromLong(value);
+ pyint = PYGLIB_PyLong_FromUnsignedLong(value);
retval = PyDict_GetItem(values, pyint);
if (!retval) {
PyErr_Clear();
@@ -221,6 +225,10 @@ pyg_flags_from_gtype (GType gtype, int value)
return retval;
}
+/*
+ * pyg_flags_add
+ * Dynamically create a class derived from PyGFlags based on the given GType.
+ */
PyObject *
pyg_flags_add (PyObject * module,
const char * typename,
@@ -241,13 +249,16 @@ pyg_flags_add (PyObject * module,
state = pyglib_gil_state_ensure();
+ /* Create a new type derived from GFlags. This is the same as:
+ * >>> stub = type(typename, (GFlags,), {})
+ */
instance_dict = PyDict_New();
stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
typename, (PyObject *)&PyGFlags_Type,
instance_dict);
Py_DECREF(instance_dict);
if (!stub) {
- PyErr_SetString(PyExc_RuntimeError, "can't create const");
+ PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype");
pyglib_gil_state_release(state);
return NULL;
}
@@ -277,7 +288,8 @@ pyg_flags_add (PyObject * module,
for (i = 0; i < eclass->n_values; i++) {
PyObject *item, *intval;
- intval = PYGLIB_PyLong_FromLong(eclass->values[i].value);
+ intval = PYGLIB_PyLong_FromUnsignedLong(eclass->values[i].value);
+ g_assert(PyErr_Occurred() == NULL);
item = pyg_flags_val_new(stub, gtype, intval);
PyDict_SetItem(values, intval, item);
Py_DECREF(intval);
@@ -312,7 +324,7 @@ pyg_flags_and(PyGFlags *a, PyGFlags *b)
(PyObject*)b);
return pyg_flags_from_gtype(a->gtype,
- PYGLIB_PyLong_AS_LONG(a) & PYGLIB_PyLong_AS_LONG(b));
+ PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b));
}
static PyObject *
@@ -322,7 +334,7 @@ pyg_flags_or(PyGFlags *a, PyGFlags *b)
return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a,
(PyObject*)b);
- return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AS_LONG(a) | PYGLIB_PyLong_AS_LONG(b));
+ return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) |
PYGLIB_PyLong_AsUnsignedLong(b));
}
static PyObject *
@@ -333,7 +345,7 @@ pyg_flags_xor(PyGFlags *a, PyGFlags *b)
(PyObject*)b);
return pyg_flags_from_gtype(a->gtype,
- PYGLIB_PyLong_AS_LONG(a) ^ PYGLIB_PyLong_AS_LONG(b));
+ PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b));
}
@@ -356,7 +368,7 @@ pyg_flags_get_first_value_name(PyGFlags *self, void *closure)
flags_class = g_type_class_ref(self->gtype);
g_assert(G_IS_FLAGS_CLASS(flags_class));
- flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AS_LONG(self));
+ flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
if (flags_value)
retval = PYGLIB_PyUnicode_FromString(flags_value->value_name);
else {
@@ -378,7 +390,7 @@ pyg_flags_get_first_value_nick(PyGFlags *self, void *closure)
flags_class = g_type_class_ref(self->gtype);
g_assert(G_IS_FLAGS_CLASS(flags_class));
- flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AS_LONG(self));
+ flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
if (flags_value)
retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick);
else {
@@ -402,7 +414,7 @@ pyg_flags_get_value_names(PyGFlags *self, void *closure)
retval = PyList_New(0);
for (i = 0; i < flags_class->n_values; i++)
- if ((PYGLIB_PyLong_AS_LONG(self) & flags_class->values[i].value) == flags_class->values[i].value)
+ if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) ==
flags_class->values[i].value)
PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_name));
g_type_class_unref(flags_class);
@@ -422,7 +434,7 @@ pyg_flags_get_value_nicks(PyGFlags *self, void *closure)
retval = PyList_New(0);
for (i = 0; i < flags_class->n_values; i++)
- if ((PYGLIB_PyLong_AS_LONG(self) & flags_class->values[i].value) == flags_class->values[i].value)
+ if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) ==
flags_class->values[i].value)
PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_nick));
g_type_class_unref(flags_class);
diff --git a/gi/_gobject/pygobject-private.h b/gi/_gobject/pygobject-private.h
index 0d1aca0..be2b6e3 100644
--- a/gi/_gobject/pygobject-private.h
+++ b/gi/_gobject/pygobject-private.h
@@ -107,7 +107,7 @@ GType pyg_type_from_object_strict (PyObject *obj, gboolean strict);
GType pyg_type_from_object (PyObject *obj);
gint pyg_enum_get_value (GType enum_type, PyObject *obj, gint *val);
-gint pyg_flags_get_value (GType flag_type, PyObject *obj, gint *val);
+gint pyg_flags_get_value (GType flag_type, PyObject *obj, guint *val);
int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr);
typedef PyObject *(* fromvaluefunc)(const GValue *value);
@@ -181,7 +181,8 @@ const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_pr
/* pygflags */
typedef struct {
- PYGLIB_PyLongObject parent;
+ PYGLIB_PyLongObject parent;
+ int zero_pad; /* must always be 0 */
GType gtype;
} PyGFlags;
@@ -194,13 +195,14 @@ extern PyObject * pyg_flags_add (PyObject * module,
const char * strip_prefix,
GType gtype);
extern PyObject * pyg_flags_from_gtype (GType gtype,
- int value);
+ guint value);
/* pygenum */
#define PyGEnum_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGEnum_Type) &&
g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_ENUM))
typedef struct {
- PYGLIB_PyLongObject parent;
+ PYGLIB_PyLongObject parent;
+ int zero_pad; /* must always be 0 */
GType gtype;
} PyGEnum;
diff --git a/gi/_gobject/pygobject.h b/gi/_gobject/pygobject.h
index 92dc030..cfd88d7 100644
--- a/gi/_gobject/pygobject.h
+++ b/gi/_gobject/pygobject.h
@@ -103,7 +103,7 @@ struct _PyGObject_Functions {
PyObject *(* type_wrapper_new)(GType type);
gint (* enum_get_value)(GType enum_type, PyObject *obj, gint *val);
- gint (* flags_get_value)(GType flag_type, PyObject *obj, gint *val);
+ gint (* flags_get_value)(GType flag_type, PyObject *obj, guint *val);
void (* register_gtype_custom)(GType gtype,
PyObject *(* from_func)(const GValue *value),
int (* to_func)(GValue *value, PyObject *obj));
@@ -168,7 +168,7 @@ struct _PyGObject_Functions {
const char *type_name_,
const char *strip_prefix,
GType gtype);
- PyObject* (*flags_from_gtype)(GType gtype, int value);
+ PyObject* (*flags_from_gtype)(GType gtype, guint value);
gboolean threads_enabled;
int (*enable_threads) (void);
diff --git a/gi/_gobject/pygtype.c b/gi/_gobject/pygtype.c
index 227178f..94014ff 100644
--- a/gi/_gobject/pygtype.c
+++ b/gi/_gobject/pygtype.c
@@ -538,7 +538,7 @@ pyg_enum_get_value(GType enum_type, PyObject *obj, gint *val)
* Returns: 0 on success or -1 on failure
*/
gint
-pyg_flags_get_value(GType flag_type, PyObject *obj, gint *val)
+pyg_flags_get_value(GType flag_type, PyObject *obj, guint *val)
{
GFlagsClass *fclass = NULL;
gint res = -1;
@@ -548,7 +548,7 @@ pyg_flags_get_value(GType flag_type, PyObject *obj, gint *val)
*val = 0;
res = 0;
} else if (PYGLIB_PyLong_Check(obj)) {
- *val = PYGLIB_PyLong_AsLong(obj);
+ *val = PYGLIB_PyLong_AsUnsignedLong(obj);
res = 0;
} else if (PyLong_Check(obj)) {
*val = PyLong_AsLongLong(obj);
@@ -944,7 +944,7 @@ pyg_value_from_pyobject(GValue *value, PyObject *obj)
break;
case G_TYPE_FLAGS:
{
- gint val = 0;
+ guint val = 0;
if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
PyErr_Clear();
return -1;
diff --git a/tests/test_overrides_gdk.py b/tests/test_overrides_gdk.py
index 070acb8..c1f10d9 100644
--- a/tests/test_overrides_gdk.py
+++ b/tests/test_overrides_gdk.py
@@ -117,3 +117,18 @@ class TestGdk(unittest.TestCase):
self.assertNotEqual(c, None)
self.assertRaises(ValueError, Gdk.Cursor, 1, 2, 3)
+
+ def test_flags(self):
+ self.assertEqual(Gdk.ModifierType.META_MASK | 0, 0x10000000)
+ self.assertEqual(hex(Gdk.ModifierType.META_MASK), '0x10000000')
+ self.assertEqual(str(Gdk.ModifierType.META_MASK),
+ '<flags GDK_META_MASK of type GdkModifierType>')
+
+ self.assertEqual(Gdk.ModifierType.RELEASE_MASK | 0, 0x40000000)
+ self.assertEqual(hex(Gdk.ModifierType.RELEASE_MASK), '0x40000000')
+ self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK),
+ '<flags GDK_RELEASE_MASK of type GdkModifierType>')
+
+ self.assertEqual(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK, 0x50000000)
+ self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK),
+ '<flags GDK_META_MASK | GDK_RELEASE_MASK of type GdkModifierType>')
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]