mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
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].
This commit is contained in:
parent
b10500b72b
commit
ad761ad2d0
Notes:
git
2024-09-12 14:24:21 +00:00
2 changed files with 99 additions and 49 deletions
23
file.c
23
file.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue