컴파일러가 명백히 초기화되지 않은 변수를 감지하지 못함
내가 사용해 본 모든 C 컴파일러는 아래 코드 스니펫에서 초기화되지 않은 변수를 감지하지 못합니다.하지만 이 사건은 명백하다.
이 스니펫의 기능에 대해서는 신경 쓰지 않아도 됩니다.이건 진짜 코드가 아니라서 이 문제를 조사하기 위해 제거했어요.
BOOL NearEqual (int tauxprecis, int max, int value)
{
int tauxtrouve; // Not initialized at this point
int totaldiff; // Not initialized at this point
for (int i = 0; i < max; i++)
{
if (2 < totaldiff) // At this point totaldiff is not initialized
{
totaldiff = 2;
tauxtrouve = value; // Commenting this line out will produce warning
}
}
return tauxtrouve == tauxprecis ; // At this point tauxtrouve is potentially
// not initialized.
}
한편, 제가 코멘트를 하면tauxtrouve = value ;
, , 이 , , , , 。"local variable 'tauxtrouve' used without having been initialized"
고합니니다다
다음 컴파일러를 사용해 봤습니다.
- GCC 4.9.2 (벽면 - WEXTra 포함)
- Microsoft Visual C++ 2013(모든 경고 사용)
이 변수가 초기화되지 않은 것이 명백하다는 것은 과장되어 있습니다.패스 분석에는 시간이 걸리고 컴파일러 벤더는 이 기능을 실장하고 싶지 않거나 시간이 너무 많이 걸린다고 생각하거나 명시적으로 동의하지 않았을 뿐입니다.
를 들어, 「」를 ,clang
:
$ clang -Wall -Wextra -c obvious.c
$ clang -Wall -Wextra --analyze -c obvious.c
obvious.c:9:11: warning: The right operand of '<' is a garbage value
if (2 < totaldiff) // at this point totaldiff is not initialized
^ ~~~~~~~~~
obvious.c:16:21: warning: The left operand of '==' is a garbage value
return tauxtrouve == tauxprecis ; // at this point tauxtrouve is potentially
~~~~~~~~~~ ^
2 warnings generated.
이러한 순진한 예에서는 실행 시간의 차이는 무시할 수 있습니다.하지만 수천 개의 행과 수십 개의 함수로 이루어진 변환 유닛을 상상해 보십시오. 각 유닛에는 루프가 있고 무거운 네스팅이 있습니다.경로의 수는 빠르게 복합되어 해당 비교 전에 할당이 발생하는지 여부를 루프를 통해 처음 반복하는지 여부를 분석하는데 큰 부담이 됩니다.
편집: @Matthieu는 LLVM/clang을 사용하면 IR에서 사용되는 SSA 표기법 때문에 초기화되지 않은 값을 찾기 위해 필요한 경로 분석이 복잡해지지 않는다고 지적합니다.
은 「처럼단 as it it」처럼 않았다.-S -emit-llvm
기대했던 대로였지만 그가 설명한 SSA 통지 결과를 찾았습니다.LLVM IR의 Mattheu에 관한 것입니다.
" "를 사용: "clang
--analyze
''를 gcc
debugs.debugs.debugsggs
; Function Attrs: nounwind uwtable
define i32 @NearEqual(i32 %tauxprecis, i32 %max, i32 %value) #0 {
br label %1
; <label>:1 ; preds = %7, %0
%tauxtrouve.0 = phi i32 [ undef, %0 ], [ %tauxtrouve.1, %7 ]
%i.0 = phi i32 [ 0, %0 ], [ %8, %7 ]
%2 = icmp slt i32 %i.0, %max
br i1 %2, label %3, label %9
; <label>:3 ; preds = %1
%4 = icmp slt i32 2, 2
br i1 %4, label %5, label %6
; <label>:5 ; preds = %3
br label %6
; <label>:6 ; preds = %5, %3
%tauxtrouve.1 = phi i32 [ %value, %5 ], [ %tauxtrouve.0, %3 ]
br label %7
; <label>:7 ; preds = %6
%8 = add nsw i32 %i.0, 1
br label %1
; <label>:9 ; preds = %1
%10 = icmp eq i32 %tauxtrouve.0, %tauxprecis
%11 = zext i1 %10 to i32
ret i32 %11
}
네, 초기화되지 않은 변수에 대한 경고가 표시되지만 GCC 버그입니다.다음은 예를 제시하겠습니다.
unsigned bmp_iter_set ();
int something (void);
void bitmap_print_value_set (void)
{
unsigned first;
for (; bmp_iter_set (); )
{
if (!first)
something ();
first = 0;
}
}
그리고 진단은-O2 -W -Wall
.
안타깝게도 올해는 이 벌레가 발견된 지 10년이 되는 해에요!
이 답변은 GCC만을 대상으로 합니다.
자세한 조사와 코멘트를 실시한 결과, 지금까지의 답변보다 더 많은 것이 진행되고 있습니다.이 코드 스니펫에는 초기화되지 않은2개의 변수가 있으며 각각 다른 이유로 검출되지 않습니다.
첫 번째로, GCC에 관한 문서-Wuninitialized
을 사용하다
이러한 경고는 최적화에 따라 달라지기 때문에 경고가 발생하는 정확한 변수 또는 요소는 사용되는 GCC의 정확한 최적화 옵션 및 버전에 따라 달라집니다.
이전 버전의 GCC 매뉴얼에서는 이를 보다 명확하게 기술하고 있습니다.다음은 GCC 3.3.6 매뉴얼에서 발췌한 것입니다.
이러한 경고는 컴파일을 최적화할 때만 계산되는 데이터 흐름 정보가 필요하기 때문에 컴파일을 최적화할 때만 가능합니다.O를 지정하지 않으면 이러한 경고가 표시되지 않습니다.
되지 않은 없이 경고 될 수 .-O
그래도 훨씬 더 좋은 결과를 얻을 수 있습니다.
, 「」를 사용해 를 정리하면,gcc -std=c99 -Wall -O
해했습습니니다
foo.c: In function ‘NearEqual’:
foo.c:15:21: warning: ‘tauxtrouve’ is used uninitialized in this function [-Wuninitialized]
return tauxtrouve == tauxprecis ; // at this point tauxtrouve is potentially
^
(이것은 GCC 4.8.2의 경우입니다.4.9.x 가 인스톨 되어 있지 않기 때문입니다만, 원칙은 같습니다).
에, 「Detect」가 「」라고 하는 사실을 검출합니다.tauxtrouve
초기화되지 않았습니다.
「」의 으로, 하면, 「alizer」는 「alizer」로 바뀝니다.tauxtrouve
(용도는 )totaldiff
、 。gcc -std=c99 -Wall -O
는 경고 없이 그것을 받아들입니다.이는 해커의 답변에서 인용된 "버그"의 한 예로 보입니다.
이것이 정말로 버그로 간주되어야 하는지에 대해서는 의문이 있습니다.GCC는 미초기화 변수의 모든 가능한 인스턴스를 검출할 것을 약속하지 않습니다.사실, 그것은 완벽한 정확성을 가질 수 없습니다. 왜냐하면 그것이 멈추는 문제이기 때문입니다.따라서 이와 같은 경고는 작동 시 도움이 될 수 있지만 경고가 없다고 해서 코드에 초기화되지 않은 변수가 없는 것은 아닙니다.그들은 당신의 코드를 주의 깊게 체크하기 위한 대체물이 아닙니다.
hackks에 의해 링크된 버그리포트에서는 버그가 수정 가능한지, 또는 이 특정 구조를 검출하려고 하면 다른 올바른 코드에 대해 허용할 수 없는 잘못된 긍정률이 발생할지에 대해 많은 논의가 이루어지고 있습니다.
마이클, 어떤 버전의 Visual Studio 2013을 사용해 보셨는지는 모르겠지만, 확실히 구식입니다.Visual Studio 2013 Update 4는 처음 사용할 때 다음 오류 메시지를 올바르게 생성합니다.totaldiff
:
error C4700: uninitialized local variable 'totaldiff' used
작업 환경의 갱신을 검토해야 합니다.
덧붙여서, 여기 에디터에서 직접 볼 수 있는 내용이 있습니다.
언급URL : https://stackoverflow.com/questions/27063678/compiler-not-detecting-obviously-uninitialized-variable
'programing' 카테고리의 다른 글
Vuej 및 부트스트랩 Vue에서 행 편집 (0) | 2022.06.20 |
---|---|
Java8에서 람다를 사용하여 null이 아닌 경우에만 값 필터링 (0) | 2022.06.20 |
Vue.js - 입력, v-model 및 계산된 속성 (0) | 2022.06.20 |
vuex 모듈 내에서 작업/변화를 청취합니다. (0) | 2022.06.19 |
구조체를 0으로 초기화 (0) | 2022.06.19 |