summaryrefslogtreecommitdiff
path: root/type_decoder.c
diff options
context:
space:
mode:
authorDaniel Elstner <daniel.kitta@gmail.com>2015-10-05 01:53:43 +0200
committerDaniel Elstner <daniel.kitta@gmail.com>2015-10-06 23:25:36 +0200
commit201a85a8ea071d37f4fda2668c0a1c488d852f4e (patch)
treef407560b61fc126291ee932d6c897a80dea79a30 /type_decoder.c
parentbd0e7d2e71e7a05b2bb0686a86a75b8fcb92fd54 (diff)
downloadlibsigrokdecode-201a85a8ea071d37f4fda2668c0a1c488d852f4e.tar.gz
libsigrokdecode-201a85a8ea071d37f4fda2668c0a1c488d852f4e.zip
Python: Restrict code to stable ABI subset
Limit usage of the Python C API to the stable ABI subset as defined by PEP 384. This removes some type definitions and functions which libsigrokdecode made use of. Convert all affected code to suitable API alternatives. Also fix a few leaks that became apparent while working on the code. The most visible change is that PyTypeObject is now an opaque type. Thus, the custom Decoder and srd_logic types are now created on the heap via an alternative API. Unfortunately, since tp_name is now inaccessible, type names had to be removed from the log output. Stack traces after Python exceptions are now formatted by calling into Python, since the trace object C API is no longer available.
Diffstat (limited to 'type_decoder.c')
-rw-r--r--type_decoder.c71
1 files changed, 43 insertions, 28 deletions
diff --git a/type_decoder.c b/type_decoder.c
index d4c592f..89b5ca1 100644
--- a/type_decoder.c
+++ b/type_decoder.c
@@ -26,13 +26,19 @@ typedef struct {
PyObject_HEAD
} srd_Decoder;
-/* This is only used for nicer srd_dbg() output. */
-static const char *OUTPUT_TYPES[] = {
- "OUTPUT_ANN",
- "OUTPUT_PYTHON",
- "OUTPUT_BINARY",
- "OUTPUT_META",
-};
+/* This is only used for nicer srd_dbg() output.
+ */
+static const char *output_type_name(unsigned int idx)
+{
+ static const char names[][16] = {
+ "OUTPUT_ANN",
+ "OUTPUT_PYTHON",
+ "OUTPUT_BINARY",
+ "OUTPUT_META",
+ "(invalid)"
+ };
+ return names[MIN(idx, G_N_ELEMENTS(names) - 1)];
+}
static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj,
struct srd_proto_data *pdata)
@@ -45,8 +51,8 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj,
/* Should be a list of [annotation class, [string, ...]]. */
if (!PyList_Check(obj) && !PyTuple_Check(obj)) {
- srd_err("Protocol decoder %s submitted %s instead of list.",
- di->decoder->name, obj->ob_type->tp_name);
+ srd_err("Protocol decoder %s submitted an annotation that"
+ " is not a list or tuple", di->decoder->name);
return SRD_ERR_PYTHON;
}
@@ -107,9 +113,8 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj,
/* Should be a tuple of (binary class, bytes). */
if (!PyTuple_Check(obj)) {
- srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY with "
- "%s instead of tuple.", di->decoder->name,
- obj->ob_type->tp_name);
+ srd_err("Protocol decoder %s submitted non-tuple for SRD_OUTPUT_BINARY.",
+ di->decoder->name);
return SRD_ERR_PYTHON;
}
@@ -171,7 +176,7 @@ static int convert_meta(struct srd_proto_data *pdata, PyObject *obj)
if (pdata->pdo->meta_type == G_VARIANT_TYPE_INT64) {
if (!PyLong_Check(obj)) {
PyErr_Format(PyExc_TypeError, "This output was registered "
- "as 'int', but '%s' was passed.", obj->ob_type->tp_name);
+ "as 'int', but something else was passed.");
return SRD_ERR_PYTHON;
}
intvalue = PyLong_AsLongLong(obj);
@@ -181,7 +186,7 @@ static int convert_meta(struct srd_proto_data *pdata, PyObject *obj)
} else if (pdata->pdo->meta_type == G_VARIANT_TYPE_DOUBLE) {
if (!PyFloat_Check(obj)) {
PyErr_Format(PyExc_TypeError, "This output was registered "
- "as 'float', but '%s' was passed.", obj->ob_type->tp_name);
+ "as 'float', but something else was passed.");
return SRD_ERR_PYTHON;
}
dvalue = PyFloat_AsDouble(obj);
@@ -229,7 +234,7 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args)
srd_spew("Instance %s put %" PRIu64 "-%" PRIu64 " %s on oid %d.",
di->inst_id, start_sample, end_sample,
- OUTPUT_TYPES[pdo->output_type], output_id);
+ output_type_name(pdo->output_type), output_id);
pdata = g_malloc0(sizeof(struct srd_proto_data));
pdata->start_sample = start_sample;
@@ -256,7 +261,7 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args)
if (!(py_res = PyObject_CallMethod(
next_di->py_inst, "decode", "KKO", start_sample,
end_sample, py_data))) {
- srd_exception_catch("Calling %s decode(): ",
+ srd_exception_catch("Calling %s decode() failed",
next_di->inst_id);
}
Py_XDECREF(py_res);
@@ -336,8 +341,7 @@ static PyObject *Decoder_register(PyObject *self, PyObject *args,
else if (meta_type_py == &PyFloat_Type)
meta_type_gv = G_VARIANT_TYPE_DOUBLE;
else {
- PyErr_Format(PyExc_TypeError, "Unsupported type '%s'.",
- meta_type_py->tp_name);
+ PyErr_Format(PyExc_TypeError, "Unsupported type.");
return NULL;
}
}
@@ -373,13 +377,24 @@ static PyMethodDef Decoder_methods[] = {
{NULL, NULL, 0, NULL}
};
-/** @cond PRIVATE */
-SRD_PRIV PyTypeObject srd_Decoder_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "sigrokdecode.Decoder",
- .tp_basicsize = sizeof(srd_Decoder),
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- .tp_doc = "sigrok Decoder base class",
- .tp_methods = Decoder_methods,
-};
-/** @endcond */
+/** Create the sigrokdecode.Decoder type.
+ * @return The new type object.
+ * @private
+ */
+SRD_PRIV PyObject *srd_Decoder_type_new(void)
+{
+ PyType_Spec spec;
+ PyType_Slot slots[] = {
+ { Py_tp_doc, "sigrok Decoder base class" },
+ { Py_tp_methods, Decoder_methods },
+ { Py_tp_new, (void *)&PyType_GenericNew },
+ { 0, NULL }
+ };
+ spec.name = "sigrokdecode.Decoder";
+ spec.basicsize = sizeof(srd_Decoder);
+ spec.itemsize = 0;
+ spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
+ spec.slots = slots;
+
+ return PyType_FromSpec(&spec);
+}