Project

General

Profile

Bug #13554

Updated by nobu (Nobuyoshi Nakada) about 7 years ago

In #9600, it was pointed out that groups can be larger than sysconf(SC_GETGR_R_SIZE_MAX) in Linux.    This was fixed in r45290 by enlarging the buffer and retrying.    That worked well, but it was broken again in r51492.    Ever since, when trying to run the following ruby code: 

 ~~~ ruby 
 begin 
   system("/bin/ls", gid: "adm") 
 rescue => exception 
   puts exception.backtrace 
   raise 
 end 
 ~~~ 

 I get the backtrace: 

 ~~~ 
 gid.rb:2:in `system' 
 gid.rb:2:in `<main>' 
 gid.rb:2:in `system': can't modify frozen false (RuntimeError) 
         from gid.rb:2:in `<main>' 
 ~~~ 

 In this case the "adm" group has about 200 members.    It's worth noting that because of the way getgrnam_r works this happens if I pick any group listed after adm.    It seems that the change in r51492 causes the buffer that is allocated for getgrnam_r to be marked as frozen, so when it's not big enough and it gets resized using rb_str_modify_expand ruby raises an exception. 

 This occurs in any release of ruby 2.3 or 2.4 and also on the trunk on either debian wheezy or jessie. 

 I don't have a deep enough knowledge of the ruby C API to know the best fix, but I was able to work around the problem with the following change: 

 ~~~diff ~~~ 
 diff --git a/process.c b/process.c 
 index 9191051..721dd4c 100644 
 --- a/process.c 
 +++ b/process.c 
 @@ -5126,9 +5126,9 @@ obj2gid(VALUE id 
                 rb_free_tmp_buffer(getgr_tmp); 
                 rb_syserr_fail(e, "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); 
 +             rb_free_tmp_buffer(getgr_tmp); 
 +             getgr_buf_len = getgr_buf_len * 2; 
 +             getgr_buf = rb_alloc_tmp_buffer(getgr_tmp, getgr_buf_len); 
         } 
  #elif defined(HAVE_GETGRNAM) 
         grptr = getgrnam(grpname); 
 ~~~ 

 Alternatively, I assume the better way to fix this would be to allocate the tmp buffer in a way that allows it to be resized but I didn't see an obvious way to do that.

Back