@@ -1336,33 +1336,39 @@ pub fn setgid(gid: Gid) -> Result<()> {
1336
1336
/// with the `opendirectoryd` service.
1337
1337
#[ cfg( not( any( target_os = "ios" , target_os = "macos" ) ) ) ]
1338
1338
pub 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 ( ) ) } ;
1341
1349
1342
1350
// Now actually get the groups. We try multiple times in case the number of
1343
1351
// groups has changed since the first call to getgroups() and the buffer is
1344
1352
// 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 ) ;
1346
1354
loop {
1347
1355
// FIXME: On the platforms we currently support, the `Gid` struct has
1348
1356
// the same representation in memory as a bare `gid_t`. This is not
1349
1357
// necessarily the case on all Rust platforms, though. See RFC 1785.
1350
- let ret = unsafe {
1358
+ let ngroups = unsafe {
1351
1359
libc:: getgroups ( groups. capacity ( ) as c_int , groups. as_mut_ptr ( ) as * mut gid_t )
1352
1360
} ;
1353
1361
1354
- match Errno :: result ( ret ) {
1362
+ match Errno :: result ( ngroups ) {
1355
1363
Ok ( s) => {
1356
1364
unsafe { groups. set_len ( s as usize ) } ;
1357
1365
return Ok ( groups) ;
1358
1366
} ,
1359
1367
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 ) ) ) ?;
1366
1372
} ,
1367
1373
Err ( e) => return Err ( e)
1368
1374
}
0 commit comments