]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
src: add curl_global_init_mem testing
authorDaniel Stenberg <daniel@haxx.se>
Tue, 24 Mar 2026 15:25:03 +0000 (16:25 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 27 Mar 2026 07:10:14 +0000 (08:10 +0100)
Build with "configure --enable-init-mem-debug" to make the tool use
curl_global_init_mem() and a set of private memory funtion callbacks for
libcurl's memory management.

Using this setup, memory mixups in tool code is more likely to cause
crashes and thus get discovered while running tests.

This curl_global_init_mem debug mode can only be done when building
libcurl shared (not static) and without debugging enabled - since it
needs to use the custom memory funtion callbacks.

Closes #21099

CMakeLists.txt
configure.ac
src/tool_cfgable.c

index 32cbeebde7834df28aceb1b82b0b3acd25093cab..06a21b1ce55bacc0921f9dff70cae44f9084c15a 100644 (file)
@@ -510,7 +510,13 @@ option(CURL_DISABLE_TYPECHECK "Disable curl_easy_setopt()/curl_easy_getinfo() ty
 mark_as_advanced(CURL_DISABLE_TYPECHECK)
 option(CURL_DISABLE_VERBOSE_STRINGS "Disable verbose strings" OFF)
 mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS)
+option(CURL_DEBUG_GLOBAL_MEM "Debug curl_global_init_mem" OFF)
+mark_as_advanced(CURL_DEBUG_GLOBAL_MEM)
 
+if(CURL_DEBUG_GLOBAL_MEM)
+  # Set it via the command-line to make it apply to the entire directory.
+  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "CURL_DEBUG_GLOBAL_MEM")
+endif()
 if(CURL_DISABLE_TYPECHECK)
   # Set it via the command-line to make it apply to examples also.
   set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "CURL_DISABLE_TYPECHECK")
index 99ecbce5bcf4324d40996ccbd6374a4ed589dd6e..9ae0cfd06811a4c58ee8eab314cb8abcfcca106e 100644 (file)
@@ -1087,6 +1087,23 @@ AS_HELP_STRING([--disable-mqtt],[Disable MQTT support]),
     AC_MSG_RESULT(no)
 )
 
+AC_MSG_CHECKING([enable curl_global_init_mem debug build])
+AC_ARG_ENABLE(init-mem-debug,
+AS_HELP_STRING([--enable-init-mem-debug],[curl_global_init_mem debug])
+AS_HELP_STRING([--disable-init-mem-debug],[]),
+[ case "$enableval" in
+  yes)
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(CURL_DEBUG_GLOBAL_MEM, 1, [curl_debug_global_mem debug build])
+    SUPPORT_FEATURES="$SUPPORT_FEATURES global-mem-debug"
+    ;;
+  *)
+    AC_MSG_RESULT(no)
+    ;;
+  esac ],
+    AC_MSG_RESULT(no)
+)
+
 dnl **********************************************************************
 dnl Check for built-in manual
 dnl **********************************************************************
index 0d151af02e6ccede7fde38e0fccc265d3ad7bac0..381ca874d9daa7fef4f981cc437a67875f7e3ba6 100644 (file)
@@ -21,6 +21,7 @@
  * SPDX-License-Identifier: curl
  *
  ***************************************************************************/
+#include <stddef.h>
 #include "tool_setup.h"
 
 #include "tool_cfgable.h"
@@ -206,6 +207,90 @@ void config_free(struct OperationConfig *config)
   }
 }
 
+#ifdef CURL_DEBUG_GLOBAL_MEM
+
+#ifdef CURL_MEMDEBUG
+#error "curl_global_init_mem() testing does not work with memdebug debugging"
+#endif
+
+/*
+ * This is the custom memory functions handed to curl when we run special test
+ * round to verify them.
+ *
+ * The main point is to make sure that what is returned is different than what
+ * the regular memory functions return so that mixup will trigger problems.
+ */
+
+struct extramem {
+  size_t extra;
+  union {
+    curl_off_t o;
+    double d;
+    void *p;
+  } mem[1];
+};
+
+static void *custom_calloc(size_t wanted_nmemb, size_t wanted_size)
+{
+  struct extramem *m;
+  size_t sz = wanted_size * wanted_nmemb;
+  sz += sizeof(struct extramem);
+  m = curlx_calloc(1, sz);
+  if(m)
+    return m->mem;
+  return NULL;
+}
+
+static void *custom_malloc(size_t wanted_size)
+{
+  struct extramem *m;
+  size_t sz = wanted_size + sizeof(struct extramem);
+  m = curlx_malloc(sz);
+  if(m)
+    return m->mem;
+  return NULL;
+}
+
+static char *custom_strdup(const char *ptr)
+{
+  struct extramem *m;
+  size_t size = strlen(ptr) + 1;
+  size_t sz = size + sizeof(struct extramem);
+  m = curlx_malloc(sz);
+  if(m) {
+    char *p = (char *)m->mem;
+    /* since strcpy is banned, we do memcpy */
+    memcpy(p, ptr, sz);
+    p[sz] = 0;
+    return (char *)m->mem;
+  }
+  return NULL;
+
+}
+
+static void *custom_realloc(void *ptr, size_t size)
+{
+  struct extramem *m = NULL;
+  size_t sz = size + sizeof(struct extramem);
+  if(ptr)
+    m = (void *)((char *)ptr - offsetof(struct extramem, mem));
+  m = curlx_realloc(ptr, sz);
+  if(m)
+    return m->mem;
+  return NULL;
+}
+
+static void custom_free(void *ptr)
+{
+  struct extramem *m = NULL;
+  if(ptr) {
+    m = (void *)((char *)ptr - offsetof(struct extramem, mem));
+    curlx_free(m);
+  }
+}
+
+#endif
+
 /*
  * This is the main global constructor for the app. Call this before
  * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
@@ -230,7 +315,13 @@ CURLcode globalconf_init(void)
   global->first = global->last = config_alloc();
   if(global->first) {
     /* Perform the libcurl initialization */
+#ifdef GLOBAL_MEM
+    result = curl_global_init_mem(CURL_GLOBAL_ALL, custom_malloc, custom_free,
+                                  custom_realloc, custom_strdup,
+                                  custom_calloc);
+#else
     result = curl_global_init(CURL_GLOBAL_DEFAULT);
+#endif
     if(!result) {
       /* Get information about libcurl */
       result = get_libcurl_info();