{"record":{"id":"f02e6204aecdd5d9","repo":"microsoft/garnet","slug":"start","errorCode":null,"errorMessage":"start","messagePattern":"start","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"libs/storage/Tsavorite/cs/src/core/Allocator/OverflowByteArray.cs","lineNumber":51,"sourceCode":"\n        /// <summary>The total heap size of the array (includes space for offset values and .net array overhead)</summary>\n        public readonly int HeapMemorySize => Array is null ? 0 : Array.Length + MemoryUtils.ByteArrayOverhead;\n\n        readonly int EndOffset => Unsafe.As<byte, OverflowHeader>(ref Array[0]).endOffset;\n\n        internal readonly int Length => Array.Length - StartOffset - EndOffset;\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"Len {Length}, IsEmpty {IsEmpty}, sOffset {StartOffset}, eOffset {EndOffset}, HeapMemSize {HeapMemorySize}, TotSize {TotalSize}\";\n\n        /// <summary>ReadOnlySpan of data between offsets</summary>\n        internal readonly ReadOnlySpan<byte> ReadOnlySpan => Array.AsSpan(StartOffset, Length);\n        /// <summary>ReadOnlySpan of data between offsets</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public readonly ReadOnlySpan<byte> AsReadOnlySpan(int start)\n        {\n            var length = Length;\n            return start <= length ? Array.AsSpan(StartOffset + start, length - start) : throw new ArgumentOutOfRangeException(nameof(start));\n        }\n        /// <summary>ReadOnlySpan of data between offsets</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public readonly ReadOnlySpan<byte> AsReadOnlySpan(int start, int len)\n        {\n            var length = Length;\n            return ((ulong)(uint)start + (uint)len <= (uint)length) ? Array.AsSpan(StartOffset + start, len) : throw new ArgumentOutOfRangeException($\"start {nameof(start)} + len {len} exceeds length {length}\");\n        }\n\n        /// <summary>Span of data between offsets</summary>\n        internal readonly Span<byte> Span => Array.AsSpan(StartOffset, Length);\n        /// <summary>Span of data between offsets</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public readonly Span<byte> AsSpan(int start)\n        {\n            var length = Length;\n            return start <= length ? Array.AsSpan(StartOffset + start, length - start) : throw new ArgumentOutOfRangeException(nameof(start));\n        }","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/storage/Tsavorite/cs/src/core/Allocator/OverflowByteArray.cs#L33-L69","documentation":"OverflowByteArray wraps a backing byte[] with StartOffset and EndOffset, exposing only the region between them as the logical 'value'. AsReadOnlySpan(int start) returns the remainder of that valid region beginning at start; it throws ArgumentOutOfRangeException(nameof(start)) when start is strictly greater than Length (the valid region size). This guards native-pointer slice creation against out-of-range starts.","triggerScenarios":"Calling AsReadOnlySpan(start) with start > Length — typically from miscomputed offsets when parsing a record's value region, reading a partially-overwritten or truncated overflow record, or off-by-one arithmetic against the record header.","commonSituations":"Forgetting StartOffset / OverflowHeader.Size when computing an offset; slicing past a value that was shrunk (filler truncation); corrupted or short reads from device; generic span-slicing code that ignores the array's logical bounds.","solutions":["Validate start against oba.Length before slicing.","Derive offsets from the record's own header fields (ActualSize, StartOffset) rather than external math.","Confirm the record was not truncated (check ActualSize and filler length) before slicing its overflow bytes.","Add a debug assertion logging start/Length so bad offsets surface early."],"exampleFix":"// before\nvar span = overflow.AsReadOnlySpan(offset);\n\n// after\nif ((uint)offset > (uint)overflow.Length)\n    throw new InvalidOperationException($\"bad offset {offset} > {overflow.Length}\");\nvar span = overflow.AsReadOnlySpan(offset);","handlingStrategy":"validation","validationCode":"if ((uint)start > (uint)overflow.Length)\n    throw new InvalidOperationException($\"start {start} > Length {overflow.Length}\");\nvar span = overflow.AsReadOnlySpan(start);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always derive offsets from the record's own header fields, not external arithmetic.","Assert start/Length relationships in debug builds.","Treat an out-of-range slice as a data-corruption signal, not a transient error."],"tags":["tsavorite","span","bounds","overflow-array","argumentoutofrange"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}