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
20 changes: 10 additions & 10 deletions swift/Sources/FlatBuffers/ByteBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ public struct ByteBuffer: @unchecked Sendable {
index: Int,
count: Int) -> [T]
{
assert(
index + count <= capacity,
precondition(
index >= 0 && count >= 0 && index <= capacity && count <= capacity - index,
"Reading out of bounds is illegal")

return _storage.readWithUnsafeRawPointer(position: index) {
Expand All @@ -393,8 +393,8 @@ public struct ByteBuffer: @unchecked Sendable {
count: Int,
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
{
assert(
index + count <= capacity,
precondition(
index >= 0 && count >= 0 && index <= capacity && count <= capacity - index,
"Reading out of bounds is illegal")
return try _storage.readWithUnsafeRawPointer(position: index) {
try body(UnsafeRawBufferPointer(start: $0, count: count))
Expand All @@ -413,9 +413,9 @@ public struct ByteBuffer: @unchecked Sendable {
count: Int,
type: String.Encoding = .utf8) -> String?
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
guard index >= 0, count >= 0, index <= capacity, count <= capacity - index else {
return nil
}
return _storage.readWithUnsafeRawPointer(position: index) {
let buf = UnsafeBufferPointer(
start: $0.bindMemory(to: UInt8.self, capacity: count),
Expand All @@ -435,9 +435,9 @@ public struct ByteBuffer: @unchecked Sendable {
at index: Int,
count: Int) -> String?
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
guard index >= 0, count >= 0, index <= capacity, count <= capacity - index else {
return nil
}
return _storage.readWithUnsafeRawPointer(position: index) {
String(cString: $0.bindMemory(to: UInt8.self, capacity: count))
}
Expand Down
16 changes: 12 additions & 4 deletions swift/Sources/FlatBuffers/Root.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ public func getPrefixedSizeRoot<T: FlatBufferTable>(
byteBuffer: inout ByteBuffer)
-> T
{
guard byteBuffer.size >= MemoryLayout<Int32>.size else {
fatalError("ByteBuffer is too small to hold a size prefix")
}
byteBuffer.skipPrefix()
return getRoot(byteBuffer: &byteBuffer)

Expand Down Expand Up @@ -139,8 +142,13 @@ public func getCheckedRoot<T: FlatBufferTable & Verifiable>(
/// - Parameter byteBuffer: Buffer that contains data
/// - Returns: Returns a Flatbuffers object
public func getRoot<T: FlatBufferTable>(byteBuffer: inout ByteBuffer) -> T {
T.init(
byteBuffer,
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader))
&+ Int32(byteBuffer.reader))
let reader = byteBuffer.reader
guard reader &+ MemoryLayout<UOffset>.size <= byteBuffer.capacity else {
fatalError("ByteBuffer is too small to hold a root offset")
}
let position = reader &+ Int(byteBuffer.read(def: UOffset.self, position: reader))
guard position &+ MemoryLayout<Int32>.size <= byteBuffer.capacity else {
fatalError("Root offset points outside of the ByteBuffer bounds")
}
return T.init(byteBuffer, o: Int32(position))
}
4 changes: 4 additions & 0 deletions swift/Sources/FlatBuffers/String+extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ extension String: FlatbuffersInitializable {
/// - o: Current position
public init(_ bb: ByteBuffer, o: Int32) {
let v = Int(o)
guard v >= 0, v &+ MemoryLayout<Int32>.size <= bb.capacity else {
self = ""
return
}
let count = bb.read(def: Int32.self, position: v)
self =
bb.readString(
Expand Down
8 changes: 4 additions & 4 deletions swift/Sources/FlatBuffers/Table.swift
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,14 @@ public struct Table {
let startPos1 = _off1 &+ memorySize
let startPos2 = _off2 &+ memorySize
let minValue = min(len1, len2)
for i in 0...minValue {
for i in 0..<minValue {
let b1 = fbb.read(def: Int8.self, position: Int(i &+ startPos1))
let b2 = fbb.read(def: Int8.self, position: Int(i &+ startPos2))
if b1 != b2 {
return Int32(b2 &- b1)
}
}
return len1 &- len2
return len2 &- len1
}

/// Compares two objects at offset A and array of `Bytes` within a ByteBuffer
Expand Down Expand Up @@ -312,14 +312,14 @@ public struct Table {
let startPos1 = _off1 &+ memorySize
let startPos2 = _off2 &+ memorySize
let minValue = min(len1, len2)
for i in 0...minValue {
for i in 0..<minValue {
let b1 = fbb.read(def: Int8.self, position: Int(i &+ startPos1))
let b2 = fbb.read(def: Int8.self, position: Int(i &+ startPos2))
if b1 != b2 {
return Int32(b2 &- b1)
}
}
return len1 &- len2
return len2 &- len1
}

/// Compares two objects at offset A and array of `Bytes` within a ByteBuffer
Expand Down
20 changes: 10 additions & 10 deletions swift/Sources/FlexBuffers/ByteBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,8 @@ public struct ByteBuffer {
index: Int,
count: Int) -> [T]
{
assert(
index + count <= capacity,
precondition(
index >= 0 && count >= 0 && index <= capacity && count <= capacity - index,
"Reading out of bounds is illegal")

return _storage.readWithUnsafeRawPointer(position: index) {
Expand All @@ -429,9 +429,9 @@ public struct ByteBuffer {
count: Int,
type: String.Encoding) -> String?
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
guard index >= 0, count >= 0, index <= capacity, count <= capacity - index else {
return nil
}
return _storage.readWithUnsafeRawPointer(position: index) {
let buf = UnsafeBufferPointer(
start: $0.bindMemory(to: UInt8.self, capacity: count),
Expand All @@ -451,9 +451,9 @@ public struct ByteBuffer {
at index: Int,
count: Int) -> String?
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
guard index >= 0, count >= 0, index <= capacity, count <= capacity - index else {
return nil
}
return _storage.readWithUnsafeRawPointer(position: index) {
String(cString: $0.bindMemory(to: UInt8.self, capacity: count))
}
Expand All @@ -470,8 +470,8 @@ public struct ByteBuffer {
count: Int,
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
{
assert(
index + count <= capacity,
precondition(
index >= 0 && count >= 0 && index <= capacity && count <= capacity - index,
"Reading out of bounds is illegal")
return try _storage.readWithUnsafeRawPointer(position: index) {
try body(UnsafeRawBufferPointer(start: $0, count: count))
Expand Down
9 changes: 9 additions & 0 deletions swift/Sources/FlexBuffers/Reader/Reference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Foundation
enum FlexBuffersErrors: Error {
case sizeOfBufferIsTooSmall
case typeCouldNotBeDetermined
case invalidByteWidth(width: UInt8)
}

@inline(__always)
Expand All @@ -35,7 +36,15 @@ public func getRoot(buffer: ByteBuffer) throws -> Reference? {

let byteWidth = buffer.read(def: UInt8.self, position: end &- 1)
let packedType = buffer.read(def: UInt8.self, position: end &- 2)

guard isValidByteWidth(byteWidth) else {
throw FlexBuffersErrors.invalidByteWidth(width: byteWidth)
}

let offset = end &- 2 &- numericCast(byteWidth)
guard offset >= 0 else {
throw FlexBuffersErrors.sizeOfBufferIsTooSmall
}

return Reference(
byteBuffer: buffer,
Expand Down
62 changes: 58 additions & 4 deletions swift/Sources/FlexBuffers/Reader/TypedVector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ public struct TypedVector: FlexBufferVector {
byteBuffer: ByteBuffer,
offset: Int,
byteWidth: UInt8,
type: FlexBufferType)
type: FlexBufferType,
count providedCount: Int? = nil)
{
self.byteBuffer = byteBuffer
self.offset = offset
self.byteWidth = byteWidth
self.type = type
count = getCount(buffer: byteBuffer, offset: offset, byteWidth: byteWidth)
count = providedCount
?? getCount(buffer: byteBuffer, offset: offset, byteWidth: byteWidth)
}

@inline(__always)
Expand Down Expand Up @@ -68,15 +70,38 @@ public struct TypedVector: FlexBufferVector {
offset: keysOffset &+ numericCast(byteWidth),
byteWidth: byteWidth)

// A corrupted buffer may report a child byte width that is not one of
// the valid flexbuffers widths (1, 2, 4, 8), or a keys location that
// lies outside of the buffer. Treat such a map as if it had no
// readable keys, instead of reading out of bounds.
guard
let width = UInt8(exactly: childByteWidth),
isValidByteWidth(width),
indirectOffset >= numericCast(width),
indirectOffset <= byteBuffer.count
else {
return TypedVector(
byteBuffer: byteBuffer,
offset: offset,
byteWidth: 1,
type: .key,
count: 0)
}

return TypedVector(
byteBuffer: byteBuffer,
offset: indirectOffset,
byteWidth: numericCast(childByteWidth),
byteWidth: width,
type: .key)
}
}

extension TypedVector {
/// Compares a key within the vector to a target string.
///
/// The comparison is bounded by the end of the hosting buffer so that a
/// corrupted buffer without a string terminator cannot cause an
/// out-of-bounds read past the end of the buffer.
@inline(__always)
func compare(offset off: Int, target: String) -> Int {

Expand All @@ -87,12 +112,41 @@ extension TypedVector {
offset: elementOffset,
byteWidth)

guard indirectoffset >= 0, indirectoffset < byteBuffer.capacity else {
return -1
}

let maxLength = byteBuffer.capacity &- indirectoffset
return byteBuffer.readWithUnsafeRawPointer(
position: indirectoffset)
{ bufPointer in
target.withCString { strPointer in
Int(strcmp(bufPointer, strPointer))
boundedStrcmp(bufPointer, strPointer, maxLength: maxLength)
}
}
}
}

@inline(__always)
private func boundedStrcmp(
_ lhs: UnsafeRawPointer,
_ rhs: UnsafePointer<CChar>,
maxLength: Int) -> Int
{
var i = 0
while i < maxLength {
let l = UInt8(bitPattern: lhs.load(fromByteOffset: i, as: Int8.self))
let r = UInt8(bitPattern: rhs[i])
if l != r {
return Int(l) &- Int(r)
}
if l == 0 {
return 0
}
i &+= 1
}
// The readable bytes ran out before a terminator or a difference was
// found: the target is either equal (it ended as well) or longer than
// the readable bytes.
return rhs[i] == 0 ? 0 : -1
}
2 changes: 1 addition & 1 deletion swift/Sources/FlexBuffers/Utils/Value.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ extension Value {
if isInline(type) {
return bitWidth
} else {
for byteWidth in stride(from: 1, to: MemoryLayout<UInt64>.size, by: 2) {
for byteWidth in [1, 2, 4, 8] {
let _offsetLoc: UInt64 = numericCast(
numericCast(size)
&+ padding(
Expand Down
7 changes: 6 additions & 1 deletion swift/Sources/FlexBuffers/Utils/functions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,18 @@ func toFixedTypedVectorElementType(type: FlexBufferType)

// MARK: - Reader functions

@inline(__always)
func isValidByteWidth(_ width: UInt8) -> Bool {
width == 1 || width == 2 || width == 4 || width == 8
}

@inline(__always)
func binarySearch(
vector: TypedVector,
target: String) -> Int?
{
var left = 0
var right = vector.count
var right = vector.count &- 1

while left <= right {
let mid = left &+ (right &- left) / 2
Expand Down
6 changes: 3 additions & 3 deletions swift/Sources/FlexBuffers/Writer/FlexBuffersWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,12 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func add(string: borrowing String, key: borrowing String) {
add(key: key)
write(str: string, len: string.count)
write(str: string, len: string.utf8.count)
}

@inline(__always)
public mutating func add(string: borrowing String) {
write(str: string, len: string.count)
write(str: string, len: string.utf8.count)
}

// MARK: - Writing Blobs
Expand Down Expand Up @@ -591,7 +591,7 @@ public struct FlexBuffersWriter {
@discardableResult
@inline(__always)
private mutating func add(key: borrowing String) -> UInt {
add(key: key, len: key.count)
add(key: key, len: key.utf8.count)
}

@discardableResult
Expand Down
Loading
Loading