getGroupEntryForID segfaults in multi-threaded applications
The following program
import Control.Monad
import Control.Concurrent
import System.Posix.User
main = do
void $ forkIO $ forever $ getGroupEntryForID 0
forever $ getGroupEntryForID 0
segfaults when executed after less than a second. I've confirmed this with HP-2013.2.0.0/GHC-7.63/unix-2.6.0.1 in many different linuxes as well as Mac OS X 10.8. After some digging I found the reason for this failure. The underlying posix function used by getGroupEntryForID is:
int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result);
getgrgid_r returns its result with its last argument which is a pointer to a struct. The struct has to be allocated by the caller as usual. The problem is that the struct contains several strings. This is what the char *buf argument is for; the caller is supposed to allocate a large enough buffer to be used by getgrgid_r to store those strings. Then the caller has to read the struct *before* the auxiliary string buffer is deallocated. What complicates things even more is that we don't know in advance the right size for that buffer; we have to pick an arbitrary size and then keep doubling it while getgrgid_r returns ERANGE. The current implementation of getGroupEntryForID uses allocaBytes to allocate that buffer but then it does not unpack the struct inside the allocaBytes block.
The posix functions getgrnam_r, getpwuid_r and getpwnam_r (used by getGroupEntryForName, getUserEntryForID and getUserEntryForName respectively) operate in the same fashion and are susceptible to the same bug.
I am really surprised that people haven't been hitting that issue earlier.
Trac metadata
Trac field | Value |
---|---|
Version | 7.6.3 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | libraries/unix |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |