jeroenp 26 Posted December 19, 2018 I am trying to track down a problem while loading PNGs that happens, but hardly, on a few end-user sites. The crash is inside this piece of code in Delphi 10.1 Berlin unit Vcl.Imaging.pngimage.pas : {Resizes the image data to fill the color type, bit depth, } {width and height parameters} procedure TChunkIHDR.PrepareImageData(); //... {Create the device independent bitmap} ImageHandle := CreateDIBSection(ImageDC, pBitmapInfo(@BitmapInfo)^, DIB_RGB_COLORS, ImageData, 0, 0); SelectObject(ImageDC, ImageHandle); {Build array and allocate bytes for each row} fillchar(ImageData^, BytesPerRow * Integer(Height), 0); end; The VCL code has diverged from for instance https://github.com/thargor6/mb3d/blob/master/pngimage.pas and http://svn.hiasm.com/packs/delphi/code/KOLPng.pas but similar to http://www.gm-software.de/units/GMPngImage.htm (the three highest deduplicated search hits I got for "TChunkIHDR.PrepareImageData" "fillchar") What happens here is that the call to CreateDIBSection is not verified to succeed. Documentation indicates that if it fails, both the returned ImageHandle are the ImageData pointer are null. I am trying to get the calling code refactored so it saves the PNG file, hoping that it will help tracking back the actual root-cause of this problem.One question I now have if people have bumped into similar problems. Of course this is a problem involving multiple libraries, in this case at least FastReport and wPDF, as you can see from the below part of the not-fully-accurate (I think the FastFreeMem is bogus) stack trace: [008080E5]{MyApplication.exe} JclHookExcept.HookedExceptObjProc (Line 391, "JclHookExcept.pas" + 2) [0040B54F]{MyApplication.exe} System.@HandleAnyException (Line 19565, "System.pas" + 13) [009894E5]{MyApplication.exe} Vcl.Imaging.pngimage.TChunkIHDR.PrepareImageData (Line 2311, "Imaging\PNGImage\Vcl.Imaging.pngimage.pas" + 67) [00989099]{MyApplication.exe} Vcl.Imaging.pngimage.TChunkIHDR.LoadFromStream (Line 2162, "Imaging\PNGImage\Vcl.Imaging.pngimage.pas" + 48) [0098D4C4]{MyApplication.exe} Vcl.Imaging.pngimage.TPngImage.LoadFromStream (Line 4904, "Imaging\PNGImage\Vcl.Imaging.pngimage.pas" + 71) [01994896]{MyApplication.exe} frxClass.TfrxPictureView.LoadPictureFromStream (Line 6574, "frxClass.pas" + 141) [00420BDF]{MyApplication.exe} FastMM4.FastFreeMem (Line 5644, "FastMM4.pas" + 18) [019348E2]{MyApplication.exe} frxPictureCache.TfrxMemoryStream.Seek (Line 351, "frxPictureCache.pas" + 4) [004CE682]{MyApplication.exe} System.Classes.TStream.SetPosition (Line 7306, "System.Classes.pas" + 1) [01934443]{MyApplication.exe} frxPictureCache.TfrxPictureCache.GetPicture (Line 213, "frxPictureCache.pas" + 24) [0194D521]{MyApplication.exe} frxPreviewPages.DoObjects (Line 1277, "frxPreviewPages.pas" + 13) [0194D540]{MyApplication.exe} frxPreviewPages.DoObjects (Line 1281, "frxPreviewPages.pas" + 17) [0194D755]{MyApplication.exe} frxPreviewPages.TfrxPreviewPages.GetPage (Line 1341, "frxPreviewPages.pas" + 56) [01A68E3A]{MyApplication.exe} wPDF.FastReportNaarWPDF$0$ActRec.$1$Body (Line 282, "wPDF.pas" + 21) [01A6888C]{MyApplication.exe} MemoryManager.TLogMemoryStatesHelper.LogMemoryStatesBeforeAndAfter (Line 797, "MemoryManager.pas" + 14) Share this post Link to post
kevind7 0 Posted February 21, 2019 Confirming that I have just encountered a similar error in Delphi 10.3.1 Rio, loading a PNG image from file. It is an 8MB file. As background, I'm just updating a project that hasn't had this area of code touched for a more than a couple of years and the code and the image it was attempting to load both worked in a previous version of Delphi at that time. The code looks the same as listed from Delphi 10.1 Berlin. In line 2330 of Vcl.Imaging.pngimage, the fillchar call has the correct BytesPerRow and Height, so IHDRData is populated, but ImageData is nil. Details copied directly from IDE System._FillChar(???,???,???) Vcl.Imaging.pngimage.TChunkIHDR.PrepareImageData Vcl.Imaging.pngimage.TChunkIHDR.LoadFromStream(???,(...),13) Vcl.Imaging.pngimage.TPngImage.LoadFromStream($E2A3B58) Vcl.Graphics.TGraphic.LoadFromFile(???) Vcl.Graphics.TPicture.LoadFromFile$ActRec.$0$Body(???) Vcl.Graphics.TPicture.Load(???,TPicture.LoadFromFile$ActRec($D4EBEB0) as TPicture.TLoadProc) Vcl.Graphics.TPicture.LoadFromFile(???) Share this post Link to post
TurboMagic 92 Posted February 24, 2019 Can you find out in which Delphi version it still worked and compare the source then? Share this post Link to post
kevind7 0 Posted February 25, 2019 Yes, that will be worth doing. I don't have an appropriate version of Delphi set up at the moment so I'll report back if I make progress on this. Share this post Link to post
Lars Fosdal 1792 Posted February 25, 2019 My guess: The SetPosition / Seek ends up with an out of bounds address? Share this post Link to post
kevind7 0 Posted February 26, 2019 Thanks for the further direction to explore. After a reboot and retesting, it is now loading the 8MB PNG file that previously failed, so this indicates the file is OK and the code is capable of reading it. It still failed on larger (128MB) PNG that worked on the older version of Delphi. Once it fails on the larger file, it will no longer load the smaller file until the software is restarted. Searching Quality portal, it could also be related to RSP-19648 - "TPngImage does not handle WinAPI errors". As a test, I have carried out the increase of GDI Handles from 10,000 to 20,000 (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota), rebooted but this hasn't changed behaviour. There is no sign of excessive GDI Handle use before trying to load the larger file. When I have time, I'll look at reinstalling an older version and checking. Share this post Link to post
kevind7 0 Posted March 4, 2019 As further update, the PNG loading is working when built as 64 bit. My original project was 32 bit only as I had a dependency that was not compatible with 64 bit. After upgrading the dependency and building 64 bit, the PNG files loaded correctly for the larger image files too. The 32 bit project still fails with the larger files. Share this post Link to post