当前位置: 首页 > 面试题库 >

Swift对象的安全内存

蒋泰
2023-03-14
问题内容

我正在编写一个需要处理内存中私钥的快速应用程序。由于此类对象的敏感性,因此在释放对象时需要清除键(也就是将其写为全零),并且无法将内存分页到磁盘(通常使用mlock()完成)。

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

因此,一种解决方案是仅在Objective-C中实现一个“ SecureData”对象,该对象使用自定义CFAllocator(也在Objective-
C中)在内部创建NSMutableData对象。

但是,有什么方法可以为纯swift对象(例如struct或[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)

您甚至可以保留自己的自定义类型:

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)

但是请
注意,如果对类,甚至数组或字符串(或包含它们的结构)执行此操作,则将要保存在内存中的只是指向这些对象分配和拥有的其他内存的指针。如果这对您很重要(例如,您正在为此内存做一些特殊的事情,例如保护它),那么这可能不是您想要的。

因此,您需要使用固定大小的对象,或者进一步利用UnsafePointer持有指向更多内存区域的指针。如果他们不需要动态调整大小,则只需分配一个不安全的指针(可能包装在UnsafeBufferPointerCollection接口中)即可。

如果需要更多动态行为,下面是一个非常简单的集合实现,可以根据需要调整大小,可以对其进行增强以涵盖特殊的内存处理逻辑:

// 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,为了实现动态增长:

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)
        }
    }
}


 类似资料:
  • Swift实例对象内存结构 class Person { var age: Int = 1 // 8 字节 var name: String = "abc" // 16 字节 } print(MemoryLayout<Int>.size) -> 8 print(MemoryLayout<String>.size) -> 16 HeapObject (metad

  • 及其不安全的发布: 可以抛出AssertionError,我同意。作者写道,这是因为不安全的出版,但另一方面没有答案:什么才是正确的出版方式?它们表示了4个安全发布习惯用语,但我不明白,为什么它们会在上面的情况下起作用: 要安全地发布对象,必须同时使对对象的引用和对象的状态对其他线程可见。通过以下方法可以安全地发布构造正确的对象: null 这里是我的第一个问题,谢谢你的帮助!

  • 内存安全 Rust推崇安全与速度至上,它没有垃圾回收机制,却成功实现了内存安全 (memory safety)。 所有权 在Rust中,所有权 (ownership) 系统是零成本抽象 (zero-cost abstraction) 的一个主要例子。 对所有权的分析是在编译阶段就完成的,并不带来任何运行时成本 (run-time cost)。 默认情况下,Rust是在栈 (stack) 上分配内存

  • 问题内容: Spring对象是线程安全的吗?如果没有,如何使它们线程安全? 问题答案: 这是两个不相关的问题: spring线程安全吗? 没有。 Spring具有不同的bean 作用域(例如Prototype,Singleton等),但是所有这些作用域都是在创建bean 时强制执行的。例如,每次“注入”一个“原型”范围的bean都会被创建,而一个“单个”范围的bean将被创建一次并在应用程序上下文

  • 当开发人员公开对内部实现对象(例如:文件,目录或数据库密钥)的引用而没有任何允许攻击者操纵这些引用来访问未授权数据的验证机制时,可能会发生直接对象引用。 通过下面每项来了解这个漏洞的威胁代理,攻击向量,安全弱点,技术影响和业务影响。 威胁代理 - 任何只能部分访问某些类型系统数据的用户。 攻击者的方法 - 攻击者是一个授权系统用户,只需将直接引用系统对象的参数值更改为用户未授权的另一个对象。 安全

  • 问题内容: 假设这将在一个真正的并行环境中同时在一个VM上发生: JVM如何确保堆上内存分配的线程安全性? 堆是所有线程的一个,它有自己的内部数据。 为简单起见,假设一个简单的压缩垃圾收集器实现-XX:+ UseSerialGC -XX:+ UseParallelGC,带有简单的增量指针,用于标记Eden(堆)中的可用空间的开始和一个连续的可用空间。 当为 Cat , Dog 和 Mouse 实例