Project

General

Profile

Bug #9008

Trigger fired when iterating a Finalizable collection allows it to be modified

Added by Dănuț Filimon almost 2 years ago. Updated almost 2 years ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
Due date:
% Done:

0%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

year1w.p Magnifier (60 Bytes) Dănuț Filimon, 07/29/2024 02:39 AM

year1.df (410 Bytes) Dănuț Filimon, 07/29/2024 02:39 AM

triggertest.p Magnifier (32 Bytes) Dănuț Filimon, 07/29/2024 02:39 AM

txwrapper.patch Magnifier (593 Bytes) Dănuț Filimon, 07/29/2024 02:39 AM

GenericTrigger.java Magnifier (596 Bytes) Dănuț Filimon, 07/29/2024 02:39 AM

generictrigger.df (217 Bytes) Dănuț Filimon, 07/29/2024 02:39 AM

generictest.p Magnifier (294 Bytes) Dănuț Filimon, 07/29/2024 02:39 AM

History

#1 Updated by Dănuț Filimon almost 2 years ago

The main issue has been discussed in #8963-40 and #8963-44, the problem is as follows:
- When the Finalizables collection is being iterated (the TransactionManager$WorkArea.nowIterating and TransactionManager$WorkArea.op properties are set), it's possible for a trigger/generic trigger to be fired which will make it possible to reset these two properties because it will process a new external procedure (TransactionManager.processEntry() will be the first method which will reset them).
- Because the properties are again null/0, it will allow the BlockDefinition.finalizables that is being iterated to be modified and in this scenario it is possible for a generic trigger that did not open the scope of the buffer and is leaking to open it after the trigger is fired, registering the RecordBuffer to the collection of Finalizables that is being iterated causing a ConcurrentModificationException.

Attaching test files from #8963-44.

For reproducing the ConcurrectModificationException it is required to use generic triggers:
  • GenericTrigger.java: The generic trigger with write which does nothing but does not open the scope of the buffers.
  • generictest.p: The startup procedure.
  • generictrigger.df
The flow for the generic trigger test:
  • When the generictest.p external procedure finishes and ends up calling processFinalizables(), it will end up calling GenericTrigger.write().
  • GenericTrigger.write() is also considered an external procedure and will call processEntry() which will reset the wa.nowIterating already set with the collection of Finalizables which ended up calling the trigger. This will reset the nowIterating property to null.
  • After the trigger is fired and because the scope of the buffer was not opened, it will try to open it and log a warning. When the scope of the buffer is opened and because the nowIterating is null, it can register a new Finalizable.
  • Because the Finalizables collection is still being iterated and was modified, the ConcurrectModificationException is thrown.
For reproducing how the nowIterating property is reset to null, it is enough to use a normal trigger, the files:
  • triggertest.p: The startup procedure
  • year1w.p: A write trigger
  • year1.df

The flow is the same as for the generic trigger, with the exception of creating a new Finalizable.

The txwrapper.patch is required for both scenarios as I did not manage to flush the record when the external procedure ends (the record was flushed too early, in processBody()).

The purpose of this task is to find a method to avoid enabling resetting the nowIterating and op properties when a trigger is fired during the iteration of a Finalizables collection.

Note: The ConcurrentModificationException can't be reproduced for normal triggers because there are no leaking buffer scopes.

Also available in: Atom PDF