{"record":{"id":"be4fe33e210f291e","repo":"dotnet/wpf","slug":"stream-length-cannot-be-negative","errorCode":null,"errorMessage":"Stream length cannot be negative.","messagePattern":"Stream length cannot be negative\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptedStream.cs","lineNumber":165,"sourceCode":"            if (temp < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(offset), SR.SeekNegative);\n            }\n\n            _streamPosition = temp;\n            return _streamPosition;\n        }        \n\n        /// <summary>\n        /// See .NET Framework SDK under System.IO.Stream\n        /// </summary>\n        public override void SetLength(long newLength)\n        {\n            CheckDisposed(); \n            \n            if (newLength < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(newLength), SR.CannotMakeStreamLengthNegative);\n            }\n\n            _streamCachedLength = newLength;\n\n            // We are not caching this transaction for the following reason. The extra data that might \n            // be added to stream when the new length is higher than the existing length, \n            // although undefined (could be junk) must be consistent. Consistent \n            // is defined in a sense of multiple read requests performed on the same stream area.\n            // In order to guarantee this consistency we either have to come up with some initial value \n            // (0 or anything else) remember the initialized area (or multiple areas like that if get a set \n            // of non contiguous writes), and take it into account during all the transactions.\n            // Alternatively we can get some real bits allocated on the baseStream and take advantage \n            // of the underlying stream capability to preserve consistent content of the extra bits being \n            // allocated here.  \n            FlushLength();\n\n            if (_streamPosition > Length)\n            {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptedStream.cs#L147-L183","documentation":"RightsManagementEncryptedStream.SetLength validates that the requested new length is non-negative before updating the cached length. A negative length has no meaning for a stream, so the API throws ArgumentOutOfRangeException with SR.CannotMakeStreamLengthNegative. Write() and other size-affecting operations funnel through this method.","triggerScenarios":"Calling SetLength(negativeValue) directly; a Write() call whose computed end position resolves to a negative length due to a bad buffer/position calculation; passing untrusted parsed lengths through to SetLength.","commonSituations":"Applying lengths parsed from a corrupted package file; off-by-one or sign errors when computing truncation sizes; wrapping this stream in code that derives newLength from signed arithmetic that underflows.","solutions":["Validate newLength >= 0 before calling SetLength and correct or reject the caller-supplied value.","Clamp with long safeLength = Math.Max(0, newLength); before invoking SetLength.","If the length originates from parsed metadata, validate it at parse time (e.g. use checked arithmetic / reject negatives) instead of propagating it to the stream.","If the intent was truncation of only a portion, recompute the delta between current and target lengths explicitly.","Catch ArgumentOutOfRangeException around SetLength when lengths come from external data and recover by re-opening the stream."],"exampleFix":"// before\nstream.SetLength(requestedLength); // requestedLength may be < 0\n// after\nif (requestedLength < 0)\n    throw new ArgumentException(\"computed length must be >= 0\", nameof(requestedLength));\nstream.SetLength(Math.Max(0, requestedLength));","handlingStrategy":"validation","validationCode":"if (newLength < 0)\n    throw new ArgumentException(\"newLength must be >= 0\", nameof(newLength));\nstream.SetLength(newLength);","typeGuard":"bool IsValidSetLength(long newLength) => newLength >= 0 && newLength <= long.MaxValue;","tryCatchPattern":"try { stream.SetLength(newLength); }\ncatch (ArgumentOutOfRangeException) { newLength = Math.Max(0, newLength); stream.SetLength(newLength); }","preventionTips":["Validate lengths at parse time with checked arithmetic before they reach SetLength.","Use unsigned/validated intermediates when computing truncation sizes.","Clamp with Math.Max(0, len) for programmatic resizing.","Never pass through lengths derived from corrupted file metadata without a sanity check."],"tags":["argumentoutofrange","stream","setlength","rights-management"],"backgroundTag":"argument-out-of-range","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"}