2012-06-28 4 views
5

llvm/compiler-rt/clang의 3.1 릴리스를 구축했으며 -fcatch-undefined-behavior가 실제로 어떤 작업을하는지 확인하려고합니다. 지금까지 행운이 없습니다. 예 : 나는 컴파일하고clang의 -fcatch-undefined-behavior가 광고 된대로 작동하지 않음

$ /usr/local/bin/clang -fcatch-undefined-behavior undef_test.c && ./a.out 
0 

난 정말 간단한 뭔가를 놓치고와

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    int* x = malloc(sizeof(int) * 10); 
    printf("%d\n", x[20]); 
    return 0; 
} 

를 실행?

+2

예, catch/all/undefined 동작이 매우 어렵고 컴파일러가 구현하기가 너무 어렵다는 사실을 알지 못합니다. – PlasmaHH

+1

-faddress-sanitizer는 valgrind와 같이이를 포착해야합니다. –

+0

고마워요, Ambroz. 이것은 가장 도움이되었습니다. – Oleg2718281828

답변

4

예 : x은 배열이 아닙니다. documentation에서

:

-fcatch - 정의되지 않은-행동 : 정의되지 않은 동작을 확인하기 위해 런타임 코드 생성을 켭니다. 이 옵션은 기본적으로 off로 설정되어 있으며 Clang이 정의되지 않은 런타임 동작에 대한 런타임 검사를 추가할지 여부를 제어합니다. 검사가 실패하면 __builtin_trap()이 실패를 나타내는 데 사용됩니다. 검사는 다음과 같습니다.

  • 아래 첨자 여기서 정적 유형의 피연산자는 배열 유형에서 감쇠되는 변수이고 다른 피연산자는 배열 크기보다 크거나 0보다 작은 변수입니다.
  • 금액이 이동 된 이동 연산자는 왼쪽의 승격 된 비트 폭보다 크거나 같거나 0보다 작습니다.
  • 제어 흐름이 __builtin_unreachable에 도달하면.
  • llvm이 __builtin_object_size 지원을 더 많이 구현하면 __builtin_object_size가 유효한 메모리에 액세스하지 않음을 나타내는 객체에 대한 읽기 및 쓰기가 수행됩니다. 비트 필드와 벡터는 아직 검사되지 않습니다.

난 당신이 불행하게도 당신이 배열을 구축하지 않았 첨자 검사를 테스트하고 싶어한다고 가정하면 (malloc에서) 메모리의 영역을 구축하고 배열로 해석하기로 결정했습니다; 그러나 컴파일러의 관점에서 보았을 때 메모리의 덩어리 일뿐입니다 (반환 유형이 mallocvoid* 임).

int main() { 
    int x[10] = {}; 
    printf("%d\n", x[20]); 
} 

그렇지 않으면, 특정 메모리 문제 추적기를 들어, 플러그인 소독제 주소로 표시되어야합니다

당신은 아마이 동작을 테스트 할 수있다.

+0

이것은'-fcatch-undefined-behaviour'가 지정되었는지 여부에 관계없이 clang에 의한 경고를 유발합니다. – detly

+0

@detly :'-fcatch-undefined-behavior'는 경고와 관련없는 코드 생성 옵션입니다. 대신에 어설 션을 위반하면 런타임 어설 션을 삽입하고 프로그램을 확실하게 중단합니다. 물론 컴파일을 시작하자마자 경고를 신뢰하고 행동하는 것이 좋습니다. '-fcatch-undefined-behavior'는 이제 더 이상 사용되지 않으며'-fsanitize'를 사용하여 다양한 주소/메모리/스레드/정의되지 않은 새니 타이 저를 활성화해야합니다 (그리고 그 중 일부는 서로 호환되지 않습니다) . –

1

-fcatch-undefined-behavior은 임의 포인터 비 참조를 처리하지 않습니다. 이 경우를 처리하기 위해 컴파일러는 포인터 옆에 지정된 데이터의 크기를 저장하고 모든 함수 호출에서 그 크기를 전달해야합니다. 기존 ABI와 호환되지 않으므로 프로그램 링크가있는 모든 라이브러리를 다시 컴파일해야합니다.

malloc은 잘 알려진 함수이며 컴파일러는 반환 된 포인터가 요청 된 크기의 배열을 가리키는 것으로 간주 할 수 있습니다.

그러나 mallocNULL을 반환 할 수 있습니다. 컴파일러에서 포인터가 NULL이 아니라고 가정하면 NULL 검사를 최적화합니다 (상당히 위험합니다).컴파일러에서 포인터가 NULL이거나 요청 된 크기의 배열에 대한 포인터라고 가정하면 관리하기가 다소 복잡해질 것입니다 (아직 freerealloc은 얘기하지 않았습니다). 또한 NULL 검사를 사용하지 않고 malloc이 포인터를 역 참조하는 코드는 정의되지 않은 동작으로 간주됩니다.

프로그램이 표준 라이브러리가 아닌 다른 의미로 malloc의 사용자 지정 구현을 제공하는 라이브러리에 연결되어있을 수도 있습니다.