2010-12-19 4 views
2

gcc -O0 -g 출력에만 나타나고 gcc -O3이 아니라 MSVC 디버그 출력이 아닌 이상한 조건이 있습니다. 에 나타납니다gcc 디버그 빌드에만 나타나는 이상한 조건

void func(void) { 
    static int enabled; 

    if (!enabled) { 
    // do stuff 
    enabled = 1; 
    } 

} 

문제 GCC -O0 -g 만 때때로 0으로 반환 가능하지만 것입니다 항상, 단지 프로그램의 실행에 드문 점. 이 함수는 일반적으로이를 반복합니다. 그것에 대해 혼란스럽게 할 수있는 것은 무엇입니까? '활성화'가 외부에서 변경 될 수 있습니까? 그러나 내부에 선언되어 있습니다.

EDIT : 함수 내에서 0으로 설정하는 방법이 있지만, 큰 뚱뚱한 printf는 전혀 인쇄되지 않습니다. [그리고 그 아래에 전혀 논리적 인 방법이 없습니다. 시험 조건]. 명시 적으로 사용할 수있는 항목에 전혀 적용되지 않는 것으로 보입니다.

EDIT2 : 주 스레드에서만 호출됩니다.

EDIT3 : 더 기괴합니다. 리눅스 gcc -O0 -g에는 나타나지 않지만 mingw-w64 [gcc -O0 -g]에만 나타납니다.

EDIT4 : if (! enabled) (읽기 전용이어야 함)의 일부 경우에 rwatch 및 watch on enabled가 변경된 것으로 표시됩니다.

EDIT5 : oftc에서 # mingw-w64의 도움을받은 후 '부울 순서'가 반전 된 경우 '수정'됩니다. enabled는 1로 초기화 된 다음 0으로 설정됩니다. "0이 아닌 값으로 정적 변수를 초기화하여 .data 섹션에 넣으므로 lcomm에 대한 문제가 있습니다." "버퍼 오버런이 있다고 가정합니다. 귀하의 코드에서 다른 장소 "

+1

이 함수를 여러 스레드에서 호출 할 수 있는지 여부를 문서화합니다. –

+0

아니요, 주 스레드에서만 호출됩니다. –

+0

해당 변수의 초기화 프로그램은 어디에 있습니까? 왜냐하면 지금은 초기화되지 않았기 때문에 처음에 0으로하고 싶다고 가정합니다. 또한 그것이 0으로 되돌아 간다고 어떻게 결정 했습니까? – thkala

답변

5

내 생각 엔 : 어딘가에 버퍼 오버플로가 있습니다. enabled 바로 전에 주 메모리에있는 변수가 잘못된 크기로 덮어 쓰여지고 이후의 모든 항목을 덮어 씁니다. 또는 겹쳐 쓰는 빗나간 포인터가 있습니다.

더 자세히 디버깅하는 유일한 방법은 thkala에서 제안한 것처럼 watchpoint를 gdb에 추가하는 것입니다.

+0

찾았습니다. 바로 전에 실행 된 함수에서 변수에 대한 명확한 오버플로 (int로가는 경우 동작을 수정하는 짧은 int)입니다. 이제는 그 크기가 정확히 무엇인지 알아 내야 만 총알 증명을 할 수 있습니다 (절대적으로 필요하지는 않지만 왜 그렇지는 않습니까). –

+0

Hah, 나를 속였던 것은 (내가 짧은 int로 설정했을 때) 특정 변수가 결국 아주 작았다고했습니다. 그러나 그 과정에서 더 복잡한 유동 계산의 일부였습니다. –

+0

아, 수정, 짧은 ints 그들을 작성하는 함수에서 매개 변수가 발생했습니다. 오류가 아마 그들에 의해 요구되는 입력 크기를 존중하지 않기 때문에 그것은 쉬워야한다. –

관련 문제