2017-09-19 5 views
1

내가 얻은 UnsafeMutableRawPointer에서 UnsafeMutablePointer을 얻으려고에 EXC_BAD_ACCESS는 Unmanaged.passUnretained().toOpaque()를 사용 : 모든 때까지 pointer에 괜찮아 보인다 여기 UnsafeMutableRawPointer는 UnsafeMutablePointer <T>에 : pointee

class C { var foo = 42, bar = "bar" } 
let c = C() 

let rawPointer = Unmanaged.passUnretained(c).toOpaque() 

let pointer = rawPointer.bindMemory(to: C.self, capacity: 1) 
let pointee = pointer.pointee 
print(pointee.foo) // EXC_BAD_ACCESS 

나에게 이상한 보이는 일부 LLDB 출력의 나는 그것의 pointee 요청 :

(lldb) frame variable -L c 
scalar: (memtest2.C) c = 0x0000000101d00030 { 
0x0000000101d00040: foo = 42 
0x0000000101d00048: bar = "bar" 
} 
(lldb) frame variable -L rawPointer 
0x00000001005e2e08: (UnsafeMutableRawPointer) rawPointer = { 
scalar: _rawValue = 0x0000000101d00030 { 
0x0000000101d00040:  foo = 42 
0x0000000101d00048:  bar = "bar" 
    } 
} 
(lldb) frame variable -L pointer 
0x00000001005e2e10: (UnsafeMutablePointer<memtest2.C>) pointer = 0x0000000101d00030 
(lldb) frame variable -L pointer._rawValue 
scalar: (memtest2.C) pointer._rawValue = 0x0000000101d00030 { 
0x0000000101d00040: foo = 42 
0x0000000101d00048: bar = "bar" 
} 
(lldb) frame variable -L pointee 
0x00000001005e2e18: (memtest2.C) pointee = 0x00000001005b65d8 { 
0x00000001005b65e8: foo = 140736790071664 
0x00000001005b65f0: bar = "" 
} 

나는 또한 assumingMemoryBound(to:), load(as:), 또는 단순히 시도했다 :

let pointer = UnsafePointer<C>(bitPattern: Int(bitPattern: rawPointer))! 
print(pointer.pointee.foo) // EXC_BAD_ACCESS 

하지만이 EXC_BAD_ACCESS 오류는 항상 발생합니다. 여기서 무슨 일이 일어나고있는거야?

+0

'obj = 관리되지 않음 .fromOpaque (rawPointer) .takeUnretainedValue(); print (obj.foo)'를 시도하십시오. – OOPer

+0

@OOPer 제 최종 목표는'C' 인스턴스에 접근하는 것이 아니라 실제로 원시 타입으로부터 유효 타입의 포인터를 얻는 것입니다. – nyg

+0

그렇다면 귀하의 _end-goal_을 (를) 이해할 수 없습니다. 어쨌든, 당신의 코드는'rawPointer'가'C' 인스턴스에 대한 참조에 대한 포인터 일 때만 작동합니다.'Unmanaged.passUnretained (c) .toOpaque()'는 그것을 만들지 않습니다. – OOPer

답변

0

rawPointerc 인스턴스 데이터가있는 위치를 가리 킵니다. 예상대로, 참조에 대한 포인터가 아닙니다. 클래스는 참조 유형입니다. c의 값은 클래스 인스턴스 데이터가있는 메모리 주소입니다. 그러나 toOpaque() 의사는 분명합니다.

관리되지 않는 클래스 참조를 포인터로 잘못 변환합니다.

기준에 대한 포인터를 가질

(toOpaque() 실제로 unsafeBitCast(c, UnsafeMutableRawPointer.self)를 호출) 하나 간단하게 수행 할 수 있습니다

let referencePointer = UnsafeMutablePointer<C>(&c) 
는 인스턴스 데이터에 내 rawPointer 점으로

pointer.pointee 이렇게하면 런타임을 알려줍니다 그 인스턴스 데이터의 첫 번째 단어는 (또는 그) 참조입니다. 물론 사실이 아니며 의미가 없습니다. (나는 약간 한 내 초기 코드를 변경 : foobar 모두 지능 있습니다)

예시 하나

(lldb) frame variable c 
(testmem.C) c = 0x0000000101833580 (foo = 42, bar = 84) 

이 인스턴스 데이터의 위치 (0x0000000101833580가)입니다. 의 메모리가이 주소에 포함 된 내용을 보자 : 그 첫 번째 단어 (e0 65 5b 00 01 00 00 00)을 배운

(lldb) memory read 0x0000000101833580 
0x101833580: e0 65 5b 00 01 00 00 00 02 00 00 00 00 00 00 00 
0x101833590: 2a 00 00 00 00 00 00 00 54 00 00 00 00 00 00 00 

하는 데이터를 입력 할 수있는 초 (02 00 00 00 00 00 00 00)는 참조 카운트 (나는이에 대한 자세한 내용을 알고하지 않음) 나머지는 인스턴스 데이터입니다. 실제로 0x2a은 42이고 0x54은 84입니다. foobar의 값입니다.

Doing pointer.pointee은 런타임에 첫 번째 단어 (e0 65 5b 00 01 00 00 00 또는 0x00000001005b65e0)가 인스턴스 데이터가있는 위치를 가리키는 참조임을 나타냅니다. pointer.pointee.foo0x00000001005b65e0 + 16 (0x00000001005b65f0) 및 bar (+24)에 위치한다는 것을 의미합니다 (0x00000001005b65f0)., 따라서 EXC_BAD_ACCESS 오류

(lldb) frame variable -L pointee 
0x00000001005e2e18: (testmem.C) pointee = 0x00000001005b65e0 { 
0x00000001005b65f0: foo = 140735845296496 // this 
0x00000001005b65f8: bar = 0 
} 

그리고이 데이터가 우리가에 대한 액세스 권한이없는 내 프로그램에 의해 할당되지 않았습니다 같이

(lldb) memory read 0x00000001005b65e0 
0x1005b65e0: a9 65 5b 00 01 80 1d 00 80 62 5b 00 03 00 00 00 
0x1005b65f0: 70 e9 10 9e ff 7f 00 00 00 00 00 00 00 00 00 00 

foo 소수점에 140,735,845,296,496과에 해당 0x0000007fff9e10e970 포함 .

생활은 이제 의미가 있습니다.

관련 문제