mirror of
https://github.com/apple/swift.git
synced 2026-10-30 22:15:52 +01:00
_swift_typedAllocate and _swift_typedDeallocate took alignment masks while EmbeddedPlatform.h documents them as taking alignments, and swift_slowDealloc passed _swift_deallocate the alignment mask and the size in the wrong order. Fix these by passing alignments and correcting the argument order in swift_slowDealloc.
267 lines
8.3 KiB
Swift
267 lines
8.3 KiB
Swift
import Builtin
|
|
|
|
// POSIX dependencies
|
|
@_extern(c, "posix_memalign")
|
|
func posix_memalign(_: UnsafeMutablePointer<UnsafeMutableRawPointer?>, _: Int, _: Int) -> CInt
|
|
|
|
@_extern(c, "free")
|
|
func free(_ p: UnsafeMutableRawPointer?)
|
|
|
|
#if os(Linux) && !SWIFT_STDLIB_HAS_ARC4RANDOM
|
|
// See EmbeddedRuntime.swift: glibc only gained arc4random_buf in 2.36.
|
|
@_extern(c, "getrandom")
|
|
func getrandom(
|
|
_ buf: UnsafeMutableRawPointer, _ nbytes: Int, _ flags: CUnsignedInt
|
|
) -> Int
|
|
|
|
@_extern(c, "__errno_location")
|
|
func __errno_location() -> UnsafeMutablePointer<CInt>
|
|
#else
|
|
@_extern(c, "arc4random_buf")
|
|
func arc4random_buf(_ buf: UnsafeMutableRawPointer, _ nbytes: Int)
|
|
#endif
|
|
|
|
@_extern(c, "putchar")
|
|
func putchar(_: CInt) -> CInt
|
|
|
|
@_extern(c, "exit")
|
|
func exit(_: CInt) /* -> Never */
|
|
|
|
@_extern(c, "malloc_type_malloc")
|
|
func malloc_type_malloc(_ : Int, _ : UInt64) -> UnsafeMutableRawPointer
|
|
|
|
@_extern(c, "malloc_type_posix_memalign")
|
|
func malloc_type_posix_memalign(_: UnsafeMutablePointer<UnsafeMutableRawPointer?>, _: Int, _: Int, _:UInt64) -> CInt
|
|
|
|
@_extern(c, "malloc_type_free")
|
|
func malloc_type_free(_ : UnsafeMutableRawPointer, _ : UInt64)
|
|
|
|
@inline(never)
|
|
private func clearMemory(pointer: UnsafeMutableRawPointer, numBytes: Int) {
|
|
let bytePtr = unsafe pointer.assumingMemoryBound(to: UInt8.self)
|
|
for i in 0..<numBytes {
|
|
unsafe bytePtr[i] = 0
|
|
}
|
|
}
|
|
|
|
// Implementations of the Embedded Swift Platform layer on top of the POSIX
|
|
// dependencies.
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_allocate(_ alignment: Int, _ size: Int, _ flags: SwiftAllocateFlags) -> UnsafeMutableRawPointer? {
|
|
var pointer: UnsafeMutableRawPointer? = nil
|
|
guard posix_memalign(&pointer, alignment, size) == 0 else {
|
|
return nil
|
|
}
|
|
|
|
// Clear the memory if requested.
|
|
if flags.contains(.zeroMemory), let pointer {
|
|
clearMemory(pointer: pointer, numBytes: size)
|
|
}
|
|
|
|
return pointer
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_deallocate(_ pointer: UnsafeMutableRawPointer, _ alignment: Int, _ size: Int, _ flags: SwiftDeallocFlags) {
|
|
free(pointer)
|
|
}
|
|
|
|
private func generateRandom(_ buf: UnsafeMutableRawPointer, _ nbytes: Int) {
|
|
#if os(Linux) && !SWIFT_STDLIB_HAS_ARC4RANDOM
|
|
let EINTR: CInt = 4
|
|
var buf = buf
|
|
var remaining = nbytes
|
|
while remaining > 0 {
|
|
let count = getrandom(buf, remaining, 0)
|
|
if count <= 0 {
|
|
// A signal can interrupt the call while it waits for the entropy pool to
|
|
// be seeded. Every other failure means there is no entropy source, and
|
|
// handing back a buffer that was never filled would silently produce
|
|
// predictable values.
|
|
if count < 0, unsafe __errno_location().pointee == EINTR { continue }
|
|
_writeStaticString(
|
|
"Fatal error: unable to obtain entropy from getrandom\n")
|
|
_swift_exit(1)
|
|
}
|
|
buf += count
|
|
remaining -= count
|
|
}
|
|
#else
|
|
arc4random_buf(buf, nbytes)
|
|
#endif
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_generateRandom(_ buf: UnsafeMutableRawPointer, _ nbytes: Int) {
|
|
generateRandom(buf, nbytes)
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_generateRandomHashSeed(_ buf: UnsafeMutableRawPointer, _ nbytes: Int) {
|
|
generateRandom(buf, nbytes)
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_writeToStandardOutput(
|
|
_ pointer: UnsafePointer<UInt8>?,
|
|
_ count: Int
|
|
) -> Int {
|
|
for unsafe char in unsafe UnsafeBufferPointer(start: pointer, count: count) {
|
|
_ = putchar(CInt(char))
|
|
}
|
|
return count
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_exit(_ code: CInt) -> Never {
|
|
exit(code)
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
/// The human-readable prefix that precedes an error message, chosen by the
|
|
/// error kind held in the low 8 bits of `flags` (a `swift_error_kind_t` /
|
|
/// `SwiftErrorKind` value).
|
|
private func _reportErrorPrefix(_ flags: UInt64) -> StaticString {
|
|
switch flags & 0xff {
|
|
case 1: return "Precondition failed" // SwiftErrorKind.precondition
|
|
case 2: return "Assertion failed" // SwiftErrorKind.assertion
|
|
default: return "Fatal error" // SwiftErrorKind.fatal
|
|
}
|
|
}
|
|
|
|
/// Writes a NUL-terminated static string to standard output.
|
|
private func _writeStaticString(_ string: StaticString) {
|
|
string.withUTF8Buffer { buffer in
|
|
_ = unsafe _swift_writeToStandardOutput(buffer.baseAddress, buffer.count)
|
|
}
|
|
}
|
|
|
|
/// Writes a non-negative integer to standard output in decimal.
|
|
private func _writeInt(_ value: Int) {
|
|
if value >= 10 { _writeInt(value / 10) }
|
|
_ = putchar(CInt(UInt8(ascii: "0") + UInt8(value % 10)))
|
|
}
|
|
|
|
/// Prints a fatal error report to standard output, optionally prefixed by a
|
|
/// source location, e.g. "file:line: Fatal error: message". Output goes through
|
|
/// `putchar` (via `_swift_writeToStandardOutput`) so it doesn't allocate and
|
|
/// honors any platform-provided unbuffered `putchar`.
|
|
private func _reportError(
|
|
prefix: StaticString,
|
|
fileName: UnsafePointer<UInt8>?, fileNameCount: Int, line: Int,
|
|
message: UnsafePointer<UInt8>?, messageCount: Int
|
|
) {
|
|
// Optional "<file>:<line>: " source-location prefix.
|
|
if let fileName, fileNameCount > 0 {
|
|
_ = unsafe _swift_writeToStandardOutput(fileName, fileNameCount)
|
|
_writeStaticString(":")
|
|
_writeInt(line)
|
|
_writeStaticString(": ")
|
|
}
|
|
|
|
// The error-kind prefix, followed by ": <message>" when a message is given.
|
|
_writeStaticString(prefix)
|
|
if let message, messageCount > 0 {
|
|
_writeStaticString(": ")
|
|
_ = unsafe _swift_writeToStandardOutput(message, messageCount)
|
|
}
|
|
_writeStaticString("\n")
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_reportError(
|
|
_ message: UnsafePointer<UInt8>?,
|
|
_ messageCount: Int,
|
|
_ flags: UInt64
|
|
) {
|
|
unsafe _reportError(
|
|
prefix: _reportErrorPrefix(flags),
|
|
fileName: nil, fileNameCount: 0, line: 0,
|
|
message: message, messageCount: messageCount)
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_reportErrorAt(
|
|
_ message: UnsafePointer<UInt8>?,
|
|
_ messageCount: Int,
|
|
_ fileName: UnsafePointer<UInt8>?,
|
|
_ fileNameCount: Int,
|
|
_ line: Int,
|
|
_ flags: UInt64
|
|
) {
|
|
unsafe _reportError(
|
|
prefix: _reportErrorPrefix(flags),
|
|
fileName: fileName, fileNameCount: fileNameCount, line: line,
|
|
message: message, messageCount: messageCount)
|
|
}
|
|
|
|
#if SWIFT_STDLIB_HAS_MALLOC_TYPE
|
|
// `#available` calls the non-inlinable `_stdlib_isOSVersionAtLeast`, which
|
|
// has no body in the embedded stdlib; call the inlinable `_AEIC` entry
|
|
// point directly instead.
|
|
@inline(__always)
|
|
private func _isMallocTypeOSVersionAtLeast() -> Bool {
|
|
#if os(macOS)
|
|
return Bool(_stdlib_isOSVersionAtLeast_AEIC(15._builtinWordValue, 0._builtinWordValue, 0._builtinWordValue))
|
|
#elseif os(iOS)
|
|
return Bool(_stdlib_isOSVersionAtLeast_AEIC(17._builtinWordValue, 0._builtinWordValue, 0._builtinWordValue))
|
|
#elseif os(tvOS)
|
|
return Bool(_stdlib_isOSVersionAtLeast_AEIC(17._builtinWordValue, 0._builtinWordValue, 0._builtinWordValue))
|
|
#elseif os(watchOS)
|
|
return Bool(_stdlib_isOSVersionAtLeast_AEIC(10._builtinWordValue, 0._builtinWordValue, 0._builtinWordValue))
|
|
#else
|
|
return false
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_typedAllocate(_ size: Int, _ alignment: Int, _ flags: SwiftAllocateFlags, _ typeId: UInt64) -> UnsafeMutableRawPointer? {
|
|
if (size == 0) {
|
|
return unsafe _swift_typedAllocate(1, alignment, flags, typeId)
|
|
}
|
|
|
|
#if SWIFT_STDLIB_HAS_MALLOC_TYPE
|
|
if _isMallocTypeOSVersionAtLeast() {
|
|
// malloc() is always 16-byte aligned on Apple platforms. This also covers
|
|
// the default alignment, 0.
|
|
let MALLOC_ALIGNMENT = 16
|
|
if alignment <= MALLOC_ALIGNMENT {
|
|
return unsafe malloc_type_malloc(size, typeId);
|
|
} else {
|
|
// Do not use malloc_type_aligned_alloc() here, because we want this
|
|
// to work if `size` is not an integer multiple of `alignment`, which
|
|
// was a requirement of the latter in C11 (but not C17 and later).
|
|
var pointer: UnsafeMutableRawPointer? = nil
|
|
guard unsafe malloc_type_posix_memalign(&pointer, alignment, size, typeId) == 0 else {
|
|
return nil
|
|
}
|
|
return pointer
|
|
}
|
|
}
|
|
#endif
|
|
return unsafe swift_slowAlloc(size, alignment &- 1)
|
|
}
|
|
|
|
@export(interface)
|
|
@implementation @c
|
|
public func _swift_typedDeallocate(_ pointer: UnsafeMutableRawPointer, _ size: Int, _ alignment: Int, _ flags: SwiftDeallocFlags, _ typeId: UInt64) {
|
|
#if SWIFT_STDLIB_HAS_MALLOC_TYPE
|
|
if _isMallocTypeOSVersionAtLeast() {
|
|
unsafe malloc_type_free(pointer, typeId);
|
|
return
|
|
}
|
|
#endif
|
|
swift_slowDealloc(pointer, size, alignment &- 1);
|
|
}
|