From 4222e1abdc2932c13cb8230c1b5abea62299d501 Mon Sep 17 00:00:00 2001 From: limengning Date: Sun, 17 Aug 2025 06:55:22 +0800 Subject: [PATCH 1/3] Fix memory leak issue when reset file in multi support mode --- src/eccodes/grib_handle.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/eccodes/grib_handle.cc b/src/eccodes/grib_handle.cc index a37df1bdda..461cf87828 100644 --- a/src/eccodes/grib_handle.cc +++ b/src/eccodes/grib_handle.cc @@ -1815,10 +1815,23 @@ void grib_multi_support_reset_file(grib_context* c, FILE* f) { if (!c) c = grib_context_get_default(); grib_multi_support* gm = c->multi_support; + grib_multi_support* prev = NULL; while (gm) { if (gm->file == f) { gm->file = NULL; + if (gm->message) + grib_context_free(c, gm->message); + grib_multi_support* old_gm = gm; + gm = gm->next; + if (prev) { + prev->next = gm; + } else { + c->multi_support = gm; + } + grib_context_free(c, old_gm); + continue; } + prev = gm; gm = gm->next; } } From 8d488c68817b19f9e96bc05a64f2452d69ffceb9 Mon Sep 17 00:00:00 2001 From: limengning Date: Wed, 20 Aug 2025 02:26:28 +0800 Subject: [PATCH 2/3] Free bitmap_section allocation --- src/eccodes/grib_handle.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/eccodes/grib_handle.cc b/src/eccodes/grib_handle.cc index 461cf87828..f0e653694b 100644 --- a/src/eccodes/grib_handle.cc +++ b/src/eccodes/grib_handle.cc @@ -1821,6 +1821,8 @@ void grib_multi_support_reset_file(grib_context* c, FILE* f) gm->file = NULL; if (gm->message) grib_context_free(c, gm->message); + if (gm->bitmap_section) + grib_context_free(c, gm->bitmap_section); grib_multi_support* old_gm = gm; gm = gm->next; if (prev) { From 110e08e7c497213636e77614b199703e428b303d Mon Sep 17 00:00:00 2001 From: limengning Date: Wed, 20 Aug 2025 02:47:47 +0800 Subject: [PATCH 3/3] Add a example --- examples/C/multi3.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 examples/C/multi3.c diff --git a/examples/C/multi3.c b/examples/C/multi3.c new file mode 100644 index 0000000000..01a05a4bea --- /dev/null +++ b/examples/C/multi3.c @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2005- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * + * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by + * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. + */ + +/* + * C Implementation: multi2.c + * + * Description: Repeatedly print data contained in a multi-field GRIB2 message + */ + +#include "eccodes.h" + +#include +#include +#include + +#ifndef HAVE_FSEEKO +#define fseeko fseek +#define ftello ftell +#endif + +const int NUM_FIELDS = 4; +const int COUNT = 5; +const char* file_path = "../../data/multi_created.grib2"; + +static void read_data(FILE* fp, int num_msgs) +{ + int err = 0, i; + long stepRange = 0; + codes_handle* h = NULL; + + printf("File offset start = %ld\n", ftello(fp)); + for (i = 0; i < num_msgs; ++i) { + h = codes_handle_new_from_file(0, fp, PRODUCT_GRIB, &err); + CODES_CHECK(err, 0); + + CODES_CHECK(codes_get_long(h, "stepRange", &stepRange), 0); + printf("%d : stepRange=%ld\n", i, stepRange); + codes_handle_delete(h); + /* These tests make sure we always start from 1st field of the grib msg */ + /* and not where we left off last time */ + if (i == 0) assert(stepRange == 0); /* 1st field */ + if (i == 1) assert(stepRange == 12); /* 2nd field */ + if (i == 2) assert(stepRange == 24); /* 3rd field */ + if (i == 3) assert(stepRange == 36); /* 4th field */ + } +} + +static void read_file() { + int i; + FILE* fp = fopen(file_path, "rb"); + if (!fp) { + fprintf(stderr, "ERROR: unable to open GRIB file %s)\n", file_path); + exit(1); + } + + /* turn on support for multi-field messages */ + codes_grib_multi_support_on(NULL); + + for (i = 1; i < COUNT; ++i) { + printf("Pass %d:\n", i); + fseeko(fp, 0, SEEK_SET); + read_data(fp, NUM_FIELDS); + + /* Reset the internal engine state using this file pointer for the next round */ + codes_grib_multi_support_reset_file(codes_context_get_default(), fp); + } + fclose(fp); + // Delete context here will cause error and exit + // codes_context_delete(NULL); +} + +int main(int argc, char** argv) +{ + int i; + for (i = 1; i < 100; ++i) { + read_file(); + } + // When we delete context here, it will use too much memory. + codes_context_delete(NULL); + printf("All OK\n"); + return 0; +}