aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2022-02-05 17:26:05 -0800
committerAndrew G. Morgan <morgan@kernel.org>2022-02-05 17:26:05 -0800
commit66a8a1421e4520e9dda0a46704e25bafb989b1ae (patch)
treea114d61d6536e3a9433b62b779ddbb8e22ac1da2
parent1d88048c314c2bc239459ed10e0685c4b1950747 (diff)
downloadlibcap-66a8a1421e4520e9dda0a46704e25bafb989b1ae.tar.gz
psx: free allocated memory at exit.
Kalen Hall reported that Valgrind detected a memory leak associated with a multi-threaded program linked against libcap and libpsx. https://bugzilla.kernel.org/show_bug.cgi?id=215551 I've been unable to validate this myself with valgrind (likely holding it wrong), but did explore psx for allocated memory and via fprintf's convinced myself that this change should pair all calloc()s with a corresponding free(). Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--psx/psx.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/psx/psx.c b/psx/psx.c
index 6b669ae..1876978 100644
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -29,6 +29,26 @@
#include "psx_syscall.h"
+#ifdef _PSX_DEBUG_MEMORY
+
+static void *_psx_calloc(const char *file, const int line,
+ size_t nmemb, size_t size) {
+ void *ptr = calloc(nmemb, size);
+ fprintf(stderr, "psx:%d:%s:%d: calloc(%ld, %ld) -> %p\n", gettid(),
+ file, line, (long int)nmemb, (long int)size, ptr);
+ return ptr;
+}
+
+static void _psx_free(const char *file, const int line, void *ptr) {
+ fprintf(stderr, "psx:%d:%s:%d: free(%p)\n", gettid(), file, line, ptr);
+ return free(ptr);
+}
+
+#define calloc(a, b) _psx_calloc(__FILE__, __LINE__, a, b)
+#define free(a) _psx_free(__FILE__, __LINE__, a)
+
+#endif /* def _PSX_DEBUG_MEMORY */
+
/*
* psx_load_syscalls() can be weakly defined in dependent libraries to
* provide a mechanism for a library to optionally leverage this psx
@@ -177,6 +197,7 @@ static void psx_posix_syscall_actor(int signum, siginfo_t *info, void *ignore) {
* Some forward declarations for the initialization
* psx_syscall_start() routine.
*/
+static void _psx_cleanup(void);
static void _psx_prepare_fork(void);
static void _psx_fork_completed(void);
static void _psx_forked_child(void);
@@ -240,6 +261,7 @@ static void psx_syscall_start(void) {
psx_confirm_sigaction();
psx_do_registration(); /* register the main thread. */
+ atexit(_psx_cleanup);
psx_tracker.initialized = 1;
}
@@ -420,7 +442,7 @@ static void _psx_exiting(void *node) {
pthread_sigmask(SIG_SETMASK, &orig_sigbits, NULL);
/*
- * Allow the rest of the psx system carry on as per normal.
+ * Allow the rest of the psx system to carry on as per normal.
*/
psx_new_state(_PSX_EXITING, _PSX_IDLE);
}
@@ -700,6 +722,26 @@ defer:
}
/*
+ * _psx_cleanup its called when the program exits. It is used to free
+ * any memory used by the thread tracker.
+ */
+static void _psx_cleanup(void) {
+ registered_thread_t *ref, *next;
+
+ /*
+ * We enter the exiting state. Unlike exiting a single thread we
+ * never leave this state since this cleanup is only done at
+ * program exit.
+ */
+ psx_new_state(_PSX_IDLE, _PSX_EXITING);
+
+ for (ref = psx_tracker.root; ref; ref = next) {
+ next = ref->next;
+ psx_do_unregister(ref);
+ }
+}
+
+/*
* Change the PSX sensitivity level. If the threads appear to have
* diverged in behavior, this can cause the library to notify the
* user.