-
-
Notifications
You must be signed in to change notification settings - Fork 754
Description
Bug description
The buffer writer and the message pack code work at a low level, with the message pack code expecting the returned buffer to be at least as big as the sizeHint. If it isn't then you can get memory corruption and crashes.
Repro steps
using System.Buffers;
using MessagePack;
using MessagePack.Resolvers;
Foo[] obj = [new Foo(), new Foo()];
var messagePackBufferWriter = new SizeTrackingBufferWriter();
MessagePackSerializer.Serialize(
messagePackBufferWriter,
obj,
MessagePackSerializerOptions.Standard.WithResolver(ContractlessStandardResolverAllowPrivate.Instance));
public class SizeTrackingBufferWriter : IBufferWriter<byte>
{
private static byte[] _buffer = new byte[10];
public void Advance(int count)
{
}
public Memory<byte> GetMemory(int sizeHint = 0)
{
return _buffer.AsMemory(0);
}
public Span<byte> GetSpan(int sizeHint = 0)
{
return _buffer.AsSpan(0);
}
}
class Foo
{
public string s_Foo = "123456789012345678901234";
}
Expected behavior
When I run this I see two calls to GetMemory - the first passes a sizeHint of 0 and the second passes a sizeHint of 80.
The code returns a buffer of size 10 and this violates the contract.
I'd expect an exception, but see heap corruption.
Actual behavior
If I watch the buffer object in the memory view of the VS debugger, I see the type handle of the next object on the heap being corrupted by the code
int byteCount = StringEncoding.UTF8.GetBytes(pValue, value.Length, pBuffer + useOffset, bufferSize);
I'd expect the code to check the returned buffer, rather than writing off the end of it.
internal static Memory<byte> GetMemoryCheckResult(this IBufferWriter<byte> bufferWriter, int size = 0)
{
var memory = bufferWriter.GetMemory(size);
if (memory.IsEmpty)
{
throw new InvalidOperationException("The underlying IBufferWriter<byte>.GetMemory(int) method returned an empty memory block, which is not allowed. This is a bug in " + bufferWriter.GetType().FullName);
}
if (size > 0 && memory.Length < size)
{
throw new InvalidOperationException("The underlying IBufferWriter<byte>.GetMemory(int) returned a buffer that is too small. This is a bug in " + bufferWriter.GetType().FullName);
}
We saw segmentation faults in our Linux containers.
- Version used: main
- Runtime: (e.g. .NET Framework, .NET Core, Unity, mono, etc.).NET 9.0.200
Additional context
Add any other context about the problem here.