diff options
author | Peter Zhu <peter@peterzhu.ca> | 2024-01-09 13:17:17 -0500 |
---|---|---|
committer | Peter Zhu <peter@peterzhu.ca> | 2024-01-11 10:09:53 -0500 |
commit | 057df4379f856a868f588cdc769f397f5739983d (patch) | |
tree | 2cc451d9af23b2c69a8804383ee754922ddff6c5 | |
parent | 4e0c2f05efc9415b52b50ee65401c5b511d269e7 (diff) | |
download | ruby-057df4379f856a868f588cdc769f397f5739983d.tar.gz |
Free environ when RUBY_FREE_AT_EXIT
The environ is malloc'd, so it gets reported as a memory leak. This
commit adds ruby_free_proctitle which frees it during shutdown when
RUBY_FREE_AT_EXIT is set.
STACK OF 1 INSTANCE OF 'ROOT LEAK: <calloc in ruby_init_setproctitle>':
5 dyld 0x18b7090e0 start + 2360
4 ruby 0x10000e3a8 main + 100 main.c:58
3 ruby 0x1000b4dfc ruby_options + 180 eval.c:121
2 ruby 0x1001c5f70 ruby_process_options + 200 ruby.c:3014
1 ruby 0x10035c9fc ruby_init_setproctitle + 76 setproctitle.c:105
0 libsystem_malloc.dylib 0x18b8c7b78 _malloc_zone_calloc_instrumented_or_legacy + 100
-rw-r--r-- | common.mk | 1 | ||||
-rw-r--r-- | internal/missing.h | 1 | ||||
-rw-r--r-- | missing/setproctitle.c | 42 | ||||
-rw-r--r-- | vm.c | 5 |
4 files changed, 45 insertions, 4 deletions
@@ -19320,6 +19320,7 @@ vm.$(OBJEXT): $(top_srcdir)/internal/gc.h vm.$(OBJEXT): $(top_srcdir)/internal/hash.h vm.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm.$(OBJEXT): $(top_srcdir)/internal/inits.h +vm.$(OBJEXT): $(top_srcdir)/internal/missing.h vm.$(OBJEXT): $(top_srcdir)/internal/numeric.h vm.$(OBJEXT): $(top_srcdir)/internal/object.h vm.$(OBJEXT): $(top_srcdir)/internal/parse.h diff --git a/internal/missing.h b/internal/missing.h index c0992a151a..6ca508c8f9 100644 --- a/internal/missing.h +++ b/internal/missing.h @@ -13,6 +13,7 @@ /* missing/setproctitle.c */ #ifndef HAVE_SETPROCTITLE extern void ruby_init_setproctitle(int argc, char *argv[]); +extern void ruby_free_proctitle(void); #endif #endif /* INTERNAL_MISSING_H */ diff --git a/missing/setproctitle.c b/missing/setproctitle.c index 6a85323818..d718123802 100644 --- a/missing/setproctitle.c +++ b/missing/setproctitle.c @@ -80,10 +80,20 @@ static char **argv1_addr = NULL; #endif /* HAVE_SETPROCTITLE */ +#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV +# define ALLOCATE_ENVIRON 1 +#else +# define ALLOCATE_ENVIRON 0 +#endif + +#if ALLOCATE_ENVIRON +static char **orig_environ = NULL; +#endif + void compat_init_setproctitle(int argc, char *argv[]) { -#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV +#if ALLOCATE_ENVIRON extern char **environ; char *lastargv = NULL; char *lastenvp = NULL; @@ -100,9 +110,10 @@ compat_init_setproctitle(int argc, char *argv[]) return; /* Fail if we can't allocate room for the new environment */ - for (i = 0; envp[i] != NULL; i++) - ; - if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { + for (i = 0; envp[i] != NULL; i++); + + orig_environ = environ = xcalloc(i + 1, sizeof(*environ)); + if (environ == NULL) { environ = envp; /* put it back */ return; } @@ -134,6 +145,29 @@ compat_init_setproctitle(int argc, char *argv[]) #endif /* SPT_REUSEARGV */ } +void +ruby_free_proctitle(void) +{ +#if ALLOCATE_ENVIRON + extern char **environ; + + if (!orig_environ) return; /* environ is allocated by OS */ + + for (int i = 0; environ[i] != NULL; i++) { + xfree(environ[i]); + } + + /* ruby_setenv could allocate a new environ, so we need to free both environ + * orig_environ in that case. */ + if (environ != orig_environ) { + xfree(orig_environ); + orig_environ = NULL; + } + + xfree(environ); +#endif +} + #ifndef HAVE_SETPROCTITLE void @@ -20,6 +20,7 @@ #include "internal/eval.h" #include "internal/gc.h" #include "internal/inits.h" +#include "internal/missing.h" #include "internal/object.h" #include "internal/proc.h" #include "internal/re.h" @@ -3034,6 +3035,10 @@ ruby_vm_destruct(rb_vm_t *vm) xfree(th->nt); th->nt = NULL; } + +#ifndef HAVE_SETPROCTITLE + ruby_free_proctitle(); +#endif } else { if (th) { |