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;
+}