Coder Social home page Coder Social logo

RecyclableMemoryStream exhausts all available RAM if requestedSize > (int.MaxValue - BlockSize) about microsoft.io.recyclablememorystream HOT 4 CLOSED

microsoft avatar microsoft commented on September 23, 2024
RecyclableMemoryStream exhausts all available RAM if requestedSize > (int.MaxValue - BlockSize)

from microsoft.io.recyclablememorystream.

Comments (4)

doubleyewdee avatar doubleyewdee commented on September 23, 2024

Making Capacity long isn't possible (note it's an override). Writing a repro test currently so I can validate a fix.

from microsoft.io.recyclablememorystream.

elgonzo avatar elgonzo commented on September 23, 2024

I didn't notice that Capacity is an overridden property from MemoryStream when i encountered the problem. Makes me wonder why the property RecyclableMemoryStreamManager.MaximumStreamCapacity is a long, though. Shouldn't it be an int as well? (Unless you plan to introduce something like RecyclableMemoryStream.CapacityLong, with the overridden MemoryStream.Capacity value being clamped to [0,int.MaxValue], perhaps. But that on the other hand might also perhaps cause bizarre problems for programs who rely on MemoryStream properties such as Position or Length always being <= int.MaxValue. Hmm...)

from microsoft.io.recyclablememorystream.

elgonzo avatar elgonzo commented on September 23, 2024

Unfortunately, there is still an issue when RecyclableMemoryStream with a size close to or exactly of int.MaxValue is being requested.

The commit from June 30th attempts clamping the property RecyclableMemoryStream.Capacity to prevent it from overflowing:

long size = this.blocks.Count * this.memoryManager.BlockSize;
return (int)Math.Min(int.MaxValue, size);

However, the calculation of the long variable size is incorrect. It will multiply two int values, and will only convert the int result to an long value. Thus, the overflow can still happen and the variable size becoming negative in the if the block count is becoming sufficiently high.

An example:
When requesting a RecyclableMemoryStream with size of int.MaxValue, the block count will eventually reach 16384 (assuming the standard block size of 131072).

The int multiplication 16384*131072 will result in the size variable (and in consequence the Capacity property) having a negative value of -2147483648. This will break the while loop in the method RecyclableMemoryStream.EnsureCapacity, which again would lead to exhaustion of the available virtual memory.


Suggested fix:

To fix the issue, the multiplication needs to be forced to operate on longs. Casting one or both of the multiplicands/multipliers as a long will do this:

long size = (long) this.blocks.Count * this.memoryManager.BlockSize;
return (int)Math.Min(int.MaxValue, size);

Additionally, the test method GiantAllocationSucceeds is not able to find this issue.
To detect this issue (using the default block size of 128KB), the requested stream size must be at least int.MaxValue - (mgr.BlockSize + 2) .

The reason why the unit test fails to find this issue is the following: int.MaxValue equals 0x7fffffff. To satisfy a requested stream size of 0x7fffffff with the default block size of 128KB (=0x20000), 16384 blocks are required. Note that the last block is not fully used, its used capacity is 0x1ffff.

However, the largest stream size requested by the unit test is only int.MaxValue - (mgr.BlockSize + 1).
(mgr.BlockSize + 1) equals 0x1ffff - which means only 16383 blocks are needed.

With only needing 16383 blocks, the unit test fails to test a scenario where the RecyclableMemoryStream.Capacity property could overflow (i.e., scenarios where 16384 blocks would be needed).

I would suggest to let the unit test request a stream size of exactly int.MaxValue to make sure that the clamping of the Capacity property works. If it works with a stream size of int.MaxValue then it should also work with any other stream sizes (as they can only be less than int.MaxValue).

from microsoft.io.recyclablememorystream.

doubleyewdee avatar doubleyewdee commented on September 23, 2024

Pretty sure the PR above resolves this per the comment (thank you for the excellent diagnosis). Will give a few days for someone to review before just merging in case any concerns arise. Thanks!

from microsoft.io.recyclablememorystream.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.