Chciałbym wiedzieć, czy możliwe jest wykrycie delete
błędu skomentowanego poniżej podczas kompilacji? Szczególnie chciałbym usłyszeć o kompilatorze g ++.
ClassTypeA *abc_ptr = new ClassTypeA[100];
abc_ptr[10].data_ = 1;
delete abc_ptr; // error, should be delete []
c++
compiler
error-detection
SebGR
źródło
źródło
std::unique_ptr<ClassTypeA[]>
a potem nie musisz.Odpowiedzi:
Ogólnie kompilator nie może wykryć takich błędów. Przykład: załóżmy, że konstruktor dla pewnej klasy przydziela część danych przy użyciu
new TypeName[]
, ale destruktor błędnie używadelete
zamiastdelete[]
. Jeśli konstruktor i destruktor są zdefiniowane w osobnych jednostkach kompilacyjnych, to skąd kompilator powinien wiedzieć, kiedy kompiluje plik, który definiuje destruktor, że użycie jest niezgodne z użytym w osobnym kompilowanym pliku, który definiuje konstruktor?W odniesieniu do kompilatorów GNU tak nie jest. Jak wspomniano powyżej, nie można tego zrobić w ogólnym przypadku. Kompilator nie musi wykrywać takich niedopasowanych błędów nowego / usuwania, ponieważ jest to niezdefiniowane zachowanie. UB to karta „wyjdź z więzienia” producenta kompilatora.
Narzędzia takie jak valgrind mogą wykrywać tego rodzaju niedopasowania nowe / usuwające, ale robią to w czasie wykonywania. Może istnieć narzędzie do analizy statycznej, które przegląda wszystkie pliki źródłowe, które ostatecznie zostaną skompilowane w celu utworzenia pliku wykonywalnego, ale nie mam takiego narzędzia do analizy statycznej, które wykryłoby ten rodzaj błędu.
źródło
Możesz użyć odpowiednich klas RAII do
delete
. Jest to jedyny bezpieczny sposób, aby to zrobić, a ten błąd jest tylko jednym z bardzo wielu osób, które mogą się nazywaćdelete
.Zawsze używaj klas do zarządzania dynamicznymi dożywotnimi zasobami, a system typów wymusi prawidłowe niszczenie zasobów.
Edycja: „Co jeśli kontrolujesz kod i nie możesz go zmienić?” Jesteś pieprzony
źródło
Ten konkretny błąd - tak. Tego rodzaju błąd ogólnie: niestety nie! Oznaczałoby to przewidywanie przepływu wykonania bez jego wykonania, a nie jest to możliwe w przypadku dowolnych programów. (Dlatego większość kompilatorów nawet nie próbuje wykryć prostych przypadków, takich jak twój przykład).
Dlatego odpowiedź DeadMG jest właściwa: nie próbuj robić tego dobrze, zwracając uwagę - ludzka uwaga jest omylna. Użyj środków podanych w języku i pozwól komputerowi zwrócić uwagę.
źródło
ClassTypeA*
więc można wstawić linię między nowym a usuwanym.if ( rand() % 2 == 1 ) abc_ptr = new ClassTypeA;
Nic w systemie typu statycznego nie pokazuje, czyabc_ptr
wskazuje na tablicę, obiekt dynamiczny, czy częściowo w inny obiekt lub tablicę.abc_ptr
, w przeciwnym razie, w jaki sposób mógłby być w stanie zwolnić odpowiednią ilość pamięci? Dlatego środowisko wykonawcze wie, ile obiektów należy zwolnić.Trywialny przypadek, który pokazujesz, można wykryć w czasie kompilacji, ponieważ tworzenie i niszczenie obiektu są w tym samym zakresie. Zasadniczo usunięcie nie ma tego samego zakresu, ani nawet tego samego pliku źródłowego, co utworzenie. A typ wskaźnika C ++ nie przenosi informacji o tym, czy odwołuje się do pojedynczego obiektu tego typu, czy tablicy, nie mówiąc już o schemacie alokacji. Dlatego nie jest możliwe zdiagnozowanie tego w ogóle podczas kompilacji.
Dlaczego nie zdiagnozować możliwych przypadków specjalnych?
W C ++ istnieją już narzędzia do radzenia sobie z wyciekiem zasobów dynamicznych powiązanych z zakresami, a mianowicie inteligentne wskaźniki i tablice wyższego poziomu (
std::vector
).Nawet jeśli użyjesz prawidłowego
delete
smaku, Twój kod nadal nie jest wyjątkowo bezpieczny. Jeśli kod międzynew[]
idelete[]
kończy się dynamicznym wyjściem, usuwanie nigdy się nie wykonuje.Jeśli chodzi o wykrywanie w czasie wykonywania,
Valgrind
narzędzie dobrze wykrywa je w czasie wykonywania. Zegarek:Oczywiście Valgrind nie działa na wszystkich platformach i nie zawsze jest praktyczne lub możliwe odtworzenie wszystkich sytuacji w czasie wykonywania za pomocą tego narzędzia.
źródło
Kilka trywialnych przykładów wykrywania w czasie kompilacji / analizy statycznej:
Na hoście RHEL7 z
cppcheck 1.77 and 1.49
http://cppcheck.sourceforge.net/
Z
clang++ 3.7.1
na RHEL7Analizator statyczny Clang może również wykryć, kiedy
std::unique_ptr
nie jest przekazywany<char[]>
https://clang-analyzer.llvm.org/
Zaktualizuj poniżej link do pracy, która dodała to do clang, testów i jednego błędu, który znalazłem.
Zostało to dodane do clang with reviews.llvm.org/D4661 - „Wykryj niedopasowane zastosowania„ nowe ”i„ usuń ” .
Testy są w teście / Analiza / NiezgodnośćDeallocator-checker-test.mm
Znalazłem ten otwarty błąd - bugs.llvm.org/show_bug.cgi?id=24819
źródło