2013-03-11 4 views
1

x86-64 코드에서 미묘한 충돌을 계산하는 데 단지 반나절을 소비합니다. 따라서 다른 사람에게는이 문제가 해결되었습니다.x86-64에서 포인터를 반환하는 선언되지 않은 함수는 잘못된 포인터 확장을 초래합니다.

올바른 선언없이 libc 함수를 사용하는 경우 gcc 을 반환한다고 가정합니다. 예 : setlocale()int setlocale()이고 EAX에는 32 비트 int 값이 반환됩니다.

암시 적 또는 명시 적 형변환을 통해이 반환 값을 포인터로 변환하려고하면 호출 된 함수가 유효한 64 bin 포인터 값을 반환하더라도 부호 확장을 통해 32 비트에서 64 비트로 강제 변환됩니다. RAX! 예 :

char *p = setlocale(0, 0);  // bear with me for a second 

1c: b8 00 00 00 00   mov $0x0,%eax 
    21: e8 00 00 00 00   callq 26 <hard_locale+0x26> 
    26: 48 98     cltq ; <--- eax is expanded in rax 

GCC로 컴파일됩니다 당신에게 말하려고조차 :

warning: initialization makes pointer from integer without a cast 

당신은 문제를 보여줍니다 명시 적 캐스트에 경고 변경, 추가 할 경우 :

warning: cast to pointer from integer of different size 

'아무 일도 발생하지 않습니다, 운,하지만 메모리의 포인터까지의 큰 값을 반환 발생하는 경우 다음과 같이, 그것은, 엉망이됩니다

function returns in RAX: 0x07ffff7b9705e 
    cltq considers EAX with negative sign: 0xf7b9705e 
    now RAX is: 0xfffffffff7b9705e 

을하고 포인터가 유효하지 않습니다.

수정 및 솔루션 :

  • 항상 x86-64의 컴파일러에 기본적해야 적절한 함수 선언

  • -Wall -Werror를 사용합니다.

+0

네가 사용하는 함수를 선언하지 않으면 나쁜 시간을 보게 될 것이다. 나는 당신이 할 수있는 한 많은 컴파일러 경고를 항상 가능하게 할 필요가 있다는 것이 잘 알려져 있다고 생각한다. 본질적으로 기본 유형 오류 인 셈플을 많이 쓰지는 않는다고 생각합니다. –

+0

이것은 C에서 예상되는 동작입니다. 해결책은 컴파일러에서 발생하는 경고를 해결하는 것입니다.이 경고에는 "call 선언되지 않은 기능으로. " –

+1

이 문제에 대한 비난의 대부분은 'int'를 32 비트로 유지하기로 결정한 컴파일러 작성자에게 맡겨야합니다. 'int'가 64 비트 인 64 비트 데이터 모델 (플랫폼의 자연적인 데이터 크기)은 상황을 잘 처리 할 것입니다. – ecatmur

답변

3

선언되지 않은 함수는 유효하지 C이다. 다만 문제가 사라집니다 -Werror=implicit-function-declaration를 추가합니다. 당신은 필요가 없습니다

다음은 GCC가 오탐 (false positive)없이 잘못된 C를 거부하는 경고 옵션 목록입니다.그것은 몇 가지를 벗어났습니다 (GCC 잡기에 대한 지원이없는)하지만 대부분 완료입니다 :

  • -Werror=implicit-function-declaration
  • -Werror=implicit-int
  • -Werror=pointer-sign
  • -Werror-pointer-arith
  • -Werror=return-type
  • -std=c99
  • (또는 -std=c11 등 ., 원하는대로)
  • -pedantic-errors (선택 사항; 유효하지만 완전히 이식 할 수 없습니다) 나는 또한 목록에 -Werror=sequence-point-Werror=array-bounds 추가 처음했다

주의의 일부 코드는 거부하지만, 그들은 단지 UB 런타임, 제약 조건 위반을 표시하지 않기 때문에 그들은 잘못된 반응이있다. 그러한 경고를 포함하는 프로그램은 UB를 호출 할 코드가 도달 할 수없는 한 여전히 올바른 프로그램이 될 수 있습니다 (좋은 예로서 if (sizeof(int)==sizeof(long)) { ... } else { ... }과 같은 분기를 생각하지 않은 분기는 UB를 호출 함). sizeof 연산자).