Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions swift/Sources/FlatBuffers/ByteBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ public struct ByteBuffer: @unchecked Sendable {
index: Int,
count: Int) -> [T]
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")

Expand All @@ -393,7 +393,7 @@ public struct ByteBuffer: @unchecked Sendable {
count: Int,
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")
return try _storage.readWithUnsafeRawPointer(position: index) {
Expand All @@ -413,7 +413,7 @@ public struct ByteBuffer: @unchecked Sendable {
count: Int,
type: String.Encoding = .utf8) -> String?
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) {
Expand All @@ -435,7 +435,7 @@ public struct ByteBuffer: @unchecked Sendable {
at index: Int,
count: Int) -> String?
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) {
Expand Down Expand Up @@ -465,6 +465,9 @@ public struct ByteBuffer: @unchecked Sendable {
@usableFromInline
@inline(__always)
mutating func skipPrefix() -> Int32 {
precondition(
_readerIndex >= MemoryLayout<Int32>.size && capacity >= MemoryLayout<Int32>.size,
"Reading out of bounds is illegal")
_readerIndex = _readerIndex &- MemoryLayout<Int32>.size
return read(def: Int32.self, position: 0)
}
Expand Down
8 changes: 4 additions & 4 deletions swift/Sources/FlexBuffers/ByteBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ public struct ByteBuffer {
index: Int,
count: Int) -> [T]
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")

Expand All @@ -429,7 +429,7 @@ public struct ByteBuffer {
count: Int,
type: String.Encoding) -> String?
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) {
Expand All @@ -451,7 +451,7 @@ public struct ByteBuffer {
at index: Int,
count: Int) -> String?
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) {
Expand All @@ -470,7 +470,7 @@ public struct ByteBuffer {
count: Int,
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
{
assert(
precondition(
index + count <= capacity,
"Reading out of bounds is illegal")
return try _storage.readWithUnsafeRawPointer(position: index) {
Expand Down
3 changes: 3 additions & 0 deletions swift/Sources/FlexBuffers/Reader/Reference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public func getRoot(buffer: ByteBuffer) throws -> Reference? {
@inline(__always)
public func getRootChecked(buffer: ByteBuffer) throws -> Reference? {
// TODO(mustiikhalil): implement verifier
// Until a full verifier exists, at minimum fail closed when the root
// header cannot possibly fit in the buffer.
precondition(buffer.capacity >= 3, "FlexBuffer too small to hold a root")
return try getRoot(buffer: buffer)
}

Expand Down
3 changes: 3 additions & 0 deletions swift/Sources/FlexBuffers/Reader/TypedVector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public struct TypedVector: FlexBufferVector {

@inline(__always)
public subscript(index: Int) -> Reference? {
precondition(
index >= 0 && index < count,
"TypedVector index out of bounds")
let elementOffset = offset &+ (numericCast(index) &* numericCast(byteWidth))
return Reference(
byteBuffer: byteBuffer,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import XCTest

@testable import FlatBuffers

/// Regression coverage for the release-enforced read guards.
///
/// `read`, `readSlice`, `readString`, `readDirectString`, and `skipPrefix`
/// guard against out-of-bounds reads with `precondition` (enforced in release
/// builds). These tests pin the in-bounds behavior so the guards cannot
/// accidentally reject well-formed access.
final class ByteBufferBoundsRegressionTests: XCTestCase {

func testReadSliceInBounds() {
let buffer = ByteBuffer(bytes: [1, 2, 3, 4, 5, 6, 7, 8])
let slice: [UInt8] = buffer.readSlice(index: 2, count: 4)
XCTAssertEqual(slice, [3, 4, 5, 6])
}

func testReadStringInBounds() {
let buffer = ByteBuffer(bytes: Array("hello flatbuffers".utf8))
let str = buffer.readString(at: 0, count: 5)
XCTAssertEqual(str, "hello")
}

func testReadStringInteriorInBounds() {
let buffer = ByteBuffer(bytes: Array("swift".utf8))
let str = buffer.readString(at: 1, count: 4)
XCTAssertEqual(str, "wift")
}

func testSkipPrefixOnPrefixedBuffer() {
var buffer = ByteBuffer(bytes: [0x03, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC])
let prefix = buffer.skipPrefix()
XCTAssertEqual(prefix, 3)
XCTAssertEqual(buffer.read(def: UInt8.self, position: 4), 0xAA) // position is _readerIndex-relative
}
}
Loading