g_socket_client_connect_to_host_async leaks memory when target host doesn't respond to ARP
When I try to connect to a host which is powered down on a same subnet with g_socket_client_connect_to_host_async(), it leaks GSocketClientAsyncConnectData it allocates.
void
g_socket_client_connect_async (...)
{
GSocketClientAsyncConnectData *data;
g_return_if_fail (G_IS_SOCKET_CLIENT (client));
data = g_slice_new0 (GSocketClientAsyncConnectData); // this memory leaks!!!
It seems the task it allocates is not unref'ed anywhere.
data->task = g_task_new (client, cancellable, callback, user_data);
This leak doesn't occur when the host rejects the connection with TCP RST.
Following is the app I used.
#include <gio/gio.h>
#include <stdio.h>
#include <stdlib.h>
static void on_connected(GObject *source_object, GAsyncResult *res, gpointer user_data);
static GMainLoop *loop;
static const char *host;
static gboolean timer_func(gpointer user_data) {
printf("connecting %s\n", host);
GSocketClient *client = g_socket_client_new();
g_socket_client_connect_to_host_async(client,
host,
8099,
NULL, // GCancellable object
on_connected,
NULL); // user data
return FALSE; //one shot
//return TRUE;
}
int main(int argc, char *argv[]) {
if (argc >= 2) {
host = argv[1];
} else {
host = "172.28.79.99";
}
g_timeout_add_seconds(5, timer_func, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
printf("main run done\n");
g_main_loop_unref(loop);
return 0;
}
void on_connected(GObject *source_object, GAsyncResult *res, gpointer user_data) {
GSocketClient *client = G_SOCKET_CLIENT(source_object);
GError *error = NULL;
GSocketConnection *connection = g_socket_client_connect_to_host_finish(client, res, &error);
if (error != NULL) {
fprintf(stderr, "Error: %s\n", error->message);
g_error_free(error);
} else if (connection != NULL) {
printf("Connected to the host successfully!\n");
g_io_stream_close(G_IO_STREAM(connection), NULL, NULL);
g_object_unref(connection);
}
g_object_unref(client);
}
Output of the app is like below. The message "Could not connect" is printed 2-3 sedonds after "connecting" is printed.
$ ./glibapp 192.168.1.50
connecting 192.168.1.50
Error: Could not connect to 192.168.1.50: No route to host
Output of valgrind is below.
==2655828== 1,329 (96 direct, 1,233 indirect) bytes in 1 blocks are definitely lost in loss record 1,047 of 1,051
==2655828== at 0x4845828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2655828== by 0x4AAB041: g_malloc (gmem.c:130)
==2655828== by 0x4908CD9: g_socket_client_connect_async (gsocketclient.c:2087)
==2655828== by 0x4908F20: g_socket_client_connect_to_host_async (gsocketclient.c:2194)
==2655828== by 0x1093A9: timer_func(void*) (main.cpp:17)
==2655828== by 0x4AA4E4D: g_timeout_dispatch (gmain.c:4989)
==2655828== by 0x4AA0ED8: g_main_dispatch (gmain.c:3344)
==2655828== by 0x4AA4136: g_main_context_dispatch_unlocked (gmain.c:4152)
==2655828== by 0x4AA4136: g_main_context_iterate_unlocked.isra.0 (gmain.c:4217)
==2655828== by 0x4AA4A3E: g_main_loop_run (gmain.c:4419)
==2655828== by 0x109426: main (main.cpp:38)
Tested on on the following two environments with libc 2.38(Ubuntu GLIBC 2.38-1ubuntu6)
- Ubuntu 23.10 + glib2.0-2.78.0
- Ubuntu 23.10 + glib master(commitid:8f37874f)