From 119d66232db60742c0110cb0019f41f912ae3aaf Mon Sep 17 00:00:00 2001 From: nobu Date: Sat, 8 Mar 2014 04:30:56 +0000 Subject: [PATCH] process.c: expand buffer on ERANGE * process.c (obj2uid, obj2gid): now getpwnam_r() and getgrnam_r() may need larger buffers than sysconf values, so retry with expanding the buffer when ERANGE is returned. [ruby-core:61325] [Bug #9600] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45290 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 7 +++++++ process.c | 28 ++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index f49e2d4819..7eb83215ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Sat Mar 8 13:30:39 2014 Nobuyoshi Nakada + + * process.c (obj2uid, obj2gid): now getpwnam_r() and getgrnam_r() + may need larger buffers than sysconf values, so retry with + expanding the buffer when ERANGE is returned. + [ruby-core:61325] [Bug #9600] + Sat Mar 8 07:35:40 2014 Nobuyoshi Nakada * enum.c (find_i): yield multiple values instead of a packed diff --git a/process.c b/process.c index 77cc65bd2f..33a294866d 100644 --- a/process.c +++ b/process.c @@ -153,6 +153,7 @@ static void check_gid_switch(void); # define USE_GETPWNAM_R 1 # define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX) # define GETPW_R_SIZE_DEFAULT 0x1000 +# define GETPW_R_SIZE_LIMIT 0x10000 # endif # ifdef USE_GETPWNAM_R # define PREPARE_GETPWNAM \ @@ -192,6 +193,7 @@ static rb_uid_t obj2uid(VALUE id); # define USE_GETGRNAM_R # define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX) # define GETGR_R_SIZE_DEFAULT 0x1000 +# define GETGR_R_SIZE_LIMIT 0x10000 # endif # ifdef USE_GETGRNAM_R # define PREPARE_GETGRNAM \ @@ -4741,8 +4743,17 @@ obj2uid(VALUE id getpw_buf = RSTRING_PTR(*getpw_tmp); getpw_buf_len = rb_str_capacity(*getpw_tmp); } - if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) - rb_sys_fail("getpwnam_r"); + errno = ERANGE; + /* gepwnam_r() on MacOS X doesn't set errno if buffer size is insufficient */ + while (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) { + if (errno != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) { + rb_free_tmp_buffer(getpw_tmp); + rb_sys_fail("getpwnam_r"); + } + rb_str_modify_expand(*getpw_tmp, getpw_buf_len); + getpw_buf = RSTRING_PTR(*getpw_tmp); + getpw_buf_len = rb_str_capacity(*getpw_tmp); + } #else pwptr = getpwnam(usrname); #endif @@ -4810,8 +4821,17 @@ obj2gid(VALUE id getgr_buf = RSTRING_PTR(*getgr_tmp); getgr_buf_len = rb_str_capacity(*getgr_tmp); } - if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) - rb_sys_fail("getgrnam_r"); + errno = ERANGE; + /* gegrnam_r() on MacOS X doesn't set errno if buffer size is insufficient */ + while (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) { + if (errno != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) { + rb_free_tmp_buffer(getgr_tmp); + rb_sys_fail("getgrnam_r"); + } + rb_str_modify_expand(*getgr_tmp, getgr_buf_len); + getgr_buf = RSTRING_PTR(*getgr_tmp); + getgr_buf_len = rb_str_capacity(*getgr_tmp); + } #else grptr = getgrnam(grpname); #endif