[GHC] #8108: getGroupEntryForID in multi-threaded applications

#8108: getGroupEntryForID in multi-threaded applications ------------------------------------+------------------------------------- Reporter: redneb | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: libraries/unix | Version: 7.6.3 Keywords: | Operating System: Unknown/Multiple Architecture: Unknown/Multiple | Type of failure: Runtime crash Difficulty: Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | ------------------------------------+------------------------------------- The following program {{{ #!haskell 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: {{{ #!c 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. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8108 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8108: getGroupEntryForID in multi-threaded applications -------------------------------------+------------------------------------ Reporter: redneb | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: libraries/unix | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: Runtime crash | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by redneb): And here's a patch that fixes the problem. The patch unifies even more the code for getGroupEntryForID, getGroupEntryForName, getUserEntryForID and getUserEntryForName and fixes the issue for all of them. As a side-effect of that unification, there is a tiny user visible change in the behavior of those functions: if they don't find what are they looking for (group id, user name etc), they now all fail with isDoesNotExistError. Previously, only getGroupEntryForName and getUserEntryForName would throw that error. getGroupEntryForID and getUserEntryForID would throw a generic IOError. I think this is a desirable change. The patch also updates the documentation to reflect that change. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8108#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8108: getGroupEntryForID segfaults in multi-threaded applications -------------------------------------+------------------------------------ Reporter: redneb | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: libraries/unix | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: Runtime crash | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8108#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8108: getGroupEntryForID segfaults in multi-threaded applications -------------------------------------+------------------------------------ Reporter: redneb | Owner: Type: bug | Status: patch Priority: normal | Milestone: Component: libraries/unix | Version: 7.6.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: Runtime crash | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Changes (by igloo): * status: new => patch -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8108#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#8108: getGroupEntryForID segfaults in multi-threaded applications
-------------------------------------+------------------------------------
Reporter: redneb | Owner:
Type: bug | Status: closed
Priority: normal | Milestone:
Component: libraries/unix | Version: 7.6.3
Resolution: fixed | Keywords:
Operating System: Unknown/Multiple | Architecture: Unknown/Multiple
Type of failure: Runtime crash | Difficulty: Unknown
Test Case: | Blocked By:
Blocking: | Related Tickets:
-------------------------------------+------------------------------------
Changes (by thoughtpolice):
* status: patch => closed
* resolution: => fixed
Comment:
Thanks for the patch! I went ahead and added tests. Fixed in the `unix`
package by commit
{{{
commit ef683c6ba703106306732f1da68adfb508236334
Author: Marios Titas
participants (1)
-
GHC