{"record":{"id":"14a10695e887a942","repo":"AvaloniaUI/Avalonia","slug":"stride","errorCode":null,"errorMessage":"stride","messagePattern":"stride","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Media/Imaging/Bitmap.cs","lineNumber":235,"sourceCode":"            return sourceRect;\n        }\n        \n        /// <summary>\n        /// Performs a row-by-row copy of pixels from a source buffer into a destination buffer.\n        /// </summary>\n        /// <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);","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Media/Imaging/Bitmap.cs#L217-L253","documentation":"Bitmap.CopyPixelsCore computes the minimum stride for one row as ((Width * BitsPerPixel) + 7) / 8 and requires the caller-supplied stride to be at least that. A smaller stride would leave insufficient room per row and corrupt the row-by-row copy.","triggerScenarios":"Passing stride = sourceRect.Width (counting pixels, not bytes); forgetting to multiply by bytes-per-pixel for formats like Bgra32 (4 bytes); using a stride sized for a different pixel format.","commonSituations":"Computing stride as width instead of width*bytesPerPixel; switching the bitmap's PixelFormat (e.g. Bgra8888 -> Bgr24) without updating the stride formula; copying into a tightly packed buffer where stride is computed correctly but BitsPerPixel is mis-assumed.","solutions":["Always compute stride from the format: int minStride = (sourceRect.Width * format.BitsPerPixel + 7) / 8; int stride = minStride; // tight, or padded.","Use 4-byte alignment (stride = ((minStride + 3) / 4) * 4) when the destination expects row padding.","Verify the PixelFormat used in the math matches the actual bitmap.","Add a debug assertion: Debug.Assert(stride >= minStride)."],"exampleFix":"// before\nint stride = sourceRect.Width; // wrong unit\nbmp.CopyPixels(rect, buffer, bufferSize, stride);\n\n// after\nint bitsPerPixel = format.BitsPerPixel;\nint stride = (sourceRect.Width * bitsPerPixel + 7) / 8;\nbmp.CopyPixels(rect, buffer, bufferSize, stride);","handlingStrategy":"validation","validationCode":"int bitsPerPixel = format.BitsPerPixel;\nint minStride = (sourceRect.Width * bitsPerPixel + 7) / 8;\nint stride = Math.Max(minStride, requestedStride); // never below minStride","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always derive stride from BitsPerPixel, not from pixel count.","Update the stride formula when changing PixelFormat.","Add Debug.Assert(stride >= minStride) before CopyPixels."],"tags":["imaging","bitmap","stride","pixel-format","buffer-size","argument-validation"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}