GExperts stores its settings under one registry key per IDE version, so two
running IDEs of the same version share it. TGExpertsSettings.WriteStrings
deletes a section before rewriting it, which makes concurrent writes from two
IDEs collide: one deletes the key while the other is writing into it, the write
fails with an ERegistryException, and the settings that were being saved can be
lost.
RAD Studio 10.2 (BDS 19.0), GExperts trunk (1.4.0), 32 bit IDE.
Not version specific: the code is unchanged since revision 1.
It is a race, so it does not happen every time.
The IDE shows, while shutting down:
GExperts error destroying expert 6 - CleanDirectories:
Failed to set data for 'Count'
Press Ignore to ignore any further errors while destroying experts.
On one occasion this was followed by:
Access violation at address 500678A9 in module 'rtl250.bpl'.
Read of address 10FD80C4.
The AV happened once and has not been reproduced; it may or may not be related.
Closing two IDEs of the same version saves both their settings without an
error dialog.
TGExpertsSettings.WriteStrings in Source/Framework/GX_ConfigurationInfo.pas
(~line 1034) does:
EraseSection(Section); // deletes the registry key
WriteInteger(Section, 'Count', 0);
... write item0..itemN ...
WriteInteger(Section, 'Count', List.Count);
With two IDEs saving the same section at once, one of them deletes the key
while the other has it open; the second one's write then fails and the
ERegistryException surfaces as "Failed to set data for 'Count'". (The message
is the RTL's; the exact API error was not captured, so the deleted-key path is
the likely cause rather than a confirmed one.)
CleanDirectories is not special - it is simply the expert that happened to be
saving when the collision occurred. Any expert that saves a string list through
WriteStrings can hit it, and nothing about it is specific to shutdown either:
two IDEs writing the same section at any time is enough.
The section is erased before the new values are written, so an interrupted
write does not merely fail: the settings that were in that section are already
gone, and what remains can be a partial list, or the "brutal" Count=0 written
at the start. This is silent - the user sees a dialog about 'Count' and not
about having lost, say, their Clean Directories configuration.
Do not delete the key at all. Write the items and the new Count first, then
delete only the leftover entries whose index is >= the new count. That removes
the delete/rewrite window entirely and is no more work than the current code.
Serialising the writes across processes (a named mutex) would also fix the
collision, but it does not address the "erase first, then fail" data loss,
which is a hazard on its own even in a single IDE if a write fails for any
other reason.