Repository navigation
Fatal error. System.AccessViolationException When Encode #2595
Description
Activity
We’ll need an input image that triggers the crash.
This is very odd code btw? Why are you creating that
byte[]and copying to it?This error does not appear in the same picture, but occurs randomly in tens of thousands of pictures.
Many steps are omitted here. Even without these steps, this code will generate errors.@br3aker I'm a little confused following this code so will need your assistance diagnosing if I can?
I'm assuming the unused property
paddedPixelsCountis meaningless? I'm not sure how we can go out of bounds here given that the lanes are created as a multiple of that width.
@wuyu8512 Are you operating on
imageoroutImage? I'm still struggling to understand why you are wrapping memory, the buffer never gets set tonulldoes it?If you need direct pixel access for your operations. This is the best and secure way.
image.ProcessPixelRows(accessor => { for (int y = 0; y < accessor.Height; y++) { Span<Bgra32> row = accessor.GetRowSpan(y); Span<byte> byteRow = MemoryMarshal.Cast<Bgra32, byte>(row); // Manipulate the row bytes directly. } });
@wuyu8512 Are you operating on
imageoroutImage?i was operating on
imageI'm still struggling to understand why you are wrapping memory
I hope to be compatible with both ImageSharp and SkiaSharp, so getting all the data and processing it will make it easier for me to write a universal library
the buffer never gets set to
nulldoes it?Yes, I updated all the code
Assuming that the object of the Save method is changed to
inputImageobject, the error will not occur, so it is suspected that something unexpected happened to WrapMemory.Save doesn't mutate the image. It only encodes it.
I can't see where
pixelsis set to null in your sample. I'm assuming then that you are passing thepixelsbuffer in its entirety to your custom filter methods to operate upon before saving?WrapMemorydepends on the buffer being available and its dimensions unchanged for the lifetime of the operation. Any change there will lead to issues.You should create a 2D buffer abstraction that allows per-row access instead of using the array for your custom methods. That would be the only type you implement for both ImageSharp and SkiaSharp.
Save doesn't mutate the image. It only encodes it.
Sorry, my express was not good, I modify my express again
I can't see where pixels is set to null in your sample. I'm assuming then that you are passing the pixels buffer in its entirety to your custom filter methods to operate upon before saving?
Yes, the pixels buffer will never set
null, This code can be reproduced directlyYou should create a 2D buffer abstraction that allows per-row access instead of using the array for your custom methods. That would be the only type you implement for both ImageSharp and SkiaSharp.
i will try
After forcing the use of Webp, the problem no longer occurs
var filePath = Path.Combine(imgaeBasePath, path); using var inputImage = await SixLabors.ImageSharp.Image.LoadAsync<Bgra32>(filePath); var pixel = new byte[inputImage.Height * inputImage.Width * Unsafe.SizeOf<Bgra32>()]; inputImage.CopyPixelDataTo(pixel); using var outputImage = SixLabors.ImageSharp.Image.WrapMemory<Bgra32>(pixel, inputImage.Width, inputImage.Height); var stream = new MemoryStream(); await outputImage.SaveAsWebpAsync(stream, new SixLabors.ImageSharp.Formats.Webp.WebpEncoder() { Quality = 95 }); stream.Position = 0; return Results.File(stream, SixLabors.ImageSharp.Formats.Webp.WebpFormat.Instance.DefaultMimeType);I suspect that
WrapMemoryis not related to the issue at all but just to check, can you see if you can replicate usingJpegEncoderonly and no wrapping?If so, please let me know and also let me know the dimension range of the images you are using?
if use
LoadPixelDataReplaceWrapMemory, Problem no longer recurs
my image are most around 1000*1500 and 500 * 750(md version)Since this issue only occurs in my production environment, I'm sorry I can't always test it
Is this sample (but using the jpeg encoder) enough to trigger the issue?
Is this sample (but using the jpeg encoder) enough to trigger the issue?
yes
Isn't it the
sourcethat has to be padded by 3 bytes actually?ImageSharp/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
Lines 200 to 211 in 0d1296f
/// Bulk operation that unpacks pixels from <paramref name="source"/> /// into 3 seperate RGB channels. The destination must have a padding of 3. /// </summary> /// <param name="redChannel">A <see cref="ReadOnlySpan{T}"/> to the red values.</param> /// <param name="greenChannel">A <see cref="ReadOnlySpan{T}"/> to the green values.</param> /// <param name="blueChannel">A <see cref="ReadOnlySpan{T}"/> to the blue values.</param> /// <param name="source">A <see cref="Span{T}"/> to the destination pixels.</param> internal virtual void UnpackIntoRgbPlanes( Span<float> redChannel, Span<float> greenChannel, Span<float> blueChannel, ReadOnlySpan<TPixel> source) I need to refresh my memory about the SIMD packing/unpacking algorithms, but I would think this could be a more likely case, assuming a83b3b6 from #2120 implemented the mirror operation of #1462.
In this case
UnpackIntoRgbPlaneswould need to operate on a copy ofsourceRowwhen processing the last row:ImageSharp/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs
Line 114 in 0d1296f
PixelOperations<TPixel>.Instance.UnpackIntoRgbPlanes(rLane, gLane, bLane, sourceRow); This is how it's done in the decoder:
ImageSharp/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
Lines 155 to 167 in 0d1296f
// PackFromRgbPlanes expects the destination to be padded, so try to get padded span containing extra elements from the next row. // If we can't get such a padded row because we are on a MemoryGroup boundary or at the last row, // pack pixels to a temporary, padded proxy buffer, then copy the relevant values to the destination row. if (this.pixelBuffer.DangerousTryGetPaddedRowSpan(yy, 3, out Span<TPixel> destRow)) { PixelOperations<TPixel>.Instance.PackFromRgbPlanes(r, g, b, destRow); } else { Span<TPixel> proxyRow = this.paddedProxyPixelRow.GetSpan(); PixelOperations<TPixel>.Instance.PackFromRgbPlanes(r, g, b, proxyRow); proxyRow[..width].CopyTo(this.pixelBuffer.DangerousGetRowSpan(yy)); } I can repro this without
WrapMemory:Configuration.Default.MemoryAllocator = new SimpleGcMemoryAllocator(); Parallel.For(0, 10_000, i => { using Image<Bgra32> image = new Image<Bgra32>(Random.Shared.Next(3000) + 1, Random.Shared.Next(3000) + 1); using MemoryStream stream = new MemoryStream(); image.SaveAsJpeg(stream); });
Reacted by James Jackson-SouthThis can be further reduced to
Configuration configuration = Configuration.CreateDefaultInstance(); configuration.MemoryAllocator = new SimpleGcMemoryAllocator(); using Image<Bgra32> image = new(configuration, 132, 1606); using MemoryStream stream = new(); image.SaveAsJpeg(stream);
Hello, (@antonfirsov, @JimBobSquarePants )
Since this issue looks similar to one we had before, I am adding this comment in case it helps you or us.
When using our tool with SaveAsJpeg in ImageSharp, we got this AVE error (see attached error log) for certain images.
Changing the method to SaveAsPng resolved the issue.
When I checked individual images with the SaveAsJpeg method using a few commands, this was fine, but I can provide some image files if you need them.@SunaeK please open a new issue providing means to replicate and image data.
Reacted by Sunae Kim
Prerequisites
DEBUGandRELEASEmodeImageSharp version
3.0.2
Other ImageSharp packages and versions
No
Environment (Operating system, version and so on)
Ubuntu 22.04.3 LTS
.NET Framework version
.Net 8
Description
Steps to Reproduce
Sorry for my bad English,
When big number of requests(about avg 2request/1s), an error will throw, But I can't reproduce it on my local computer
Images
No response