{"record":{"id":"fca0cb61a3fb26ee","repo":"AvaloniaUI/Avalonia","slug":"output-span-must-be-at-least-as-long-as-input-span","errorCode":null,"errorMessage":"Output span must be at least as long as input span","messagePattern":"Output span must be at least as long as input span","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Media/GlyphTypeface.cs","lineNumber":764,"sourceCode":"\n            return true;\n        }\n\n        /// <summary>\n        /// Attempts to retrieve glyph metrics for multiple glyphs in a single operation.\n        /// </summary>\n        /// <remarks>This method is significantly more efficient than calling <see cref=\"TryGetGlyphMetrics(ushort, out GlyphMetrics)\"/>\n        /// multiple times as it minimizes memory access overhead and exploits data locality. This is the preferred\n        /// method for batch glyph metrics retrieval in text layout and rendering scenarios. Returns false if neither\n        /// horizontal nor vertical metrics are available.</remarks>\n        /// <param name=\"glyphIds\">Read-only span of glyph identifiers for which to retrieve metrics.</param>\n        /// <param name=\"metrics\">Output span to write the glyph metrics. Must be at least as long as <paramref name=\"glyphIds\"/>.</param>\n        /// <returns>true if metrics are available and all were successfully retrieved; otherwise, false.</returns>\n        public bool TryGetGlyphMetrics(ReadOnlySpan<ushort> glyphIds, Span<GlyphMetrics> metrics)\n        {\n            if (metrics.Length < glyphIds.Length)\n            {\n                throw new ArgumentException(\"Output span must be at least as long as input span\", nameof(metrics));\n            }\n\n            if (!_hasHorizontalMetrics && !_hasVerticalMetrics)\n            {\n                return false;\n            }\n\n            // Use stackalloc for temporary buffers to avoid heap allocations\n            Span<HorizontalGlyphMetric> hMetrics = glyphIds.Length <= 256\n                ? stackalloc HorizontalGlyphMetric[glyphIds.Length]\n                : new HorizontalGlyphMetric[glyphIds.Length];\n\n            Span<VerticalGlyphMetric> vMetrics = glyphIds.Length <= 256\n                ? stackalloc VerticalGlyphMetric[glyphIds.Length]\n                : new VerticalGlyphMetric[glyphIds.Length];\n\n            bool hasHorizontal = false;\n            bool hasVertical = false;","sourceCodeStart":746,"sourceCodeEnd":782,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Media/GlyphTypeface.cs#L746-L782","documentation":"GlyphTypeface.TryGetGlyphMetrics(ReadOnlySpan<ushort> glyphIds, Span<GlyphMetrics> metrics) writes one GlyphMetrics per glyph id, so the output span must be at least as long as the input. The guard prevents writing past the end of the caller's buffer.","triggerScenarios":"Allocating the output span with the wrong length (e.g. glyphIds.Length / 2); reusing a pre-sized buffer that is too small for the current request; passing a stackalloc sized against a different constant.","commonSituations":"Batching glyph lookups and sizing the destination from a cached value rather than the live input length; off-by-one in array allocation; reusing a buffer pool sized for a previous, smaller batch.","solutions":["Allocate the output span from the input length: Span<GlyphMetrics> dst = new GlyphMetrics[glyphIds.Length];","If pooling, rent a buffer of size >= glyphIds.Length and slice to that length.","Add an assertion before the call: Debug.Assert(metrics.Length >= glyphIds.Length).","Refactor so callers always derive the destination length from the source."],"exampleFix":"// before\nvar dst = new GlyphMetrics[32]; // fixed size; batch > 32 throws\nif (gt.TryGetGlyphMetrics(glyphIds, dst)) { ... }\n\n// after\nSpan<GlyphMetrics> dst = glyphIds.Length <= 64\n    ? stackalloc GlyphMetrics[glyphIds.Length]\n    : new GlyphMetrics[glyphIds.Length];\nif (gt.TryGetGlyphMetrics(glyphIds, dst)) { ... }","handlingStrategy":"validation","validationCode":"Span<GlyphMetrics> dst = glyphIds.Length <= 64\n    ? stackalloc GlyphMetrics[glyphIds.Length]\n    : new GlyphMetrics[glyphIds.Length];\nDebug.Assert(dst.Length >= glyphIds.Length);\ngt.TryGetGlyphMetrics(glyphIds, dst);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always size the destination span from the live input length.","When pooling, slice the rented buffer to the input length.","Add a Debug.Assert before the call."],"tags":["text","glyph-typeface","spans","buffer-size","argument-validation"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}