diff options
author | Jeremy Evans <[email protected]> | 2024-07-18 12:08:06 -0700 |
---|---|---|
committer | Jeremy Evans <[email protected]> | 2024-09-12 07:24:02 -0700 |
commit | ad761ad2d0a63270fbd243a477dc962446a5116e (patch) | |
tree | 1d06d07e3781b77d3ba515fc9c08336b455a4480 /file.c | |
parent | b10500b72b2a696608015c2a2e60422a296d8614 (diff) |
Release GVL for get{pwnam,pwuid,grgid,grnam}_r calls in process.c
Do not release GVL around get{pwuid,pwnam,grgid,grnam} calls,
as doing so is not thread-safe. Another C extension could have
a concurrent call, and derefencing the returned pointer from
these calls could result in a segfault.
Have rb_home_dir_of call rb_getpwdirnam_for_login if available,
so it can use getpwnam_r and release GVL in a thread-safe manner.
This is related to GVL releasing work in [Bug #20587].
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/11202
Diffstat (limited to 'file.c')
-rw-r--r-- | file.c | 23 |
1 files changed, 5 insertions, 18 deletions
@@ -3690,25 +3690,20 @@ copy_home_path(VALUE result, const char *dir) return result; } -#ifdef HAVE_PWD_H -static void * -nogvl_getpwnam(void *login) -{ - return (void *)getpwnam((const char *)login); -} -#endif - VALUE rb_home_dir_of(VALUE user, VALUE result) { #ifdef HAVE_PWD_H - struct passwd *pwPtr; + VALUE dirname = rb_getpwdirnam_for_login(user); + if (dirname == Qnil) { + rb_raise(rb_eArgError, "user %"PRIsVALUE" doesn't exist", user); + } + const char *dir = RSTRING_PTR(dirname); #else extern char *getlogin(void); const char *pwPtr = 0; const char *login; # define endpwent() ((void)0) -#endif const char *dir, *username = RSTRING_PTR(user); rb_encoding *enc = rb_enc_get(user); #if defined _WIN32 @@ -3720,21 +3715,13 @@ rb_home_dir_of(VALUE user, VALUE result) dir = username = RSTRING_PTR(rb_str_conv_enc(user, enc, fsenc)); } -#ifdef HAVE_PWD_H - pwPtr = (struct passwd *)IO_WITHOUT_GVL(nogvl_getpwnam, (void *)username); -#else if ((login = getlogin()) && strcasecmp(username, login) == 0) dir = pwPtr = getenv("HOME"); -#endif if (!pwPtr) { - endpwent(); rb_raise(rb_eArgError, "user %"PRIsVALUE" doesn't exist", user); } -#ifdef HAVE_PWD_H - dir = pwPtr->pw_dir; #endif copy_home_path(result, dir); - endpwent(); return result; } |