From: Gerhard Sittig Date: Sun, 24 Nov 2019 08:52:42 +0000 (+0100) Subject: decoder: internal 'always false' term, handle invalid skip and channel X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=1cb40e1077894db4c92cfa01b285e28b202cce6f;p=libsigrokdecode.git decoder: internal 'always false' term, handle invalid skip and channel Introduce an "always false" type for .wait() terms. Map invalid counts of skip conditions (zero or negative numbers) as well as invalid channel references for level/edge conditions to this type which never matches. Keep this "always false" term type an internal detail of the common support code. This is most robust and least intrusive at the same time, it keeps the existing API, and simplifies the implementation of Python decoders for rare edge cases (optional input signals or optional features, handling of initial samples at the very start of a capture). This commit passes sample counts internally in a signed data type. This is essential for proper operation, and the loss of one bit out of 64 shall not be considered a severe limitation. This fixes bug #1444. --- diff --git a/instance.c b/instance.c index 36fb2d0..5264bd0 100644 --- a/instance.c +++ b/instance.c @@ -895,6 +895,8 @@ static gboolean all_terms_match(const struct srd_decoder_inst *di, for (l = cond; l; l = l->next) { term = l->data; + if (term->type == SRD_TERM_ALWAYS_FALSE) + return FALSE; if (!term_matches(di, term, sample_pos)) return FALSE; } diff --git a/libsigrokdecode-internal.h b/libsigrokdecode-internal.h index d5a34a2..af245f6 100644 --- a/libsigrokdecode-internal.h +++ b/libsigrokdecode-internal.h @@ -28,6 +28,7 @@ #include "libsigrokdecode.h" enum { + SRD_TERM_ALWAYS_FALSE, SRD_TERM_HIGH, SRD_TERM_LOW, SRD_TERM_RISING_EDGE, @@ -123,7 +124,7 @@ SRD_PRIV int py_attr_as_strlist(PyObject *py_obj, const char *attr, GSList **out SRD_PRIV int py_dictitem_as_str(PyObject *py_obj, const char *key, char **outstr); SRD_PRIV int py_listitem_as_str(PyObject *py_obj, Py_ssize_t idx, char **outstr); SRD_PRIV int py_pydictitem_as_str(PyObject *py_obj, PyObject *py_key, char **outstr); -SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, uint64_t *out); +SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, int64_t *out); SRD_PRIV int py_str_as_str(PyObject *py_str, char **outstr); SRD_PRIV int py_strseq_to_char(PyObject *py_strseq, char ***out_strv); SRD_PRIV GVariant *py_obj_to_variant(PyObject *py_obj); diff --git a/type_decoder.c b/type_decoder.c index 17204f0..454e7ea 100644 --- a/type_decoder.c +++ b/type_decoder.c @@ -625,18 +625,20 @@ static PyObject *get_current_pinvalues(const struct srd_decoder_inst *di) * * If there are no terms in the condition, 'term_list' will be NULL. * + * @param di The decoder instance to use. Must not be NULL. * @param py_dict A Python dict containing terms. Must not be NULL. * @param term_list Pointer to a GSList which will be set to the newly * created list of terms. Must not be NULL. * * @return SRD_OK upon success, a negative error code otherwise. */ -static int create_term_list(PyObject *py_dict, GSList **term_list) +static int create_term_list(struct srd_decoder_inst *di, + PyObject *py_dict, GSList **term_list) { Py_ssize_t pos = 0; PyObject *py_key, *py_value; struct srd_term *term; - uint64_t num_samples_to_skip; + int64_t num_samples_to_skip; char *term_str; PyGILState_STATE gstate; @@ -653,7 +655,6 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) /* Check whether the current key is a string or a number. */ if (PyLong_Check(py_key)) { /* The key is a number. */ - /* TODO: Check if the number is a valid channel. */ /* Get the value string. */ if ((py_pydictitem_as_str(py_dict, py_key, &term_str)) != SRD_OK) { srd_err("Failed to get the value."); @@ -662,10 +663,12 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) term = g_malloc(sizeof(struct srd_term)); term->type = get_term_type(term_str); term->channel = PyLong_AsLong(py_key); + if (term->channel < 0 || term->channel >= di->dec_num_channels) + term->type = SRD_TERM_ALWAYS_FALSE; g_free(term_str); } else if (PyUnicode_Check(py_key)) { /* The key is a string. */ - /* TODO: Check if it's "skip". */ + /* TODO: Check if the key is "skip". */ if ((py_pydictitem_as_long(py_dict, py_key, &num_samples_to_skip)) != SRD_OK) { srd_err("Failed to get number of samples to skip."); goto err; @@ -674,6 +677,8 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) term->type = SRD_TERM_SKIP; term->num_samples_to_skip = num_samples_to_skip; term->num_samples_already_skipped = 0; + if (num_samples_to_skip < 1) + term->type = SRD_TERM_ALWAYS_FALSE; } else { srd_err("Term key is neither a string nor a number."); goto err; @@ -784,7 +789,7 @@ static int set_new_condition_list(PyObject *self, PyObject *args) } /* Create the list of terms in this condition. */ - if ((ret = create_term_list(py_dict, &term_list)) < 0) + if ((ret = create_term_list(di, py_dict, &term_list)) < 0) break; /* Add the new condition to the PD instance's condition list. */ diff --git a/util.c b/util.c index 442d0a6..b7fd4fb 100644 --- a/util.c +++ b/util.c @@ -303,7 +303,7 @@ err: * * @private */ -SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, uint64_t *out) +SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, int64_t *out) { PyObject *py_value; PyGILState_STATE gstate; @@ -328,7 +328,7 @@ SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, uint64_t goto err; } - *out = PyLong_AsUnsignedLongLong(py_value); + *out = PyLong_AsLongLong(py_value); PyGILState_Release(gstate);