Skip to content

Access Violation in 2.1, works fine in 1.04 #2075

Description

@alex-jitbit

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

ImageSharp version

2.1.0

Other ImageSharp packages and versions

none

Environment (Operating system, version and so on)

Windows 2016

.NET Framework version

6.0

Description

We have an ASP.NET 6 app that uses ImageSharp 2.1 to resize images and create thumbnails (and that's it) for UGC. Several times a day, during high-load, our app crashes with this error:

Application: w3wp.exe
CoreCLR Version: 6.0.322.12309
.NET Version: 6.0.3
Description: The process was terminated due to an internal error in the .NET Runtime at IP 00007FF932A2A5A9 (00007FF932940000) with exit code 80131506.

It's very simple code. But this uncatchable error crashes our entire process.

Reverting back to 1.0.4 seems to help.

Steps to Reproduce

Unfortunately I'm unable to reliably tell which images caused this, since it's a busy app with millions of HTTP requests. Also I had no time to create process dumps or anything, But I did narrow this down to ImageSharp - reverting nuget from 2.1 to 1.0.4 fixed the issue immediately. So I thought you should know.

PS. Also, posting this is to help someone who's going to google for a solution desperately

Images

No response

Activity

  1. JimBobSquarePants commented on Mar 25, 2022

    @JimBobSquarePants
    Member

    Thanks @alex-jitbit for raising this.

    However, without either a stack trace, dump or image we’re absolutely powerless to do anything about it. You’ll need to provide means to replicate the issue or submit a patch.

  2. alex-jitbit commented on Mar 25, 2022

    @alex-jitbit
    Author

    @JimBobSquarePants 100% understand. I will try to set up automated crash-dump saving, and then let it run on 2.1 for a while. If I won't be able to provide more details feel free to close.

  3. JimBobSquarePants commented on Mar 26, 2022

    @JimBobSquarePants
    Member

    Thanks. We definitely won’t be closing this issue. It’s top priority to avoid memory access violations.

  4. JimBobSquarePants commented on Mar 26, 2022

    @JimBobSquarePants
    Member

    This may or may not be related but I have noticed we're missing a sanitation check here.

    if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker.Slice(0, ExifMarkerLength)))
    {
    int remainingXmpMarkerBytes = XmpMarkerLength - ExifMarkerLength;
    stream.Read(this.temp, ExifMarkerLength, remainingXmpMarkerBytes);
    remaining -= remainingXmpMarkerBytes;
    if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker))
    {
    this.hasXmp = true;
    byte[] profile = new byte[remaining];
    stream.Read(profile, 0, remaining);
    if (this.xmpData is null)

    We really should be checking for a valid length before reading despite how rare this should be.

    if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker.Slice(0, ExifMarkerLength)))
    {
        const int remainingXmpMarkerBytes = XmpMarkerLength - ExifMarkerLength;
        if (remaining < remainingXmpMarkerBytes || this.IgnoreMetadata)
        {
            // Skip the application header length.
            stream.Skip(remaining);
            return;
        }
    
        stream.Read(this.temp, ExifMarkerLength, remainingXmpMarkerBytes);
  5. alex-jitbit commented on Mar 26, 2022

    @alex-jitbit
    Author

    @JimBobSquarePants thanks! Will try my best to dig some more debug info. I completely understand.

    JFYI, this is the code we use, like I said it's very basic

    using (Image srcBmp = Image.Load(imgData)) //"imgData" is a MemoryStream
    {
    	//omitted some custom code that does not use ImageSharp (calculating target dimensions)
    	//...
    	
    	srcBmp.Mutate(x => x.Resize(newWidth, newHeight));
    	
    	//sometimes we use this instead of the above
    	srcBmp.Mutate(x => x.Resize(new ResizeOptions { Mode = ResizeMode.Pad, Position = AnchorPositionMode.Center, Size = new Size(newWidth, newHeight), Sampler = KnownResamplers.NearestNeighbor }));
    
    	using (var resultMs = new MemoryStream())
    	{
    		srcBmp.Save(resultMs, IsJpeg(imgData) ? new JpegEncoder() : new PngEncoder());
    		//"IsJpeg" is our custom function that uses "magic numbers" to tell JPG from everything else
    	}
    }
  6. tocsoft commented on Mar 26, 2022

    @tocsoft
    Member

    @alex-jitbit unrelated to the bug reported but thought you would like to know but there is an overload of Image.Load(imgData, out IImageFormat imageFormat) that returns the format of the image loaded, saves you having to process the imgData stream twice as we have already done exactly that during load. Also there is an overload/extension method on Image for saving that takes in an IImageFormat so you can call srcBmp.Save(resultMs, imageFormat); to save in the same format as the source image and avoid create a new encoder instance on each call. (at the very least you want to make them singletons, there is no need to create a new one every image).

  7. JimBobSquarePants commented on Apr 4, 2022

    @JimBobSquarePants
    Member

    @alex-jitbit any update on means of replicating? We’re blocked from any further development of the libraries until we get this sorted.

  8. alex-jitbit commented on Apr 4, 2022

    @alex-jitbit
    Author

    @JimBobSquarePants no, sorry, I was prohibited from setting up the automated crash dumps on production and can't replicate this on staging or local dev machine. I completely understand this issue is useless without STR, so feel free to close

  9. JimBobSquarePants commented on Apr 4, 2022

    @JimBobSquarePants
    Member

    Not even a try… catch around the relevant code to identify a problematic image? You don’t need a process dump.

  10. alex-jitbit commented on Apr 5, 2022

    @alex-jitbit
    Author

    @JimBobSquarePants we do have a try-catch around it, but no exception is thrown.

  11. JimBobSquarePants commented on Apr 5, 2022

    @JimBobSquarePants
    Member

    Damn.... That's nasty! And you definitely have the same version deployed on both staging and production with the same images?

  12. br3aker commented on Apr 5, 2022

    @br3aker
    Contributor

    @alex-jitbit corrupted state exceptions are not caught by try-catch by default, 'access violation' is one of them. Unfortunately, dotnet6 dropped support of the CSE exception handling but you can use this event: AppDomain.UnhandledException.

    Problem is that process crash can be caused by various exceptions, so it's better to confirm exact exception type before watching for potential access violations.

  13. JimBobSquarePants commented on Apr 13, 2022

    @JimBobSquarePants
    Member

    @alex-jitbit Did you get permission to ad @br3aker suggested capture approach?

  14. added this to the 2.1.1 milestone on Apr 15, 2022
  15. JimBobSquarePants commented on Apr 20, 2022

    @JimBobSquarePants
    Member

    @alex-jitbit We've pushed some significant decoder sanitation code to main which is now in build 2.1.1-alpha.0.4 which should fix any memory access issues.

    It would be great if you could test this release for us before we ship a release to NuGet

  16. alex-jitbit commented on May 31, 2022

    @alex-jitbit
    Author

    Just updated to 2.1.2 and let it run for 2 days. Today received another access violation

    Application: w3wp.exe
    CoreCLR Version: 6.0.522.21309
    .NET Version: 6.0.5
    Description: The process was terminated due to an internal error in the .NET Runtime at IP 00007FFBF6DBA639 (00007FFBF6CD0000) with exit code 80131506.
    
  17. JimBobSquarePants commented on May 31, 2022

    @JimBobSquarePants
    Member

    It’s more than a little disappointing that you took so long to get back to us. I’m not sure what you expect us to be able to do.

  18. alex-jitbit commented on May 31, 2022

    @alex-jitbit
    Author

    @JimBobSquarePants Sorry about that. It's OK I'll just stick to v1 then. JFYI it appears it's not related to some particular image, but to a high-load scenario with ~15k requests per minute. Must be the new pooling/pool trimming mechanisms.

  19. JimBobSquarePants commented on Jun 1, 2022

    @JimBobSquarePants
    Member

    It's OK I'll just stick to v1 then

    @alex-jitbit Unfortunately that doesn't really help us, or anyone else who may encounter issues. Did you try the suggestion by @br3aker to gather more information?

  20. antonfirsov commented on Jun 1, 2022

    @antonfirsov
    Member

    @alex-jitbit you can't stay on 1.0 forever, so it would be great to give another try to figure this out :)

    Is 2 days the actual up-time before your high-load service dies? What does your service do? (=what ImageSharp API-s are called).

  21. alex-jitbit commented on Jun 2, 2022

    @alex-jitbit
    Author

    @JimBobSquarePants I will add an AppDomain.UnhandledException handler and try to gather more info and get back to you. But I doubt it will help, since I run on Windows and it logs unhandled exceptions in Event Log anyway.

    @antonfirsov here is the code we use. Our app a is CRUD business app (asp.net core) with file attachments, that simply generates thumbnails for UGC images before storing those on CDN.

  22. alex-jitbit commented on Jan 17, 2023

    @alex-jitbit
    Author

    I just realized that my app is published as ReadyToRun so it might be connected to #2148

  23. JimBobSquarePants commented on Jan 21, 2023

    @JimBobSquarePants
    Member

    Have you tried .NET 7?

  24. alex-jitbit commented on Mar 5, 2023

    @alex-jitbit
    Author

    @JimBobSquarePants unfortunately, no because it's STS, while most of enterprise-grade customers have policies that require LTS releases only

  25. antonfirsov commented on Mar 7, 2023

    @antonfirsov
    Member

    @alex-jitbit any further information you could share upon the fact that the load is ~15k RPM? (Typical formats, image sizes, hardware configuration etc.) Any chance you can create a crash dump?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions