Opened 6 years ago

Closed 6 years ago

Last modified 12 months ago

#5402 closed bug (fixed)

Exit code is wrong with dynamically loaded libraries

Reported by: Lennart Owned by:
Priority: normal Milestone: 7.2.2
Component: Runtime System Version: 7.1
Keywords: Cc: malcolm.wallace@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case: ffi/should_run/5402
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:


Here's a simple scenario that goes wrong:

Program starts, calls hs_init(), hs_init_count=1

Program loads some Haskell library that calls hs_init(), hs_init_count=2.

Program does exitWith 99, which calls shutdownHaskellAndExit(99), which calls hs_exit_(). Since hs_init_count>1 it will do nothing. Control returns to shutdownHaskellAndExit, since hs_init_count>0 it will do nothing, i.e., it throws away the exit code 99.

Now real_main() gets control back, and calls shutdownHaskellAndExit(0). The whole program now exits with code 0, rather than 99.

The solution is probably to track the last non-0 exit code encountered in shutdownHaskellAndExit and use that as the exit code in real_main().

Attachments (1)

ghcShutdown.patch (642 bytes) - added by malcolmw 6 years ago.
proposed fix

Download all attachments as: .zip

Change History (13)

comment:1 Changed 6 years ago by malcolm.wallace@…

Cc: malcolm.wallace@… added

Changed 6 years ago by malcolmw

Attachment: ghcShutdown.patch added

proposed fix

comment:2 Changed 6 years ago by malcolmw

I attached a proposed patch. (The line numbers might be slightly off, because my copy of the ghc sources is a couple of months old.)

comment:3 Changed 6 years ago by simonmar

Does this fix have any justification other than that it works in your scenario? I'm struggling to understand exactly who is at fault here.

Another alternative that might be more correct is for shutdownHaskellAndExit to set hs_init_count to 1 before calling hs_exit, so that it definitely shuts down the RTS. The justification is that we're about to exit!

comment:4 Changed 6 years ago by Lennart

It's clearly an RTS bug. All the application is doing is to loading a shared library which will call hs_init() (unless calling hs_init(0 more than once is now banned) and then trying to exit.

I don't know what you think the proper fix is. Right now we FFI import stg_exit() and call that instead of exitWith, and that works.

comment:5 Changed 6 years ago by simonmar

Ok, I'm not claiming it's not an RTS bug, just trying to figure out what assumption has been broken to find out where to apply a fix.

I think that shutdownHaskellAndExit() should do exactly what it says on the tin: shut down the RTS regardless of how many hs_inits there have been previously, and then exit. It sounds like that would work in your case - would it?

comment:6 Changed 6 years ago by Lennart

If shutdownHaskellAndExit() did just that it would work fine.

comment:7 Changed 6 years ago by Lennart

We'll probably do a binary patch to 6.12.3 to fix the urgent problem.

comment:8 Changed 6 years ago by marlowsd@…

commit d18b5d53e74318e4a6bc2ad0557ff71a00c1abe1

Author: Simon Marlow <>
Date:   Fri Aug 12 14:26:34 2011 +0100

    make shutdownHaskellAndExit() shut down the RTS and exit immediately

 includes/RtsAPI.h |    6 +++++-
 rts/RtsMain.c     |    2 +-
 rts/RtsMain.h     |    3 ++-
 rts/RtsStartup.c  |    8 +++++---
 4 files changed, 13 insertions(+), 6 deletions(-)

comment:9 Changed 6 years ago by simonmar

Milestone: 7.4.1
Resolution: fixed
Status: newclosed
Test Case: ffi/should_run/5402

Fixed, test added.

comment:10 Changed 6 years ago by simonmar

Status: closedmerge

comment:11 Changed 6 years ago by igloo

Status: mergeclosed

comment:12 Changed 12 months ago by Simon Marlow <marlowsd@…>

In 9cbcdb48/ghc:

shutdownHaskellAndExit: just do a normal hs_exit() (#5402)

If we want to keep the RTS alive a bit longer by having another
hs_init()/hs_exit() pair in a library that will destruct itself after
main() has exited, then the forced shutdown here thwarts that.

I think we just "fixed" #5402 in the wrong way before, this should be
Note: See TracTickets for help on using tickets.