Summary
Next.Core.Promises.pas creates a TPromiseScheduler with 10+ worker threads in its initialization section but has no finalization section to clean them up. This causes EAccessViolation crashes during application shutdown because the promise threads are still running while Delphi's @Halt0 destroys forms and other objects.
Steps to Reproduce
-
Use any TMS FNC component that references
Next.Core.Promises(e.g.TTMSFNCGoogleMaps,TTMSFNCWebBrowser) -
Run the application normally for some time
-
Close the application
Expected Behavior
Application shuts down cleanly. All promise threads are terminated before forms are destroyed.
Actual Behavior
EAccessViolation at address $00000000 ("Ausführung von Adresse 00000000") during shutdown. The promise threads are still active when @Halt0 starts destroying forms, leading to access violations on already-freed objects.
Background threads still running at crash time: 1x TThreadPool.TQueueWorkerThread, 10x TPromiseScheduler.TPromiseThread
Root Cause Analysis
In Next.Core.Promises.pas:
initialization
CreatePromiseSchedulerIf; // Creates TPromiseScheduler + starts 10+ threads
end. // No finalization!
The _Scheduler: IPromiseScheduler variable is never explicitly set to nil. Without a finalization section, the scheduler's reference count is not decremented before @Halt0 runs. The promise threads continue executing while Delphi tears down forms, VCL objects and other resources, causing access violations.
The TPromiseScheduler.Destroy already implements proper cleanup (signals FCancel, waits for controller, frees threads) — it just never gets called at the right time.
Suggested Fix
Add a finalization section:
initialization
CreatePromiseSchedulerIf;
finalization
_Scheduler := nil;
end.
Since _Scheduler is an IPromiseScheduler (interface reference), setting it to nil triggers reference counting, which calls TPromiseScheduler.Destroy, which properly signals all threads to stop and waits for them before the application continues with @Halt0.
Additional Note
The comment block at line 381-385 mentions a THelperDestroyFactory that should set _Scheduler to nil in its destructor, but this class does not exist in the current version of the unit. This suggests the cleanup mechanism was either removed or never fully implemented.