]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
debuginfod, libdwfl: Initialize libcurl and dlopen debuginfod-client lazily
authorMark Wielaard <mark@klomp.org>
Fri, 22 Apr 2022 21:36:30 +0000 (23:36 +0200)
committerMark Wielaard <mark@klomp.org>
Mon, 25 Apr 2022 14:09:41 +0000 (16:09 +0200)
We used to go out of our way to initialize libcurl early before any other
thread/code was running. But this meant that we might pay startup cost,
which under FIPS is significant, even for code that never uses libdebuginfod
or TLS libcurl connections. Although curl_global_init itself isn't thread-safe
we can use pthread_once to make sure we don't race against ourselves. This
still means we might race against any application code that might use
libcurl. But we can assume they will have called curl_global_init before
calling dwfl_begin or debuginfod_begin.

Signed-off-by: Mark Wielaard <mark@klomp.org>
debuginfod/ChangeLog
debuginfod/Makefile.am
debuginfod/debuginfod-client.c
libdwfl/ChangeLog
libdwfl/debuginfod-client.c

index 0f1bca6f25fe7e688f6d7a8fcff7cdf28d9b41b2..93c8ae114dbd34abfff77f537e276f3b1de6b70e 100644 (file)
@@ -1,3 +1,13 @@
+2022-04-22  Mark Wielaard  <mark@klomp.org>
+
+       * Makefile.am (libdebuginfod): Add -lpthread.
+       (libdebuginfod_so_LDLIBS): Likewise.
+       * debuginfod-client.c (init_control): New static pthread_once_t.
+       (libcurl_init): New static function.
+       (debuginfod_begin): Use ptrace_once to call libcurl_init.
+       (libdebuginfod_ctor): Removed.
+       (libdebuginfod_dtor): Likewise.
+
 2022-04-24  Mark Wielaard  <mark@klomp.org>
 
        * debuginfod.cxx (main): Add MHD_USE_ITC to MHD_start_daemon flags.
index 3adb27559c9cf247f4ab47c37f044448f0d6b120..435cb8a6839c03d6afff03a4c22e062e494c23c9 100644 (file)
@@ -47,7 +47,7 @@ libelf = ../libelf/libelf.a -lz
 if DUMMY_LIBDEBUGINFOD
 libdebuginfod = ./libdebuginfod.a
 else
-libdebuginfod = ./libdebuginfod.a $(libcurl_LIBS)
+libdebuginfod = ./libdebuginfod.a -lpthread $(libcurl_LIBS)
 endif
 else
 libasm = ../libasm/libasm.so
@@ -97,7 +97,7 @@ libdebuginfod_so_LIBS = libdebuginfod_pic.a
 if DUMMY_LIBDEBUGINFOD
 libdebuginfod_so_LDLIBS =
 else
-libdebuginfod_so_LDLIBS = $(libcurl_LIBS) $(fts_LIBS)
+libdebuginfod_so_LDLIBS = -lpthread $(libcurl_LIBS) $(fts_LIBS)
 endif
 $(LIBDEBUGINFOD_SONAME): $(srcdir)/libdebuginfod.map $(libdebuginfod_so_LIBS)
        $(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
index 58ef64427ed423a52182f1af19b5121fb732f4fe..45a27b5efb48748d90c119a7e4df30c5d9af4a74 100644 (file)
@@ -1,6 +1,6 @@
 /* Retrieve ELF / DWARF / source files from the debuginfod.
    Copyright (C) 2019-2021 Red Hat, Inc.
-   Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
+   Copyright (C) 2021, 2022 Mark J. Wielaard <mark@klomp.org>
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -98,6 +98,16 @@ void debuginfod_end (debuginfod_client *c) { }
   #include <fts.h>
 #endif
 
+#include <pthread.h>
+
+static pthread_once_t init_control = PTHREAD_ONCE_INIT;
+
+static void
+libcurl_init(void)
+{
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+}
+
 struct debuginfod_client
 {
   /* Progress/interrupt callback function. */
@@ -1475,6 +1485,9 @@ debuginfod_query_server (debuginfod_client *c,
 debuginfod_client  *
 debuginfod_begin (void)
 {
+  /* Initialize libcurl lazily, but only once.  */
+  pthread_once (&init_control, libcurl_init);
+
   debuginfod_client *client;
   size_t size = sizeof (struct debuginfod_client);
   client = calloc (1, size);
@@ -1608,18 +1621,4 @@ debuginfod_set_verbose_fd(debuginfod_client *client, int fd)
   client->verbose_fd = fd;
 }
 
-
-/* NB: these are thread-unsafe. */
-__attribute__((constructor)) attribute_hidden void libdebuginfod_ctor(void)
-{
-  curl_global_init(CURL_GLOBAL_DEFAULT);
-}
-
-/* NB: this is very thread-unsafe: it breaks other threads that are still in libcurl */
-__attribute__((destructor)) attribute_hidden void libdebuginfod_dtor(void)
-{
-  /* ... so don't do this: */
-  /* curl_global_cleanup(); */
-}
-
 #endif /* DUMMY_LIBDEBUGINFOD */
index 9c5c85178834f540a6f4ec6d9fabd739da672e0d..76053039a6967af4b2bb44d085d55495f0563201 100644 (file)
@@ -1,3 +1,10 @@
+2022-04-22  Mark Wielaard  <mark@klomp.org>
+
+       * debuginfod-client.c (init_control): New static pthread_once_t.
+       (get_client): Use pthread_once to call __libdwfl_debuginfod_init.
+       (__libdwfl_debuginfod_init): Make static, remove attribute
+       constructor.
+
 2022-02-18  Mark Wielaard  <mark@klomp.org>
 
        * image-header.c (__libdw_image_header): Assign header values for
index 99b66b6eedf4a8a06024b2bb89da4824847fcd4d..153260c3febca031f25a7ddc390d8abd94efd532 100644 (file)
@@ -1,5 +1,6 @@
 /* Try to get an ELF or debug file through the debuginfod.
    Copyright (C) 2019 Red Hat, Inc.
+   Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -31,6 +32,7 @@
 #endif
 
 #include "libdwflP.h"
+#include <pthread.h>
 #include <dlfcn.h>
 
 static __typeof__ (debuginfod_begin) *fp_debuginfod_begin;
@@ -38,6 +40,10 @@ static __typeof__ (debuginfod_find_executable) *fp_debuginfod_find_executable;
 static __typeof__ (debuginfod_find_debuginfo) *fp_debuginfod_find_debuginfo;
 static __typeof__ (debuginfod_end) *fp_debuginfod_end;
 
+static void __libdwfl_debuginfod_init (void);
+
+static pthread_once_t init_control = PTHREAD_ONCE_INIT;
+
 /* NB: this is slightly thread-unsafe */
 
 static debuginfod_client *
@@ -46,6 +52,8 @@ get_client (Dwfl *dwfl)
   if (dwfl->debuginfod != NULL)
     return dwfl->debuginfod;
 
+  pthread_once (&init_control, __libdwfl_debuginfod_init);
+
   if (fp_debuginfod_begin != NULL)
     {
       dwfl->debuginfod = (*fp_debuginfod_begin) ();
@@ -96,9 +104,9 @@ __libdwfl_debuginfod_end (debuginfod_client *c)
     (*fp_debuginfod_end) (c);
 }
 
-/* Try to get the libdebuginfod library functions to make sure
-   everything is initialized early.  */
-void __attribute__ ((constructor))
+/* Try to get the libdebuginfod library functions.
+   Only needs to be called once from get_client.  */
+static void
 __libdwfl_debuginfod_init (void)
 {
   void *debuginfod_so = dlopen(DEBUGINFOD_SONAME, RTLD_LAZY);