Opened 4 years ago

Closed 4 years ago

#4221 closed bug (fixed)

Calling freeHaskellFunctionPtr from C finalizer leads to crashes

Reported by: ravi_n Owned by:
Priority: normal Milestone: 7.0.1
Component: Runtime System Version: 6.12.3
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Runtime crash Difficulty:
Test Case: Blocked By:
Blocking: Related Tickets:

Description

I recently discovered that calling freeHaskellFunctionPtr from a C finalizer (as seems natural to do if the object you're cleaning up on the C side is holding on to a Haskell function wrapper) leads to strange crashes.

The attached program (which is a stress-test loop of allocating function wrappers, using them and then freeing them) illustrates the problem.

You can compile it with:

ghc --make !WrapperTest2.hs HsFunction.c -o !WrapperTest2 -main-is !WrapperTest2

Depending on the platform and compilation flags I've noticed different results. Compiled as above (on Windows) I get: !WrapperTest2.exe: internal error: stg_ap_p_ret

Compiled with -debug I get: !WrapperTest2.exe: internal error: ASSERTION FAILED: file rts\Stable.c, line 224

On Windows, these results do not change if I compile with -threaded.

On Linux, without -threaded, I get the same results as Windows.

However, with -threaded I get different behavior.

With -threaded and without -debug the program eventually deadlocks.

With -threaded and -debug I get the following message: !WrapperTest2: internal error: multiple ACQUIRE_LOCK: rts/Stable.c 284

I'm currently working around the issue by using Haskell finalizers (which don't seem to have this problem), but I thought I should report the bug. I'd also appreciate feedback on whether using Haskell finalizers is actually a safe workaround for this issue or if I've just been lucky so far.

Attachments (2)

WrapperTest2.hs (1.3 KB) - added by ravi_n 4 years ago.
HsFunction.c (552 bytes) - added by ravi_n 4 years ago.

Download all attachments as: .zip

Change History (5)

Changed 4 years ago by ravi_n

Changed 4 years ago by ravi_n

comment:1 Changed 4 years ago by igloo

  • Milestone set to 6.14.1

comment:2 Changed 4 years ago by simonmar

I found and fixed the bug, but I was confused for a while that the program was still crashing after I'd fixed the bug. Then I noticed the program has a pretty serious bug in it:

callFnBlob :: ForeignPtr FnBlob -> CDouble -> IO (CDouble)
callFnBlob fnblob d = withForeignPtr fnblob $ 
                        \ptrblob -> return(call_fn_blob ptrblob d) 

this is an invalid use of withForeignPtr, because the pointer escapes from the context (in the closure call_fn_blob ptrblob d). Hence the finalizer runs before the call, and you get a crash.

comment:3 Changed 4 years ago by simonmar

  • Resolution set to fixed
  • Status changed from new to closed

Fixed:

Tue Aug 10 06:37:39 PDT 2010  Simon Marlow <marlowsd@gmail.com>
  * Run finalizers *after* updating the stable pointer table (#4221)
  Silly bug really, we were running the C finalizers while the StablePtr
  table was still in a partially-updated state during GC, but finalizers
  are allowed to call freeStablePtr() (via hs_free_fun_ptr(), for
  example), and chaos ensues.
Note: See TracTickets for help on using tickets.