1
0
mirror of https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git synced 2026-10-25 12:39:18 +03:00
Files
libgpiod/bindings/python/gpiod/ext/line-config.c
Bartosz Golaszewski 81b732d9b5 bindings: python: check for errors after PyIter_Next() in set_output_values
PyIter_Next() returns NULL both at end-of-iteration and when an exception
is raised. The code breaks out of the loop without checking
PyErr_Occurred(), potentially swallowing Python exceptions and continuing
with a partially filled buffer.

Add the missing error check.

Fixes: 27a69b0bfd ("bindings: python: add the output_values argument to Chip.request_lines()")
Assisted-by: Claude Opus 4.6
Reviewed-by: Vincent Fazio <vfazio@xes-inc.com>
Tested-by: Vincent Fazio <vfazio@xes-inc.com>
Link: https://patch.msgid.link/20260604-pre-2-3-fixes-v2-13-781bcaf47475@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
2026-06-08 10:20:00 +02:00

202 lines
4.1 KiB
C

// SPDX-License-Identifier: LGPL-2.1-or-later
// SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
#include "internal.h"
typedef struct {
PyObject_HEAD;
struct gpiod_line_config *cfg;
} line_config_object;
static int line_config_init(line_config_object *self,
PyObject *Py_UNUSED(args), PyObject *Py_UNUSED(ignored))
{
self->cfg = gpiod_line_config_new();
if (!self->cfg) {
Py_gpiod_SetErrFromErrno();
return -1;
}
return 0;
}
static void line_config_finalize(line_config_object *self)
{
if (self->cfg)
gpiod_line_config_free(self->cfg);
}
static unsigned int *make_offsets(PyObject *obj, Py_ssize_t len)
{
unsigned int *offsets;
PyObject *offset;
Py_ssize_t i;
offsets = PyMem_Calloc(len, sizeof(unsigned int));
if (!offsets)
return (unsigned int *)PyErr_NoMemory();
for (i = 0; i < len; i++) {
offset = PyList_GetItem(obj, i);
if (!offset) {
PyMem_Free(offsets);
return NULL;
}
offsets[i] = Py_gpiod_PyLongAsUnsignedInt(offset);
if (PyErr_Occurred()) {
PyMem_Free(offsets);
return NULL;
}
}
return offsets;
}
static PyObject *
line_config_add_line_settings(line_config_object *self, PyObject *args)
{
PyObject *offsets_obj, *settings_obj;
struct gpiod_line_settings *settings;
unsigned int *offsets;
Py_ssize_t num_offsets;
int ret;
ret = PyArg_ParseTuple(args, "OO", &offsets_obj, &settings_obj);
if (!ret)
return NULL;
num_offsets = PyObject_Size(offsets_obj);
if (num_offsets < 0)
return NULL;
offsets = make_offsets(offsets_obj, num_offsets);
if (!offsets)
return NULL;
settings = Py_gpiod_LineSettingsGetData(settings_obj);
if (!settings) {
PyMem_Free(offsets);
return NULL;
}
ret = gpiod_line_config_add_line_settings(self->cfg, offsets,
num_offsets, settings);
PyMem_Free(offsets);
if (ret)
return Py_gpiod_SetErrFromErrno();
Py_RETURN_NONE;
}
static PyObject *
line_config_set_output_values(line_config_object *self, PyObject *args)
{
PyObject *values, *iter, *next, *val_stripped;
enum gpiod_line_value *valbuf;
Py_ssize_t num_values, pos;
int ret;
values = PyTuple_GetItem(args, 0);
if (!values)
return NULL;
num_values = PyObject_Size(values);
if (num_values < 0)
return NULL;
valbuf = PyMem_Calloc(num_values, sizeof(*valbuf));
if (!valbuf)
return PyErr_NoMemory();
iter = PyObject_GetIter(values);
if (!iter) {
PyMem_Free(valbuf);
return NULL;
}
for (pos = 0;; pos++) {
next = PyIter_Next(iter);
if (!next) {
Py_DECREF(iter);
if (PyErr_Occurred()) {
PyMem_Free(valbuf);
return NULL;
}
break;
}
val_stripped = PyObject_GetAttrString(next, "value");
Py_DECREF(next);
if (!val_stripped) {
PyMem_Free(valbuf);
Py_DECREF(iter);
return NULL;
}
valbuf[pos] = PyLong_AsLong(val_stripped);
Py_DECREF(val_stripped);
if (PyErr_Occurred()) {
PyMem_Free(valbuf);
Py_DECREF(iter);
return NULL;
}
}
ret = gpiod_line_config_set_output_values(self->cfg,
valbuf, num_values);
PyMem_Free(valbuf);
if (ret)
return Py_gpiod_SetErrFromErrno();
Py_RETURN_NONE;
}
static PyMethodDef line_config_methods[] = {
{
.ml_name = "add_line_settings",
.ml_meth = (PyCFunction)line_config_add_line_settings,
.ml_flags = METH_VARARGS,
},
{
.ml_name = "set_output_values",
.ml_meth = (PyCFunction)line_config_set_output_values,
.ml_flags = METH_VARARGS,
},
{ }
};
PyTypeObject line_config_type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "gpiod._ext.LineConfig",
.tp_basicsize = sizeof(line_config_object),
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = PyType_GenericNew,
.tp_init = (initproc)line_config_init,
.tp_finalize = (destructor)line_config_finalize,
.tp_dealloc = (destructor)Py_gpiod_dealloc,
.tp_methods = line_config_methods,
};
struct gpiod_line_config *Py_gpiod_LineConfigGetData(PyObject *obj)
{
line_config_object *line_cfg;
PyObject *type;
type = PyObject_Type(obj);
if (!type)
return NULL;
if ((PyTypeObject *)type != &line_config_type) {
PyErr_SetString(PyExc_TypeError,
"not a gpiod._ext.LineConfig object");
Py_DECREF(type);
return NULL;
}
Py_DECREF(type);
line_cfg = (line_config_object *)obj;
return line_cfg->cfg;
}