{"record":{"id":"a57cb4c0b7e877f4","repo":"AvaloniaUI/Avalonia","slug":"buffersize","errorCode":null,"errorMessage":"bufferSize","messagePattern":"bufferSize","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Media/Imaging/Bitmap.cs","lineNumber":241,"sourceCode":"        /// <remarks>\n        /// <paramref name=\"sourceRowBytes\"/> is signed and may be negative: a negative value means the\n        /// source rows are laid out bottom-up, with <paramref name=\"sourceAddress\"/> pointing at the\n        /// first (top) row. The destination <paramref name=\"stride\"/> must be positive and at least the\n        /// tightly-packed row size. The caller is responsible for validating <paramref name=\"sourceRect\"/>\n        /// against the source bounds (e.g. via <see cref=\"ValidateSourceRect\"/>).\n        /// </remarks>\n        internal static unsafe void CopyPixelsCore(PixelRect sourceRect, IntPtr sourceAddress, int sourceRowBytes,\n            PixelFormat sourceFormat, IntPtr buffer, int bufferSize, int stride)\n        {\n            int minStride = checked(((sourceRect.Width * sourceFormat.BitsPerPixel) + 7) / 8);\n            if (stride < minStride)\n                throw new ArgumentOutOfRangeException(nameof(stride));\n\n            // 64-bit to avoid overflowing the guard for very large strides/heights, which would\n            // otherwise let an oversized contiguous blit/loop run past the buffers.\n            var minBufferSize = (long)stride * sourceRect.Height;\n            if (minBufferSize > bufferSize)\n                throw new ArgumentOutOfRangeException(nameof(bufferSize));\n\n            var offsetX = checked(((sourceRect.X * sourceFormat.BitsPerPixel) + 7) / 8);\n\n            // Fast-path: when the source and destination layouts are identical, tightly-packed and\n            // forward (no row padding, no X offset, positive stride), the whole region is contiguous in\n            // both buffers and can be copied with a single blit. This is meaningfully faster than the\n            // per-row loop (up to ~5x for small images, ~30% for large ones). Requiring stride == minStride\n            // also guarantees we don't read past the source's last row.\n            if (offsetX == 0 && sourceRowBytes == stride && stride == minStride)\n            {\n                Unsafe.CopyBlock(buffer.ToPointer(),\n                    (sourceAddress + sourceRowBytes * sourceRect.Y).ToPointer(), (uint)minBufferSize);\n                return;\n            }\n\n            for (var y = 0; y < sourceRect.Height; y++)\n            {\n                var srcAddress = sourceAddress + sourceRowBytes * (sourceRect.Y + y) + offsetX;","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Media/Imaging/Bitmap.cs#L223-L259","documentation":"CopyPixelsCore requires the destination buffer to be at least stride * sourceRect.Height bytes. The check is performed in 64-bit to avoid an integer overflow that would otherwise let an oversized blit run past the buffer end. A smaller buffer produces a buffer overrun, hence the guard.","triggerScenarios":"Allocating bufferSize from width*height without accounting for stride padding; passing a buffer sized for a different (smaller) sourceRect; using stride*Height with the wrong height; reusing a buffer pool entry sized for a previous, smaller image.","commonSituations":"Pooling image buffers without rounding up to the largest expected stride*Height; switching destination to a padded stride without enlarging the buffer; copying a tall crop into a buffer sized for the original (shorter) image.","solutions":["Size the buffer from the exact parameters you will pass: int bufferSize = checked((int)((long)stride * sourceRect.Height));","When pooling, round the rented size up to stride*Height and slice to that length.","Recompute bufferSize whenever stride or sourceRect changes.","Use checked arithmetic to surface overflow as an exception rather than a too-small buffer."],"exampleFix":"// before\nbyte[] buf = new byte[stride * (int)bmp.PixelSize.Height]; // wrong if sourceRect is taller\nbmp.CopyPixels(rect, buf, buf.Length, stride);\n\n// after\nlong minBufferSize = (long)stride * rect.Height;\nbyte[] buf = new byte[checked((int)minBufferSize)];\nbmp.CopyPixels(rect, buf, buf.Length, stride);","handlingStrategy":"validation","validationCode":"long minBufferSize = (long)stride * sourceRect.Height;\nint bufferSize = checked((int)minBufferSize);\nbyte[] buffer = new byte[bufferSize];\nbmp.CopyPixels(sourceRect, buffer, bufferSize, stride);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Size the destination buffer from the exact stride and rect you pass.","Use checked arithmetic to surface overflow.","When pooling, round the rented buffer up to stride*Height."],"tags":["imaging","bitmap","buffer-size","overflow","stride","argument-validation"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}