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