Commit caeeeb7e authored by Martin Pitt's avatar Martin Pitt

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
parent b3a3da37
......@@ -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)
......
......@@ -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,
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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>')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment