4

선사 시대는 : C에서 분할을 테스트에도 불구하고 0으로 프로그램 제기 부문 ++ :나누기 ++ 2015

우리는 단지 우리가 문제를 발견 그 후 VC++ 2008 오른쪽에서 ++ 2015 VC에 우리의 개발 환경을 전환 한 암호.

테스트 코드 : 기본 릴리스 옵션 VC++ 2015 업데이트 3 또는 VC++ 2017 컴파일

#include <cstdlib> 

int test(int n, int test_for_zero) 
{ 
    int result = 0; 
    for (int i = 0; i < n; ++i) { 

     if (test_for_zero) 
      result += rand() >> ((8 % test_for_zero) * test_for_zero); 
    } 

    return result; 
} 

int main() 
{ 
    return test(rand(), rand() & 0x80000000); 
} 

, 그것은 0으로 나누기를 제기 실행에. VC 2008에 의해 컴파일 된 잘 실행됩니다.

분석 :

; 6 : for (int i = 0; i < n; ++i) { 

    test edi, edi 
    jle SHORT [email protected] 

; 7 : 
; 8 :  if (test_for_zero) 
; 9 :   result += rand() >> ((8 % test_for_zero) * test_for_zero); 

    mov ecx, DWORD PTR _test_for_zero$1$[ebp] 
    mov eax, 8 
    cdq 
    idiv ecx ; <== IT'S HERE, IDIV BEFORE CHECKING FOR ZERO 
    mov eax, edx 
    imul eax, ecx 
    mov DWORD PTR tv147[ebp], eax 
    test ecx, ecx 
    je SHORT [email protected] 
[email protected]: 
    call ebx 
    mov ecx, DWORD PTR tv147[ebp] 
    sar eax, cl 
    add esi, eax 
    sub edi, 1 
    jne SHORT [email protected] 

컴파일러는 루프 본문에서 일정 부분 ((8 % test_for_zero) * test_for_zero) 소요 단지 분할하기 전에 테스트 test_for_zero에 대해 잊어 버려. 분명히 컴파일러 작업을 수행하는 것만으로 장소에서 쉽게 수정할 수 있습니다.

나는 여러 컴파일러 옵션 (예 : -d2SSAOptimizer--Oxx)을 사용했지만이 문제를 해결할 수있는 유일한 방법은 -Od입니다.

질문 :

  1. 는 버그인지? VC 2008 이후로 C++ 표준이 크게 변경되었으므로 이런 영향을받을 수 있습니까?
  2. 주 질문은 컴파일러 옵션을 통해 문제를 해결할 수있는 해결 방법이 있습니까?
+0

이 질문에 대한 답변을하지 않지만 해당 변수가 0이면 루프를 건너 뛰는 것이 더 합리적이지 않습니까? 당신은 결코 그것을 바꿀 수 없기 때문에, 하나의 반복에서 0이라면, 그것들 모두에 대해 0이 될 것이고,이 경우 루프는 아무것도하지 않는다. – Carcigenicate

+0

또한 숫자가 진실인지 확인하는 대신 0을 확인하기 위해 조건을 변경하면 어떻게됩니까? 상관 없지만이 오류는 의미가 없습니다. – Carcigenicate

+0

중괄호도 부족할 수 있습니다. Idk는 정확히 어떻게 C++이 그런 구문을 파싱 하는지를 설명합니다. 중괄호를 추가하십시오. – Carcigenicate

답변

1

보고서 및 작은 repro (특히 Visual Studio 내에서의 피드백) 덕분에 문제를 격리하는 데 매우 도움이되었습니다.

이것은 실제로 컴파일러 자체의 버그입니다. 특히 "불변 코드 모션"최적화 단계의 안전성 검사입니다. 이 문제는 VS 15.7에 나타나야합니다. 지금은

는 가장 쉬운 해결 방법은 https://docs.microsoft.com/en-us/cpp/preprocessor/optimize 통해이 코드 패턴이 기능 최적화를 비활성화하는 것입니다 : 불행하게도이 최적화 패스가 최적화에 직접 연결되어

#pragma optimize("", off) 
    <Function containing code with this loop> 
    #pragma optimize("", on) 

을, 그래서 컴파일러 옵션은 완전히 외부 없다 발견 한 것처럼 최적화 도구 (-Od)를 사용하지 않도록 설정하십시오.