Commit 4864754416 for frr
commit 486475441629b4fac988497b548744de57151601
Author: Philippe Guibert <philippe.guibert@6wind.com>
Date: Mon Oct 26 14:22:10 2026 +0100
tests: fix memory leaks in test_ospf_spf
When running the ospfd unit tests with address sanitizer, the
test_ospf_spf test still fails with memory leaks after the TI-LFA
fix:
> $ make check
> [..]
> E -end.
> [..]
> ==1620107==ERROR: LeakSanitizer: detected memory leaks
> Direct leak of [..] in 10 object(s) allocated from:
> #0 calloc
> #1 qcalloc lib/memory.c:111
> #2 route_table_init_with_delegate lib/table.c:46
> #3 route_table_init lib/table.c:629
> #4 test_run_spf tests/ospfd/test_ospf_spf.c:84
> [..]
> Indirect leak of 40400 byte(s) in 10 object(s) allocated from:
> #2 ospf_new_alloc ospfd/ospfd.c:362
> [..]
The missing "end." line is a side effect: LeakSanitizer exits
before stdout is flushed.
Each test run allocates an ospf instance, an area and their LSDB, and
the route tables and SPF tree of the computation, and none of them
are freed. ospf_finish() can not be used here: it relies on the ospf
master and on the opaque functions that are not initialised by the
test, and it stops segment routing, which is needed by the next runs.
Fix this:
- free the route tables and the SPF tree at the end of
test_run_spf().
- add test_finish() that frees the area and the ospf instance, as
done by ospf_finish_final() for what ospf_new_alloc() and
ospf_area_new() allocate.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
diff --git a/tests/ospfd/test_ospf_spf.c b/tests/ospfd/test_ospf_spf.c
index cb3153e846..0345979987 100644
--- a/tests/ospfd/test_ospf_spf.c
+++ b/tests/ospfd/test_ospf_spf.c
@@ -15,6 +15,9 @@
#include "ospfd/ospfd.h"
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_opaque.h"
+#include "ospfd/ospf_gr.h"
#include "ospfd/ospf_route.h"
#include "ospfd/ospf_spf.h"
#include "ospfd/ospf_ti_lfa.h"
@@ -66,6 +69,39 @@ static struct ospf *test_init(struct ospf_test_node *root)
return ospf;
}
+static void test_finish(struct ospf *ospf)
+{
+ ospf_area_check_free(ospf, ospf->backbone->area_id);
+
+ event_cancel(&ospf->t_maxage_walker);
+ event_cancel(&ospf->t_lsa_refresher);
+
+ ospf_opaque_type11_lsa_term(ospf);
+ ospf_gr_helper_instance_stop(ospf);
+
+ ospf_lsdb_delete_all(ospf->lsdb);
+ ospf_lsdb_free(ospf->lsdb);
+
+ route_table_finish(ospf->networks);
+ route_table_finish(ospf->nbr_nbma);
+ route_table_finish(ospf->new_external_route);
+ route_table_finish(ospf->old_external_route);
+ route_table_finish(ospf->external_lsas);
+ route_table_finish(ospf->maxage_lsa);
+ route_table_finish(ospf->distance_table);
+ route_table_finish(ospf->rt_aggr_tbl);
+
+ list_delete(&ospf->oiflist);
+ list_delete(&ospf->vlinks);
+ list_delete(&ospf->areas);
+ list_delete(&ospf->oi_write_q);
+ stream_free(ospf->ibuf);
+
+ QOBJ_UNREG(ospf);
+ XFREE(MTYPE_OSPF_TOP, ospf->name);
+ XFREE(MTYPE_OSPF_TOP, ospf);
+}
+
static void test_run_spf(struct vty *vty, struct ospf *ospf,
enum protection_type protection_type, bool verbose)
{
@@ -151,6 +187,13 @@ static void test_run_spf(struct vty *vty, struct ospf *ospf,
"\n\nFinal Routing Table including backup paths:\n\n");
print_route_table(vty, new_table);
+
+ ospf_route_table_free(new_table);
+ ospf_rtrs_free(new_rtrs);
+ ospf_rtrs_free(all_rtrs);
+ ospf_spf_cleanup(area->spf, area->spf_vertex_list);
+ area->spf = NULL;
+ area->spf_vertex_list = NULL;
}
static int test_run(struct vty *vty, struct ospf_topology *topology,
@@ -164,6 +207,7 @@ static int test_run(struct vty *vty, struct ospf_topology *topology,
/* Inject LSAs into the OSPF backbone according to the topology */
if (topology_load(vty, topology, root, ospf)) {
vty_out(vty, "%% Failed to load topology\n");
+ test_finish(ospf);
return CMD_WARNING;
}
@@ -174,6 +218,8 @@ static int test_run(struct vty *vty, struct ospf_topology *topology,
test_run_spf(vty, ospf, protection_type, verbose);
+ test_finish(ospf);
+
return 0;
}