Bug 15777

Summary: memory leaks.
Product: [Yocto Project Subprojects] opkg Reporter: Sunny Wong <unintialized>
Component: opkgAssignee: Alex Stewart <alex.stewart>
Status: IN PROGRESS REVIEW --- QA Contact:
Severity: minor    
Priority: Low    
Version: 0.8.0   
Target Milestone: next-patch   
Hardware: Other   
OS: arm64   
Whiteboard:
OS type for building Yocto: --- Type of Regression: ---
Verified: Documentation change: Don't know

Description Sunny Wong 2025-03-02 06:32:07 UTC
opkg version is v0.8.0.

The test command is: opkg install test/pack_name_0.0.1_aarch64.ipk --force-reinstall

The call stack looks like this:

=================================================================
==22017==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fb09c8760 in __interceptor_calloc (/lib64/libasan.so.8+0xc8760)
    #1 0x55675c1734 in xcalloc opkg-master/libopkg/xfuncs.c:56
    #2 0x55675b29bc in pkg_vec_alloc opkg-master/libopkg/pkg_vec.c:33
    #3 0x556759833c in pkg_init opkg-master/libopkg/pkg.c:96
    #4 0x5567598b8c in pkg_new opkg-master/libopkg/pkg.c:143
    #5 0x556758e138 in opkg_prepare_file_for_install opkg-master/libopkg/opkg_download.c:421
    #6 0x556758eba0 in opkg_prepare_url_for_install opkg-master/libopkg/opkg_download.c:552
    #7 0x55675884bc in opkg_install_cmd opkg-master/libopkg/opkg_cmd.c:420
    #8 0x556758c514 in opkg_cmd_exec opkg-master/libopkg/opkg_cmd.c:1310
    #9 0x5567585ab4 in main opkg-master/src/opkg.c:544
    #10 0x7fad80e368  (/lib/libc.so.6+0x2b368)
    #11 0x7fad80e444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #12 0x55675831ac in _start (/usr/bin/opkg+0x1e1ac)

Direct leak of 16 byte(s) in 2 object(s) allocated from:
    #0 0x7fb09a2884 in __interceptor_strdup (/lib64/libasan.so.8+0xa2884)
    #1 0x55675c1818 in xstrdup opkg-master/libopkg/xfuncs.c:71
    #2 0x55675b75b0 in file_info_init opkg-master/libopkg/file_list.c:30
    #3 0x55675b790c in file_list_append opkg-master/libopkg/file_list.c:78
    #4 0x55675a0e30 in pkg_get_installed_files opkg-master/libopkg/pkg.c:1261
    #5 0x55675af918 in file_hash_set_file_owner opkg-master/libopkg/pkg_hash.c:923
    #6 0x55675d5b34 in update_file_ownership opkg-master/libopkg/opkg_install.c:69
    #7 0x55675d9e50 in opkg_install_pkg opkg-master/libopkg/opkg_install.c:964
    #8 0x55675d4b84 in libsolv_solver_execute_transaction solvers/libsolv/opkg_solver_libsolv.c:1009
    #9 0x55675cf6b8 in opkg_solver_install solvers/libsolv/opkg_solver_libsolv.c:153
    #10 0x5567588500 in opkg_install_cmd opkg-master/libopkg/opkg_cmd.c:426
    #11 0x556758c514 in opkg_cmd_exec opkg-master/libopkg/opkg_cmd.c:1310
    #12 0x5567585ab4 in main opkg-master/src/opkg.c:544
    #13 0x7fad80e368  (/lib/libc.so.6+0x2b368)
    #14 0x7fad80e444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #15 0x55675831ac in _start (/usr/bin/opkg+0x1e1ac)

Direct leak of 16 byte(s) in 2 object(s) allocated from:
    #0 0x7fb09a2884 in __interceptor_strdup (/lib64/libasan.so.8+0xa2884)
    #1 0x55675c1818 in xstrdup opkg-master/libopkg/xfuncs.c:71
    #2 0x55675b75b0 in file_info_init opkg-master/libopkg/file_list.c:30
    #3 0x55675b790c in file_list_append opkg-master/libopkg/file_list.c:78
    #4 0x55675a0e30 in pkg_get_installed_files opkg-master/libopkg/pkg.c:1261
    #5 0x55675d8428 in check_data_file_clashes_change opkg-master/libopkg/opkg_install.c:619
    #6 0x55675da418 in opkg_install_pkg opkg-master/libopkg/opkg_install.c:1049
    #7 0x55675d4b84 in libsolv_solver_execute_transaction solvers/libsolv/opkg_solver_libsolv.c:1009
    #8 0x55675cf6b8 in opkg_solver_install solvers/libsolv/opkg_solver_libsolv.c:153
    #9 0x5567588500 in opkg_install_cmd opkg-master/libopkg/opkg_cmd.c:426
    #10 0x556758c514 in opkg_cmd_exec opkg-master/libopkg/opkg_cmd.c:1310
    #11 0x5567585ab4 in main opkg-master/src/opkg.c:544
    #12 0x7fad80e368  (/lib/libc.so.6+0x2b368)
    #13 0x7fad80e444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #14 0x55675831ac in _start (/usr/bin/opkg+0x1e1ac)

Direct leak of 10 byte(s) in 1 object(s) allocated from:
    #0 0x7fb09a2884 in __interceptor_strdup (/lib64/libasan.so.8+0xa2884)
    #1 0x7fad9d0f64 in solv_strdup (/lib/libsolv.so.1+0x44f64)
    #2 0x7fad9c87d8 in datamatcher_init (/lib/libsolv.so.1+0x3c7d8)
    #3 0x7fad9c9440 in dataiterator_init (/lib/libsolv.so.1+0x3d440)
    #4 0x55675cf268 in opkg_solver_install solvers/libsolv/opkg_solver_libsolv.c:110
    #5 0x5567588500 in opkg_install_cmd opkg-master/libopkg/opkg_cmd.c:426
    #6 0x556758c514 in opkg_cmd_exec opkg-master/libopkg/opkg_cmd.c:1310
    #7 0x5567585ab4 in main opkg-master/src/opkg.c:544
    #8 0x7fad80e368  (/lib/libc.so.6+0x2b368)
    #9 0x7fad80e444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #10 0x55675831ac in _start (/usr/bin/opkg+0x1e1ac)

SUMMARY: AddressSanitizer: 58 byte(s) leaked in 6 allocation(s).
Comment 1 Sunny Wong 2025-03-03 03:32:44 UTC
If I install the same pkg over and over again, it goes to libopkg/opkg_download.c:443:
          if (old_pkg && (pkg_compare_versions(pkg, old_pkg) == 0){
          }

and doesn't release pkg->provides_str and pkg->replaces_str before return-1.


The call stack looks like this:

error: opkg_prepare_file_for_install: Refusing to load file 'test/pack_name_0.0.1_aarch64.ipk' as it matches the installed version of pack_name (0.0.1).
=================================================================
==23274==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fb332d688 in __interceptor_realloc.part.0 (/lib64/libasan.so.8+0xc7688)
    #1 0x555cf27974 in xrealloc /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/xfuncs.c:46
    #2 0x555cf25fd4 in parse_list /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:76
    #3 0x555cf17f10 in pkg_parse_line /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:256
    #4 0x555cf26854 in parse_from_stream_nomalloc /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:175
    #5 0x555cf18b20 in pkg_parse_from_stream /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:351
    #6 0x555cf00048 in pkg_init_from_file /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg.c:302
    #7 0x555cef4388 in opkg_prepare_file_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:423
    #8 0x555cef4de8 in opkg_prepare_url_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:552
    #9 0x555ceee6dc in opkg_install_cmd /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:420
    #10 0x555cef2754 in opkg_cmd_exec /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:1310
    #11 0x555ceebcf4 in main /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/src/opkg.c:544
    #12 0x7fb0174368  (/lib/libc.so.6+0x2b368)
    #13 0x7fb0174444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #14 0x555cee93ec in _start (/usr/bin/opkg+0x1e3ec)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fb332d688 in __interceptor_realloc.part.0 (/lib64/libasan.so.8+0xc7688)
    #1 0x555cf27974 in xrealloc /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/xfuncs.c:46
    #2 0x555cf25fd4 in parse_list /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:76
    #3 0x555cf18114 in pkg_parse_line /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:269
    #4 0x555cf26854 in parse_from_stream_nomalloc /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:175
    #5 0x555cf18b20 in pkg_parse_from_stream /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:351
    #6 0x555cf00048 in pkg_init_from_file /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg.c:302
    #7 0x555cef4388 in opkg_prepare_file_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:423
    #8 0x555cef4de8 in opkg_prepare_url_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:552
    #9 0x555ceee6dc in opkg_install_cmd /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:420
    #10 0x555cef2754 in opkg_cmd_exec /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:1310
    #11 0x555ceebcf4 in main /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/src/opkg.c:544
    #12 0x7fb0174368  (/lib/libc.so.6+0x2b368)
    #13 0x7fb0174444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #14 0x555cee93ec in _start (/usr/bin/opkg+0x1e3ec)

Indirect leak of 46 byte(s) in 2 object(s) allocated from:
    #0 0x7fb332e454 in __interceptor_malloc (/lib64/libasan.so.8+0xc8454)
    #1 0x7fb32f7c40 in __interceptor_strndup.part.0 (/lib64/libasan.so.8+0x91c40)
    #2 0x555cf27bfc in xstrndup /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/xfuncs.c:89
    #3 0x555cf262a8 in parse_list /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:92
    #4 0x555cf17f10 in pkg_parse_line /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:256
    #5 0x555cf26854 in parse_from_stream_nomalloc /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:175
    #6 0x555cf18b20 in pkg_parse_from_stream /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:351
    #7 0x555cf00048 in pkg_init_from_file /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg.c:302
    #8 0x555cef4388 in opkg_prepare_file_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:423
    #9 0x555cef4de8 in opkg_prepare_url_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:552
    #10 0x555ceee6dc in opkg_install_cmd /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:420
    #11 0x555cef2754 in opkg_cmd_exec /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:1310
    #12 0x555ceebcf4 in main /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/src/opkg.c:544
    #13 0x7fb0174368  (/lib/libc.so.6+0x2b368)
    #14 0x7fb0174444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #15 0x555cee93ec in _start (/usr/bin/opkg+0x1e3ec)

Indirect leak of 46 byte(s) in 2 object(s) allocated from:
    #0 0x7fb332e454 in __interceptor_malloc (/lib64/libasan.so.8+0xc8454)
    #1 0x7fb32f7c40 in __interceptor_strndup.part.0 (/lib64/libasan.so.8+0x91c40)
    #2 0x555cf27bfc in xstrndup /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/xfuncs.c:89
    #3 0x555cf262a8 in parse_list /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:92
    #4 0x555cf18114 in pkg_parse_line /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:269
    #5 0x555cf26854 in parse_from_stream_nomalloc /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/parse_util.c:175
    #6 0x555cf18b20 in pkg_parse_from_stream /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg_parse.c:351
    #7 0x555cf00048 in pkg_init_from_file /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/pkg.c:302
    #8 0x555cef4388 in opkg_prepare_file_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:423
    #9 0x555cef4de8 in opkg_prepare_url_for_install /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_download.c:552
    #10 0x555ceee6dc in opkg_install_cmd /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:420
    #11 0x555cef2754 in opkg_cmd_exec /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/libopkg/opkg_cmd.c:1310
    #12 0x555ceebcf4 in main /home/rk3568/rk3568_linux6.1_b01/buildroot/output/rockchip_rk3568/build/opkg-master/src/opkg.c:544
    #13 0x7fb0174368  (/lib/libc.so.6+0x2b368)
    #14 0x7fb0174444 in __libc_start_main (/lib/libc.so.6+0x2b444)
    #15 0x555cee93ec in _start (/usr/bin/opkg+0x1e3ec)

SUMMARY: AddressSanitizer: 124 byte(s) leaked in 6 allocation(s).
Comment 2 Sunny Wong 2025-03-03 08:34:20 UTC
I've fixed it. Please review it.


From 96b028cd5eb560928c897adf58903f764d41c914 Mon Sep 17 00:00:00 2001
From: "unintialized@gmail.com"
Date: Mon, 3 Mar 2025 16:31:38 +0800
Subject: [PATCH] Fix multiple memory leak issues

---
 libopkg/file_list.c                           |  8 +--
 libopkg/opkg_download.c                       | 49 +++++++++++++++++++
 libopkg/pkg.c                                 |  6 ++-
 libopkg/pkg.h                                 |  2 +
 libopkg/solvers/libsolv/opkg_solver_libsolv.c |  5 +-
 5 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/libopkg/file_list.c b/libopkg/file_list.c
index 03c3c12..c34758a 100644
--- a/libopkg/file_list.c
+++ b/libopkg/file_list.c
@@ -90,11 +90,13 @@ static int file_list_cmp(const void *left, const void *right)
 
 void file_list_remove_elt(file_list_t *list, const char *path)
 {
-    char *str = void_list_remove_elt((void_list_t *)list,
+    file_info_t *info = void_list_remove_elt((void_list_t *)list,
                                      (void *)path,
                                      file_list_cmp);
-    if (str)
-        free(str);
+    if (info){
+        file_info_deinit(info);
+        free(info);
+    }
 }
 
 file_list_elt_t *file_list_first(file_list_t *list)
diff --git a/libopkg/opkg_download.c b/libopkg/opkg_download.c
index 4086f83..8ed126f 100644
--- a/libopkg/opkg_download.c
+++ b/libopkg/opkg_download.c
@@ -446,6 +446,55 @@ static int opkg_prepare_file_for_install(const char *path, char **namep)
                      "Refusing to load file '%s' as it matches the installed version of %s (%s).\n",
                      path, old_pkg->name, version);
             free(version);
+            if (pkg->provides_count >0){
+                for (int i = 0; i < pkg->provides_count; i++) 
+                    free(pkg->provides_str[i]);
+                free(pkg->provides_str);
+                pkg->provides_count = 0;
+            }
+
+            if (pkg->conflicts_count >0){
+                for (int i = 0; i < pkg->conflicts_count; i++) 
+                    free(pkg->conflicts_str[i]);
+                free(pkg->conflicts_str);
+                pkg->conflicts_count = 0;
+            }
+
+            if (pkg->replaces_count >0){
+                for (int i = 0; i < pkg->replaces_count; i++) 
+                    free(pkg->replaces_str[i]);
+                free(pkg->replaces_str);
+                pkg->replaces_count = 0;
+            }
+
+            if (pkg->pre_depends_count >0){
+                for (int i = 0; i < pkg->pre_depends_count; i++) 
+                    free(pkg->pre_depends_str[i]);
+                free(pkg->pre_depends_str);
+                pkg->pre_depends_count = 0;
+            }
+
+            if (pkg->depends_count >0){
+                for (int i = 0; i < pkg->depends_count; i++) 
+                    free(pkg->depends_str[i]);
+                free(pkg->depends_str);
+                pkg->depends_count = 0;
+            }
+
+            if (pkg->recommends_count >0){
+                for (int i = 0; i < pkg->recommends_count; i++) 
+                    free(pkg->recommends_str[i]);
+                free(pkg->recommends_str);
+                pkg->recommends_count = 0;
+            }
+
+            if (pkg->suggests_count >0){
+                for (int i = 0; i < pkg->suggests_count; i++) 
+                    free(pkg->suggests_str[i]);
+                free(pkg->suggests_str);
+                pkg->suggests_count = 0;
+            }
+
             pkg_deinit(pkg);
             free(pkg);
             return -1;
diff --git a/libopkg/pkg.c b/libopkg/pkg.c
index 6b1bd8f..5caa8fe 100644
--- a/libopkg/pkg.c
+++ b/libopkg/pkg.c
@@ -93,7 +93,9 @@ static void pkg_init(pkg_t * pkg)
     pkg->description = NULL;
     pkg->tags = NULL;
     pkg->state_want = SW_UNKNOWN;
-    pkg->wanted_by = pkg_vec_alloc();
+#if HAVE_SOLVER_INTERNAL
+    // pkg->wanted_by = pkg_vec_alloc();
+#endif
     pkg->state_flag = SF_OK;
     pkg->state_status = SS_NOT_INSTALLED;
     pkg->depends_str = NULL;
@@ -191,7 +193,9 @@ void pkg_deinit(pkg_t * pkg)
     pkg->description = NULL;
 
     pkg->state_want = SW_UNKNOWN;
+#if HAVE_SOLVER_INTERNAL
     pkg_vec_free(pkg->wanted_by);
+#endif
     pkg->state_flag = SF_OK;
     pkg->state_status = SS_NOT_INSTALLED;
 
diff --git a/libopkg/pkg.h b/libopkg/pkg.h
index a62c065..cdbe30c 100644
--- a/libopkg/pkg.h
+++ b/libopkg/pkg.h
@@ -127,7 +127,9 @@ struct pkg {
     char *description;
     char *tags;
     pkg_state_want_t state_want;
+#if HAVE_SOLVER_INTERNAL
     pkg_vec_t *wanted_by;
+#endif
     pkg_state_flag_t state_flag;
     pkg_state_status_t state_status;
     char **depends_str;
diff --git a/libopkg/solvers/libsolv/opkg_solver_libsolv.c b/libopkg/solvers/libsolv/opkg_solver_libsolv.c
index d152174..dd66a5c 100644
--- a/libopkg/solvers/libsolv/opkg_solver_libsolv.c
+++ b/libopkg/solvers/libsolv/opkg_solver_libsolv.c
@@ -115,6 +115,8 @@ int opkg_solver_install(int num_pkgs, char **pkg_names)
             found_match = 1;
         }
 
+        dataiterator_free(&di);
+
         if (!found_match) {
             /*
              * pkg wasn't found in repo_available which would be ok if it is present in another repo
@@ -130,8 +132,10 @@ int opkg_solver_install(int num_pkgs, char **pkg_names)
                           SOLVABLE_NAME | SOLVABLE_PROVIDES, name, SEARCH_GLOB);
                 if (dataiterator_step(&di)) {
                     found_match = 1;
+                    dataiterator_free(&di);
                     break;
                 }
+                dataiterator_free(&di);
             }
 
             if (!found_match) {
@@ -141,7 +145,6 @@ int opkg_solver_install(int num_pkgs, char **pkg_names)
             }
         }
 
-        dataiterator_free(&di);
         free(name);
         free(version);
     }
-- 
2.43.0