Skip to content

Commit 140c4dc

Browse files
committed
unistd: Avoid allocations for getgroups/setgroups
1 parent 6c10e02 commit 140c4dc

File tree

1 file changed

+16
-7
lines changed

1 file changed

+16
-7
lines changed

src/unistd.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -958,11 +958,17 @@ pub fn getgroups() -> Result<Vec<Gid>> {
958958
let ret = unsafe { libc::getgroups(size, groups.as_mut_ptr()) };
959959

960960
Errno::result(ret).map(|s| {
961-
// Use the size returned from the second getgroups call: the user could have been removed
962-
// from a group between the two calls and we don't want to incorrectly set the length of
963-
// the Vec and expose uninitialized memory.
964-
unsafe { groups.set_len(s as usize) };
965-
groups.iter().cloned().map(|gid| Gid::from_raw(gid)).collect()
961+
// We can coerce a pointer to some `gid_t`s as a pointer to some `Gid`s
962+
// as they have the same representation in memory.
963+
// https://doc.rust-lang.org/1.19.0/std/mem/fn.transmute.html#alternatives
964+
let gids = unsafe {
965+
Vec::from_raw_parts(
966+
groups.as_mut_ptr() as *mut Gid,
967+
s as usize,
968+
groups.capacity())
969+
};
970+
mem::forget(groups);
971+
gids
966972
})
967973
}
968974

@@ -982,8 +988,11 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
982988
type setgroups_ngroups_t = size_t;
983989
}
984990
}
985-
let gids: Vec<gid_t> = groups.iter().cloned().map(Into::into).collect();
986-
let res = unsafe { libc::setgroups(groups.len() as setgroups_ngroups_t, gids.as_ptr()) };
991+
// We can coerce a pointer to some `Gid`s as a pointer to some `gid_t`s as
992+
// they have the same representation in memory.
993+
let res = unsafe {
994+
libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
995+
};
987996

988997
Errno::result(res).map(drop)
989998
}

0 commit comments

Comments
 (0)