Auditing Pointer Usage

Panther·2021년 8월 14일
0

https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/auditing_pointer_usage

"Ensure that the pointers in your code are safe for the 64-bit runtime."

코드에 있는 포인터가 64비트 런타임에서 안전하도록 보장합니다.

Overview

포인터는 객체 및 메모리에 있는 다른 데이터를 참조하며, 객체를 함수에 전달하거나 메모리의 컨텐츠를 조작하기 위해 C 및 Objective-C에서 사용됩니다. 32비트에서 64비트 아키텍처로 업데이트하는 경우 코드 전체에 영향을 미치는 코드의 포인터 크기가 두 배로 늘어납니다. 포인터 사이즈에 대해 만드는 모든 가정은 정의되지 않는 동작, 메모리 손상, 충돌을 야기시킬 수 있슨비다.

적합한 포인터 사용을 위해 코드를 리뷰하려면, 포인터가 다른 타입으로 캐스팅 되거나 강제되는 영역을 살펴봐야 합니다. 인티저와 같은 다른 타입에 포인터를 캐스팅하는 것을 피하시기 바랍니다. 만약 NSLog 혹은 printf와 같은 함수를 사용해서 포인터의 값을 출력하는 경우 값이 정확하게 표시될 수 있도록 포맷 스트링에서 사전에 규정된 매크로를 사용하시기 바랍니다.

Cast Pointers to Integers Selectively

포인터를 인티저 타입으로 캐스팅하는 경우 포인터 타입을 일관적으로 사용해서 모든 변수가 주소를 갖기에 충분히 클 수 잇도록 해줘야 합니다.

아래 코드는 주소에서 산술을 수행하기 위해 포인터를 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 타입을 사용하시기 바랍니다. 인티저 수학을 거쳐서 포인터 값을 수정하는 것과 이후 포인터로 다시 변환하는 것은 기본 타입 알리아싱 규칙을 위반할 수 있다는 것을 알아두셔야 합니다. 이는 컴파일러로부터 예기치 않은 동작을 초래할 수 있고 프로세서는 잘못 정렬된 포인터에 접근될 때 장애가 발생하게 됩니다.

Allocate Memory Using sizeof

모든 구조 혹은 할당하려는 변수에 대한 정확한 크기를 가져오기 위해 항상 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.

Access Objective-C Internal Structures Using Approved Methods

객체의 isa 필드에 직접적으로 접근하는 코드를 갖고 있는 경우 해당 코드는 64비트 런타임에서 실행 시 실패합니다. 왜냐하면 isa 필드는 더 이상 포인터를 갖지 않기 때문입니다. 대신 isa 필드는 몇 가지 포인터 데이터를 포함하고 있고, 다른 런타임 정보를 가지고 있기 위해 남아있는 비트를 사용합니다.

객체의 isa 필드를 읽으려면, 클래스 속성을 사용하거나 object_getClass(_:) 함수를 사용하시기 바랍니다. 객체의 isa 필드에 쓰려면, bject_setClass(_:_:) 함수를 호출하시기 바랍니다.

Important
시뮬레이터 앱은 여기에서 설명한 오류를 감지하지 못합니다. 항상 실제 하드웨어에서 앱을 테스트해야 합니다.

Update Format Strings

printf와 같은 프린트 함수는 코드가 32비트 및 64비트 모두를 지원해야만 하는 경우에 쓰기 어려울 수 있습니다. 왜냐하면 데이터 타입이 하나의 런타임에서 다른 한 쪽으로 바뀌기 때문입니다. 이 문제를 해결하려면 표준 타입과 포인터 크기화된 인티저에 대해 아래 테이블 및 Table 2에서 보여주고 있는 다양한 매크로를 사용하시기 바랍니다.

Table 1 Standard format strings

TypeFormat 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

TypeFormat string
int[N]_t (such as int32_t)PRId[N] (such as PRId32)
uint[N]_tPRIu[N]
int_least[N]_tPRIdLEAST[N]
uint_least[N]_tPRIuLEAST[N]
int_fast[N]_tPRIdFAST[N]
uint_fast[N]_tPRIuFAST[N]
intptr_tPRIdPTR
uintptr_tPRIuPTR
intmax_tPRIdMAX
uintmax_tPRIuMAX

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

See Also


Memory and Pointer Access

Updating Data Structures

앱의 데이터 디자인을 리뷰하고 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

Managing Functions and Function Pointers

코드가 정확하게 함수, 함수 포인터, 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


0개의 댓글