{"record":{"id":"d121bc7847b50626","repo":"dotnet/wpf","slug":"buffer-range-is-smaller-than-expected-expected-size","errorCode":null,"errorMessage":"Buffer range is smaller than expected expected size","messagePattern":"Buffer range is smaller than expected expected size","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/StrokeSerializer.cs","lineNumber":486,"sourceCode":"            // Now that we've read packet data, we must read button data if it is there\n            byte[] buttonData = null;\n            // since the button state is a simple bit value (either down or up), the button state\n            // for a series of packets is packed into an array of bits rather than integers\n            // For example, if there are 16 packets, and 2 buttons, then 32 bits can be used (e.g. 1 32-bit integer)\n            if (0 != locallyDecodedBytesRemaining && buttonCount > 0)\n            {\n                    // calculate the number of full bytes used for buttons per packet\n                    //   Example: 10 buttons would require 1 full byte\n                int fullBytesForButtonsPerPacket = buttonCount / Native.BitsPerByte;\n                    // calculate the number of bits that spill beyond the full byte boundary\n                    //   Example: 10 buttons would require 2 extra bits (8 fit in a full byte)\n                int partialBitsForButtonsPerPacket = buttonCount % Native.BitsPerByte;\n\n                // Now figure out how many bytes we need to read for the button data\n                localBytesRead = (uint)((buttonCount * pointCount + 7) / Native.BitsPerByte);\n                if (localBytesRead > locallyDecodedBytesRemaining)\n                {\n                    throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage(\"Buffer range is smaller than expected expected size\"));\n                }\n                locallyDecodedBytesRemaining -= localBytesRead;\n\n                int buttonSizeInBytes = (buttonCount + 7)/Native.BitsPerByte;\n                buttonData = new byte[pointCount * buttonSizeInBytes];\n\n                // Create a bit reader to unpack the bits from the ISF stream into\n                //    loosely packed byte buffer (e.g. button data aligned on full byte\n                //    boundaries only)\n                BitStreamReader bitReader =\n                    new BitStreamReader(inputBuffer, (uint)buttonCount * pointCount);\n\n                // unpack the button data into each packet\n                int byteCounter = 0;\n                while (!bitReader.EndOfStream)\n                {\n                    // unpack the fully bytes first\n                    for (int fullBytes = 0; fullBytes < fullBytesForButtonsPerPacket; fullBytes++)","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/StrokeSerializer.cs#L468-L504","documentation":"Thrown by StrokeSerializer.LoadPackets when the button data section of an ISF packet stream claims more bytes than remain in the decoded buffer. The library computes the expected button-byte count from buttonCount*pointCount and validates it against the remaining range before allocating.","triggerScenarios":"DecodeISFIntoStroke encounters an ISF stream where buttonCount and pointCount decoded from the packet description imply a byte count larger than the bytes actually available.","commonSituations":"Corrupt or truncated ISF clipboard payloads, ISF written by non-WPF tools with inconsistent button descriptors, manual editing of persisted ink streams.","solutions":["Re-save the ink from the original application to produce valid ISF","Validate that the ISF stream length matches its internal size fields before decoding","Check that producer/consumer ink serialization versions match","Wrap decode in try-catch and degrade gracefully (drop the stroke)"],"exampleFix":"// before\nvar strokes = DecodeISFIntoStroke(rawBytes); // throws on truncated buffer\n// after\ntry { var strokes = DecodeISFIntoStroke(rawBytes); }\ncatch (ArgumentException) { Log.Warn(\"Invalid ISF: button data truncated\"); strokes = new StrokeCollection(); }","handlingStrategy":"validation","validationCode":"// Check ISF byte stream is complete before decoding\nif (isfBytes == null || isfBytes.Length < 8) throw new InvalidDataException(\"ISF too short\");","typeGuard":"bool IsPlausibleIsfBuffer(byte[] b) => b is { Length: > 8 };","tryCatchPattern":"try { DecodeISFIntoStroke(buffer); }\ncatch (ArgumentException) { DiscardStroke(); }","preventionTips":["Verify serialization size fields against actual payload length","Avoid trimming/compressing ISF with lossy tools","Test round-trip Save/Load in CI","Drop invalid strokes gracefully rather than crashing the app"],"tags":["ink","isf","deserialization","buffer"],"backgroundTag":"schema-validation-failed","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}