Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
HTTP/1.x and HTTP/2.0 decoder Buffer visibility and data corruption #898
Motivation: ServiceTalk attempts to effectivley disable Netty's reference counting by using a strategy similar to Netty's `UnreleasableByteBuf` to short circit operations which attempt to modify the reference count, and therefore prevent the reference count from reaching zero and prematruley freeing memory. ServiceTalk's ByteBuf instances will therefore always have a `refCnt() == 1`. However Netty's ByteToMessageDecoder uses `refCnt() > 1` to determine if the cumulation ByteBuf maybe shared, and if not it may compact data in place. This compacting data in place may result in a corrupted view of data from the perspective of offloaded threads in ServiceTalk, and for example result in failures to decode HTTP/2 data such as gRPC frames. ServiceTalk's `ByteToMessageDecoder` uses Netty's `ByteToMessageDecoder#MERGE_CUMULATOR` to manage accumulation of data. As of Netty 4.1.43.Final this may result in writing into the `cumulation` ByteBuf such that a reallocation opearation occurs. This reallocation operation is not done in a thread safe way and this may result in visibility issues when referencing the same `Buffer` object from another thread (e.g. when offloading is enabled). This may result in the applicaiton thread observing an empty `Buffer` if the reference to the newly allocated memory is visibile before the copy operation is visible. Modifications: - All `ByteBuf` objects generated by `ServiceTalkBufferAllocator` should have a `refCnt() > 1` to avoid any optimizations which may assume exclusive ownership of a `ByteBuf` in Netty. This will prevent corrupted content for HTTP/2.x and gRPC use cases. This may result in more reallocation/copy operations in Netty's `ByteToMessageDecoder` and there is a Netty PR netty/netty#9877 intended to improve this behavior. - ServiceTalk's `ByteToMessageDecoder` should not use `ByteToMessageDecoder#MERGE_CUMULATOR` and instead use a strategy similar to netty/netty#9877 to do the accumulation of bytes. It is also unecessary to attempt to compact the buffer after accumulation has been attempted, as any compaction can be handled in the accumulation. Result: No more decode related visibility issues for HTTP/1.x and no more content corruption and visibility issues for HTTP/2.0 / gRPC.