"Ensure that the pointers in your code are safe for the 64-bit runtime."
코드에 있는 포인터가 64비트 런타임에서 안전하도록 보장합니다.
포인터는 객체 및 메모리에 있는 다른 데이터를 참조하며, 객체를 함수에 전달하거나 메모리의 컨텐츠를 조작하기 위해 C 및 Objective-C에서 사용됩니다. 32비트에서 64비트 아키텍처로 업데이트하는 경우 코드 전체에 영향을 미치는 코드의 포인터 크기가 두 배로 늘어납니다. 포인터 사이즈에 대해 만드는 모든 가정은 정의되지 않는 동작, 메모리 손상, 충돌을 야기시킬 수 있슨비다.
적합한 포인터 사용을 위해 코드를 리뷰하려면, 포인터가 다른 타입으로 캐스팅 되거나 강제되는 영역을 살펴봐야 합니다. 인티저와 같은 다른 타입에 포인터를 캐스팅하는 것을 피하시기 바랍니다. 만약 NSLog
혹은 printf
와 같은 함수를 사용해서 포인터의 값을 출력하는 경우 값이 정확하게 표시될 수 있도록 포맷 스트링에서 사전에 규정된 매크로를 사용하시기 바랍니다.
포인터를 인티저 타입으로 캐스팅하는 경우 포인터 타입을 일관적으로 사용해서 모든 변수가 주소를 갖기에 충분히 클 수 잇도록 해줘야 합니다.
아래 코드는 주소에서 산술을 수행하기 위해 포인터를 int
타입으로 캐스팅하고 있습니다. 32비트 런타임에서 이 코든느 작동합니다. 왜냐하면 int
타입과 포인터는 같은 크기이기 때문입니다. 그러나 64비트 런타임에서 포인터는 int
타입보다 더 큽니다. 그렇기 때문에 할당은 포인터의 데이터 일부분을 잃게 됩니다. 이를 해결하려면 캐스팅을 제거해야 합니다. 이제 컴파일러에서 생상된 코드가 포인터를 정확히 작동하도록 해줍니다.
int *c = something passed in as an argument....
int *d = (int *)((int)c + 4); // Incorrect.
int *d = c + 1; // Correct.
만약 포인터를 인티저 타입으로 캐스팅해야 한다면, 잘림을 방지하기 위해 uintptr_t
타입을 사용하시기 바랍니다. 인티저 수학을 거쳐서 포인터 값을 수정하는 것과 이후 포인터로 다시 변환하는 것은 기본 타입 알리아싱 규칙을 위반할 수 있다는 것을 알아두셔야 합니다. 이는 컴파일러로부터 예기치 않은 동작을 초래할 수 있고 프로세서는 잘못 정렬된 포인터에 접근될 때 장애가 발생하게 됩니다.
모든 구조 혹은 할당하려는 변수에 대한 정확한 크기를 가져오기 위해 항상 sizeof
를 사용하시기 바랍니다. 변수를 위한 공간 할당을 하고자 명시적인 크기를 갖는 malloc
은 절대 호출하지 않아야 합니다.
// Incorrect.
uint32_t *x = (uint32_t *)malloc(4);
// Correct.
uint32_t *x = (uint32_t *)malloc(sizeof(uint32_t));
Search your code for any instance of malloc that isn’t followed by sizeof.
객체의 isa 필드에 직접적으로 접근하는 코드를 갖고 있는 경우 해당 코드는 64비트 런타임에서 실행 시 실패합니다. 왜냐하면 isa 필드는 더 이상 포인터를 갖지 않기 때문입니다. 대신 isa 필드는 몇 가지 포인터 데이터를 포함하고 있고, 다른 런타임 정보를 가지고 있기 위해 남아있는 비트를 사용합니다.
객체의 isa 필드를 읽으려면, 클래스 속성을 사용하거나 object_getClass(_:)
함수를 사용하시기 바랍니다. 객체의 isa 필드에 쓰려면, bject_setClass(_:_:)
함수를 호출하시기 바랍니다.
Important
시뮬레이터 앱은 여기에서 설명한 오류를 감지하지 못합니다. 항상 실제 하드웨어에서 앱을 테스트해야 합니다.
printf
와 같은 프린트 함수는 코드가 32비트 및 64비트 모두를 지원해야만 하는 경우에 쓰기 어려울 수 있습니다. 왜냐하면 데이터 타입이 하나의 런타임에서 다른 한 쪽으로 바뀌기 때문입니다. 이 문제를 해결하려면 표준 타입과 포인터 크기화된 인티저에 대해 아래 테이블 및 Table 2에서 보여주고 있는 다양한 매크로를 사용하시기 바랍니다.
Table 1 Standard format strings
Type | Format string |
---|---|
int | %d |
long | %ld |
long long | %lld |
size_t | %zu |
ptrdiff_t | %td |
any pointer | %p |
Table 2 Format strings for pointer-sized integers
Type | Format string |
---|---|
int[N]_t (such as int32_t) | PRId[N] (such as PRId32) |
uint[N]_t | PRIu[N] |
int_least[N]_t | PRIdLEAST[N] |
uint_least[N]_t | PRIuLEAST[N] |
int_fast[N]_t | PRIdFAST[N] |
uint_fast[N]_t | PRIuFAST[N] |
intptr_t | PRIdPTR |
uintptr_t | PRIuPTR |
intmax_t | PRIdMAX |
uintmax_t | PRIuMAX |
This example code prints an intptr_t variable (a pointer-sized integer) and a pointer.
#include <inttypes.h>
void *foo;
intptr_t k = (intptr_t) foo;
void *ptr = &k;
printf("The value of k is %" PRIdPTR "\n", k);
printf("The value of ptr is %p\n", ptr);
앱의 데이터 디자인을 리뷰하고 64비트 아키텍처를 따르도록 업데이트합니다.
https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/updating_data_structures
https://velog.io/@panther222128/Updating-Data-Structures
코드가 정확하게 함수, 함수 포인터, Objective-C 메시지를 처리할 수 있도록 보장합니다.
https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/managing_functions_and_function_pointers
https://velog.io/@panther222128/Managing-Functions-and-Function-Pointers