swift-nio-extras/Tests/NIOExtrasTests/LengthFieldBasedFrameDecoderTest.swift
David Nadoba de1c80ad1f
fix crash in LengthFieldBasedFrameDecoder for malicious length values (#115)
* fix crash in LengthFieldBasedFrameDecoder for malicious length values

Motivation:

LengthFieldBasedFrameDecoder will cause a fatal error if the length value does not fit into an `Int`.
This can happen if `lengthFieldLength` is set to `.eight` and we are on a 64 bit platform or if `lengthFieldLength` is set to `.four` and we are on a 32-bit platform.
If we then receive a length field value which is greater than `Int.max` the conversion from `UInt` to `Int` will cause a fatal error.
This could be abused to crash a server by only sending 4 or 8 bytes.

Modifications:

safely convert UInt64 & UInt32 to Int and throw an error if they can't be represented as an Int

Result:

- LengthFieldBasedFrameDecoder with lengthFieldLength set to `.eight` can no longer crash the server on a 64-bit platform
- LengthFieldBasedFrameDecoder with lengthFieldLength set to `.four` can no longer crash the server on a 32-bit platform

* use early exit instead of XCTSkipIf

* add support for `.eight` on 32-bit platforms

* limit frame length to `Int32.max`

* change test names

* throw correct error

* fix compilation for Swift 5.0 and add NIO prefix to error enum

* add test for maximum allowed length and one above the maximum allowed length

Signed-off-by: David Nadoba <dnadoba@gmail.com>

* run XCTest script

Signed-off-by: David Nadoba <dnadoba@gmail.com>

Co-authored-by: Johannes Weiss <johannesweiss@apple.com>
2021-02-18 12:37:41 +00:00

571 lines
26 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import XCTest
import NIO
@testable import NIOExtras
import NIOTestUtils
private let standardDataString = "abcde"
class LengthFieldBasedFrameDecoderTest: XCTestCase {
private var channel: EmbeddedChannel!
private var decoderUnderTest: ByteToMessageHandler<LengthFieldBasedFrameDecoder>!
override func setUp() {
self.channel = EmbeddedChannel()
}
func testReadUInt32From3Bytes() {
var buffer = ByteBuffer(bytes: [
0, 0, 5,
5, 0, 0,
])
XCTAssertEqual(buffer.read24UInt(endianness: .big), 5)
print(buffer.readableBytesView)
XCTAssertEqual(buffer.read24UInt(endianness: .little), 5)
}
func testReadAndWriteUInt32From3BytesBasicVerification() {
let inputs: [UInt32] = [
0,
1,
5,
UInt32(UInt8.max),
UInt32(UInt16.max),
UInt32(UInt16.max) << 8 &+ UInt32(UInt8.max),
UInt32(UInt8.max) - 1,
UInt32(UInt16.max) - 1,
UInt32(UInt16.max) << 8 &+ UInt32(UInt8.max) - 1,
UInt32(UInt8.max) + 1,
UInt32(UInt16.max) + 1,
]
for input in inputs {
var buffer = ByteBuffer()
buffer.write24UInt(input, endianness: .big)
XCTAssertEqual(buffer.read24UInt(endianness: .big), input)
buffer.write24UInt(input, endianness: .little)
XCTAssertEqual(buffer.read24UInt(endianness: .little), input)
}
}
func testDecodeWithUInt8HeaderWithData() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .one,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataBytes: [UInt8] = [10, 20, 30, 40]
let dataBytesLengthHeader = UInt8(dataBytes.count)
var buffer = self.channel.allocator.buffer(capacity: 5)
buffer.writeBytes([dataBytesLengthHeader])
buffer.writeBytes(dataBytes)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(dataBytes,
try self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView.map {
$0
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithUInt16HeaderWithString() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .two,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: UInt16 = 5
var buffer = self.channel.allocator.buffer(capacity: 7) // 2 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .little, as: UInt16.self)
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithUInt24HeaderWithString() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldBitLength: .threeBytes,
lengthFieldEndianness: .big))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
var buffer = self.channel.allocator.buffer(capacity: 8) // 3 byte header + 5 character string
buffer.writeBytes([0, 0, 5])
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithUInt32HeaderWithString() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .four,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: UInt32 = 5
var buffer = self.channel.allocator.buffer(capacity: 9) // 4 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .little, as: UInt32.self)
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithUInt64HeaderWithString() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: UInt64 = 5
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .little, as: UInt64.self)
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithInt64HeaderWithString() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: Int64 = 5
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .little, as: Int64.self)
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithInt64HeaderStringBigEndian() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight,
lengthFieldEndianness: .big))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: Int64 = 5
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .big, as: Int64.self)
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithInt64HeaderStringDefaultingToBigEndian() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: Int64 = 5
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .big, as: Int64.self)
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithUInt8HeaderTwoFrames() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .one,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let firstFrameDataLength: UInt8 = 5
let secondFrameDataLength: UInt8 = 3
let secondFrameString = "123"
var buffer = self.channel.allocator.buffer(capacity: 10) // 1 byte header + 5 character string + 1 byte header + 3 character string
buffer.writeInteger(firstFrameDataLength, endianness: .little, as: UInt8.self)
buffer.writeString(standardDataString)
buffer.writeInteger(secondFrameDataLength, endianness: .little, as: UInt8.self)
buffer.writeString(secondFrameString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertNoThrow(XCTAssertEqual(secondFrameString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithUInt8HeaderFrameSplitIncomingData() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .two,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let frameDataLength: UInt16 = 5
// Write and try to read both bytes of the data individually
let frameDataLengthFirstByte: UInt8 = UInt8(frameDataLength)
let frameDataLengthSecondByte: UInt8 = 0
var firstBuffer = self.channel.allocator.buffer(capacity: 1) // Byte 1 of 2 byte header header
firstBuffer.writeInteger(frameDataLengthFirstByte, endianness: .little, as: UInt8.self)
XCTAssertTrue(try self.channel.writeInbound(firstBuffer).isEmpty)
// Read should fail because there is not yet enough data.
XCTAssertNoThrow(XCTAssertNil(try self.channel.readInbound()))
var secondBuffer = self.channel.allocator.buffer(capacity: 1) // Byte 2 of 2 byte header header
secondBuffer.writeInteger(frameDataLengthSecondByte, endianness: .little, as: UInt8.self)
XCTAssertTrue(try self.channel.writeInbound(secondBuffer).isEmpty)
// Read should fail because there is not yet enough data.
XCTAssertNoThrow(XCTAssertNil(try self.channel.readInbound()))
// Write and try to read each byte of the data individually
for (index, character) in standardDataString.enumerated() {
var characterBuffer = self.channel.allocator.buffer(capacity: 1)
characterBuffer.writeString(String(character))
if index < standardDataString.count - 1 {
XCTAssertTrue(try self.channel.writeInbound(characterBuffer).isEmpty)
// Read should fail because there is not yet enough data.
XCTAssertNoThrow(XCTAssertNil(try self.channel.readInbound()))
} else {
XCTAssertTrue(try self.channel.writeInbound(characterBuffer).isFull)
}
}
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testEmptyBuffer() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .one,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let buffer = self.channel.allocator.buffer(capacity: 1)
XCTAssertTrue(try self.channel.writeInbound(buffer).isEmpty)
XCTAssertTrue(try self.channel.finish().isClean)
}
func testDecodeWithUInt16HeaderWithPartialHeader() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .two,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: UInt8 = 5 // 8 byte is only half the length required
var buffer = self.channel.allocator.buffer(capacity: 7) // 2 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .little, as: UInt8.self)
XCTAssertTrue(try self.channel.writeInbound(buffer).isEmpty)
XCTAssertThrowsError(try channel.finish()) { error in
if let error = error as? NIOExtrasErrors.LeftOverBytesError {
XCTAssertEqual(1 /* just the one byte of the length that arrived */, error.leftOverBytes.readableBytes)
} else {
XCTFail("unexpected error: \(error)")
}
}
}
func testDecodeWithUInt16HeaderWithPartialBody() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .two,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength: UInt16 = 7
var buffer = self.channel.allocator.buffer(capacity: 9) // 2 byte header + 7 character string
buffer.writeInteger(dataLength, endianness: .little, as: UInt16.self)
buffer.writeString(standardDataString) // 2 bytes short of the 7 required.
XCTAssertTrue(try self.channel.writeInbound(buffer).isEmpty)
XCTAssertThrowsError(try channel.finish()) { error in
if let error = error as? NIOExtrasErrors.LeftOverBytesError {
XCTAssertEqual(Int(dataLength) - 2 /* we're 2 bytes short of the required 7 */,
error.leftOverBytes.readableBytes)
} else {
XCTFail("unexpected error: \(error)")
}
}
}
func testRemoveHandlerWhenBufferIsEmpty() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight,
lengthFieldEndianness: .little))
try? self.channel.pipeline.addHandler(self.decoderUnderTest).wait()
let dataLength: Int64 = 5
var buffer = self.channel.allocator.buffer(capacity: 13) // 8 byte header + 5 character string
buffer.writeInteger(dataLength, endianness: .little, as: Int64.self)
buffer.writeString(standardDataString)
XCTAssertTrue(try self.channel.writeInbound(buffer).isFull)
let removeFuture = self.channel.pipeline.removeHandler(self.decoderUnderTest)
(channel.eventLoop as! EmbeddedEventLoop).run()
XCTAssertNoThrow(try removeFuture.wait())
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertNoThrow(try self.channel.throwIfErrorCaught())
XCTAssertTrue(try self.channel.finish().isClean)
}
func testRemoveHandlerWhenBufferIsNotEmpty() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight,
lengthFieldEndianness: .little))
try? self.channel.pipeline.addHandler(self.decoderUnderTest).wait()
let extraUnusedDataString = "fghi"
let dataLength: Int64 = 5
var buffer = self.channel.allocator.buffer(capacity: 17) // 8 byte header + 5 character string + 4 unused
buffer.writeInteger(dataLength, endianness: .little, as: Int64.self)
buffer.writeString(standardDataString + extraUnusedDataString)
XCTAssertTrue(try channel.writeInbound(buffer).isFull)
let removeFuture = self.channel.pipeline.removeHandler(self.decoderUnderTest)
(channel.eventLoop as! EmbeddedEventLoop).run()
XCTAssertNoThrow(try removeFuture.wait())
XCTAssertThrowsError(try self.channel.throwIfErrorCaught()) { error in
guard let error = error as? NIOExtrasErrors.LeftOverBytesError else {
XCTFail()
return
}
var expectedBuffer = self.channel.allocator.buffer(capacity: 7)
expectedBuffer.writeString(extraUnusedDataString)
XCTAssertEqual(error.leftOverBytes, expectedBuffer)
}
XCTAssertNoThrow(XCTAssertEqual(standardDataString,
try (self.channel.readInbound(as: ByteBuffer.self)?.readableBytesView).map {
String(decoding: $0, as: Unicode.UTF8.self)
}))
XCTAssertTrue(try self.channel.finish().isClean)
}
func testCloseInChannelRead() {
let channel = EmbeddedChannel(handler: ByteToMessageHandler(LengthFieldBasedFrameDecoder(lengthFieldLength: .four)))
class CloseInReadHandler: ChannelInboundHandler {
typealias InboundIn = ByteBuffer
private var numberOfReads = 0
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
self.numberOfReads += 1
XCTAssertEqual(1, self.numberOfReads)
XCTAssertEqual([UInt8(100)], Array(self.unwrapInboundIn(data).readableBytesView))
context.close().whenFailure { error in
XCTFail("unexpected error: \(error)")
}
context.fireChannelRead(data)
}
}
XCTAssertNoThrow(try channel.pipeline.addHandler(CloseInReadHandler()).wait())
var buf = channel.allocator.buffer(capacity: 1024)
buf.writeBytes([UInt8(0), 0, 0, 1, 100])
XCTAssertNoThrow(try channel.writeInbound(buf))
XCTAssertNoThrow(XCTAssertEqual([100], Array((try channel.readInbound() as ByteBuffer?)!.readableBytesView)))
XCTAssertNoThrow(XCTAssertNil(try channel.readInbound()))
}
func testBasicVerification() {
let inputs: [(NIOLengthFieldBitLength, [(Int, String)])] = [
(.oneByte, [
(6, "abcdef"),
(0, ""),
(9, "123456789"),
(Int(UInt8.max),
String(decoding: Array(repeating: UInt8(ascii: "X"), count: Int(UInt8.max)), as: Unicode.UTF8.self)),
]),
(.twoBytes, [
(1, "a"),
(0, ""),
(9, "123456789"),
(307,
String(decoding: Array(repeating: UInt8(ascii: "X"), count: 307), as: Unicode.UTF8.self)),
]),
(.threeBytes, [
(1, "a"),
(0, ""),
(9, "123456789"),
(307,
String(decoding: Array(repeating: UInt8(ascii: "X"), count: 307), as: Unicode.UTF8.self)),
]),
(.fourBytes, [
(1, "a"),
(0, ""),
(3, "333"),
(307,
String(decoding: Array(repeating: UInt8(ascii: "X"), count: 307), as: Unicode.UTF8.self)),
]),
(.eightBytes, [
(1, "a"),
(0, ""),
(4, "aaaa"),
(307,
String(decoding: Array(repeating: UInt8(ascii: "X"), count: 307), as: Unicode.UTF8.self)),
]),
]
for input in inputs {
let (lenBytes, inputData) = input
func byteBuffer(length: Int, string: String) -> ByteBuffer {
var buf = self.channel.allocator.buffer(capacity: string.utf8.count + 8)
buf.writeInteger(length)
buf.moveReaderIndex(forwardBy: 8 - lenBytes.length)
buf.writeString(string)
return buf
}
let inputOutputPairs = inputData.map { (input: (Int, String)) -> (ByteBuffer, [ByteBuffer]) in
let bytes = byteBuffer(length: input.0, string: input.1)
return (bytes, [bytes.getSlice(at: bytes.readerIndex + lenBytes.length, length: input.0)!])
}
XCTAssertNoThrow(try ByteToMessageDecoderVerifier.verifyDecoder(inputOutputPairs: inputOutputPairs) {
LengthFieldBasedFrameDecoder(lengthFieldBitLength: lenBytes)
})
}
}
func testMaximumAllowedLengthWith32BitFieldLength() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .four,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength = UInt32(Int32.max)
var buffer = self.channel.allocator.buffer(capacity: 4) // 4 byte header
buffer.writeInteger(dataLength, endianness: .little, as: UInt32.self)
buffer.writeString(standardDataString)
XCTAssertNoThrow(try self.channel.writeInbound(buffer))
}
func testMaliciousLengthWith32BitFieldLength() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .four,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength = UInt32(Int32.max) + 1
var buffer = self.channel.allocator.buffer(capacity: 4) // 4 byte header
buffer.writeInteger(dataLength, endianness: .little, as: UInt32.self)
buffer.writeString(standardDataString)
XCTAssertThrowsError(try self.channel.writeInbound(buffer))
}
func testMaximumAllowedLengthWith64BitFieldLength() throws {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength = UInt64(Int32.max)
var buffer = self.channel.allocator.buffer(capacity: 8) // 8 byte header
buffer.writeInteger(dataLength, endianness: .little, as: UInt64.self)
buffer.writeString(standardDataString)
XCTAssertNoThrow(try self.channel.writeInbound(buffer))
}
func testMaliciousLengthWith64BitFieldLength() {
self.decoderUnderTest = .init(LengthFieldBasedFrameDecoder(lengthFieldLength: .eight,
lengthFieldEndianness: .little))
XCTAssertNoThrow(try self.channel.pipeline.addHandler(self.decoderUnderTest).wait())
let dataLength = UInt64(Int32.max) + 1
var buffer = self.channel.allocator.buffer(capacity: 8) // 8 byte header
buffer.writeInteger(dataLength, endianness: .little, as: UInt64.self)
XCTAssertThrowsError(try self.channel.writeInbound(buffer))
}
}