Opened 6 years ago

Closed 10 months ago

Last modified 10 months ago

#2161 closed bug (duplicate)

finaliser of a ForeignPtr called while references from unreachable threads exist

Reported by: agl Owned by:
Priority: low Milestone: 7.6.2
Component: Runtime System Version: 6.8.2
Keywords: Cc: pho@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect result at runtime Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

Description

I believe that I've managed to distill a crash which has been driving
me crazy for a few days into a short enough test case (22 lines) that
it might be useful.

In short: the threaded RTS will call the finialiser of a ForeignPtr?
while an exception handler still holds a reference to it:

% ghc -make fptest.hs cbits.c -threaded
[1 of 1] Compiling Main             ( fptest.hs, fptest.o )
Linking fptest ...
% ./fptest
New object getting created: 66f010
Finaliser getting called for 66f010
Use called for 66f010

I'm hoping that this is useful to someone who knows the RTS.

Cheers,

Attachments (2)

fptest.hs (596 bytes) - added by agl 6 years ago.
cbits.c (311 bytes) - added by agl 6 years ago.

Download all attachments as: .zip

Change History (13)

Changed 6 years ago by agl

Changed 6 years ago by agl

comment:1 Changed 6 years ago by simonmar

  • Difficulty set to Unknown
  • Milestone set to _|_
  • Summary changed from GHC threaded RTS will call the finaliser of a ForeignPtr while references still exist to finaliser of a ForeignPtr called while references from unreachable threads exist

Ok, what's happening here is the thread that has a reference to the ForeignPtr is itself unreachable, and so the GC considers both the thread and the ForeignPtr unreachable. It then sends an exception to the thread, and starts the finalizer for the ForeignPtr simultaneously.

This is similar to the case where two finalizers refer to each others' ForeignPtrs: they can both be invoked simultaneously.

You may argue that a reference from a thread, even an unreachable one, should keep a ForeignPtr alive. But it's equally valid to argue the reverse: a reference from a finalizer should keep a thread alive - you don't want a thread to be considered deadlocked if it can be unblocked by a finalizer. We can't have both, because then a cycle between a finalizer and a thread would never be collected even when both were unreachable.

OTOH, perhaps this is a case where C finalizers should be treated differently from Haskell finalizers. A weak pointer with a C finalizer could be kept alive by an unreachable thread. I'll leave this bug open to remind us if we ever special-case C finalizers (which is probably a good idea for other reasons).

comment:2 Changed 6 years ago by PHO

  • Cc pho@… added

comment:3 Changed 4 years ago by simonmar

  • Milestone changed from _|_ to 6.14.1
  • Type of failure set to None/Unknown

comment:4 Changed 4 years ago by simonmar

  • Architecture changed from x86_64 (amd64) to Unknown/Multiple
  • Operating System changed from Linux to Unknown/Multiple
  • Type of failure changed from None/Unknown to Incorrect result at runtime

comment:5 Changed 3 years ago by igloo

  • Milestone changed from 7.0.1 to 7.0.2

comment:6 Changed 3 years ago by igloo

  • Milestone changed from 7.0.2 to 7.2.1

comment:7 Changed 3 years ago by igloo

  • Milestone changed from 7.2.1 to 7.4.1

comment:8 Changed 2 years ago by igloo

  • Milestone changed from 7.4.1 to 7.6.1
  • Priority changed from normal to low

comment:9 Changed 19 months ago by igloo

  • Milestone changed from 7.6.1 to 7.6.2

comment:10 Changed 10 months ago by simonmar

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

Closing in favour of #7970

comment:11 Changed 10 months ago by marlowsd@…

commit 1ae72ac45e51e63cbf6f3d627d77acc6a36aa0f9

Author: Simon Marlow <marlowsd@gmail.com>
Date:   Tue Jul 2 12:10:53 2013 +0100

    Fix #7970, #2161, unfix #551
    
    Establish the reachability of threads before weak pointers.  Hence a
    deadlocked thread can keep a weak pointer alive and prevent it from
    being finalized early.  However, an reference from the finalizer of a
    weak pointer will no longer prevent a thread from being considered
    deadlocked (#551).  To keep the thread alive in that situation you
    need to use a StablePtr.
    
    See comments on #7970 and in the code for more details.

 rts/sm/MarkWeak.c |  100 +++++++++++++++++++++++++++-------------------------
 1 files changed, 52 insertions(+), 48 deletions(-)
Note: See TracTickets for help on using tickets.