Avoid cleaning up the output modules more than once. Currently, if the analog module is explicitly requested in sigrok-cli, the program attempts to clean it twice, thus resulting in g_variant_unref() assertion failures at runtime. This patch makes sure that the analog output module is not cleaned up more than once. The same check is applied to the other output modules for consistency. Signed-off-by: Guido Trentalancia --- src/output/analog.c | 21 +++++++++++++++++-- src/output/ascii.c | 30 ++++++++++++++++++++++------ src/output/bits.c | 25 ++++++++++++++++++----- src/output/chronovu_la8.c | 11 ++++++++++ src/output/csv.c | 49 +++++++++++++++++++++++++++++++--------------- src/output/hex.c | 28 +++++++++++++++++++++----- src/output/ols.c | 11 ++++++++++ src/output/srzip.c | 19 +++++++++++++++++ src/output/vcd.c | 11 ++++++++++ src/output/wav.c | 20 +++++++++++++++++- 10 files changed, 191 insertions(+), 34 deletions(-) diff -pru libsigrok-git-orig/src/output/analog.c libsigrok-git-no-double-output-module-cleanup/src/output/analog.c --- libsigrok-git-orig/src/output/analog.c 2018-12-08 00:18:39.748857429 +0100 +++ libsigrok-git-no-double-output-module-cleanup/src/output/analog.c 2018-12-08 00:27:11.171855338 +0100 @@ -41,6 +41,9 @@ enum { DIGITS_SPEC, }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int init(struct sr_output *o, GHashTable *options) { struct context *ctx; @@ -69,6 +72,8 @@ static int init(struct sr_output *o, GHa } ctx->fdata = NULL; + cleaned = FALSE; + return SR_OK; } @@ -186,18 +191,30 @@ static const struct sr_option *get_optio static int cleanup(struct sr_output *o) { struct context *ctx; + unsigned int i; if (!o || !o->sdi) return SR_ERR_ARG; ctx = o->priv; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (options[i].def) + g_variant_unref(options[i].def); + if (options[i].values) + g_slist_free_full(options[i].values, (GDestroyNotify)g_variant_unref); + } + g_ptr_array_free(ctx->channellist, 1); - g_variant_unref(options[0].def); - g_slist_free_full(options[0].values, (GDestroyNotify)g_variant_unref); g_free(ctx->fdata); g_free(ctx); o->priv = NULL; + cleaned = TRUE; + return SR_OK; } diff -pru libsigrok-git-orig/src/output/ascii.c libsigrok-git-no-double-output-module-cleanup/src/output/ascii.c --- libsigrok-git-orig/src/output/ascii.c 2018-10-20 13:12:30.977966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/ascii.c 2018-12-08 00:30:11.429854601 +0100 @@ -54,6 +54,9 @@ struct context { gboolean edges; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int init(struct sr_output *o, GHashTable *options) { struct context *ctx; @@ -103,6 +106,8 @@ static int init(struct sr_output *o, GHa j++; } + cleaned = FALSE; + return SR_OK; } @@ -232,6 +237,12 @@ static int receive(const struct sr_outpu return SR_OK; } +static struct sr_option options[] = { + { "width", "Width", "Number of samples per line", NULL, NULL }, + { "charset", "Charset", "Characters for 0/1 bits (and fall/rise edges)", NULL, NULL }, + ALL_ZERO +}; + static int cleanup(struct sr_output *o) { struct context *ctx; @@ -243,6 +254,17 @@ static int cleanup(struct sr_output *o) if (!(ctx = o->priv)) return SR_OK; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (options[i].def) + g_variant_unref(options[i].def); + if (options[i].values) + g_slist_free_full(options[i].values, (GDestroyNotify)g_variant_unref); + } + g_free(ctx->channel_index); g_free(ctx->prev_sample); g_free(ctx->channel_names); @@ -253,15 +275,11 @@ static int cleanup(struct sr_output *o) g_free(ctx); o->priv = NULL; + cleaned = TRUE; + return SR_OK; } -static struct sr_option options[] = { - { "width", "Width", "Number of samples per line", NULL, NULL }, - { "charset", "Charset", "Characters for 0/1 bits (and fall/rise edges)", NULL, NULL }, - ALL_ZERO -}; - static const struct sr_option *get_options(void) { if (!options[0].def) { diff -pru libsigrok-git-orig/src/output/bits.c libsigrok-git-no-double-output-module-cleanup/src/output/bits.c --- libsigrok-git-orig/src/output/bits.c 2018-10-20 13:12:30.977966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/bits.c 2018-12-08 00:24:26.902856010 +0100 @@ -40,6 +40,9 @@ struct context { GString **lines; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int init(struct sr_output *o, GHashTable *options) { struct context *ctx; @@ -81,6 +84,8 @@ static int init(struct sr_output *o, GHa j++; } + cleaned = FALSE; + return SR_OK; } @@ -203,6 +208,11 @@ static int receive(const struct sr_outpu return SR_OK; } +static struct sr_option options[] = { + { "width", "Width", "Number of samples per line", NULL, NULL }, + ALL_ZERO +}; + static int cleanup(struct sr_output *o) { struct context *ctx; @@ -214,6 +224,14 @@ static int cleanup(struct sr_output *o) if (!(ctx = o->priv)) return SR_OK; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + + for (i = 0; i < ARRAY_SIZE(options); i++) + if (options[i].def) + g_variant_unref(options[i].def); + g_free(ctx->channel_index); g_free(ctx->channel_names); for (i = 0; i < ctx->num_enabled_channels; i++) @@ -222,14 +240,11 @@ static int cleanup(struct sr_output *o) g_free(ctx); o->priv = NULL; + cleaned = TRUE; + return SR_OK; } -static struct sr_option options[] = { - { "width", "Width", "Number of samples per line", NULL, NULL }, - ALL_ZERO -}; - static const struct sr_option *get_options(void) { if (!options[0].def) { diff -pru libsigrok-git-orig/src/output/chronovu_la8.c libsigrok-git-no-double-output-module-cleanup/src/output/chronovu_la8.c --- libsigrok-git-orig/src/output/chronovu_la8.c 2018-10-20 13:12:30.978966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/chronovu_la8.c 2018-12-08 00:07:26.670860181 +0100 @@ -36,6 +36,9 @@ struct context { GString *pretrig_buf; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + /** * Check if the given samplerate is supported by the LA8 hardware. * @@ -101,6 +104,8 @@ static int init(struct sr_output *o, GHa ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels); ctx->pretrig_buf = g_string_sized_new(1024); + cleaned = FALSE; + return SR_OK; } @@ -173,6 +178,10 @@ static int cleanup(struct sr_output *o) if (!o || !o->sdi) return SR_ERR_ARG; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + if (o->priv) { ctx = o->priv; g_string_free(ctx->pretrig_buf, TRUE); @@ -181,6 +190,8 @@ static int cleanup(struct sr_output *o) o->priv = NULL; } + cleaned = TRUE; + return SR_OK; } diff -pru libsigrok-git-orig/src/output/csv.c libsigrok-git-no-double-output-module-cleanup/src/output/csv.c --- libsigrok-git-orig/src/output/csv.c 2018-10-20 13:12:30.978966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/csv.c 2018-12-08 00:29:13.005854840 +0100 @@ -102,6 +102,9 @@ struct context { const char *title; /* Don't free: will point into the driver struct. */ }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + /* * TODO: * - Option to print comma-separated bits, or whole bytes/words (for 8/16 @@ -201,6 +204,8 @@ static int init(struct sr_output *o, GHa } } + cleaned = FALSE; + return SR_OK; } @@ -603,13 +608,40 @@ static int receive(const struct sr_outpu return SR_OK; } +static struct sr_option options[] = { + {"gnuplot", "gnuplot", "gnuplot script file name", NULL, NULL}, + {"scale", "scale", "Scale gnuplot graphs", NULL, NULL}, + {"value", "Value separator", "Character to print between values", NULL, NULL}, + {"record", "Record separator", "String to print between records", NULL, NULL}, + {"frame", "Frame separator", "String to print between frames", NULL, NULL}, + {"comment", "Comment start string", "String used at start of comment lines", NULL, NULL}, + {"header", "Output header", "Output header comment with capture metdata", NULL, NULL}, + {"label", "Label values", "Type of column labels", NULL, NULL}, + {"time", "Time column", "Output sample time as column 1", NULL, NULL}, + {"trigger", "Trigger column", "Output trigger indicator as last column ", NULL, NULL}, + {"dedup", "Dedup rows", "Set to false to output duplicate rows", NULL, NULL}, + ALL_ZERO +}; + static int cleanup(struct sr_output *o) { struct context *ctx; + unsigned int i; if (!o || !o->sdi) return SR_ERR_ARG; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (options[i].def) + g_variant_unref(options[i].def); + if (options[i].values) + g_slist_free_full(options[i].values, (GDestroyNotify)g_variant_unref); + } + if (o->priv) { ctx = o->priv; g_free((gpointer)ctx->record); @@ -623,24 +655,11 @@ static int cleanup(struct sr_output *o) o->priv = NULL; } + cleaned = TRUE; + return SR_OK; } -static struct sr_option options[] = { - {"gnuplot", "gnuplot", "gnuplot script file name", NULL, NULL}, - {"scale", "scale", "Scale gnuplot graphs", NULL, NULL}, - {"value", "Value separator", "Character to print between values", NULL, NULL}, - {"record", "Record separator", "String to print between records", NULL, NULL}, - {"frame", "Frame separator", "String to print between frames", NULL, NULL}, - {"comment", "Comment start string", "String used at start of comment lines", NULL, NULL}, - {"header", "Output header", "Output header comment with capture metdata", NULL, NULL}, - {"label", "Label values", "Type of column labels", NULL, NULL}, - {"time", "Time column", "Output sample time as column 1", NULL, NULL}, - {"trigger", "Trigger column", "Output trigger indicator as last column ", NULL, NULL}, - {"dedup", "Dedup rows", "Set to false to output duplicate rows", NULL, NULL}, - ALL_ZERO -}; - static const struct sr_option *get_options(void) { GSList *l = NULL; diff -pru libsigrok-git-orig/src/output/hex.c libsigrok-git-no-double-output-module-cleanup/src/output/hex.c --- libsigrok-git-orig/src/output/hex.c 2018-10-20 13:12:30.979966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/hex.c 2018-12-08 00:31:25.212854300 +0100 @@ -43,6 +43,9 @@ struct context { GString **lines; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int init(struct sr_output *o, GHashTable *options) { struct context *ctx; @@ -86,6 +89,8 @@ static int init(struct sr_output *o, GHa j++; } + cleaned = FALSE; + return SR_OK; } @@ -216,6 +221,11 @@ static int receive(const struct sr_outpu return SR_OK; } +static struct sr_option options[] = { + { "width", "Width", "Number of samples per line", NULL, NULL }, + ALL_ZERO +}; + static int cleanup(struct sr_output *o) { struct context *ctx; @@ -227,6 +237,17 @@ static int cleanup(struct sr_output *o) if (!(ctx = o->priv)) return SR_OK; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (options[i].def) + g_variant_unref(options[i].def); + if (options[i].values) + g_slist_free_full(options[i].values, (GDestroyNotify)g_variant_unref); + } + g_free(ctx->channel_index); g_free(ctx->sample_buf); g_free(ctx->channel_names); @@ -236,14 +257,11 @@ static int cleanup(struct sr_output *o) g_free(ctx); o->priv = NULL; + cleaned = TRUE; + return SR_OK; } -static struct sr_option options[] = { - { "width", "Width", "Number of samples per line", NULL, NULL }, - ALL_ZERO -}; - static const struct sr_option *get_options(void) { if (!options[0].def) { diff -pru libsigrok-git-orig/src/output/ols.c libsigrok-git-no-double-output-module-cleanup/src/output/ols.c --- libsigrok-git-orig/src/output/ols.c 2018-10-20 13:12:30.979966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/ols.c 2018-12-08 00:35:00.859853418 +0100 @@ -38,6 +38,9 @@ struct context { uint64_t num_samples; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int init(struct sr_output *o, GHashTable *options) { struct context *ctx; @@ -49,6 +52,8 @@ static int init(struct sr_output *o, GHa ctx->samplerate = 0; ctx->num_samples = 0; + cleaned = FALSE; + return SR_OK; } @@ -139,10 +144,16 @@ static int cleanup(struct sr_output *o) if (!o || !o->sdi) return SR_ERR_ARG; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + ctx = o->priv; g_free(ctx); o->priv = NULL; + cleaned = TRUE; + return SR_OK; } diff -pru libsigrok-git-orig/src/output/srzip.c libsigrok-git-no-double-output-module-cleanup/src/output/srzip.c --- libsigrok-git-orig/src/output/srzip.c 2018-10-20 13:12:30.979966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/srzip.c 2018-12-08 00:33:21.914853823 +0100 @@ -37,6 +37,9 @@ struct out_context { gint *analog_index_map; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int init(struct sr_output *o, GHashTable *options) { struct out_context *outc; @@ -52,6 +55,8 @@ static int init(struct sr_output *o, GHa outc->filename = g_strdup(o->filename); o->priv = outc; + cleaned = FALSE; + return SR_OK; } @@ -474,6 +479,18 @@ static const struct sr_option *get_optio static int cleanup(struct sr_output *o) { struct out_context *outc; + unsigned int i; + + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + + for (i = 0; i < ARRAY_SIZE(options); i++) { + if (options[i].def) + g_variant_unref(options[i].def); + if (options[i].values) + g_slist_free_full(options[i].values, (GDestroyNotify)g_variant_unref); + } outc = o->priv; g_free(outc->analog_index_map); @@ -481,6 +498,8 @@ static int cleanup(struct sr_output *o) g_free(outc); o->priv = NULL; + cleaned = TRUE; + return SR_OK; } diff -pru libsigrok-git-orig/src/output/vcd.c libsigrok-git-no-double-output-module-cleanup/src/output/vcd.c --- libsigrok-git-orig/src/output/vcd.c 2018-10-20 13:12:30.980966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/vcd.c 2018-12-08 00:37:48.448852733 +0100 @@ -37,6 +37,9 @@ struct context { uint64_t samplecount; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int init(struct sr_output *o, GHashTable *options) { struct context *ctx; @@ -75,6 +78,8 @@ static int init(struct sr_output *o, GHa ctx->channel_index[i++] = ch->index; } + cleaned = FALSE; + return SR_OK; } @@ -259,11 +264,17 @@ static int cleanup(struct sr_output *o) if (!o || !o->priv) return SR_ERR_ARG; + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + ctx = o->priv; g_free(ctx->prevsample); g_free(ctx->channel_index); g_free(ctx); + cleaned = TRUE; + return SR_OK; } diff -pru libsigrok-git-orig/src/output/wav.c libsigrok-git-no-double-output-module-cleanup/src/output/wav.c --- libsigrok-git-orig/src/output/wav.c 2018-10-20 13:12:30.980966965 +0200 +++ libsigrok-git-no-double-output-module-cleanup/src/output/wav.c 2018-12-08 00:39:08.219852407 +0100 @@ -39,6 +39,9 @@ struct out_context { float *fdata; }; +/* Avoid cleaning up this module more than once. */ +static gboolean cleaned = FALSE; + static int realloc_chanbufs(const struct sr_output *o, int size) { struct out_context *outc; @@ -114,6 +117,8 @@ static int init(struct sr_output *o, GHa /* Start off the interleaved buffer with 100 samples/channel. */ realloc_chanbufs(o, 100); + cleaned = FALSE; + return SR_OK; } @@ -351,8 +356,19 @@ static int cleanup(struct sr_output *o) int i; outc = o->priv; + + /* Avoid cleaning it up more than once. */ + if (cleaned) + return SR_OK; + + for (i = 0; i < (int) ARRAY_SIZE(options); i++) { + if (options[i].def) + g_variant_unref(options[i].def); + if (options[i].values) + g_slist_free_full(options[i].values, (GDestroyNotify)g_variant_unref); + } + g_slist_free(outc->channels); - g_variant_unref(options[0].def); for (i = 0; i < outc->num_channels; i++) g_free(outc->chanbuf[i]); g_free(outc->chanbuf_used); @@ -361,6 +377,8 @@ static int cleanup(struct sr_output *o) g_free(outc); o->priv = NULL; + cleaned = TRUE; + return SR_OK; }