Fixing Rad Studio/Delphi RTL’s MakeObjectInstance()
A few days ago, investigating some core issues reported by one of our IntraWeb customers, we found that there may be an issue with Delphi RTL’s function, MakeObjectInstance().
This function is declared in Classes.pas and it is used by all TWinControl descendants, called during object creation. The issue here is: MakeObjectInstance() is not thread safe. It uses a global list without any locking mechanism. If two or more threads are creating TWinControl descendants and both are calling MakeObjectInstance() at the same time… guess what? The global list may get corrupted and then any sort of malfunction may happen within your application. TFrame class, and also IntraWeb classes TIWForm and TIWRegion descend from TWinControl, so the issue may have impact on heavy loaded IntraWeb applications.
This issue is perfectly explained by Primoz Gabrijelcic (creator of Omni Thread Library) in his blog: http://www.thedelphigeek.com/2007/06/allocatehwnd-is-not-thread-safe.html
There is also a Quality Central report about that: http://qc.embarcadero.com/wc/qcmain.aspx?d=47559. Note that this QC dates from 2007, so this is not new.
Primoz Gabrijelcic’s post covers AllocateHwnd() but the root of the problem is the same: MakeObjectInstance() called simultaneously by different threads. This not only affects IntraWeb applications, but also any multi-threaded application where two or more threads may call MakeObjectInstance (TTimers in threads are another example, as pointed by Primoz).
With the valuable help of TeamZed member Pedro Lopes (thanks Pedro!) we created a patch to fix MakeObjectInstance(). Pedro had already released a patch to fix MakeObjectInstance(), but we are using a different approach: We are using a TRTLCriticalSection to avoid concurrency issues. The critical section is used whenever the global list is accessed.
Most of the code used to patch original MakeObjectInstance function is copied from Classes.pas. Due to copyright restrictions we cannot release the source code, so we are providing a tool that will generate the unit IWRtlFix.pas, based on installed Classes.pas. This tool requires that Rad Studio / Delphi IDE and original RTL source file Classes.pas are both installed. Of course we will also provide compiled dcu/obj files so the user may skip the creation of the patch source file.
How to use the fix:
- Download the Patch creator tool from here.
- Unzip it and run the program. It will automatically detect the installed versions of Rad Studio / Delphi IDE’s. Doesn’t matter which IDE is checked in “Detected Rad Studio / Delphi IDE’s” option.
- Choose a Destination path and click “Create Patch”
- The tool will create a file called IWRtlFix.pas
- Add this unit to your IW project and rebuild it
- You are done!
- Due to copyright restrictions the tool will only create the IWRtlFix.pas file if you have Rad Studio / Delphi IDE and original Classes.pas installed on your machine.
- The file created is compatible (and was tested) with Rad Studio / Delphi versions: 2009, 2010, XE, XE2, XE3 and XE4 (the same IDE’s currently supported by IntraWeb).