Bug Report T816182
Visible to All Users

Memory leaks occur if the PDF Viewer reopens a document multiple times in rapid succession

created 6 years ago (modified 5 years ago)

To whom it may concern,

We are having problems with memory leaks and unexpected exceptions in our production environment using the DevExpress-VCL PdfViewer 19.1.5.

In our production applications, the user is able to select from multiple available pdf documents.
Clicking between the different pdfs (e.g in a grid, list or button) forces the viewer to abort the previously selected pdf and start loading the next selected pdf.
It is in this scenario that the issues arise.

To reproduce these errors I have created a "Simple" stress testing application, using a windows timer, to emulate the production circumstances.
The stress testing application has been able to surface these errors.

The problem has been replicated in both Delphi XE3 and Delphi 10.3.2, using the DevExpress VCL subscription 19.1.5

Please find attached a zip file with a Delphi project "Simple.dproj" including some of our production PDFs to reproduce the problem.
I have included two screen shots, in the Errors folder, to highlight some of the memory errors encountered in production.
Note: FastMM is included and must be enabled with FullDebugMode turned on.

To run the test
  - Enable / Disable the "Destroy Viewer" Checkbox to highlight different errors
  - Enable / Disable the "Clear Viewer" Checkbox to influence the type of failure
  - Click the Test button
  - Let the test perform at least a couple of iterations
  - Click the Abort button
  - Exit the application

The following points highlight some of the issues encountered in our testing.
  1. Memory leaks
    - Even without an application error, memory leaks are surfaced.
    - When closing the application, it may take a long time for it to actually close.
      It eventually does, but FastMM will display many memory leak instances.

2. Memory Errors
    - FastMM has detected an error during a free block scan operation.
    - FastMM detected that a block has been modified after being freed.
    - FastMM has detected an attempt to call a virtual method on a freed object.

3. Exceptions raised
    - Invalid class typecast

The attached test application has certainly assisted me in discovering thread-related and race-condition-related issues.
However the supplied code only scratches the surface so I believe more intensive and targeted tests may need to be developed.

Please could you also tackle the thread related memory leak problems as our production environment encounters many "out of memory" related issues tied to the PDFViewer.

Kind Regards,
John Vander Reest

[Attachment removed by DevExpress]

Show previous comments (5)
DevExpress Support Team 5 years ago

    Hello,

    We have found a solution that should help you overcome this problem. Would you please help us test it?

    Attached is an archive containing new versions of our source files. Please install the latest version of our controls (19.2.5), replace default files with attached units, and run our installer in Recompile mode. I hope this patch will resolve the issue.

      Hi Paulo,

      I'm happy to report the tests in the "PDFViewer Stess Test" application, passed with flying colors.
      I also found no memory leaks when running the tests.
      I extensively tested with no options, as well as "Destroy Viewer" = True, and "Clear Viewer" = True
      Everything worked beautifully.
      Very happy indeed.

      I have added some additional user simulation tests.
      These include "Change Page", "Zoom Page", and "Rotate Page"
      These tests, once successfully having loaded the document, attempt to emulate the user

      • Changing to a another page
      • Zooming in or out on the page
      • Rotating the page clockwise or counter-clockwise

      …, prior to changing pre-maturely to a new document.

      These tests sadly did not fair as well.
      I have included the new source as well as the test results for each of the above tests.

      Also please find the memory leak reports, for each test, in the Errors folder.
      "Simple\Errors\Change_Page - Simple_MemoryManager_EventLog_20200303.txt"
      "Simple\Errors\Change_Zoom - Simple_MemoryManager_EventLog_20200303.txt"
      "Simple\Errors\Rotate_Error - Simple_MemoryManager_EventLog_20200303.txt"

      The new simulations were added to emulate typical user behaviour and to tease out potential threading problems.
      From my understanding of the "DevExpress" code any requested action in the PDF Viewer is passed on to the "dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter" to execute the request in a separate thread.
      I would therefore assume that it doesn't matter what type of request is made (load document, close document, goto page, zoom, rotate, export, select text, save images, etc.)
      The action should always be protected (serialized) to avoid conflicts or threading issues.

      Thank you for the already discernible invested effort.
      What has been accomplishment is a vast improvement.
      I believe the changes will eliminate some of the current issues we are having with the PDF Viewer.
      I hope my newly found issues will highlight the general pattern and trust the remaining issues can be expeditiously resolved.

      Kind Regards,
      John Vander Reest

      === Test Results ===

      DevExpress Vcl Subscription 19.2.5 + Supplied Fixes

      Test Program Simple.exe (Source provided)

      Edition: Windows 10 Pro, 32.0 GB (x64-bit)
      Version: 1909
      OS build: 18363.657
      Delphi Version: XE3 - Update 2, Rio 10.3.3

      === 1. Test: Change Page is True ===

      Error: Raised Exception class EInvalidCast with message 'Invalid class typecast'

      Debugger stopped @ line 3938 of dxPDFCore.pas

      Delphi
      function TdxPDFInteractiveFormField.GetFontInfo(AState: TdxPDFDocumentState): TdxPDFFontInfo; begin Result.FontSize := TextState.FontSize; Result.FontData := AState.SearchFontData(TextState.FontCommand) as TdxPDFEditableFontData; <<=== Debugger Stopped Here! === end;

      Call Stack - Thread 08372

      Call Stack
      :76aa3db2 KERNELBASE.RaiseException + 0x62 dxPDFCore.TdxPDFInteractiveFormField.GetFontInfo($C07931) System.ErrorAt(10,$C07931) System._AsClass(???,???) dxPDFCore.TdxPDFInteractiveFormField.GetFontInfo($7EDD8D40) dxPDFCommandConstructor.{dxPDFCommandConstructor}TdxPDFTextBasedFormFieldAppearanceBuilder<dxPDFInteractivity.TdxPDFTextFormField>.Create($7EADA720,$7F998950,$7EDD8D40) dxPDFInteractivity.TdxPDFTextFormField.CreateAppearanceBuilder($7EDD8D40) dxPDFInteractivity.TdxPDFWidgetAnnotation.CreateAppearanceBuilder($7EDD8D40) dxPDFCore.TdxPDFCustomAnnotation.EnsureAppearance($7EDD8D40,nil) dxPDFCore.TdxPDFCustomAnnotation.GetAppearanceForm($7EDD8D40) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.DrawAnnotation($7EADA720) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.ExportAnnotation dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.DoExport($7F83D980) dxPDFCommandInterpreter.TdxPDFGraphicsDevice.ExportContent($7F83D980) dxPDFCommandInterpreter.TdxPDFGraphicsDevice.DoExport($7F83D980) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.Export($7F83D980,$7EF5A600) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.ExportAndPack($782F6C50,$7EF5A600) dxPDFCore.TdxPDFPage.Export$13041$ActRec.$0$Body dxPDFCore.TdxPDFPage.LockAndExecute(TdxPDFPage.Export$13041$ActRec($782E2928) as TProc,False) dxPDFCore.TdxPDFPage.Export($7EED1610,$7EF5A600) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.Export($782F6C50,$7EF5A600) dxPDFDocumentViewer.TdxPDFRenderPageByScaleFactorTask.Render($7FA02440,(dxThreading.TdxTask.GetCanceled,$7F45B240)) dxPDFDocumentViewer.TdxPDFRenderPageTask.Run((dxThreading.TdxTask.GetCanceled,$7F45B240)) dxThreading.TdxTaskDispatcher.TTaskWrapper.Execute dxThreading.TdxTaskDispatcher.AsyncRun($7F45B240) dxThreading.TdxTaskDispatcher.ThreadProc($7F45B240) :77920afd ; :77926af7 ; :77436359 KERNEL32.BaseThreadInitThunk + 0x19 :77937b74 ntdll.RtlGetAppContainerNamedObjectPath + 0xe4 :77937b44 ntdll.RtlGetAppContainerNamedObjectPath + 0xb4

      === 2. Test: Zoom Page is True ===

      Error: Raised Exception class EInvalidCast with message 'Invalid class typecast'

      Debugger stopped @ line 3938 of dxPDFCore.pas

      Delphi
      function TdxPDFInteractiveFormField.GetFontInfo(AState: TdxPDFDocumentState): TdxPDFFontInfo; begin Result.FontSize := TextState.FontSize; Result.FontData := AState.SearchFontData(TextState.FontCommand) as TdxPDFEditableFontData; <<=== Debugger Stopped Here! === end;

      Call Stack - Thread 13744

      Call Stack
      :76aa3db2 KERNELBASE.RaiseException + 0x62 dxPDFCore.TdxPDFInteractiveFormField.GetFontInfo($C07931) System.ErrorAt(10,$C07931) System._AsClass(???,???) dxPDFCore.TdxPDFInteractiveFormField.GetFontInfo($7F567670) dxPDFCommandConstructor.{dxPDFCommandConstructor}TdxPDFTextBasedFormFieldAppearanceBuilder<dxPDFInteractivity.TdxPDFTextFormField>.Create($7F802410,$7F4DAA80,$7F567670) dxPDFInteractivity.TdxPDFTextFormField.CreateAppearanceBuilder($7F567670) dxPDFInteractivity.TdxPDFWidgetAnnotation.CreateAppearanceBuilder($7F567670) dxPDFCore.TdxPDFCustomAnnotation.EnsureAppearance($7F567670,nil) dxPDFCore.TdxPDFCustomAnnotation.GetAppearanceForm($7F567670) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.DrawAnnotation($7F802410) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.ExportAnnotation dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.DoExport($7F666EE0) dxPDFCommandInterpreter.TdxPDFGraphicsDevice.ExportContent($7F666EE0) dxPDFCommandInterpreter.TdxPDFGraphicsDevice.DoExport($7F666EE0) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.Export($7F666EE0,$7EB1AC90) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.ExportAndPack($77E85E20,$7EB1AC90) dxPDFCore.TdxPDFPage.Export$13041$ActRec.$0$Body dxPDFCore.TdxPDFPage.LockAndExecute(TdxPDFPage.Export$13041$ActRec($7EECD078) as TProc,False) dxPDFCore.TdxPDFPage.Export($7F40A090,$7EB1AC90) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.Export($77E85E20,$7EB1AC90) dxPDFDocumentViewer.TdxPDFRenderPageByScaleFactorTask.Render($7E9AD930,(dxThreading.TdxTask.GetCanceled,$7F2441D0)) dxPDFDocumentViewer.TdxPDFRenderPageTask.Run((dxThreading.TdxTask.GetCanceled,$7F2441D0)) dxThreading.TdxTaskDispatcher.TTaskWrapper.Execute dxThreading.TdxTaskDispatcher.AsyncRun($7F2441D0) dxThreading.TdxTaskDispatcher.ThreadProc($7F2441D0) :77920afd ; :77926af7 ; :77436359 KERNEL32.BaseThreadInitThunk + 0x19 :77937b74 ntdll.RtlGetAppContainerNamedObjectPath + 0xe4 :77937b44 ntdll.RtlGetAppContainerNamedObjectPath + 0xb4

      Local Variables - Thread 13744

      Code
      - Self + - FAlternateName = 'gCompleteMessage'#0#0 ... - FForm = $930092 - FFormCreated = True - FKids = $970096 - FKidsResolved = True - FParent = $2140201 - FResources = $335 - FTextJustification = tjLeftJustified - FTextState = nil - FValuesProvider = nil - FWidget = nil

      === 3. Test: Rotate Page is True ===

      Error: Raised Exception class EAccessViolation with message 'Access Violation at address xxxxxxxx'

      Debugger stopped @ line 1631 of System.Generics.Collections.pas

      Delphi
      function TDictionary<TKey,TValue>.GetBucketIndex(const Key: TKey; HashCode: Integer): Integer; . . . while True do begin hc := FItems[Result].HashCode; <<=== Debugger Stopped Here! ===

      Call Stack - Thread 15044

      Call Stack
      :76aa3db2 KERNELBASE.RaiseException + 0x62 :0040898c NotifyNonDelphiException + $1C :77958d84 ; dxPDFFontUtils.{System.Generics.Collections}TDictionary<System.Integer,dxPDFFontUtils.TdxPDFEditableFontData>.GetBucketIndex(409959543,661139492) dxPDFFontUtils.{System.Generics.Collections}TDictionary<System.Integer,dxPDFFontUtils.TdxPDFEditableFontData>.AddOrSetValue(409959543,$7F2855E0) dxPDFFontUtils.TdxPDFEditableFontDataCache.CacheEditableFontData(('Verdana', FontStyleRegular),$7F2855E0) dxPDFFontUtils.TdxPDFGDIEditableFontDataCache.GetFontData('Verdana',FontStyleRegular,True) dxPDFFontUtils.TdxPDFGDIEditableFontDataCache.SearchFontData('Verdana',FontStyleRegular) dxPDFCore.TdxPDFFontDataStorage.SearchFontData('Verdana',FontStyleRegular) dxPDFCore.TdxPDFDocumentState.CreateFontData('Verdana',FontStyleRegular) dxPDFCore.TdxPDFDocumentState.SearchFontData($7F35EF80) dxPDFCore.TdxPDFInteractiveFormField.GetFontInfo($7F6D1AA0) dxPDFCommandConstructor.{dxPDFCommandConstructor}TdxPDFTextBasedFormFieldAppearanceBuilder<dxPDFInteractivity.TdxPDFTextFormField>.Create($7FA31000,$7F269AE0,$7F6D1AA0) dxPDFInteractivity.TdxPDFTextFormField.CreateAppearanceBuilder($7F6D1AA0) dxPDFInteractivity.TdxPDFWidgetAnnotation.CreateAppearanceBuilder($7F6D1AA0) dxPDFCore.TdxPDFCustomAnnotation.EnsureAppearance($7F6D1AA0,nil) dxPDFCore.TdxPDFCustomAnnotation.GetAppearanceForm($7F6D1AA0) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.DrawAnnotation($7FA31000) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.ExportAnnotation dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.DoExport($7F8466D0) dxPDFCommandInterpreter.TdxPDFGraphicsDevice.ExportContent($7F8466D0) dxPDFCommandInterpreter.TdxPDFGraphicsDevice.DoExport($7F8466D0) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.Export($7F8466D0,$7EDE1320) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.ExportAndPack($7FE4E4B0,$7EDE1320) dxPDFCore.TdxPDFPage.Export$322907$ActRec.$0$Body dxPDFCore.TdxPDFPage.LockAndExecute(TdxPDFPage.Export$322907$ActRec($7F69B148) as TProc,False) dxPDFCore.TdxPDFPage.Export($7F19FBC0,$7EDE1320) dxPDFCommandInterpreter.TdxPDFCustomCommandInterpreter.Export($7FE4E4B0,$7EDE1320) dxPDFDocumentViewer.TdxPDFRenderPageByScaleFactorTask.Render($7F658E90,(dxThreading.TdxTask.GetCanceled,$7F235A60)) dxPDFDocumentViewer.TdxPDFRenderPageTask.Run((dxThreading.TdxTask.GetCanceled,$7F235A60)) dxThreading.TdxTaskDispatcher.TTaskWrapper.Execute dxThreading.TdxTaskDispatcher.AsyncRun($7F235A60) dxThreading.TdxTaskDispatcher.ThreadProc($7F235A60) :77920afd ; :77926af7 ; :77436359 KERNEL32.BaseThreadInitThunk + 0x19 :77937b74 ntdll.RtlGetAppContainerNamedObjectPath + 0xe4 :77937b44 ntdll.RtlGetAppContainerNamedObjectPath + 0xb4

      Local Variables - Thread 15044

      Code
      - Self + - FItems [0] - HashCode = 661139492 - Key = 409959543 - Value = $7F2826E0 [1] = (-1, 0, nil) [2] = (-1, 0, nil) [3] = (-1, 0, nil) - FCount = 1 - GrowThreashhold = 3 - Key = 409959543 - HashCode = 661139492 - Result = 661139492 - start = 661139492 - hc == 4503230

      end.

      [Attachment removed by DevExpress]

      DevExpress Support Team 5 years ago

        Thank you for sharing your test results. To my regret, we were not able to reproduce this new problem. However, we examined your log files and modified our source code accordingly. Would you please check if adding the attached file to our previous patch can help you overcome it?

        Answers approved by DevExpress Support

        created 5 years ago

        We have fixed the issue described in this ticket and will include the fix in our next maintenance update. To apply this solution before the official update, request a hotfix by clicking the corresponding link for product versions you require.

        Note: Hotfixes may be unavailable for beta versions and updates that are about to be released.

          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.