Access Violation when destroying a TEvent with handlers after the finalization of Spring.HazardEra

Issue #359 resolved
Deeem2031 created an issue

With the latest develop version (9bc9edc) i get an access violation in Spring.HazardEra.EraArrayClear/Retire when aquiring the criticalsection after the finalization of Spring.HazardEra. In my specific case this is due to the DUnit-TestFramework clearing its registry and all ITestSuite/Case which seem to still hold an instance of TEvent.

At first I thought this is always (destroying event after finalization) the case but the TEvent also has to have at least one handler remaining.

A small example:

program Project41;

uses
  Unit17 in 'Unit17.pas',
  Spring;

type
  TEvent = procedure(aArg: Integer) of object;

type
  TC = class
  public
    Event: Event<TEvent>;
    procedure EventHandler(aArg: Integer);
    procedure InvokeEvent();
  end;

procedure TC.EventHandler(aArg: Integer);
begin
  aArg := aArg;
end;

procedure TC.InvokeEvent;
begin
  Event.Invoke(2031);
end;

begin
  var c := TC.Create;
  c.Event.Add(c.EventHandler);
  //c.Event.Remove(c.EventHandler); this "solves" it
  Unit17.x := c;
end.

unit Unit17;

interface

var
  x: TObject;

implementation

initialization
finalization
  x.Free;
end.

Comments (11)

  1. Stefan Glienke repo owner

    Seems because of unit in uses order the finalization of Spring is being executed before the destruction of the object holding the event.

    Please try this change and let me know if that also fixes the issue in your unit test and does not leave any memory leaks.

  2. Stefan Glienke repo owner

    Then please provide the project

    Edit: nevermind, I can repro with a TTestCase class containing a Mock

  3. Stefan Glienke repo owner

    I just created a branch for this to make it easier to test the changes - I had the scenario you posted initially and some TTestCase with a Mock in it which was being initialized during the test and thus was still allocated until TestFramework.pas finalizes which might be after Spring. I could reproduce the issue there but not after the fix.

    I tested with FastMM4, FastMM5 and LeakCheck and could not find any exceptions nor memory leaks.

    Please let me know if you can confirm these results.

  4. Deeem2031 reporter

    The actual project is way too massive to share but I found that the cause is a event notifying destruction of the instance (after the whole finalization part). So i tried adding a destructor like this to the project in the description

    destructor TC.Destroy;
    begin
      InvokeEvent;
      inherited;
    end;
    

    This does cause an error with FastMM4.FullDebugMode (access on freed memory) which I can’t reproduce in the actual project but I still think it might be the same issue.

  5. Deeem2031 reporter

    Ok, I mistakenly assumed the branch only contains the changes from the patch. I tested all my scenarios again with the current state of the branch and everything looks fine. No memory leak or exception.

    Good job

  6. Log in to comment