Skip to content

System.ExecutionEngineException when trying to save image as webp #2411

Description

@claustsen

Prerequisites

  • I have bought a Commercial License
  • 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

3.0.0

Other ImageSharp packages and versions

None

Environment (Operating system, version and so on)

Windows 11

.NET Framework version

dotnet 6.0.15 and dotnet 7.0.4

Description

When running the below code on attached image I get a System.ExecutionEngineException when n reaches 2. Have tried multiple quality settings where it also fails. Does not fail on loss less encoding.

It fails with the following stacktrace

Fatal error. Internal CLR error. (0x80131506)
   at System.Buffer._Memmove(Byte ByRef, Byte ByRef, UIntPtr)
   at System.Buffer.Memmove(Byte ByRef, Byte ByRef, UIntPtr)
   at System.IO.Strategies.BufferedFileStreamStrategy.WriteSpan(System.ReadOnlySpan`1<Byte>, System.ArraySegment`1<Byte>)
   at System.IO.FileStream.Write(System.ReadOnlySpan`1<Byte>)
   at SixLabors.ImageSharp.Formats.Webp.BitWriter.BitWriterBase.WriteAlphaChunk(System.IO.Stream, System.Span`1<Byte>, Boolean)
   at SixLabors.ImageSharp.Formats.Webp.BitWriter.Vp8BitWriter.WriteEncodedImageToStream(System.IO.Stream, SixLabors.ImageSharp.Metadata.Profiles.Exif.ExifProfile, SixLabors.ImageSharp.Metadata.Profiles.Xmp.XmpProfile, SixLabors.ImageSharp.Metadata.Profiles.Icc.IccProfile, UInt32, UInt32, Boolean, System.Span`1<Byte>, Boolean)
   at SixLabors.ImageSharp.Formats.Webp.Lossy.Vp8Encoder.Encode[[SixLabors.ImageSharp.PixelFormats.Rgba32, SixLabors.ImageSharp, Version=3.0.0.0, Culture=neutral, PublicKeyToken=d998eea7b14cab13]](SixLabors.ImageSharp.Image`1<SixLabors.ImageSharp.PixelFormats.Rgba32>, System.IO.Stream)
   at SixLabors.ImageSharp.Formats.Webp.WebpEncoderCore.Encode[[SixLabors.ImageSharp.PixelFormats.Rgba32, SixLabors.ImageSharp, Version=3.0.0.0, Culture=neutral, PublicKeyToken=d998eea7b14cab13]](SixLabors.ImageSharp.Image`1<SixLabors.ImageSharp.PixelFormats.Rgba32>, System.IO.Stream, System.Threading.CancellationToken)
   at SixLabors.ImageSharp.Formats.Webp.WebpEncoder.Encode[[SixLabors.ImageSharp.PixelFormats.Rgba32, SixLabors.ImageSharp, Version=3.0.0.0, Culture=neutral, PublicKeyToken=d998eea7b14cab13]](SixLabors.ImageSharp.Image`1<SixLabors.ImageSharp.PixelFormats.Rgba32>, System.IO.Stream, System.Threading.CancellationToken)
   at SixLabors.ImageSharp.Formats.ImageEncoder.EncodeWithSeekableStream[[SixLabors.ImageSharp.PixelFormats.Rgba32, SixLabors.ImageSharp, Version=3.0.0.0, Culture=neutral, PublicKeyToken=d998eea7b14cab13]](SixLabors.ImageSharp.Image`1<SixLabors.ImageSharp.PixelFormats.Rgba32>, System.IO.Stream, System.Threading.CancellationToken)
   at SixLabors.ImageSharp.Formats.ImageEncoder.Encode[[SixLabors.ImageSharp.PixelFormats.Rgba32, SixLabors.ImageSharp, Version=3.0.0.0, Culture=neutral, PublicKeyToken=d998eea7b14cab13]](SixLabors.ImageSharp.Image`1<SixLabors.ImageSharp.PixelFormats.Rgba32>, System.IO.Stream)
   at SixLabors.ImageSharp.ImageExtensions.Save(SixLabors.ImageSharp.Image, System.String, SixLabors.ImageSharp.Formats.IImageEncoder)
   at SixLabors.ImageSharp.ImageExtensions.SaveAsWebp(SixLabors.ImageSharp.Image, System.String, SixLabors.ImageSharp.Formats.Webp.WebpEncoder)
   at Program.<Main>$(System.String[])

Steps to Reproduce

Using the following code

using SixLabors.ImageSharp.Formats.Webp;

Image image = Image.Load<Rgba32>("mightfail.png");
           
for (int n = 0; n < 100; n++)
{
    Console.Write($"{n} ");
    image.SaveAsWebp("test.webp", new WebpEncoder() { Quality = 90});
}

Images

mightfail

Activity

  1. brianpopow commented on Mar 23, 2023

    @brianpopow
    Collaborator

    I have trouble reproducing the error, it works for all n for me. Is the reproduction code really correct? Its doing the same thing in the loop 100 times.

  2. tocsoft commented on Mar 23, 2023

    @tocsoft
    Member

    the stacktrace ends up deep in framework code... could be an issue when writing to a particular file location.

    @claustsen what type of location are you trying to write to? is it just a local drive or is it a network path? or even some virtual file path (one drive or equivalent online folder sync) location?

  3. claustsen commented on Mar 24, 2023

    @claustsen
    Author

    In the sample code I am writing to a local ssd on my laptop. I tried to reduce it to bare minimum. I can see this morning that it does not fail when running it.

    We have it running on some web servers on
    https://content.cylindo.com/api/v2/4960/products/AAC%20121%20SOFT%20DUO/frames/13/MIKASTOOL.webp?version=3&size=1025 there it fails some times and gives correct result at other times.
    It works by giving the HttpContext.Response.Body stream to SaveAsWebpAsync. This approach works fine for other image formats you have implemented.

    I have attached a sample of a successfull image and a failed image. From a quick look and a lack of deeper knowledge of webp format it seems like it is only the alpha part which is wrong, the rest is saved correct. The alpha is in the beginning of the file and the RGB is in the later part. Does it write the RGB first and then spools back the stream to write the alpha?
    fail and succes dl.zip

  4. tocsoft commented on Mar 24, 2023

    @tocsoft
    Member

    FYI when targeting HttpContext.Response.Body we actually end up writing to an in intermediate MemoryStream due to the sync nature of our encoders and aspnet core error on sync writes. Before flushing that out to the Body stream.

    So as a work around you should be able to save to a memory stream first then flush that directly to the file on disk.

  5. brianpopow commented on Mar 24, 2023

    @brianpopow
    Collaborator

    I have attached a sample of a successfull image and a failed image. From a quick look and a lack of deeper knowledge of webp format it seems like it is only the alpha part which is wrong, the rest is saved correct. The alpha is in the beginning of the file and the RGB is in the later part. Does it write the RGB first and then spools back the stream to write the alpha?

    The alpha chunk is actually written first: Webp extended format
    I really wonder how it can write a valid webp, if it fails in WriteAlphaChunk. I have checked the images in fail and succes dl.zip they are correct.

  6. antonfirsov commented on Mar 24, 2023

    @antonfirsov
    Member

    @brianpopow I think the alphaData span leaks out of the lifetime scope of its' IMemoryOwner<byte> encodedAlphaData:

    Span<byte> alphaData = Span<byte>.Empty;
    if (hasAlpha)
    {
    // TODO: This can potentially run in an separate task.
    using IMemoryOwner<byte> encodedAlphaData = AlphaEncoder.EncodeAlpha(
    image,
    this.configuration,
    this.memoryAllocator,
    this.skipMetadata,
    this.alphaCompression,
    out alphaDataSize);
    alphaData = encodedAlphaData.GetSpan();
    if (alphaDataSize < pixelCount)
    {
    // Only use compressed data, if the compressed data is actually smaller then the uncompressed data.
    alphaCompressionSucceeded = true;
    }
    }

    Which leads to memory corruption later when alphaData is written to the destination stream. Depending on the app's memory load, it can lead to crashes.

  7. JimBobSquarePants commented on Mar 24, 2023

    @JimBobSquarePants
    Member

    Good catch @antonfirsov !

  8. brianpopow commented on Mar 24, 2023

    @brianpopow
    Collaborator

    Sorry for closing the issue, this was done automatically.

  9. antonfirsov commented on Mar 27, 2023

    @antonfirsov
    Member

    @claustsen can you try whether the latest nightlies fix the issue for you?
    You should be able to see them by adding https://f.feedz.io/sixlabors/sixlabors/nuget/index.json to your NuGet feed and enabling prerelease.

  10. claustsen commented on Mar 28, 2023

    @claustsen
    Author

    Thanks for the quick fix, event though I did not give much to make it reproduceable.

    Will test it out on our servers and locally and hope that they give correct images.

  11. claustsen commented on Mar 28, 2023

    @claustsen
    Author

    Have been testing it multiple times today. Found no occurrences of the error. So would say that it works now.

  12. antonfirsov commented on Mar 28, 2023

    @antonfirsov
    Member

    We just released 3.0.1 with the fix, you should be able to consume the official package:
    https://www.nuget.org/packages/SixLabors.ImageSharp/3.0.1

    Closing for now, feel free to reopen if we are wrong and the issue persists.

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

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions