2013-07-17 11 views
13

Następujący kod ma zmienną, która może być niezainicjowanymi. Wydaje się, że gcc należy generować ostrzeżenia, ale nie jest:GCC braku ostrzec niezainicjowanego zmiennej

$ cat a.c 
int foo(int b) { 
    int a; 
    if (b) 
    a = 1; 
    return a; 
} 

$ gcc-4.7 -c -Wall -Wmaybe-uninitialized -o a.o ./a.c 
$ gcc-4.7 -v 
Using built-in specs. 
COLLECT_GCC=gcc-4.7 
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper 
Target: x86_64-linux-gnu 
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.3-2ubuntu1~12.04' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu 
Thread model: posix 
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) 

Wszelkie wskazówki, w jaki sposób uzyskać gcc zgłosić zmiennej niezainicjowanej?

+0

jakaś szansa, że ​​kompilator jest wystarczająco inteligentny, aby zobaczyć, że b jest ustawiony na zawsze niezerowe gdzie indziej? –

+0

@MichaelDorgan, tam * nie ma * innego kodu w przykładzie OP. –

+0

Nie złapałem tego. Zakładałem, że bez "głównego" zdefiniowanego, musiał być inny kod ... –

Odpowiedz

10

Wygląda na to, że nie może - patrz this bug report. (I this one, który jest oznaczony jako dupe tego jednego. - to ma identyczny przypadek testowy Twoi) Ponieważ wygląda na to bug root przyczyną jest prawie 10 lat, wydaje się, że nie jest to łatwe do rozwiązania problemem. W rzeczywistości drugi błąd, z którym się łączyłem, ma w dyskusji "frazę, która nigdy nie zostanie naprawiona", więc nie wygląda dobrze.

Jeśli jest to naprawdę ważne dla Ciebie, clangrobi połów to jeden z -Wsometimes-uninitialized, który jest dołączony do -Wall:

a.c:3:7: warning: variable 'a' is used uninitialized whenever 'if' condition is 
     false [-Wsometimes-uninitialized] 
    if (b) 
    ^
a.c:5:10: note: uninitialized use occurs here 
    return a; 
     ^
a.c:3:3: note: remove the 'if' if its condition is always true 
    if (b) 
    ^~~~~~ 
a.c:2:8: note: initialize the variable 'a' to silence this warning 
    int a; 
    ^
     = 0 
1 warning generated. 
+0

Mój clang (wersja 3.0) nie rozpoznaje ani "-Wimimetimes-uninitialized" ani "-Wmaybe-uninitialized". Udało mi się wygenerować powyższe ostrzeżenia za pomocą opcji - Bezwarunkowy-niezainicjowany lub -Wszystko. – clandau

+1

Clang 3.0 jest dość stary. –

4

Problemem jest to, że nie może wiedzieć gcc będziesz wywołać funkcję z zerowy argument. W tym przypadku fakt, że testujesz może być dobrą wskazówką, że zamierzasz to zrobić, ale ogólny przypadek jest o wiele trudniejszy. Rozważmy:

int foo(int b) { 
    int a; 
    switch(b) { 
    case 1: 
    a = 1; 
    break; 
    case 2: 
    a = 0; 
    break; 
    case 3: 
    a = 2; 
    break; 
    } 
    return a; 
} 

Byłoby to całkowicie uzasadnione funkcja którego umowa interfejs jest to, że tylko przekazać 1, 2 lub 3 do niego, a wszelkie „niezainicjowany” ostrzeżenie byłoby w tym przypadku nie może być fałszywy, a tym samym zmniejszyć stosunek sygnału do szumu generowania ostrzeżeń przez kompilator.

Zgadzam się, że byłoby miło, gdyby kompilatory dały lepszą diagnostykę dla takich rzeczy, ale nie jest to łatwe, a ostrzeżenia, które mogą mieć fałszywe alarmy, zawsze są delikatnym balansowaniem pomiędzy zagracającym kodem a obejściem ostrzeżeń i nieudanym łapać błędy.

+0

To jest dokładnie przykład podany w [podręczniku gcc] (http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Warning-Options.html) przy wpisie dla '-Wuninitialized'. Jak to tam mówi, "te ostrzeżenia są opcjonalne" z tego powodu. Najwyraźniej jest to błędne i nie ma opcji, aby uzyskać ostrzeżenie. – clandau

+1

W takich przypadkach z przyjemnością przyjmuję fałszywe pozytywne, alias fałszywe ostrzeżenie, szczególnie gdy wyraźnie włączono opcję "-Wuninitialized" lub "-Wall". Znacznie lepsze niż obecnie wszystkie fałszywe negatywy (tzn. Brak ostrzeżenia, gdy powinno być jedno). Prawdopodobnie, jeśli kompilator nie może tego stwierdzić w sposób niezawodny, to nie może też niezawodnie człowieka, więc zmienna powinna mieć intialiser. –

1

uninitializedTest.c:

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


int main(void) 
{ 
    int result; 
    if(rand()) 
     result = 1; 

    printf("%d\n", result); 

    return 0; 
} 

Oto kilka przebiega testowe:

$ avr-gcc -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-4.2 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-4.0 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
uninitializedTest.c: In function ‘main’: 
uninitializedTest.c:32: warning: ‘result’ may be used uninitialized in this function 

$ gcc-4.2 -Os -Wmaybe-uninitialized -o uninitializedTest uninitializedTest.c 
cc1: error: unrecognized command line option "-Wmaybe-uninitialized" 
$ gcc-4.2 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-mp-4.8 -Os -Wuninitialized -o uninitializedTest uninitializedTest.c 
$ gcc-mp-4.8 -Os -Wmaybe-uninitialized -o uninitializedTest uninitializedTest.c 

AVR GCC 4,8 (niewykrytych także z avr-gcc-4.4.5)

Wygląda na to, że gcc-4.0 miał zdolność rozpoznania problemu.

$ gcc-4.0 -v 
Configured with: /var/tmp/gcc/gcc-5493~1/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --program-prefix= --host=powerpc-apple-darwin9 --target=powerpc-apple-darwin9 
Thread model: posix 
gcc version 4.0.1 (Apple Inc. build 5493) 

Czy ... Czy dodatek Apple jest specyficzny, że posiadają licencję? A może właśnie dlatego Apple odchodzi od open source ... Czy to możliwe, że naprawili dziesięcioletni błąd, a społeczność gcc go nie zaakceptowała?

1

Musisz włączyć optymalizacje jakiegoś rodzaju. Ponownie skompiluj swój przykład za pomocą -O2, a pojawi się ostrzeżenie.

Ponieważ wymaga to analizy ścieżek kodu i jest to dość kosztowne obliczenia, GCC pozwala ją tylko wtedy, gdy poproszony o optymalizacji kodu.

+0

To zadziałało dla mnie. Niefortunne, że nie mogę uzyskać tego zachowania bez -O2. –