@@ -1336,33 +1336,39 @@ pub fn setgid(gid: Gid) -> Result<()> {
13361336/// with the `opendirectoryd` service.
13371337#[ cfg( not( any( target_os = "ios" , target_os = "macos" ) ) ) ]
13381338pub fn getgroups ( ) -> Result < Vec < Gid > > {
1339- // First get the number of groups so we can size our Vec
1340- let ret = unsafe { libc:: getgroups ( 0 , ptr:: null_mut ( ) ) } ;
1339+ // First get the maximum number of groups. The value returned
1340+ // shall always be greater than or equal to one and less than or
1341+ // equal to the value of {NGROUPS_MAX} + 1.
1342+ let ngroups_max = match sysconf ( SysconfVar :: NGROUPS_MAX ) {
1343+ Ok ( Some ( n) ) => ( n + 1 ) as usize ,
1344+ Ok ( None ) | Err ( _) => <usize >:: max_value ( ) ,
1345+ } ;
1346+
1347+ // Next, get the number of groups so we can size our Vec
1348+ let ngroups = unsafe { libc:: getgroups ( 0 , ptr:: null_mut ( ) ) } ;
13411349
13421350 // Now actually get the groups. We try multiple times in case the number of
13431351 // groups has changed since the first call to getgroups() and the buffer is
13441352 // now too small.
1345- let mut groups = Vec :: < Gid > :: with_capacity ( Errno :: result ( ret ) ? as usize ) ;
1353+ let mut groups = Vec :: < Gid > :: with_capacity ( Errno :: result ( ngroups ) ? as usize ) ;
13461354 loop {
13471355 // FIXME: On the platforms we currently support, the `Gid` struct has
13481356 // the same representation in memory as a bare `gid_t`. This is not
13491357 // necessarily the case on all Rust platforms, though. See RFC 1785.
1350- let ret = unsafe {
1358+ let ngroups = unsafe {
13511359 libc:: getgroups ( groups. capacity ( ) as c_int , groups. as_mut_ptr ( ) as * mut gid_t )
13521360 } ;
13531361
1354- match Errno :: result ( ret ) {
1362+ match Errno :: result ( ngroups ) {
13551363 Ok ( s) => {
13561364 unsafe { groups. set_len ( s as usize ) } ;
13571365 return Ok ( groups) ;
13581366 } ,
13591367 Err ( Error :: Sys ( Errno :: EINVAL ) ) => {
1360- // EINVAL indicates that the buffer size was too small. Trigger
1361- // the internal buffer resizing logic of `Vec` by requiring
1362- // more space than the current capacity.
1363- let cap = groups. capacity ( ) ;
1364- unsafe { groups. set_len ( cap) } ;
1365- groups. reserve ( 1 ) ;
1368+ // EINVAL indicates that the buffer size was too
1369+ // small, resize it up to ngroups_max as limit.
1370+ reserve_double_buffer_size ( & mut groups, ngroups_max)
1371+ . or ( Err ( Error :: Sys ( Errno :: EINVAL ) ) ) ?;
13661372 } ,
13671373 Err ( e) => return Err ( e)
13681374 }
0 commit comments