Skip to content

Commit

Permalink
Make tests work on 32-bit (#486)
Browse files Browse the repository at this point in the history
* 32-bit fix for tests: Replace 0xDEADBEEF w/ 0x1337BEEF

Motivation:

Make tests compile on Raspberry Pi.

Modifications:

- Change tests so that they compile on 32-bit machines,
like Raspi. Replaced 0xDEADBEEF which doesn't fit into
an Int32, w/ 0x1337BEEF.
- make ByteBuffer work better on 32-bit
- fix other wrong assertions and limits that are too big on 32bit

Also use TimeAmount.Value in one test.

Result:

Tests will compile on Raspi ...
  • Loading branch information
helje5 authored and weissi committed Aug 16, 2018
1 parent 0ce3cf5 commit e8c04e0
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 38 deletions.
12 changes: 10 additions & 2 deletions Sources/NIO/ByteBuffer-int.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,29 @@ extension FixedWidthInteger {
}

extension UInt32 {
/// Returns the next power of two unless that would overflow in which case UInt32.max is returned.
/// Returns the next power of two unless that would overflow, in which case UInt32.max (on 64-bit systems) or
/// Int32.max (on 32-bit systems) is returned. The returned value is always safe to be cast to Int and passed
/// to malloc on all platforms.
public func nextPowerOf2ClampedToMax() -> UInt32 {
guard self > 0 else {
return 1
}

var n = self

#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let max = UInt32(Int32.max)
#else
let max = UInt32.max
#endif

n -= 1
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
if n != .max {
if n != max {
n += 1
}

Expand Down
9 changes: 8 additions & 1 deletion Sources/NIO/Socket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ public typealias IOVector = iovec

/// The maximum number of bytes to write per `writev` call.
static var writevLimitBytes: Int {
return Int(Int32.max)
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// Note(hh): This is not a _proper_ fix, but necessary because
// other places extend on that. Should be fine in
// practice on 32-bit platforms.
return Int(Int32.max / 4)
#else
return Int(Int32.max)
#endif
}

/// The maximum number of `IOVector`s to write per `writev` call.
Expand Down
9 changes: 8 additions & 1 deletion Sources/NIOWebSocket/WebSocketFrameEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ import NIO

private let maxOneByteSize = 125
private let maxTwoByteSize = Int(UInt16.max)
private let maxNIOFrameSize = Int(UInt32.max)
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// Note(hh): This is not a _proper_ fix, but necessary because
// other places extend on that. Should be fine in
// practice on 32-bit platforms.
private let maxNIOFrameSize = Int(Int32.max / 4)
#else
private let maxNIOFrameSize = Int(UInt32.max)
#endif

/// An inbound `ChannelHandler` that serializes structured websocket frames into a byte stream
/// for sending on the network.
Expand Down
47 changes: 31 additions & 16 deletions Tests/NIOTests/ByteBufferTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1073,22 +1073,37 @@ class ByteBufferTest: XCTestCase {
}

func testAllocationOfReallyBigByteBuffer() throws {
let alloc = ByteBufferAllocator(hookedMalloc: { testAllocationOfReallyBigByteBuffer_mallocHook($0) },
hookedRealloc: { testAllocationOfReallyBigByteBuffer_reallocHook($0, $1) },
hookedFree: { testAllocationOfReallyBigByteBuffer_freeHook($0) },
hookedMemcpy: { testAllocationOfReallyBigByteBuffer_memcpyHook($0, $1, $2) })

XCTAssertEqual(AllocationExpectationState.begin, testAllocationOfReallyBigByteBuffer_state)
var buf = alloc.buffer(capacity: Int(Int32.max))
XCTAssertEqual(AllocationExpectationState.mallocDone, testAllocationOfReallyBigByteBuffer_state)
XCTAssertGreaterThanOrEqual(buf.capacity, Int(Int32.max))

buf.set(bytes: [1], at: 0)
/* now make it expand (will trigger realloc) */
buf.set(bytes: [1], at: buf.capacity)

XCTAssertEqual(AllocationExpectationState.reallocDone, testAllocationOfReallyBigByteBuffer_state)
XCTAssertEqual(buf.capacity, Int(UInt32.max))
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// FIXME: Fails hard on Raspi 32-bit even with Int16.max in `__memcpy_neon`. Figure out how and why.
XCTAssertTrue(false, "testAllocationOfReallyBigByteBuffer fails on 32-bit Raspi")
#else
let alloc = ByteBufferAllocator(hookedMalloc: { testAllocationOfReallyBigByteBuffer_mallocHook($0) },
hookedRealloc: { testAllocationOfReallyBigByteBuffer_reallocHook($0, $1) },
hookedFree: { testAllocationOfReallyBigByteBuffer_freeHook($0) },
hookedMemcpy: { testAllocationOfReallyBigByteBuffer_memcpyHook($0, $1, $2) })

#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let reallyBigSize = Int(Int16.max) // well, but Int32 is too big (1GB RAM, no swap)
#else
let reallyBigSize = Int(Int32.max)
#endif
XCTAssertEqual(AllocationExpectationState.begin, testAllocationOfReallyBigByteBuffer_state)
var buf = alloc.buffer(capacity: reallyBigSize)
XCTAssertEqual(AllocationExpectationState.mallocDone, testAllocationOfReallyBigByteBuffer_state)
XCTAssertGreaterThanOrEqual(buf.capacity, reallyBigSize)

buf.set(bytes: [1], at: 0)
/* now make it expand (will trigger realloc) */
buf.set(bytes: [1], at: buf.capacity)

XCTAssertEqual(AllocationExpectationState.reallocDone, testAllocationOfReallyBigByteBuffer_state)
#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
// TODO(hh): no idea, but not UInt32.max :-)
XCTAssertGreaterThanOrEqual(buf.capacity, reallyBigSize)
#else
XCTAssertEqual(buf.capacity, Int(UInt32.max))
#endif
#endif
}

func testWritableBytesAccountsForSlicing() throws {
Expand Down
22 changes: 14 additions & 8 deletions Tests/NIOTests/ChannelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,15 @@ public class ChannelTests: XCTestCase {
for _ in 0..<bufferSize {
buffer.write(staticString: "a")
}


#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let lotsOfData = Int(Int32.max / 8)
#else
let lotsOfData = Int(Int32.max)
#endif
var written = 0
while written <= Int(INT32_MAX) {
while written <= lotsOfData {
clientChannel.write(NIOAny(buffer), promise: nil)
written += bufferSize
}
Expand Down Expand Up @@ -208,7 +214,7 @@ public class ChannelTests: XCTestCase {
var iovecs: [IOVector] = Array(repeating: iovec(), count: Socket.writevLimitIOVectors + 1)
var managed: [Unmanaged<AnyObject>] = Array(repeating: Unmanaged.passUnretained(o), count: Socket.writevLimitIOVectors + 1)
/* put a canary value at the end */
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)!, iov_len: 0xdeadbeef)
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0x1337beef)!, iov_len: 0x1337beef)
try iovecs.withUnsafeMutableBufferPointer { iovecs in
try managed.withUnsafeMutableBufferPointer { managed in
let pwm = NIO.PendingStreamWritesManager(iovecs: iovecs, storageRefs: managed)
Expand All @@ -225,8 +231,8 @@ public class ChannelTests: XCTestCase {
}
/* assert that the canary values are still okay, we should definitely have never written those */
XCTAssertEqual(managed.last!.toOpaque(), Unmanaged.passUnretained(o).toOpaque())
XCTAssertEqual(0xdeadbeef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0xdeadbeef, iovecs.last!.iov_len)
XCTAssertEqual(0x1337beef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0x1337beef, iovecs.last!.iov_len)
}
}

Expand Down Expand Up @@ -664,8 +670,8 @@ public class ChannelTests: XCTestCase {
/// Test that with a few massive buffers, we don't offer more than we should to `writev` if the individual chunks fit.
func testPendingWritesNoMoreThanWritevLimitIsWritten() throws {
let el = EmbeddedEventLoop()
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */
Expand Down Expand Up @@ -696,8 +702,8 @@ public class ChannelTests: XCTestCase {
/// Test that with a massive buffers (bigger than writev size), we don't offer more than we should to `writev`.
func testPendingWritesNoMoreThanWritevLimitIsWrittenInOneMassiveChunk() throws {
let el = EmbeddedEventLoop()
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedRealloc: { _, _ in UnsafeMutableRawPointer(bitPattern: 0x1337beef)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */
Expand Down
7 changes: 6 additions & 1 deletion Tests/NIOTests/DatagramChannelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,13 @@ final class DatagramChannelTests: XCTestCase {
}
let envelope = AddressedEnvelope(remoteAddress: self.secondChannel.localAddress!, data: buffer)

#if arch(arm) // 32-bit, Raspi/AppleWatch/etc
let lotsOfData = Int(Int32.max / 8)
#else
let lotsOfData = Int(Int32.max)
#endif
var written = 0
while written <= Int(INT32_MAX) {
while written <= lotsOfData {
self.firstChannel.write(NIOAny(envelope), promise: myPromise)
overall = EventLoopFuture<Void>.andAll([overall, myPromise.futureResult], eventLoop: self.firstChannel.eventLoop)
written += bufferSize
Expand Down
2 changes: 1 addition & 1 deletion Tests/NIOTests/EmbeddedEventLoopTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public class EmbeddedEventLoopTest: XCTestCase {
var sentinel = 0
let loop = EmbeddedEventLoop()
for index in 1...10 {
_ = loop.scheduleTask(in: .nanoseconds(index)) {
_ = loop.scheduleTask(in: .nanoseconds(TimeAmount.Value(index))) {
sentinel = index
}
}
Expand Down
14 changes: 7 additions & 7 deletions Tests/NIOTests/PendingDatagramWritesManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class PendingDatagramWritesManagerTests: XCTestCase {
var msgs: [MMsgHdr] = Array(repeating: MMsgHdr(), count: Socket.writevLimitIOVectors + 1)
var addresses: [sockaddr_storage] = Array(repeating: sockaddr_storage(), count: Socket.writevLimitIOVectors + 1)
/* put a canary value at the end */
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)!, iov_len: 0xdeadbeef)
iovecs[iovecs.count - 1] = iovec(iov_base: UnsafeMutableRawPointer(bitPattern: 0x1337beef)!, iov_len: 0x1337beef)
try iovecs.withUnsafeMutableBufferPointer { iovecs in
try managed.withUnsafeMutableBufferPointer { managed in
try msgs.withUnsafeMutableBufferPointer { msgs in
Expand All @@ -83,8 +83,8 @@ class PendingDatagramWritesManagerTests: XCTestCase {
}
/* assert that the canary values are still okay, we should definitely have never written those */
XCTAssertEqual(managed.last!.toOpaque(), Unmanaged.passUnretained(o).toOpaque())
XCTAssertEqual(0xdeadbeef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0xdeadbeef, iovecs.last!.iov_len)
XCTAssertEqual(0x1337beef, Int(bitPattern: iovecs.last!.iov_base))
XCTAssertEqual(0x1337beef, iovecs.last!.iov_len)
}
}

Expand Down Expand Up @@ -433,8 +433,8 @@ class PendingDatagramWritesManagerTests: XCTestCase {
/// Test that with a few massive buffers, we don't offer more than we should to `writev` if the individual chunks fit.
func testPendingWritesNoMoreThanWritevLimitIsWritten() throws {
let el = EmbeddedEventLoop()
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */
Expand Down Expand Up @@ -466,8 +466,8 @@ class PendingDatagramWritesManagerTests: XCTestCase {
func testPendingWritesNoMoreThanWritevLimitIsWrittenInOneMassiveChunk() throws {
let el = EmbeddedEventLoop()
let address = try SocketAddress(ipAddress: "127.0.0.1", port: 65535)
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef)! },
let alloc = ByteBufferAllocator(hookedMalloc: { _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedRealloc: { _, _ in return UnsafeMutableRawPointer(bitPattern: 0xdeadbeef as UInt)! },
hookedFree: { _ in },
hookedMemcpy: { _, _, _ in })
/* each buffer is half the writev limit */
Expand Down
2 changes: 1 addition & 1 deletion Tests/NIOTests/SystemCallWrapperHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func runSystemCallWrapperPerformanceTest(testAssertFunction: (@autoclosure () ->
}

let iterations = isDebugMode ? 100_000 : 1_000_000
let pointer = UnsafePointer<UInt8>(bitPattern: 0xdeadbeef)!
let pointer = UnsafePointer<UInt8>(bitPattern: 0x1337beef)!

let directCallTime = try measureRunTime { () -> Int in
/* imitate what the system call wrappers do to have a fair comparison */
Expand Down

0 comments on commit e8c04e0

Please sign in to comment.