]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
memdebug: close debug logfile explicitly on exit
authorJay Satiro <raysatiro@yahoo.com>
Wed, 17 Feb 2021 22:46:16 +0000 (17:46 -0500)
committerJay Satiro <raysatiro@yahoo.com>
Sat, 20 Feb 2021 19:40:24 +0000 (14:40 -0500)
- Use atexit to register a dbg cleanup function that closes the logfile.

LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is
detected on exit so the logfile must be closed explicitly or data could
be lost. Though _exit() does not call atexit handlers such as this,
LSAN's call to _exit() comes after the atexit handlers are called.

Prior to this change the logfile was not explicitly closed so it was
possible that if LSAN detected a leak and called _exit (which does
not flush or close files like exit) then the logfile could be missing
data. That could then cause curl's memanalyze to report false leaks
(eg a malloc was recorded to the logfile but the corresponding free was
discarded from the buffer instead of written to the logfile, then
memanalyze reports that as a leak).

Ref: https://github.com/google/sanitizers/issues/1374

Bug: https://github.com/curl/curl/pull/6591#issuecomment-780396541

Closes https://github.com/curl/curl/pull/6620

lib/memdebug.c

index 0aba6ef6baf358cf99d4e4312519157834015f0a..8b763577bbe1b47c57c9112d06a5fe1e9e8fbc34 100644 (file)
@@ -55,9 +55,24 @@ struct memdebug {
  */
 
 FILE *curl_dbg_logfile = NULL;
+static bool registered_cleanup = FALSE; /* atexit registered cleanup */
 static bool memlimit = FALSE; /* enable memory limit */
 static long memsize = 0;  /* set number of mallocs allowed */
 
+/* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected
+   on exit so the logfile must be closed explicitly or data could be lost.
+   Though _exit() does not call atexit handlers such as this, LSAN's call to
+   _exit() comes after the atexit handlers are called. curl/curl#6620 */
+static void curl_dbg_cleanup(void)
+{
+  if(curl_dbg_logfile &&
+     curl_dbg_logfile != stderr &&
+     curl_dbg_logfile != stdout) {
+    fclose(curl_dbg_logfile);
+  }
+  curl_dbg_logfile = NULL;
+}
+
 /* this sets the log file name */
 void curl_dbg_memdebug(const char *logname)
 {
@@ -72,6 +87,8 @@ void curl_dbg_memdebug(const char *logname)
       setbuf(curl_dbg_logfile, (char *)NULL);
 #endif
   }
+  if(!registered_cleanup)
+    registered_cleanup = !atexit(curl_dbg_cleanup);
 }
 
 /* This function sets the number of malloc() calls that should return