安全的内存对于Swift对象

我正在写一个快速的应用程序,需要处理内存中的私钥。 由于这些对象的敏感性,当对象被释放时,这些键需要被清除(也被写为全零),并且内存不能被分页到磁盘(通常使用mlock()完成)。

在Objective-C中,您可以提供一个自定义的CFAllocator对象,它允许您使用自己的函数来分配/释放/重新分配对象使用的内存。

所以一个解决scheme是在objective-c中实现一个“SecureData”对象,该对象使用自定义的CFAllocator(也在objective-c中)在内部创build一个NSMutableData对象。

然而,有没有办法让我提供我自己的自定义内存分配函数的纯Swift对象(例如,一个结构或[UInt8])? 还是有更好的,“适当”的方式来实现这样的快速安全的内存?

如果你想完全控制你自己分配的内存区域,你可以使用UnsafePointer和co:

 // allocate enough memory for ten Ints var ump = UnsafeMutablePointer<Int>.alloc(10) // memory is in an uninitialized raw state // initialize that memory with Int objects // (here, from a collection) ump.initializeFrom(reverse(0..<10)) // memory property gives you access to the underlying value ump.memory // 9 // UnsafeMutablePointer acts like an IndexType ump.successor().memory // 8 // and it has a subscript, but it's not a CollectionType ump[3] // = 6 // wrap it in an UnsafeMutableBufferPointer to treat it // like a collection (or UnsafeBufferPointer if you don't // need to be able to alter the values) let col = UnsafeMutableBufferPointer(start: ump, count: 10) col[3] = 99 println(",".join(map(col,toString))) // prints 9,8,7,99,5,4,3,2,1,0 ump.destroy(10) // now the allocated memory is back in a raw state // you could re-allocate it... ump.initializeFrom(0..<10) ump.destroy(10) // when you're done, deallocate the memory ump.dealloc(10) 

你也可以让UnsafePointer指向其他的内存,比如你由一些C API传递的内存。

UnsafePointer可以被传递到C函数中,该函数将指针指向连续的内存块。 因此,为了您的目的,您可以将这个指针传递给像mlock这样的函数:

 let count = 10 let ump = UnsafeMutablePointer.allocate<Int>(count) mlock(ump, UInt(sizeof(Int) * count)) // initialize, use, and destroy the memory munlock(ump, UInt(sizeof(Int) * count)) ump.dealloc(count) 

你甚至可以拥有自己的自定义types:

 struct MyStruct { let a: Int let b: Int } var pointerToStruct = UnsafeMutablePointer<MyStruct>.alloc(1) pointerToStruct.initialize(MyStruct(a: 1, b: 2)) pointerToStruct.memory.b // 2 pointerToStruct.destroy() pointerToStruct.dealloc(1) 

但是要知道,如果使用类,甚至数组或string(或包含它们的结构)来完成此操作,那么您将在内存中保留的所有内容都是指向这些对象分配和拥有的其他内存的指针。 如果这对你很重要(即你正在做一些特殊的内存,如保护它,在你的例子),这可能不是你想要的。

所以要么需要使用固定大小的对象,要么进一步使用UnsafePointer来保存指向更多内存区域的指针。 如果他们不需要dynamicresize,那么可能包含在一个UnsafeBufferPointer集合接口中的一个不安全指针的单个分配就可以完成。

如果你需要更多的dynamic行为,下面是一个非常简单的集合实现,可以根据需要resize,可以增强以涵盖专业的内存处理逻辑:

 // Note this is a class not a struct, so it does NOT have value semantics, // changing a copy changes all copies. public class UnsafeCollection<T> { private var _len: Int = 0 private var _buflen: Int = 0 private var _buf: UnsafeMutablePointer<T> = nil public func removeAll(keepCapacity: Bool = false) { _buf.destroy(_len) _len = 0 if !keepCapacity { _buf.dealloc(_buflen) _buflen = 0 _buf = nil } } public required init() { } deinit { self.removeAll(keepCapacity: false) } public var count: Int { return _len } public var isEmpty: Bool { return _len == 0 } } 

为了覆盖MutableCollectionType的要求(即CollectionType加上可分配的下标):

 extension UnsafeCollection: MutableCollectionType { typealias Index = Int public var startIndex: Int { return 0 } public var endIndex: Int { return _len } public subscript(idx: Int) -> T { get { precondition(idx < _len) return _buf[idx] } set(newElement) { precondition(idx < _len) let ptr = _buf.advancedBy(idx) ptr.destroy() ptr.initialize(newElement) } } typealias Generator = IndexingGenerator<UnsafeCollection> public func generate() -> Generator { return Generator(self) } } 

ExtensibleCollectionType ,允许dynamic增长:

 extension UnsafeCollection: ExtensibleCollectionType { public func reserveCapacity(n: Index.Distance) { if n > _buflen { let newBuf = UnsafeMutablePointer<T>.alloc(n) newBuf.moveInitializeBackwardFrom(_buf, count: _len) _buf.dealloc(_buflen) _buf = newBuf _buflen = n } } public func append(x: T) { if _len == _buflen { reserveCapacity(Int(Double(_len) * 1.6) + 1) } _buf.advancedBy(_len++).initialize(x) } public func extend<S: SequenceType where S.Generator.Element == T> (newElements: S) { var g = newElements.generate() while let x: T = g.next() { self.append(x) } } }