Ticket #400 (closed bug: None)

Opened 8 years ago

Last modified 43 years ago

socketToHandle, hGetContents cause errors in ghci

Reported by: pimlott Owned by: simonmar
Priority: normal Milestone:
Component: libraries/network Version: None
Keywords: Cc:
Operating System: Architecture:
Type of failure: Difficulty:
Test Case: Blocked By:
Blocking: Related Tickets:

Description

I wrote a server using socketToHandle and hGetContents.
 The first request worked fine, but the second request
crashed with "internal error: scavenge_stack: weird
activation record found on stack: 9".  I tried to
create a test case.  I couldn't reproduce the same
problem, but I did get an intermittent "Bad file
descriptor".  I think it may be a related problem, and
it may have to do with garbage collection (based on a
strace showing a call to getrusage).

The program is below, and when I run it with runghc and
feed it a line of input with nc, it crashes on the 17th
request.  It's not important to me that you fix it; in
fact I only tried this as an experiment to simplify
some working code.  But if you would like more
information, let me know.

I am using the Debian package ghc6 6.4-4.

import Network.Socket
import System.IO

main = do 
  s <- socket AF_INET Stream 0
  h <- inet_addr "127.0.0.1"
  bindSocket s (SockAddrInet 1236 h)
  listen s 5 
  loop s 

loop listenSock = do
  (s,_) <- accept listenSock
  h <- socketToHandle s ReadMode
  input <- hGetContents h
  putStrLn (take 10 input)
  send s "got it\n"
  sClose s
  loop listenSock

Change History

Changed 8 years ago by simonmar

  • status changed from assigned to closed
Logged In: YES 
user_id=48280

The "Bad file descriptor" error messages are to be expected:
when you turn a Socket into a Handle, it gets a finalizer
attached which closes the socket when the Handle is no
longer referenced.  You want to call hClose h rather than
sClose s in the code above.

I've added some documentation for socketToHandle to reflect
this.

If you can reproduce the "scavenge_stack" error, please
follow up with more info, for now I'll close this bug.

Changed 8 years ago by pimlott

Logged In: YES 
user_id=498741

I should have detailed my test scenario, but what I see when
I run "echo hello world | nc localhost 1236" repeatedly is
that "hello worl" is printed 16 times, then

*** Exception: <socket: 5>: lazyRead: invalid argument (Bad
file descriptor)

So the error happens while trying to print out "input".  As
I understand, input should keep a reference to h, which
should keep a reference to s, so nothing should get garbage
collected too soon.  Moreover, something that happens later
(sClose) shouldn't be able to affect it.  That said, when I
use hClose, or remove the close, I can't reproduce the
problem.  So I'm perplexed.  Can I ask you to explain in
more detail?

Changed 8 years ago by simonmar

Logged In: YES 
user_id=48280

It looks like a bug, but it has a rationale explanation. 
After you call sClose, there is still a finalizer in the
system waiting to close the Handle.  However, since the file
descriptor has been closed, it can be re-used by the next
call to accept, at which point the finalizer can run and
close a file descriptor that is in use again, leading to the
lazyRead error you see.

I've added some code to Network.Socket to prevent the use of
 sClose and other socket operations after socketToHandle.

Changed 8 years ago by pimlott

Logged In: YES 
user_id=498741

doh, thank you for the clear explanation!
Note: See TracTickets for help on using tickets.