summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--process.c54
-rw-r--r--version.h2
3 files changed, 58 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index c9c6692b12..7256f0d61a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Mon Jun 23 17:29:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * 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]
+
Mon Jun 23 17:20:10 2014 Tanaka Akira <akr@fsij.org>
* ext/socket/socket.c (sock_s_getnameinfo): Save errno for EAI_SYSTEM.
diff --git a/process.c b/process.c
index d351a398d3..6c9cc7c153 100644
--- a/process.c
+++ b/process.c
@@ -147,6 +147,9 @@ static void check_gid_switch(void);
#if defined(HAVE_PWD_H)
# if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
# 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 \
@@ -171,6 +174,9 @@ static rb_uid_t obj2uid(VALUE id);
#if defined(HAVE_GRP_H)
# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
# 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 \
@@ -4744,8 +4750,28 @@ obj2uid(VALUE id
struct passwd *pwptr;
#ifdef USE_GETPWNAM_R
struct passwd pwbuf;
- if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr))
- rb_sys_fail("getpwnam_r");
+ char *getpw_buf;
+ long getpw_buf_len;
+ if (!*getpw_tmp) {
+ getpw_buf_len = GETPW_R_SIZE_INIT;
+ if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
+ getpw_buf = rb_alloc_tmp_buffer(getpw_tmp, getpw_buf_len);
+ }
+ else {
+ getpw_buf = RSTRING_PTR(*getpw_tmp);
+ getpw_buf_len = rb_str_capacity(*getpw_tmp);
+ }
+ 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
@@ -4792,8 +4818,28 @@ obj2gid(VALUE id
struct group *grptr;
#ifdef USE_GETGRNAM_R
struct group grbuf;
- if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr))
- rb_sys_fail("getgrnam_r");
+ char *getgr_buf;
+ long getgr_buf_len;
+ if (!*getgr_tmp) {
+ getgr_buf_len = GETGR_R_SIZE_INIT;
+ if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
+ getgr_buf = rb_alloc_tmp_buffer(getgr_tmp, getgr_buf_len);
+ }
+ else {
+ getgr_buf = RSTRING_PTR(*getgr_tmp);
+ getgr_buf_len = rb_str_capacity(*getgr_tmp);
+ }
+ 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
diff --git a/version.h b/version.h
index 1d1ae195f9..e9c45d552e 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.0.0"
#define RUBY_RELEASE_DATE "2014-06-23"
-#define RUBY_PATCHLEVEL 493
+#define RUBY_PATCHLEVEL 494
#define RUBY_RELEASE_YEAR 2014
#define RUBY_RELEASE_MONTH 6