2014-12-31 35 views
22

Piszę szybką aplikację, która wymaga obsługi kluczy prywatnych w pamięci. Ze względu na wrażliwość takich obiektów, klucze muszą być wyczyszczone (a.k.a. zapisane do wszystkich zer), gdy obiekt jest zwolniony, a pamięć nie może być stronicowana na dysk (co zwykle odbywa się za pomocą mlock()).Bezpieczna pamięć dla obiektów Swift

W Objective-C można udostępnić niestandardowy obiekt CFAllocator, który umożliwia wykorzystanie własnych funkcji do alokacji/zwolnienia/ponownego przydzielenia pamięci używanej przez obiekt.

Jednym z rozwiązań jest po prostu zaimplementowanie obiektu "SecureData" w obiekcie-c, który wewnętrznie tworzy obiekt NSMutableData za pomocą niestandardowego CFAllocator (również w funkcji -c).

Jednak czy jest jakiś sposób dla mnie, aby zapewnić własne funkcje przydzielania pamięci dla czystego obiektu szybkiego (na przykład, struct lub [UInt8])? Czy istnieje lepszy, "właściwy" sposób na szybkie wdrożenie bezpiecznej pamięci?

+0

Dlaczego po prostu nie stosujesz metody deinit tego obiektu, który posiada klucz i który usuwa klucz? – CouchDeveloper

+0

@ 0x7fffffff - jakiego rodzaju dodatkowych informacji szukasz na podstawie mojej odpowiedzi? Będę musiał go dodać. –

+0

@AirspeedVelocity Odpowiedź, którą podałeś, jest już wyjątkowa. Jeśli cokolwiek, po prostu szukam dodatkowego przykładu lub, jeśli to możliwe, wyjaśnienia, w jaki sposób można próbować ominąć problemy związane z łańcuchami i tablicami. (w większości tylko ciągi) Dzięki za kontynuację. –

Odpowiedz

26

Jeśli chcesz pełną kontrolę nad regionem pamięci przydzielić siebie, można użyć UnsafePointer i Kolorado:

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

można również UnsafePointer punkt do drugiej pamięci, takie jak pamięć jesteś wręczył niektóre API C.

UnsafePointer można przekazywać do funkcji języka C, które pobierają wskaźnik do sąsiedniego bloku pamięci. Więc dla swoich celów, można następnie przekazać ten wskaźnik do funkcji jak 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) 

Można nawet posiadać własne typy niestandardowe:

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) 

Jednak mieć świadomość, jeśli robi to z klas lub nawet tablice lub łańcuchy (lub strukturę, która je zawiera), że wszystko, co będziesz trzymał w swojej pamięci, będzie wskazywać na inną pamięć, którą te obiekty przydzielają i posiadają. Jeśli ma to dla Ciebie znaczenie (np. Robisz coś specjalnego dla tej pamięci, na przykład zabezpieczając ją w twoim przykładzie), prawdopodobnie nie jest to, czego chcesz.

Musisz więc użyć obiektów o stałych rozmiarach lub użyć kolejnego UnsafePointer do przechowywania wskaźników do większej liczby regionów pamięci. Jeśli nie trzeba dynamicznie zmieniać rozmiaru, to wystarczy jedna alokacja niebezpiecznego wskaźnika, ewentualnie opakowanego w interfejs użytkownika kolekcji UnsafeBufferPointer.

Jeśli potrzebujesz bardziej dynamiczne zachowanie, poniżej jest realizacja bardzo goły z kolekcji, które można zmieniać rozmiaru w razie potrzeby, że można zwiększyć do pokrycia specjalne pamięci obsługę logicznych:

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

na pokrycie wymagania MutableCollectionType (tj CollectionType powiększonej cesji indeksu):

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

I ExtensibleCollectionType, aby umożliwić dynamiczny wzrost:

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

Dzięki! Wydaje się, że większość tam się znajduje. Czy pamięć jest przydzielona w ciągłym kawałku? Na przykład z tym kodem: pozwól myPtr = UnsafeMutablePointer .alloc (10) Chciałbym zrobić coś takiego jak mlock (myPtr, 10), aby zapobiec przywołaniu pamięci na dysk. – kgreenek

+0

Wierzę, że tak (oznacza to, że możesz przekazać go jako obiekt typu tablica-wskaźnik do funkcji C) –

Powiązane problemy