Skip to content

Commit 2b07f8d

Browse files
bors[bot]otavio
andauthored
Merge #1129
1129: Getgroups reserve up to limit r=posborne a=otavio Co-authored-by: Otavio Salvador <[email protected]>
2 parents 2fc246c + 258bc13 commit 2b07f8d

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

src/unistd.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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")))]
13381338
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()) };
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

Comments
 (0)