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-18.104.22.168 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.